Add helper functions to encode and decode L3 messages
Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
This commit is contained in:
parent
10444c84e6
commit
45a0d3b856
|
@ -149,6 +149,7 @@
|
|||
#define CAUSE_NORMALUNSPECIFIED 31
|
||||
#define CAUSE_NO_CHANNEL 34
|
||||
#define CAUSE_TEMPORARY_FAILURE 41
|
||||
#define CAUSE_REQUESTED_CHANNEL 44
|
||||
#define CAUSE_RESOURCES_UNAVAIL 47
|
||||
#define CAUSE_INVALID_CALLREF 81
|
||||
#define CAUSE_INCOMPATIBLE_DEST 88
|
||||
|
@ -162,15 +163,6 @@
|
|||
|
||||
#define NO_CAUSE 254
|
||||
|
||||
/*
|
||||
* Progress values
|
||||
*/
|
||||
#define PROGRESS_NOT_E2E_ISDN 1
|
||||
#define PROGRESS_DEST_NOT_ISDN 2
|
||||
#define PROGRESS_ORIG_NOT_ISDN 3
|
||||
#define PROGRESS_RET_TO_ISDN 4
|
||||
#define PROGRESS_TONE 8
|
||||
|
||||
/*
|
||||
* Parser error codes
|
||||
*/
|
||||
|
@ -181,6 +173,118 @@
|
|||
#define Q931_ERROR_IELEN 0x100000
|
||||
#define Q931_ERROR_UNKNOWN 0x200000
|
||||
#define Q931_ERROR_COMPREH 0x400000
|
||||
#define Q931_ERROR_IESEQ 0x800000 /* do not carein our implementation */
|
||||
#define Q931_ERROR_IESEQ 0x800000 /* do not care in our implementation */
|
||||
|
||||
/* Bearer capability */
|
||||
#define Q931_CAP_SPEECH 0x00
|
||||
#define Q931_CAP_UNRES_DIGITAL 0x08
|
||||
#define Q931_CAP_RES_DIGITAL 0x09
|
||||
#define Q931_CAP_3KHZ_AUDIO 0x10
|
||||
#define Q931_CAP_7KHZ_AUDIO 0x11
|
||||
#define Q931_CAP_VIDEO 0x18
|
||||
|
||||
/* Bearer L1 user info */
|
||||
#define Q931_L1INFO_V110 0x01
|
||||
#define Q931_L1INFO_ULAW 0x02
|
||||
#define Q931_L1INFO_ALAW 0x03
|
||||
#define Q931_L1INFO_G721 0x04
|
||||
#define Q931_L1INFO_G722_5 0x05
|
||||
#define Q931_L1INFO_G7XX_VIDEO 0x06
|
||||
#define Q931_L1INFO_NONE_CCITT 0x07
|
||||
#define Q931_L1INFO_V120 0x08
|
||||
#define Q931_L1INFO_X31 0x09
|
||||
|
||||
struct misdn_channel_info {
|
||||
unsigned char nr; /* channel number/slot or special */
|
||||
unsigned char flags; /* exclusiv, not Basic, ANY, NONE */
|
||||
unsigned char type; /* B-channel, D-channel, H0, H11, H12 */
|
||||
unsigned char ctrl; /* Allocated, updated, needsend, sent */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* special channel number defines
|
||||
*/
|
||||
#define MI_CHAN_ANY 0xff
|
||||
#define MI_CHAN_NONE 0xfe
|
||||
#define MI_CHAN_DCHANNEL 0xfd
|
||||
|
||||
#define MI_CHAN_FLG_NONE 0x01
|
||||
#define MI_CHAN_FLG_ANY 0x02
|
||||
#define MI_CHAN_FLG_DCHANNEL 0x04
|
||||
#define MI_CHAN_FLG_EXCLUSIVE 0x08
|
||||
#define MI_CHAN_FLG_OTHER_IF 0x20
|
||||
|
||||
#define MI_CHAN_TYP_NONE 0
|
||||
#define MI_CHAN_TYP_B 1
|
||||
#define MI_CHAN_TYP_D 2
|
||||
#define MI_CHAN_TYP_H0 3
|
||||
#define MI_CHAN_TYP_H11 4
|
||||
#define MI_CHAN_TYP_H12 5
|
||||
|
||||
#define MI_CHAN_CTRL_UPDATED 0x01
|
||||
#define MI_CHAN_CTRL_NEEDSEND 0x02
|
||||
#define MI_CHAN_CTRL_SENT 0x04
|
||||
#define MI_CHAN_CTRL_ALLOCATED 0x10
|
||||
#define MI_CHAN_CTRL_DOWN 0x20
|
||||
|
||||
/* progress info */
|
||||
struct misdn_progress_info {
|
||||
unsigned char loc; /* location, octet 3 */
|
||||
unsigned char desc; /* description, octet 3 */
|
||||
unsigned char resv; /* reserved */
|
||||
unsigned char ctrl; /* ctrl info flags */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Q931 location
|
||||
*/
|
||||
#define Q931_LOC_USER 0
|
||||
#define Q931_LOC_PRVN_LOCUSER 1
|
||||
#define Q931_LOC_PUBN_LOCUSER 2
|
||||
#define Q931_LOC_PUBN_RMTUSER 4
|
||||
#define Q931_LOC_PRVN_RMTUSER 5
|
||||
#define Q931_LOC_INTERNATIONAL 7
|
||||
|
||||
/*
|
||||
* Progress values
|
||||
*/
|
||||
#define PROGRESS_NOT_E2E_ISDN 1
|
||||
#define PROGRESS_DEST_NOT_ISDN 2
|
||||
#define PROGRESS_ORIG_NOT_ISDN 3
|
||||
#define PROGRESS_RET_TO_ISDN 4
|
||||
#define PROGRESS_INBAND 8
|
||||
|
||||
/* Progress control flags */
|
||||
#define MI_PROG_CTRL_UPDATED 0x01
|
||||
#define MI_PROG_CTRL_NEEDSEND 0x02
|
||||
#define MI_PROG_CTRL_SENT 0x04
|
||||
|
||||
|
||||
/* Common IE encode helpers */
|
||||
struct l3_msg;
|
||||
|
||||
extern int mi_encode_bearer(struct l3_msg *, unsigned int, unsigned int, unsigned int, unsigned int);
|
||||
extern int mi_encode_channel_id(struct l3_msg *, struct misdn_channel_info *);
|
||||
extern int mi_encode_calling_nr(struct l3_msg *, char *, int, unsigned int, unsigned int, unsigned int);
|
||||
extern int mi_encode_called_nr(struct l3_msg *, char *, unsigned int, unsigned int);
|
||||
extern int mi_encode_redir_nr(struct l3_msg *, char *, int, unsigned int, unsigned int, unsigned int, int);
|
||||
extern int mi_encode_useruser(struct l3_msg *, int, int, char *);
|
||||
extern int mi_encode_cause(struct l3_msg *l, int cause, int, int, unsigned char *);
|
||||
extern int mi_encode_progress(struct l3_msg *, struct misdn_progress_info *);
|
||||
extern int mi_encode_date(struct l3_msg *, time_t);
|
||||
|
||||
/* Common IE decode helpers */
|
||||
extern int mi_decode_progress(struct l3_msg *, struct misdn_progress_info *);
|
||||
extern int mi_decode_bearer_capability(struct l3_msg *, int *, int *, int *, int *, int *,
|
||||
int *, int *, int *, int *, int *, int *, int *, int *, int *);
|
||||
extern int mi_decode_cause(struct l3_msg *, int *, int *, int *, int *, int *, unsigned char *);
|
||||
extern int mi_decode_channel_id(struct l3_msg *, struct misdn_channel_info *);
|
||||
extern int mi_decode_calling_nr(struct l3_msg *, int *, int *, int *, int *, char *);
|
||||
extern int mi_decode_called_nr(struct l3_msg *, int *, int *, char *);
|
||||
extern int mi_decode_display(struct l3_msg *, char *, int);
|
||||
extern int mi_decode_useruser(struct l3_msg *, int *, int *, char *, int);
|
||||
|
||||
/* some print helpers */
|
||||
extern const char *mi_bearer2str(int);
|
||||
extern const char *mi_msg_type2str(unsigned int);
|
||||
#endif
|
||||
|
|
628
lib/q931.c
628
lib/q931.c
|
@ -5,6 +5,7 @@
|
|||
* Author Karsten Keil <kkeil@novell.com>
|
||||
*
|
||||
* Copyright 2007 by Karsten Keil <kkeil@novell.com>
|
||||
* Copyright 2010 by Karsten Keil <kkeil@linux-pingi.de>
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
|
||||
|
@ -202,7 +203,7 @@ int
|
|||
assembleQ931(l3_process_t *pc, struct l3_msg *l3m)
|
||||
{
|
||||
struct mbuffer *mb = container_of(l3m, struct mbuffer, l3);
|
||||
unsigned char ie = 0, **v_ie = &l3m->bearer_capability;
|
||||
unsigned char ie, **v_ie = &l3m->bearer_capability;
|
||||
int i, l, eidx = -1;
|
||||
|
||||
mb->data = mb->tail = mb->head;
|
||||
|
@ -302,3 +303,628 @@ add_layer3_ie(struct l3_msg *l3m, unsigned char ie, int len, unsigned char *data
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* helper functions to encode common Q931 info elements */
|
||||
|
||||
int
|
||||
mi_encode_bearer(struct l3_msg *l3m, unsigned int capability, unsigned int l1user, unsigned int mode, unsigned int rate)
|
||||
{
|
||||
unsigned char ie[8];
|
||||
int l = 2, multi = -1, user;
|
||||
|
||||
user = l1user;
|
||||
|
||||
switch (capability) {
|
||||
case Q931_CAP_UNRES_DIGITAL:
|
||||
user = -1;
|
||||
break;
|
||||
case Q931_CAP_RES_DIGITAL:
|
||||
user = -1;
|
||||
break;
|
||||
default:
|
||||
rate = 0x10;
|
||||
mode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ie[0] = 0x80 | capability;
|
||||
ie[1] = 0x80 | (mode << 5) | rate;
|
||||
if (multi >= 0) {
|
||||
ie[2] = 0x80 | multi;
|
||||
l++;
|
||||
}
|
||||
if (user >= 0) {
|
||||
ie[l] = 0xa0 | user;
|
||||
l++;
|
||||
}
|
||||
|
||||
return add_layer3_ie(l3m, IE_BEARER, l, ie);
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_channel_id(struct l3_msg *l3m, struct misdn_channel_info *ci)
|
||||
{
|
||||
unsigned char ie[3];
|
||||
int ret, l, excl = 1;
|
||||
|
||||
if (ci->ctrl & MI_CHAN_CTRL_SENT) /* already sent */
|
||||
return 0;
|
||||
|
||||
if (!(ci->ctrl & MI_CHAN_CTRL_NEEDSEND)) /* we do not need send the ie */
|
||||
return 0;
|
||||
|
||||
if (ci->nr == MI_CHAN_ANY || ci->nr == MI_CHAN_NONE ||
|
||||
(ci->flags & MI_CHAN_FLG_NONE) || (ci->flags & MI_CHAN_FLG_ANY))
|
||||
excl = 0;
|
||||
|
||||
if (ci->flags & MI_CHAN_FLG_OTHER_IF) { /* PRI */
|
||||
if (ci->nr == MI_CHAN_NONE)
|
||||
return 0; /* IE is not included */
|
||||
else if (ci->nr == MI_CHAN_ANY || (ci->flags & MI_CHAN_FLG_ANY)) {
|
||||
l = 1;
|
||||
ie[0] = 0x80 | 0x20 | 0x03;
|
||||
} else {
|
||||
l = 3;
|
||||
ie[0] = 0x80 | 0x20 | (excl << 3) | 1;
|
||||
if (ci->type & MI_CHAN_TYP_H0)
|
||||
ie[1] = 0x86;
|
||||
else if (ci->type & MI_CHAN_TYP_H11)
|
||||
ie[1] = 0x88;
|
||||
else if (ci->type & MI_CHAN_TYP_H12)
|
||||
ie[1] = 0x89;
|
||||
else /* default B-channel */
|
||||
ie[1] = 0x83;
|
||||
ie[2] = 0x80 | ci->nr;
|
||||
}
|
||||
} else { /* BRI */
|
||||
l = 1;
|
||||
if (ci->nr == MI_CHAN_DCHANNEL || ci->type == MI_CHAN_TYP_D || (ci->flags & MI_CHAN_FLG_DCHANNEL))
|
||||
ie[0] = MI_CHAN_FLG_DCHANNEL;
|
||||
else if (ci->nr == MI_CHAN_ANY || (ci->flags & MI_CHAN_FLG_ANY))
|
||||
ie[0] = 3;
|
||||
else if (ci->nr == MI_CHAN_NONE || (ci->flags & MI_CHAN_FLG_NONE))
|
||||
ie[0] = 0;
|
||||
else
|
||||
ie[0] = ci->nr & 3;
|
||||
ie[0] |= 0x80 | (excl << 3);
|
||||
}
|
||||
ret = add_layer3_ie(l3m, IE_CHANNEL_ID, l, ie);
|
||||
if (!ret) {
|
||||
ci->ctrl |= MI_CHAN_CTRL_SENT;
|
||||
ci->ctrl &= ~MI_CHAN_CTRL_SENT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_calling_nr(struct l3_msg *l3m, char *nr, int pres, unsigned int screen, unsigned int type, unsigned int plan)
|
||||
{
|
||||
unsigned char ie[32];
|
||||
int l;
|
||||
|
||||
if (pres < 0 && screen < 0 && (nr == NULL || *nr == 0)) /* defaults, no number provided */
|
||||
return 0;
|
||||
if (nr && strlen(nr) > 30)
|
||||
return -EINVAL;
|
||||
|
||||
if (pres >= 0) {
|
||||
l = 2;
|
||||
ie[0] = (type << 4) | plan;
|
||||
ie[1] = 0x80 | (pres << 5) | screen;
|
||||
} else {
|
||||
l = 1;
|
||||
ie[0] = 0x80 | (type << 4) | plan;
|
||||
}
|
||||
if (nr && *nr) {
|
||||
strncpy((char *)&ie[l], nr, 30);
|
||||
l += strlen(nr);
|
||||
}
|
||||
return add_layer3_ie(l3m, IE_CALLING_PN, l, ie);
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_called_nr(struct l3_msg *l3m, char *nr, unsigned int type, unsigned int plan)
|
||||
{
|
||||
unsigned char ie[32];
|
||||
int l;
|
||||
|
||||
if (nr == NULL || *nr == 0) /* not provided */
|
||||
return 0;
|
||||
if (nr && strlen(nr) > 30)
|
||||
return -EINVAL;
|
||||
|
||||
l = 1;
|
||||
ie[0] = 0x80 | (type << 4) | plan;
|
||||
if (nr && *nr) {
|
||||
strncpy((char *)&ie[l], nr, 30);
|
||||
l += strlen(nr);
|
||||
}
|
||||
return add_layer3_ie(l3m, IE_CALLED_PN, l, ie);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mi_encode_redir_nr(struct l3_msg *l3m, char *nr, int pres, unsigned int screen, unsigned int type, unsigned int plan, int reason)
|
||||
{
|
||||
unsigned char ie[34];
|
||||
int l;
|
||||
|
||||
if (nr == NULL || *nr == 0) /* not provided */
|
||||
return 0;
|
||||
if (nr && strlen(nr) > 30)
|
||||
return -EINVAL;
|
||||
|
||||
if (pres >= 0) {
|
||||
l = 2;
|
||||
ie[0] = (type << 4) | plan;
|
||||
ie[1] = (pres << 5) | screen;
|
||||
if (reason >= 0) {
|
||||
l++;
|
||||
ie[2] = 0x80 | reason;
|
||||
} else
|
||||
ie[1] |= 0x80;
|
||||
} else {
|
||||
l = 1;
|
||||
ie[0] = 0x80 | (type << 4) | plan;
|
||||
}
|
||||
if (nr && *nr) {
|
||||
strncpy((char *)&ie[l], nr, 30);
|
||||
l += strlen(nr);
|
||||
}
|
||||
return add_layer3_ie(l3m, IE_REDIR_NR, l, ie);
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_useruser(struct l3_msg *l3m, int protocol, int len, char *data)
|
||||
{
|
||||
unsigned char ie[256];
|
||||
|
||||
if (len <= 0) /* not included */
|
||||
return 0;
|
||||
if (len > 250 || !data)
|
||||
return -EINVAL;
|
||||
if (protocol<0 || protocol>127)
|
||||
return -EINVAL;
|
||||
ie[0] = protocol & 0xff;
|
||||
memcpy(&ie[1], data, len);
|
||||
return add_layer3_ie(l3m, IE_USER_USER, len + 1, ie);
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_cause(struct l3_msg *l3m, int cause, int loc, int dlen, unsigned char *diag)
|
||||
{
|
||||
unsigned char ie[32];
|
||||
int l;
|
||||
|
||||
if (cause < 0 || cause == NO_CAUSE) /* not included */
|
||||
return 0;
|
||||
if (cause > 127)
|
||||
return -EINVAL;
|
||||
if (loc < 0 || loc > 7)
|
||||
return -EINVAL;
|
||||
if (dlen > 30)
|
||||
return -EINVAL;
|
||||
if (dlen && !diag)
|
||||
return -EINVAL;
|
||||
l = 2 + dlen;
|
||||
ie[0] = 0x80 | loc;
|
||||
ie[1] = 0x80 | cause;
|
||||
if (dlen)
|
||||
memcpy(&ie[2], diag, dlen);
|
||||
return add_layer3_ie(l3m, IE_CAUSE, l, ie);
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_progress(struct l3_msg *l3m, struct misdn_progress_info *prg)
|
||||
{
|
||||
unsigned char ie[2];
|
||||
int ret;
|
||||
|
||||
if (prg->ctrl & MI_PROG_CTRL_SENT)
|
||||
return 0;
|
||||
|
||||
if (!(prg->ctrl & MI_PROG_CTRL_NEEDSEND))
|
||||
return 0;
|
||||
|
||||
ie[0] = 0x80 | prg->loc;
|
||||
ie[1] = 0x80 | prg->desc;
|
||||
|
||||
ret = add_layer3_ie(l3m, IE_PROGRESS, 2, ie);
|
||||
if (!ret) {
|
||||
prg->ctrl |= MI_PROG_CTRL_SENT;
|
||||
prg->ctrl &= ~MI_PROG_CTRL_SENT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mi_encode_date(struct l3_msg *l3m, time_t ti)
|
||||
{
|
||||
unsigned char ie[5];
|
||||
struct tm tm;
|
||||
|
||||
localtime_r(&ti, &tm);
|
||||
ie[0] = tm.tm_year % 100;
|
||||
ie[1] = tm.tm_mon + 1;
|
||||
ie[2] = tm.tm_mday;
|
||||
ie[3] = tm.tm_hour;
|
||||
ie[4] = tm.tm_min;
|
||||
return add_layer3_ie(l3m, IE_DATE, 5, ie);
|
||||
}
|
||||
|
||||
/* helper functions to decode common IE */
|
||||
|
||||
#define _ASSIGN_PVAL(p, v) if (p) *p = (v)
|
||||
|
||||
int
|
||||
mi_decode_progress(struct l3_msg *l3m, struct misdn_progress_info *progress)
|
||||
{
|
||||
struct misdn_progress_info prg;
|
||||
|
||||
if (l3m == NULL || !l3m->progress)
|
||||
return 0;
|
||||
|
||||
if (l3m->progress[0] < 2)
|
||||
return -EINVAL;
|
||||
prg.loc = l3m->progress[1] & 0x7f;
|
||||
prg.desc = l3m->progress[2] & 0x7f;
|
||||
prg.ctrl = MI_PROG_CTRL_UPDATED;
|
||||
_ASSIGN_PVAL(progress, prg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_bearer_capability(struct l3_msg *l3m, int *coding, int *capability, int *mode, int *rate,
|
||||
int *oct_4a, int *oct_4b, int *oct_5, int *oct_5a, int *oct_5b1,
|
||||
int *oct_5b2, int *oct_5c, int *oct_5d, int *oct_6, int *oct_7)
|
||||
{
|
||||
int opt[10];
|
||||
int i,j;
|
||||
enum {
|
||||
octet_4a = 0,
|
||||
octet_4b = 1,
|
||||
octet_5 = 2,
|
||||
octet_5a = 3,
|
||||
octet_5b1 = 4,
|
||||
octet_5b2 = 5,
|
||||
octet_5c = 6,
|
||||
octet_5d = 7,
|
||||
octet_6 = 8,
|
||||
octet_7 = 9
|
||||
};
|
||||
|
||||
if (!l3m->bearer_capability || *l3m->bearer_capability < 2)
|
||||
return -EINVAL;
|
||||
_ASSIGN_PVAL(coding, (l3m->bearer_capability[1] & 0x60) >> 5);
|
||||
_ASSIGN_PVAL(capability, l3m->bearer_capability[1] & 0x1f);
|
||||
_ASSIGN_PVAL(mode, (l3m->bearer_capability[2] & 0x60) >> 5);
|
||||
_ASSIGN_PVAL(rate, l3m->bearer_capability[2] & 0x1f);
|
||||
|
||||
/* Now the optional octets */
|
||||
for (j = 0; j < 10; j++)
|
||||
opt[j] = -1;
|
||||
i = 2;
|
||||
if (*l3m->bearer_capability <= i)
|
||||
goto done;
|
||||
if (!(l3m->bearer_capability[i] & 0x80)) {
|
||||
i++;
|
||||
j = octet_4a;
|
||||
opt[j] = l3m->bearer_capability[i];
|
||||
if (*l3m->bearer_capability <= i)
|
||||
goto done;
|
||||
j++; /* octet4b */
|
||||
if (!(l3m->bearer_capability[i] & 0x80)) {
|
||||
i++;
|
||||
opt[j] = l3m->bearer_capability[i];
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if (*l3m->bearer_capability < i)
|
||||
goto done;
|
||||
opt[octet_5] = l3m->bearer_capability[i];
|
||||
if (*l3m->bearer_capability <= i)
|
||||
goto done;
|
||||
j = octet_5a;
|
||||
while (j <= octet_5d && *l3m->bearer_capability > i) {
|
||||
if (l3m->bearer_capability[i] & 0x80)
|
||||
break;
|
||||
i++;
|
||||
opt[j] = l3m->bearer_capability[i];
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
if (*l3m->bearer_capability < i)
|
||||
goto done;
|
||||
opt[octet_6] = l3m->bearer_capability[i];
|
||||
i++;
|
||||
if (*l3m->bearer_capability < i)
|
||||
goto done;
|
||||
opt[octet_7] = l3m->bearer_capability[i];
|
||||
done:
|
||||
_ASSIGN_PVAL(oct_4a, opt[octet_4a]);
|
||||
_ASSIGN_PVAL(oct_4b, opt[octet_4b]);
|
||||
_ASSIGN_PVAL(oct_5, opt[octet_5]);
|
||||
_ASSIGN_PVAL(oct_5a, opt[octet_5a]);
|
||||
_ASSIGN_PVAL(oct_5b1, opt[octet_5b1]);
|
||||
_ASSIGN_PVAL(oct_5b2, opt[octet_5b2]);
|
||||
_ASSIGN_PVAL(oct_5c, opt[octet_5c]);
|
||||
_ASSIGN_PVAL(oct_5d, opt[octet_5d]);
|
||||
_ASSIGN_PVAL(oct_6, opt[octet_6]);
|
||||
_ASSIGN_PVAL(oct_7, opt[octet_7]);
|
||||
return 0;
|
||||
};
|
||||
|
||||
int
|
||||
mi_decode_cause(struct l3_msg *l3m, int *coding, int *loc, int *rec, int *val, int *dialen, unsigned char *dia)
|
||||
{
|
||||
int r = 0, l = 2, dl = 0;
|
||||
|
||||
if (l3m == NULL || !l3m->cause)
|
||||
return 0;
|
||||
if (*l3m->cause < 2)
|
||||
return -EINVAL;
|
||||
_ASSIGN_PVAL(coding, (l3m->cause[1] & 0x60) >> 5);
|
||||
_ASSIGN_PVAL(loc, l3m->cause[1] & 0x0f);
|
||||
if (!(l3m->cause[1] & 0x80)) {
|
||||
r = l3m->cause[2] & 0x7f;
|
||||
l++;
|
||||
} else
|
||||
r = 0;
|
||||
_ASSIGN_PVAL(rec, r);
|
||||
_ASSIGN_PVAL(val, l3m->cause[l] & 0x7f);
|
||||
dl = *l3m->cause - l;
|
||||
if (dl > 0 && dia)
|
||||
memcpy(dia, &l3m->cause[l + 1], dl);
|
||||
_ASSIGN_PVAL(dialen, dl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_channel_id(struct l3_msg *l3m, struct misdn_channel_info *cip)
|
||||
{
|
||||
struct misdn_channel_info c = {MI_CHAN_NONE, 0, 0, 0};
|
||||
|
||||
if (l3m == NULL || !l3m->channel_id)
|
||||
return 0;
|
||||
if (*l3m->channel_id == 0)
|
||||
return 0;
|
||||
if (!cip)
|
||||
return 0;
|
||||
c.ctrl = cip->ctrl & (MI_CHAN_CTRL_ALLOCATED | MI_CHAN_CTRL_NEEDSEND | MI_CHAN_CTRL_SENT);
|
||||
/* We ignore explicit interface settings */
|
||||
c.flags = l3m->channel_id[1] & 0x2c;
|
||||
|
||||
switch (l3m->channel_id[1] & 3) {
|
||||
case 0:
|
||||
c.nr = MI_CHAN_NONE;
|
||||
c.flags |= MI_CHAN_FLG_NONE;
|
||||
break;
|
||||
case 3:
|
||||
c.nr = MI_CHAN_ANY;
|
||||
c.flags |= MI_CHAN_FLG_ANY;
|
||||
break;
|
||||
default:
|
||||
c.nr = l3m->channel_id[1] & 3;
|
||||
}
|
||||
if ((c.flags & MI_CHAN_FLG_OTHER_IF) == 0) { /* BRI */
|
||||
if (c.flags & MI_CHAN_FLG_DCHANNEL) {
|
||||
c.nr = MI_CHAN_DCHANNEL;
|
||||
c.flags &= 0xfc; /* clear NONE,ANY */
|
||||
c.type = MI_CHAN_TYP_D;
|
||||
} else
|
||||
c.type = MI_CHAN_TYP_B;
|
||||
} else { /* PRI */
|
||||
if (*l3m->channel_id < 2)
|
||||
return -EINVAL;
|
||||
/* We ignore coding so CCITT/ETSI is assumed, no support for multiple channels or channelmaps */
|
||||
switch (l3m->channel_id[2] & 0x7f) {
|
||||
default:
|
||||
case 3:
|
||||
c.type = MI_CHAN_TYP_B;
|
||||
break;
|
||||
case 6:
|
||||
c.type = MI_CHAN_TYP_H0;
|
||||
break;
|
||||
case 8:
|
||||
c.type = MI_CHAN_TYP_H11;
|
||||
break;
|
||||
case 9:
|
||||
c.type = MI_CHAN_TYP_H12;
|
||||
break;
|
||||
}
|
||||
if (*l3m->channel_id > 2 && ((c.flags & (MI_CHAN_FLG_ANY | MI_CHAN_FLG_NONE)) == 0))
|
||||
c.nr = l3m->channel_id[3];
|
||||
}
|
||||
if (cip->nr != c.nr || cip->type != c.type || cip->flags != c.flags)
|
||||
c.ctrl |= MI_CHAN_CTRL_UPDATED;
|
||||
_ASSIGN_PVAL(cip, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_calling_nr(struct l3_msg *l3m, int *type, int *plan, int *pres, int *screen, char *nr)
|
||||
{
|
||||
int _pres = 0, _screen = 0, i = 2, l;
|
||||
|
||||
if (l3m == NULL || !l3m->calling_nr)
|
||||
return 0;
|
||||
if (*l3m->calling_nr < 2)
|
||||
return -EINVAL;
|
||||
if (*l3m->calling_nr > 32)
|
||||
return -EINVAL;
|
||||
_ASSIGN_PVAL(type, (l3m->calling_nr[1] & 0x70) >> 4);
|
||||
_ASSIGN_PVAL(plan, l3m->calling_nr[1] & 0x0f);
|
||||
if ((l3m->calling_nr[1] & 0x80) == 0 && *l3m->calling_nr >= 2) {
|
||||
_pres = (l3m->calling_nr[2] & 0x60) >> 5;
|
||||
_screen = l3m->calling_nr[2] & 0x03;
|
||||
i++;
|
||||
}
|
||||
l = *l3m->calling_nr + 1 - i;
|
||||
if (nr) {
|
||||
memcpy(nr, &l3m->calling_nr[i], l);
|
||||
nr[l] = 0;
|
||||
}
|
||||
_ASSIGN_PVAL(pres, _pres);
|
||||
_ASSIGN_PVAL(screen, _screen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_called_nr(struct l3_msg *l3m, int *type, int *plan, char *nr)
|
||||
{
|
||||
int l;
|
||||
if (l3m == NULL || !l3m->called_nr)
|
||||
return 0;
|
||||
if (*l3m->called_nr < 1)
|
||||
return -EINVAL;
|
||||
if (*l3m->called_nr > 32)
|
||||
return -EINVAL;
|
||||
_ASSIGN_PVAL(type, (l3m->called_nr[1] & 0x70) >> 4);
|
||||
_ASSIGN_PVAL(plan, l3m->called_nr[1] & 0x0f);
|
||||
l = *l3m->called_nr - 1;
|
||||
if (nr) {
|
||||
memcpy(nr, &l3m->called_nr[2], l);
|
||||
nr[l] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_display(struct l3_msg *l3m, char *display, int maxlen)
|
||||
{
|
||||
if (l3m == NULL || !l3m->display)
|
||||
return 0;
|
||||
if (!display)
|
||||
return 0;
|
||||
maxlen--;
|
||||
if (*l3m->display < maxlen)
|
||||
maxlen = *l3m->display;
|
||||
memcpy(display, &l3m->display[1], maxlen);
|
||||
display[maxlen] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mi_decode_useruser(struct l3_msg *l3m, int *pd, int *uulen, char *uu, int maxlen)
|
||||
{
|
||||
int l;
|
||||
if (l3m == NULL || !l3m->useruser)
|
||||
return 0;
|
||||
if (!uu)
|
||||
return 0;
|
||||
if (*l3m->useruser < 1)
|
||||
return 0;
|
||||
if (*l3m->useruser < maxlen)
|
||||
l = *l3m->useruser - 1;
|
||||
else
|
||||
l = maxlen;
|
||||
if (l > 0)
|
||||
memcpy(uu, &l3m->useruser[2], l);
|
||||
_ASSIGN_PVAL(uulen, l);
|
||||
_ASSIGN_PVAL(pd, l3m->useruser[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
mi_bearer2str(int cap)
|
||||
{
|
||||
static char *bearers[] = {
|
||||
"Speech",
|
||||
"Audio 3.1 kHz",
|
||||
"Audio 7 kHz",
|
||||
"Unrestricted Digital",
|
||||
"Restricted Digital",
|
||||
"Video",
|
||||
"Unknown Bearer"
|
||||
};
|
||||
|
||||
switch (cap) {
|
||||
case Q931_CAP_SPEECH:
|
||||
return bearers[0];
|
||||
break;
|
||||
case Q931_CAP_3KHZ_AUDIO:
|
||||
return bearers[1];
|
||||
break;
|
||||
case Q931_CAP_7KHZ_AUDIO:
|
||||
return bearers[2];
|
||||
break;
|
||||
case Q931_CAP_UNRES_DIGITAL:
|
||||
return bearers[3];
|
||||
break;
|
||||
case Q931_CAP_RES_DIGITAL:
|
||||
return bearers[4];
|
||||
break;
|
||||
case Q931_CAP_VIDEO:
|
||||
return bearers[5];
|
||||
break;
|
||||
default:
|
||||
return bearers[6];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct _cmdtab {
|
||||
unsigned int cmd;
|
||||
const char *name;
|
||||
} cmdtab[] = {
|
||||
{MT_ALERTING , "ALERTING"},
|
||||
{MT_CALL_PROCEEDING , "CALL_PROCEEDING"},
|
||||
{MT_CONNECT , "CONNECT"},
|
||||
{MT_CONNECT_ACKNOWLEDGE , "CONNECT_ACKNOWLEDGE"},
|
||||
{MT_PROGRESS , "PROGRESS"},
|
||||
{MT_SETUP , "SETUP"},
|
||||
{MT_SETUP_ACKNOWLEDGE , "SETUP_ACKNOWLEDGE"},
|
||||
{MT_RESUME , "RESUME"},
|
||||
{MT_RESUME_ACKNOWLEDGE , "RESUME_ACKNOWLEDGE"},
|
||||
{MT_RESUME_REJECT , "RESUME_REJECT"},
|
||||
{MT_SUSPEND , "SUSPEND"},
|
||||
{MT_SUSPEND_ACKNOWLEDGE , "SUSPEND_ACKNOWLEDGE"},
|
||||
{MT_SUSPEND_REJECT , "SUSPEND_REJECT"},
|
||||
{MT_USER_INFORMATION , "USER_INFORMATION"},
|
||||
{MT_DISCONNECT , "DISCONNECT"},
|
||||
{MT_RELEASE , "RELEASE"},
|
||||
{MT_RELEASE_COMPLETE , "RELEASE_COMPLETE"},
|
||||
{MT_RESTART , "RESTART"},
|
||||
{MT_RESTART_ACKNOWLEDGE , "RESTART_ACKNOWLEDGE"},
|
||||
{MT_SEGMENT , "SEGMENT"},
|
||||
{MT_CONGESTION_CONTROL , "CONGESTION_CONTROL"},
|
||||
{MT_INFORMATION , "INFORMATION"},
|
||||
{MT_FACILITY , "FACILITY"},
|
||||
{MT_NOTIFY , "NOTIFY"},
|
||||
{MT_STATUS , "STATUS"},
|
||||
{MT_STATUS_ENQUIRY , "STATUS_ENQUIRY"},
|
||||
{MT_HOLD , "HOLD"},
|
||||
{MT_HOLD_ACKNOWLEDGE , "HOLD_ACKNOWLEDGE"},
|
||||
{MT_HOLD_REJECT , "HOLD_REJECT"},
|
||||
{MT_RETRIEVE , "RETRIEVE"},
|
||||
{MT_RETRIEVE_ACKNOWLEDGE, "RETRIEVE_ACKNOWLEDGE"},
|
||||
{MT_RETRIEVE_REJECT , "RETRIEVE_REJECT"},
|
||||
{MT_REGISTER , "REGISTER"},
|
||||
{MT_ASSIGN , "ASSIGN_PID"},
|
||||
{MT_FREE , "FREE_PID"},
|
||||
{MT_L2ESTABLISH , "L2ESTABLISH"},
|
||||
{MT_L2RELEASE , "L2RELEASE"},
|
||||
{MT_ERROR , "ERROR"},
|
||||
{MT_TIMEOUT , "TIMEOUT"},
|
||||
{MPH_ACTIVATE_IND , "MPH_ACTIVATE_IND"},
|
||||
{MPH_DEACTIVATE_IND , "MPH_DEACTIVATE_IND"},
|
||||
{MPH_INFORMATION_IND , "MPH_INFORMATION_IND"},
|
||||
{0xFFFFFFFF , "UNKNOWN"}
|
||||
};
|
||||
|
||||
|
||||
const char *
|
||||
mi_msg_type2str(unsigned int cmd)
|
||||
{
|
||||
struct _cmdtab *ct = cmdtab;
|
||||
|
||||
while (ct->cmd != 0xFFFFFFFF) {
|
||||
if (ct->cmd == cmd)
|
||||
break;
|
||||
ct++;
|
||||
}
|
||||
if (ct->cmd == 0xFFFFFFFF)
|
||||
return NULL;
|
||||
else
|
||||
return ct->name;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue