📄 l4isup.c
字号:
{
mtp_enqueue_isup_packet(pvt->link, pvt->cic, msg, msglen, MTP_REQ_ISUP);
}
static void mtp_enqueue_isup_forward(struct ss7_chan* pvt, unsigned char *msg, int msglen)
{
mtp_enqueue_isup_packet(pvt->link, pvt->cic, msg, msglen, MTP_REQ_ISUP_FORWARD);
}
static struct ss7_chan* find_pvt(struct link* slink, int cic)
{
struct linkset* ls;
int lsi;
ls = slink->linkset;
if (ls->cic_list[cic])
return ls->cic_list[cic];
for (lsi = 0; lsi < n_linksets; lsi++)
if (is_combined_linkset(ls, &linksets[lsi]))
if (linksets[lsi].cic_list[cic])
return linksets[lsi].cic_list[cic];
return NULL;
}
/* This function must be called with the global lock mutex held. */
static void remove_from_idlelist(struct ss7_chan *pvt) {
struct linkset* linkset = pvt->link->linkset;
struct ss7_chan *prev, *cur;
cur = linkset->idle_list;
prev = NULL;
while(cur != NULL) {
if(pvt->cic == cur->cic) {
if(prev == NULL) {
linkset->idle_list = pvt->next_idle;
} else {
prev->next_idle = pvt->next_idle;
}
pvt->next_idle = NULL;
return;
}
prev = cur;
cur = cur->next_idle;
}
ast_log(LOG_NOTICE, "Trying to remove CIC=%d from idle list, but not "
"found?!?.\n", pvt->cic);
}
/* This function must be called with the global lock mutex held. */
static void add_to_idlelist(struct ss7_chan *pvt) {
struct linkset* linkset = pvt->link->linkset;
struct ss7_chan *prev, *cur;
#if 1
cur = linkset->idle_list;
prev = NULL;
while(cur != NULL) {
if(pvt->cic == cur->cic) {
ast_log(LOG_NOTICE, "Trying to add CIC=%d to idle list, but already there?!?\n", pvt->cic);
return;
}
cur = cur->next_idle;
}
#endif
pvt->next_idle = linkset->idle_list;
linkset->idle_list = pvt;
}
/* This implements hunting policy. It must be called with the global lock mutex
held. */
/* This implements the policy: Primary hunting group odd CICs, secondary
hunting group even CICs. Choose least recently used CIC. */
static struct ss7_chan *cic_hunt_odd_lru(struct linkset* linkset) {
struct ss7_chan *cur, *prev, *best, *best_prev;
int odd;
best = NULL;
best_prev = NULL;
for(odd = 1; odd >= 0; odd--) {
for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
/* Don't select lines that are resetting or blocked. */
if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
continue;
}
if((cur->cic % 2) == odd) {
best = cur;
best_prev = prev;
}
}
if(best != NULL) {
if(best_prev == NULL) {
linkset->idle_list = best->next_idle;
} else {
best_prev->next_idle = best->next_idle;
}
best->next_idle = NULL;
return best;
}
}
ast_log(LOG_WARNING, "No idle circuit found.\n");
return NULL;
}
/* This implements the policy: Primary hunting group even CICs, secondary
hunting group odd CICs. Choose most recently used CIC. */
static struct ss7_chan *cic_hunt_even_mru(struct linkset* linkset) {
struct ss7_chan *cur, *prev, *best, *best_prev;
best = NULL;
best_prev = NULL;
for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
/* Don't select lines that are resetting or blocked. */
if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
continue;
}
if((cur->cic % 2) == 0) {
/* Choose the first idle even circuit, if any. */
best = cur;
best_prev = prev;
break;
} else if(best == NULL) {
/* Remember the first odd circuit, in case no even circuits are
available. */
best = cur;
best_prev = prev;
}
}
if(best != NULL) {
if(best_prev == NULL) {
linkset->idle_list = best->next_idle;
} else {
best_prev->next_idle = best->next_idle;
}
best->next_idle = NULL;
return best;
} else {
ast_log(LOG_WARNING, "No idle circuit found.\n");
return NULL;
}
}
/* This implements the policy: Sequential low to high CICs */
static struct ss7_chan *cic_hunt_seq_lth_htl(struct linkset* linkset, int lth)
{
struct ss7_chan *cur, *prev, *best = NULL, *best_prev = NULL;
for(cur = linkset->idle_list, prev = NULL; cur != NULL; prev = cur, cur = cur->next_idle) {
/* Don't select lines that are resetting or blocked. */
if(!cur->reset_done || (cur->blocked & (BL_LH|BL_RM|BL_RH|BL_UNEQUIPPED|BL_LINKDOWN))) {
continue;
}
if (!best) {
best = cur;
continue;
}
if (lth) {
if (cur->cic < best->cic) {
best = cur;
best_prev = prev;
}
}
else {
if (cur->cic > best->cic) {
best = cur;
best_prev = prev;
}
}
}
if(best != NULL) {
if(best_prev == NULL) {
linkset->idle_list = best->next_idle;
} else {
best_prev->next_idle = best->next_idle;
}
best->next_idle = NULL;
return best;
} else {
ast_log(LOG_WARNING, "No idle circuit found.\n");
return NULL;
}
}
/* Send a "release" message. */
static void isup_send_rel(struct ss7_chan *pvt, int cause) {
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
unsigned char param[2];
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_REL, ¤t);
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 1);
param[0] = 0x85; /* Last octet, ITU-T coding, private network */
param[1] = 0x80 | (cause & 0x7f); /* Last octet */
isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, param, 2);
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);
}
/* Send a "release confirmed" message. */
static void isup_send_rlc(struct ss7_chan* pvt) {
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
int cic = pvt->cic;
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_RLC, ¤t);
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 1);
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);
}
/* Send a "reset circuit" message. */
static void isup_send_rsc(struct ss7_chan* pvt) {
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
int cic = pvt->cic;
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_RSC, ¤t);
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 0);
mtp_enqueue_isup(pvt, msg, current);
}
/* Send an "address complete" message. */
static void isup_send_acm(struct ss7_chan* pvt) {
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
unsigned char param[2];
int cic = pvt->cic;
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), cic, ISUP_ACM, ¤t);
param[0] = 0x12;
param[1] = 0x14;
isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 2);
if (pvt->has_inband_ind) {
unsigned char param_opt_backw_ind[1];
param_opt_backw_ind[0] = 0x01;
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_OPTIONAL_BACKWARD_CALL_INDICATORS,
param_opt_backw_ind, 1);
isup_msg_end_optional_part(msg, sizeof(msg), ¤t);
}
else {
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 1);
}
mtp_enqueue_isup(pvt, msg, current);
}
/* Send a "circuit group blocking" message. */
static void isup_send_cgb(struct ss7_chan* pvt, int mask) {
int sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
int cic = pvt->cic;
if (pvt->equipped)
sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
else
sup_type_ind = 0x01; /* Hardware failure oriented */
do_group_circuit_block_unblock(pvt->link->linkset, cic, mask, sup_type_ind, 0, 0, 1);
}
/* Send a "circuit group unblocking" message. */
static void isup_send_cgu(struct ss7_chan* pvt, int mask) {
int sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
int cic = pvt->cic;
if (pvt->equipped)
sup_type_ind = 0x00; /* Maintenance oriented supervision message type */
else
sup_type_ind = 0x01; /* Hardware failure oriented */
do_group_circuit_block_unblock(pvt->link->linkset, cic, mask, sup_type_ind, 0, 0, 0);
}
/* Send a "blocked" message. */
static void isup_send_blk(struct ss7_chan *pvt)
{
unsigned char msg[MTP_MAX_PCK_SIZE];
int current, varptr;
isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_BLK, ¤t);
isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 0);
mtp_enqueue_isup(pvt, msg, current);
}
/* Reset circuit. Called with pvt->lock held */
static void reset_circuit(struct ss7_chan* pvt)
{
isup_send_rsc(pvt);
t16_start(pvt);
}
/* Initiate release circuit. Called with pvt->lock held */
static void initiate_release_circuit(struct ss7_chan* pvt, int cause)
{
pvt->hangupcause = cause; /* Remember for REL retransmit */
/* We sometimes get hangupcause=0 (seen when no match in dialplan, not
even invalid handler). This doesn't work too well, for example
ast_softhangup() doesn't actually hang up when hangupcause=0. */
if(pvt->hangupcause == 0) {
pvt->hangupcause = AST_CAUSE_NORMAL_CLEARING;
}
isup_send_rel(pvt, pvt->hangupcause);
pvt->state = ST_SENT_REL;
/* Set up timer T1 and T5 waiting for RLC. */
t1_start(pvt);
t5_start(pvt);
}
/* Setup a new channel, for an incoming or an outgoing call.
Assumes called with global lock and pvt->lock held. */
static struct ast_channel *ss7_new(struct ss7_chan *pvt, int state, char* cid_num, char* exten) {
struct ast_channel *chan;
#ifdef USE_ASTERISK_1_2
chan = ast_channel_alloc(1);
if(!chan) {
return NULL;
}
snprintf(chan->name, sizeof(chan->name), "%s/%s/%d", type, pvt->link->linkset->name, pvt->cic);
chan->type = type;
#else
chan = ast_channel_alloc(1, state, cid_num, NULL, NULL, exten, pvt->context, 0, "%s/%s/%d", type, pvt->link->linkset->name, pvt->cic);
ast_jb_configure(chan, ss7_get_global_jbconf());
if(!chan) {
return NULL;
}
#endif
chan->tech = &ss7_tech;
chan->nativeformats = AST_FORMAT_ALAW;
chan->rawreadformat = AST_FORMAT_ALAW;
chan->rawwriteformat = AST_FORMAT_ALAW;
chan->readformat = AST_FORMAT_ALAW;
chan->writeformat = AST_FORMAT_ALAW;
ast_setstate(chan, state);
chan->fds[0] = pvt->zaptel_fd;
chan->tech_pvt = pvt;
pvt->owner = chan;
incr_usecount();
flushchannel(pvt->zaptel_fd, pvt->cic);
pvt->lastread.tv_sec = pvt->lastread.tv_usec = 0;
return chan;
}
/* hunt free CIC */
static struct ss7_chan* cic_hunt(struct linkset* linkset)
{
struct ss7_chan* pvt;
switch(linkset->hunt_policy) {
case HUNT_ODD_LRU:
pvt = cic_hunt_odd_lru(linkset);
break;
case HUNT_EVEN_MRU:
pvt = cic_hunt_even_mru(linkset);
break;
case HUNT_SEQ_LTH:
pvt = cic_hunt_seq_lth_htl(linkset, 1);
break;
case HUNT_SEQ_HTL:
pvt = cic_hunt_seq_lth_htl(linkset, 0);
break;
default:
pvt = NULL;
ast_log(LOG_ERROR, "Internal error: invalid hunting policy %d.\n",
linkset->hunt_policy);
}
return pvt;
}
/* Request an SS7 channel. */
static struct ast_channel *ss7_requester(const char *type, int format,
void *data, int *cause) {
char *arg = data;
struct ast_channel *chan;
struct ss7_chan *pvt;
struct linkset* linkset = this_host->default_linkset;
char *sep = strchr(arg, '/');
ast_log(LOG_DEBUG, "SS7 request (%s/%s) format = 0x%X.\n", type, arg, format);
if(!(format & AST_FORMAT_ALAW)) {
ast_log(LOG_NOTICE, "Audio format 0x%X not supported by SS7 channel.\n",
format);
return NULL;
}
if (sep) {
char name_buf[100];
strncpy(name_buf, arg, sep-arg);
name_buf[sep-arg] = 0;
linkset = lookup_linkset(name_buf);
if (!linkset) {
ast_log(LOG_ERROR, "SS7 requester: No such linkset: '%s', using default\n", name_buf);
linkset = this_host->default_linkset;
}
}
lock_global();
pvt = cic_hunt(linkset);
if(pvt == NULL) {
unlock_global();
*cause = AST_CAUSE_CONGESTION;
ast_log(LOG_WARNING, "SS7 requester: No idle circuit available.\n");
return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -