📄 l4isup.c
字号:
}/* This should be called with pvt->lock held. */static void t36_clear(struct ss7_chan *pvt) { if(pvt->t36 != -1) { stop_timer(pvt->t36); pvt->t36 = -1; }}/* This should be called with pvt->lock held. */static void t36_start(struct ss7_chan* pvt){ t36_clear(pvt); pvt->t36 = start_timer(12000, t36_timeout, pvt);}static void isup_send_grs(struct ss7_chan *pvt, int count, int do_timers) { unsigned char msg[MTP_MAX_PCK_SIZE]; int current, varptr; unsigned char param[1]; if(pvt == NULL) { ast_log(LOG_NOTICE, "Error: NULL pvt passed in?!?.\n"); return; } if(count < 2) { ast_log(LOG_NOTICE, "Error (CIC=%d), cannot send group reset for %d " "circuits (need at least 2).\n", pvt->cic, count); return; } isup_msg_init(msg, sizeof(msg), this_host->opc, peerpc(pvt), pvt->cic, ISUP_GRS, ¤t); isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 0); param[0] = count - 1; isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, param, 1); mtp_enqueue_isup(pvt, msg, current); if(do_timers) { t22_start(pvt); t23_start(pvt); }}/* At startup, send an initial GRS to reset all circuits, and setup a timer to wait for the ack. */static void send_init_grs(struct linkset* linkset) { int i; int first_equipped; /* Left end of a range in CIC scan. */ int range; ast_log(LOG_DEBUG, "Sending GROUP RESET messages on linkset '%s'.\n", linkset->name); lock_global(); /* Send a GRS for each continuous range of circuits. */ first_equipped = -1; for(i = linkset->first_cic; i <= linkset->last_cic; i++) { if(linkset->cic_list[i] && linkset->cic_list[i]->equipped) { /* Clear the blocked status for the circuits; any remote blocking will be reported by the peer. */ linkset->cic_list[i]->blocked = 0; /* Look for the start of a range. */ if(first_equipped == -1) { first_equipped = i; } } /* Look for the end of a range. */ if(first_equipped != -1 && (i == linkset->last_cic || !(linkset->cic_list[i+1] && linkset->cic_list[i+1]->equipped) || first_equipped + 31 == i)) { range = i - first_equipped; if(range == 0) { struct ss7_chan *pvt = linkset->cic_list[first_equipped]; ast_mutex_lock(&pvt->lock); pvt->state = ST_SENT_REL; isup_send_rsc(pvt); t16_start(pvt); ast_mutex_unlock(&pvt->lock); first_equipped = -1; } else { linkset->cic_list[first_equipped]->grs_count = range + 1; isup_send_grs(linkset->cic_list[first_equipped], range + 1, 1); } ast_log(LOG_DEBUG, "Group reset first %d, range %d \n", first_equipped, range); first_equipped = -1; } } unlock_global(); /* When the reset acknowledge arrives, the pvt->reset_done is set true for all affected circuits. Until then, messages for that circuit are discarded. */}/* Release circuit after receiving GRS */static void release_circuit(struct ss7_chan* pvt){ struct ast_channel *chan = pvt->owner; if(chan != NULL) { ast_mutex_lock(&chan->lock); } ast_mutex_lock(&pvt->lock); if(pvt->state != ST_IDLE) { pvt->state = ST_IDLE; if(chan != NULL) { request_hangup(chan, AST_CAUSE_NETWORK_OUT_OF_ORDER); } else { /* Channel already hung up */ } } 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); ast_mutex_unlock(&pvt->lock); if(chan != NULL) { ast_mutex_unlock(&chan->lock); }}static void free_cic(struct ss7_chan* pvt){ pvt->state = ST_IDLE; pvt->hangupcause = 0; pvt->dohangup = 0; pvt->has_inband_ind = 0; pvt->owner = NULL; add_to_idlelist(pvt);}static void handle_complete_address(struct ss7_chan *pvt){ int res; struct iam* iam = &pvt->iam; struct ast_channel *chan = ss7_new(pvt, AST_STATE_RING, iam->ani.present ? iam->ani.num : NULL, iam->dni.num); if(chan == NULL) { ast_log(LOG_WARNING, "Failed to allocate struct ast_channel * " "for CIC=%d.\n", pvt->cic); /* Q.764 2.2 c) Initiate release procedure */ initiate_release_circuit(pvt, AST_CAUSE_NORMAL_CLEARING); return; }#ifdef USE_ASTERISK_1_2 ast_copy_string(chan->exten, iam->dni.num, sizeof(chan->exten)); ast_copy_string(chan->context, pvt->context, sizeof(chan->context)); ast_copy_string(chan->language, pvt->language, sizeof(chan->language));#else ast_string_field_set(chan, language, pvt->language);#endif if(iam->ani.present) { chan->cid.cid_num = strdup(iam->ani.num); /* ToDo: Handle screening. */ if(iam->ani.restricted) { chan->cid.cid_pres = AST_PRES_PROHIB_NETWORK_NUMBER; } else { chan->cid.cid_pres = AST_PRES_ALLOWED_NETWORK_NUMBER; } } if(iam->rni.present) { /* ToDo: implement redirection reason in Asterisk, and handle it here. */ chan->cid.cid_rdnis = strdup(iam->rni.num); } if(iam->redir_inf.is_redirect) { char *string_reason; /* The names here are taken to match with those used in chan_zap.c redirectingreason2str(). */ switch(iam->redir_inf.reason) { case 1: string_reason = "BUSY"; break; case 2: /* Cause 4 "deflection during alerting"; not sure, but it seems to be more or less equivalent to "no reply".*/ case 4: string_reason = "NO_REPLY"; break; case 3: /* Cause 5 "deflection immediate response"; not sure, but it seems to be more or less equivalent to "unconditional".*/ case 5: string_reason = "UNCONDITIONAL"; break; case 6: string_reason = "UNREACHABLE"; break; default: string_reason = "UNKNOWN"; break; } /* Use underscore variable to make it inherit like other callerid info. */ pbx_builtin_setvar_helper(chan, "__PRIREDIRECTREASON", string_reason); } if (!pvt->link->linkset->use_connect) { isup_send_acm(pvt); pvt->state = ST_SENT_ACM; } res = ast_pbx_start(chan); if(res != 0) { ast_log(LOG_WARNING, "Unable to start PBX for incoming call on CIC=%d.\n", pvt->cic); ast_hangup(chan); }}static void check_iam_sam(struct ss7_chan* pvt){ int complete = (pvt->link->linkset->enable_st && pvt->iam.dni.complete) || ast_exists_extension(pvt->owner, pvt->context, pvt->iam.dni.num, 1, pvt->iam.rni.num); if (complete) { pvt->iam.dni.complete = 1; ast_log(LOG_DEBUG, "Setting iam.dni.complete\n"); handle_complete_address(pvt); } else { if (ast_canmatch_extension(pvt->owner, pvt->context, pvt->iam.dni.num, 1, pvt->iam.rni.num) != 0) { ast_log(LOG_DEBUG, "Processing addr %s, incomplete, starting T35\n", pvt->iam.dni.num); t35_start(pvt); } else { ast_log(LOG_DEBUG, "Unable to match extension, context: %s, dni: %s, rni: %s\n", pvt->context, pvt->iam.dni.num, pvt->iam.rni.num); initiate_release_circuit(pvt, AST_CAUSE_UNALLOCATED); } }}static void check_obci(struct ss7_chan* pvt, int obci){ struct ast_channel* chan = pvt->owner; if ((obci & 0x1) == 1) { if (!pvt->has_inband_ind) { ast_log(LOG_DEBUG, "Got optional backward call indicator, queueing PROGRESS (Inband-information available) indication for Asterisk, CIC=%d.\n", pvt->cic); ast_queue_control(chan, AST_CONTROL_PROGRESS); pvt->has_inband_ind = 1; } }}static int isup_phonenum_check(char **number, int *nlen, int *is_international) { if(*number == NULL) { ast_log(LOG_DEBUG, "NULL phonenumber, encoding failed.\n"); return -1; } *nlen = strlen(*number); if(*nlen == 0) { ast_log(LOG_DEBUG, "Empty phonenumber, encoding failed.\n"); return -1; } /* Handle both '00' and '+' as international prefix. */ if(strncmp(*number, "00", 2) == 0) { *is_international = 1; *number += 2; *nlen -= 2; } else if(strncmp(*number, "+", 1) == 0) { *is_international = 1; *number += 1; *nlen -= 1; } else { *is_international = 0; } return 0; /* Success */}static int isup_phonenum_digits(char *number, int add_st, int nlen, unsigned char *param) { int i, d; for(i = 0; i <= nlen; i++) { if(i == nlen) { if(add_st) { d = 0xf; /* Digit "ST", meaning "number complete" */ } else { break; } } else { if ((number[i] >= '0') && (number[i] <= '9')) d = number[i] - '0'; else if ((number[i] == 'b') || (number[i] == 'B')) d = 0x0b; else if ((number[i] == 'c') || (number[i] == 'C')) d = 0x0c; else { ast_log(LOG_DEBUG, "Invalid digit '%c' in phonenumber.\n", number[i]); return -1; } } if((i % 2) == 0) { param[2 + i/2] = d; } else { param[2 + (i - 1)/2] |= d << 4; } } return 0;}/* 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(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 terminate the number with ST to signify that the number is complete (no overlapped dialing). Hence length is one more than nlen. */ is_odd = (nlen + 1) % 2; /* Need room for two header bytes + all of the (nlen + 1) digits. */ result_len = 2 + (nlen + 2)/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, 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] = 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), 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--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -