📄 l4isup.c
字号:
ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
"len %d < %d.\n", plen, result_len);
return -1;
}
param[0] = (is_odd << 7) | (is_international ? 4 : 3);
param[1] = 0x10; /* Internal routing allowed, ISDN number plan */
if(isup_phonenum_digits(number, 1, nlen, param) == -1) {
return -1;
}
return result_len; /* Success */
}
/* Encode a phone number in ISUP "Called Party Number" format. (Q.763 (3.9))
Returns encoded length on success, -1 on error. */
int isup_called_party_num_encode_no_st(char *number, unsigned char *param,
int plen) {
int nlen;
int is_odd;
int is_international;
int result_len;
if(isup_phonenum_check(&number, &nlen, &is_international) == -1) {
return -1;
}
/* We do not termminate the number with ST to signify that the number is incomplete
(overlapped dialing). */
is_odd = (nlen) % 2;
/* Need room for two header bytes + all of the (nlen) digits. */
result_len = 2 + (nlen + 1)/2;
if(result_len > plen) {
ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
"len %d < %d.\n", plen, result_len);
return -1;
}
param[0] = (is_odd << 7) | (is_international ? 4 : 3);
param[1] = 0x10; /* Internal routing allowed, ISDN number plan */
if(isup_phonenum_digits(number, 0, nlen, param) == -1) {
return -1;
}
return result_len; /* Success */
}
/* Encode a phone number in ISUP "Calling Party Number" format. (Q.763 (3.10))
Returns encoded length on success, -1 on error. */
int isup_calling_party_num_encode(char *number, int pres_restr,
unsigned char *param, int plen) {
int nlen;
int is_odd;
int is_international;
int result_len;
if(isup_phonenum_check(&number, &nlen, &is_international) == -1) {
return -1;
}
is_odd = nlen % 2;
/* Need room for two header bytes + all of the nlen digits. */
result_len = 2 + (nlen + 1)/2;
if(result_len > plen) {
ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
"len %d < %d.\n", plen, result_len);
return -1;
}
param[0] = (is_odd << 7) | (is_international ? 4 : 3);
param[1] = 0x13; /* Number complete; ISDN number plan; network provided */
/* 0x11: Number complete; ISDN number plan; user provided, verified and passed */
if(pres_restr) {
param[1] |= (0x1 << 2);
}
if(isup_phonenum_digits(number, 0, nlen, param) == -1) {
return -1;
}
return result_len; /* Success */
}
static int isup_send_sam(struct ss7_chan *pvt, char* addr, int complete)
{
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
unsigned char param[2 + PHONENUM_MAX];
int res;
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_SAM, ¤t);
if (complete)
res = isup_called_party_num_encode(addr, param, sizeof(param));
else
res = isup_called_party_num_encode_no_st(addr, param, sizeof(param));
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 0);
/* Param index 1 not used with SAM, change it */
param[1] = param[0]; res--;
isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, ¶m[1], res);
isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t);
isup_msg_end_optional_part(msg, sizeof(msg), ¤t);
mtp_enqueue_isup(pvt, msg, current);
return 0;
}
static int isup_send_iam(struct ast_channel *chan, char *addr, char *rdni, char *dni, int dnilimit) {
struct ss7_chan *pvt = chan->tech_pvt;
unsigned char msg[MTP_MAX_PCK_SIZE];
unsigned char param[2 + PHONENUM_MAX];
int current, varptr;
char dnicpy[100];
int pres_restr;
int res;
const char *isdn_h324m;
int h324m_usi=0, h324m_llc=0;
isdn_h324m = pbx_builtin_getvar_helper(chan, "ISDN_H324M");
if (isdn_h324m) {
ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: ISDN_H324M=%s\n", isdn_h324m);
if (strstr(isdn_h324m,"USI")) {
h324m_usi = 1;
}
if (strstr(isdn_h324m,"LLC")) {
h324m_llc = 1;
}
ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: h324m_usi=%d, h324m_llc=%d\n", h324m_usi, h324m_llc);
} else {
ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: ISDN_H324M is not set.\n");
}
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_IAM, ¤t);
/* Nature of connection indicators Q.763 (3.35). */
param[0] = 0x00; /* No sattelite, no continuity check, no echo control */
isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1);
/* Forward call indicator Q.763 (3.23). */
if (h324m_usi || h324m_llc) {
param[0] = 0xA0; /* No end-to-end method , no interworking, no end-to-end
info, ISDN all the way, ISDN required */
} else {
param[0] = 0x60; /* No end-to-end method , no interworking, no end-to-end
info, ISDN all the way, ISDN not required */
}
param[1] = 0x01; /* Originating access ISDN, no SCCP indication */
isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 2);
/* Calling party's category Q.763 (3.11). */
param[0] = 0x0a; /* Ordinary calling subscriber */
//ast_log(LOG_ERROR,"Subcriber is %d",msg);
isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1);
/* Transmission medium requirement Q.763 (3.54). */
if (h324m_usi || h324m_llc) {
param[0] = 0x02; /* 64 kbit/s unrestricted */
pvt->is_digital = 1;
} else {
param[0] = 0x00; /* Speech */
}
isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1);
/* Called party number Q.763 (3.9). */
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 1);
if (dnilimit > 0 && strlen(dni) > dnilimit) {
/* Make part of dni */
strncpy(dnicpy, dni, dnilimit);
dnicpy[dnilimit] = '\0';
res = isup_called_party_num_encode_no_st(dnicpy, param, sizeof(param));
} else {
res = isup_called_party_num_encode(dni, param, sizeof(param));
}
if(res < 0) {
ast_log(LOG_NOTICE, "Invalid format for phonenumber '%s'.\n", dni);
request_hangup(chan, AST_CAUSE_INVALID_NUMBER_FORMAT);
ast_mutex_unlock(&pvt->lock);
return -1;
}
isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, param, res);
isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t);
/* Calling partys number Q.763 (3.10). */
if((chan->cid.cid_pres & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) {
pres_restr = 1;
} else {
pres_restr = 0;
}
res = isup_calling_party_num_encode(chan->cid.cid_num, pres_restr,
param, sizeof(param));
if(res < 0) {
ast_log(LOG_DEBUG, "Invalid format for calling number, dropped.\n");
} else {
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_CALLING_PARTY_NUMBER,
param, res);
}
/* Some switches do not understand H.223. Those switches use Access Transport
* (Low Layer Compatibility) to signal the video call end-to-end.
*/
if (h324m_usi) {
/* User Service Information: Q.763 3.57 */
param[0] = 0x88; /* unrestricted digital information */
param[1] = 0x90; /* circuit mode, 64 kbit */
param[2] = 0xA6; /* UL1, H.223 and H.245 */
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_USER_SERVICE_INFORMATION,
param, 3);
}
if (h324m_llc) {
/* Access Transport Q.763 3.3 */
param[0] = 0x7C; /* unrestricted digital information */
param[1] = 0x03; /* circuit mode, 64 kbit */
param[2] = 0x88; /* UL1, H.223 and H.245 */
param[3] = 0x90; /* UL1, H.223 and H.245 */
param[4] = 0xA6; /* UL1, H.223 and H.245 */
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_ACCESS_TRANSPORT,
param, 5);
}
if (*rdni) {
res = isup_calling_party_num_encode(rdni, pres_restr, param, sizeof(param));
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_REDIRECTING_ORINUM, param, res);
/* ToDo: Pass on RDNIS (and redirection cause when we implement that) as
ISUP parameters? */
/* Q.763 3.45 */
res = isup_calling_party_num_encode(rdni, pres_restr, param, sizeof(param));
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_REDIRECTING_NUMBER, param, res);
param[0] = 0x31; /* redirecting indicator: call diverted, all redirection information presentation restricted,
original redirection reason: unknown */
param[1] = 0x31; /* reredicting counter: 1
redirection reason: unconditional */
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_REDIRECTION_INFORMATION, param, 2);
}
/* End and send the message. */
isup_msg_end_optional_part(msg, sizeof(msg), ¤t);
mtp_enqueue_isup(pvt, msg, current);
ast_verbose(VERBOSE_PREFIX_3 "Sent IAM CIC=%-3d ANI=%s DNI=%s RNI=%s\n", pvt->cic,
pres_restr ? "*****" : chan->cid.cid_num,
dni,
rdni);
return 0;
}
/* Assume that we are called with chan->lock held (as ast_call() does). */
static int ss7_call(struct ast_channel *chan, char *addr, int timeout) {
struct ss7_chan *pvt = chan->tech_pvt;
char *sep = strchr(addr, '/');
char rdni[100];
char dnicpy[100];
char dni[100];
int chunk_limit, chunk_sofar=0;
int res;
ast_mutex_lock(&pvt->lock);
ast_log(LOG_DEBUG, "SS7 call, addr=%s, cid=%s(0x%x/%s) CIC=%d. linkset '%s'\n",
(addr ? addr : "<NULL>"),
(chan->cid.cid_num ? chan->cid.cid_num : "<NULL>"),
chan->cid.cid_pres,
ast_describe_caller_presentation(chan->cid.cid_pres),
pvt->cic, pvt->link->linkset->name);
pvt->addr = addr;
pvt->attempts = 1;
if (sep)
addr = sep+1;
strcpy(dni, addr);
strcpy(rdni, chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "");
sep = strchr(dni, ':');
if (sep) {
*sep = '\0';
strcpy(rdni, sep+1);
}
chunk_limit = pvt->link->linkset->dni_chunk_limit;
pvt->link->linkset->outgoing_calls++;
res = isup_send_iam(chan, addr, rdni, dni, chunk_limit);
if (res < 0) {
ast_log(LOG_WARNING, "SS7 call failed, addr=%s CIC=%d. linkset '%s'\n", (addr ? addr : "<NULL>"), pvt->cic, pvt->link->linkset->name);
free_cic(pvt);
ast_mutex_unlock(&pvt->lock);
return res;
}
if (chunk_limit > 0 && strlen(dni) > chunk_limit) {
while(chunk_sofar < strlen(dni)) {
strncpy(dnicpy, &dni[chunk_sofar], chunk_limit);
chunk_sofar += chunk_limit;
dnicpy[chunk_sofar] = '\0';
isup_send_sam(pvt, dnicpy, 1);
}
}
pvt->state = ST_SENT_IAM;
t7_start(chan);
ast_mutex_unlock(&pvt->lock);
return 0;
}
static int ss7_hangup(struct ast_channel *chan) {
struct ss7_chan *pvt = chan->tech_pvt;
if (!pvt || pvt->cic == -1) {
decr_usecount();
ast_update_use_count();
return 0;
}
ast_verbose( VERBOSE_PREFIX_3 "SS7 hangup '%s' CIC=%d Cause=%d (state=%d)\n",
chan->name, pvt->cic, chan->hangupcause, pvt->state);
/* Digium insists that ss7_hangup() must be called with chan->lock() held,
even though it is the wrong thing to do (bug 5051). So we have to unlock
it on entry and re-lock it on exit to get sane locking semantics. */
ast_mutex_unlock(&chan->lock);
/* First remove us from the global circuit list. */
lock_global();
ast_mutex_lock(&pvt->lock);
decr_usecount();
ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d (state=%d), chan=0x%08lx\n",
chan->name, pvt->cic, pvt->state, (unsigned long) chan);
chan->tech_pvt = NULL;
pvt->owner = NULL;
/* Clear all the timers that may hold on to references to chan. This must be
done while global lock is held to prevent races. */
t1_clear(pvt);
t2_clear(pvt);
t5_clear(pvt);
t6_clear(pvt);
t7_clear(pvt);
t9_clear(pvt);
t16_clear(pvt);
t17_clear(pvt);
t18_clear(pvt);
t19_clear(pvt);
t20_clear(pvt);
t21_clear(pvt);
t35_clear(pvt);
if(pvt->state == ST_GOT_REL) {
isup_send_rlc(pvt);
ast_setstate(chan, AST_STATE_DOWN);
free_cic(pvt);
}
else if(pvt->state == ST_SENT_REL) {
t1_start(pvt);
t5_start(pvt);
} else if(pvt->state != ST_IDLE) {
ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d cause=%d\n", chan->name, pvt->cic, chan->hangupcause);
initiate_release_circuit(pvt, chan->hangupcause);
}
if (pvt->echocancel) {
io_disable_echo_cancellation(pvt->zaptel_fd, pvt->cic);
pvt->echocancel = 0;
}
clear_audiomode(pvt->zaptel_fd);
ast_mutex_unlock(&pvt->lock);
unlock_global();
ast_update_use_count();
ast_mutex_lock(&chan->lock); /* See above */
return 0;
}
static int ss7_answer(struct ast_channel *chan) {
struct ss7_chan *pvt = chan->tech_pvt;
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
unsigned char param[2];
ast_mutex_lock(&pvt->lock);
ast_log(LOG_DEBUG, "SS7 answer CIC=%d, pvt->state=%d.\n", pvt->cic, pvt->state);
/* Send ANM instead of CON if previously sent ACM. */
if (pvt->state == ST_SENT_ACM) {
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_ANM, ¤t);
param[0] = 0x14; /* Subscriber free, ordinary subscriber, no end-to-end */
param[1] = 0x14; /* No interworking, no end-to-end, ISDN all the way, no
hold, terminating access ISDN, no echo control */
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 1);
isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t);
isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_BACKWARD_CALL_INDICATORS, param, 2);
isup_msg_end_optional_part(msg, sizeof(msg), ¤t);
mtp_enqueue_isup(pvt, msg, current);
} else if (pvt->state == ST_GOT_IAM) {
isup_msg_init(msg, sizeof(msg), variant(pvt),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -