📄 l4isup.c
字号:
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), 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), 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), 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), 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), 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; 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; } ast_mutex_lock(&pvt->lock); chan = ss7_new(pvt, AST_STATE_DOWN, NULL, sep ? sep+1 : arg); if(!chan) { ast_mutex_unlock(&pvt->lock); unlock_global(); *cause = AST_CAUSE_CONGESTION; ast_log(LOG_WARNING, "Unable to allocate SS7 channel structure.\n"); return NULL; } ast_mutex_unlock(&pvt->lock); unlock_global(); ast_update_use_count(); ast_log(LOG_DEBUG, "SS7 channel %s/%s allocated successfully.\n", type, arg); return chan;}static int ss7_send_digit_begin(struct ast_channel *chan, char digit) { struct ss7_chan *pvt = chan->tech_pvt; ast_mutex_lock(&pvt->lock); if (!io_send_dtmf(pvt->zaptel_fd, pvt->cic, digit)) pvt->sending_dtmf = 1; ast_mutex_unlock(&pvt->lock); return 0;}static int ss7_send_digit_end(struct ast_channel *chan, char digit, unsigned int duration) { return 0;}static void ss7_send_call_progress(struct ss7_chan *pvt, int value) { unsigned char msg[MTP_MAX_PCK_SIZE]; int current, varptr; unsigned char param[1]; unsigned char param_backward_ind[2]; unsigned char param_opt_backw_ind[1]; isup_msg_init(msg, sizeof(msg), this_host->opc, peerpc(pvt), pvt->cic, ISUP_CPR, ¤t); param[0] = value; /* Event information */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -