00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 #if defined(HAVE_SS7)
00037
00038 #include <signal.h>
00039
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/causes.h"
00042 #include "asterisk/musiconhold.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/transcap.h"
00045
00046 #include "sig_ss7.h"
00047 #if defined(LIBSS7_ABI_COMPATIBILITY)
00048 #error "Your installed libss7 is not compatible"
00049 #endif
00050
00051
00052
00053 static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level)
00054 {
00055 switch (level) {
00056 case SIG_SS7_CALL_LEVEL_IDLE:
00057 return "Idle";
00058 case SIG_SS7_CALL_LEVEL_ALLOCATED:
00059 return "Allocated";
00060 case SIG_SS7_CALL_LEVEL_CONTINUITY:
00061 return "Continuity";
00062 case SIG_SS7_CALL_LEVEL_SETUP:
00063 return "Setup";
00064 case SIG_SS7_CALL_LEVEL_PROCEEDING:
00065 return "Proceeding";
00066 case SIG_SS7_CALL_LEVEL_ALERTING:
00067 return "Alerting";
00068 case SIG_SS7_CALL_LEVEL_CONNECT:
00069 return "Connect";
00070 case SIG_SS7_CALL_LEVEL_GLARE:
00071 return "Glare";
00072 }
00073 return "Unknown";
00074 }
00075
00076 static void sig_ss7_unlock_private(struct sig_ss7_chan *p)
00077 {
00078 if (p->calls->unlock_private) {
00079 p->calls->unlock_private(p->chan_pvt);
00080 }
00081 }
00082
00083 static void sig_ss7_lock_private(struct sig_ss7_chan *p)
00084 {
00085 if (p->calls->lock_private) {
00086 p->calls->lock_private(p->chan_pvt);
00087 }
00088 }
00089
00090 void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm)
00091 {
00092 p->inalarm = in_alarm;
00093 if (p->calls->set_alarm) {
00094 p->calls->set_alarm(p->chan_pvt, in_alarm);
00095 }
00096 }
00097
00098 static void sig_ss7_set_dialing(struct sig_ss7_chan *p, int is_dialing)
00099 {
00100 if (p->calls->set_dialing) {
00101 p->calls->set_dialing(p->chan_pvt, is_dialing);
00102 }
00103 }
00104
00105 static void sig_ss7_set_digital(struct sig_ss7_chan *p, int is_digital)
00106 {
00107 if (p->calls->set_digital) {
00108 p->calls->set_digital(p->chan_pvt, is_digital);
00109 }
00110 }
00111
00112 static void sig_ss7_set_outgoing(struct sig_ss7_chan *p, int is_outgoing)
00113 {
00114 p->outgoing = is_outgoing;
00115 if (p->calls->set_outgoing) {
00116 p->calls->set_outgoing(p->chan_pvt, is_outgoing);
00117 }
00118 }
00119
00120 static void sig_ss7_set_inservice(struct sig_ss7_chan *p, int is_inservice)
00121 {
00122 if (p->calls->set_inservice) {
00123 p->calls->set_inservice(p->chan_pvt, is_inservice);
00124 }
00125 }
00126
00127 static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked)
00128 {
00129 p->locallyblocked = is_blocked;
00130 if (p->calls->set_locallyblocked) {
00131 p->calls->set_locallyblocked(p->chan_pvt, is_blocked);
00132 }
00133 }
00134
00135 static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked)
00136 {
00137 p->remotelyblocked = is_blocked;
00138 if (p->calls->set_remotelyblocked) {
00139 p->calls->set_remotelyblocked(p->chan_pvt, is_blocked);
00140 }
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 static void sig_ss7_open_media(struct sig_ss7_chan *p)
00153 {
00154 if (p->calls->open_media) {
00155 p->calls->open_media(p->chan_pvt);
00156 }
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 static void sig_ss7_set_caller_id(struct sig_ss7_chan *p)
00169 {
00170 struct ast_party_caller caller;
00171
00172 if (p->calls->set_callerid) {
00173 ast_party_caller_init(&caller);
00174
00175 caller.id.name.str = p->cid_name;
00176 caller.id.name.presentation = p->callingpres;
00177 caller.id.name.valid = 1;
00178
00179 caller.id.number.str = p->cid_num;
00180 caller.id.number.plan = p->cid_ton;
00181 caller.id.number.presentation = p->callingpres;
00182 caller.id.number.valid = 1;
00183
00184 if (!ast_strlen_zero(p->cid_subaddr)) {
00185 caller.id.subaddress.valid = 1;
00186
00187
00188 caller.id.subaddress.str = p->cid_subaddr;
00189 }
00190
00191 caller.ani.number.str = p->cid_ani;
00192
00193
00194 caller.ani.number.valid = 1;
00195
00196 caller.ani2 = p->cid_ani2;
00197 p->calls->set_callerid(p->chan_pvt, &caller);
00198 }
00199 }
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 static void sig_ss7_set_dnid(struct sig_ss7_chan *p, const char *dnid)
00212 {
00213 if (p->calls->set_dnid) {
00214 p->calls->set_dnid(p->chan_pvt, dnid);
00215 }
00216 }
00217
00218 static int sig_ss7_play_tone(struct sig_ss7_chan *p, enum sig_ss7_tone tone)
00219 {
00220 int res;
00221
00222 if (p->calls->play_tone) {
00223 res = p->calls->play_tone(p->chan_pvt, tone);
00224 } else {
00225 res = -1;
00226 }
00227 return res;
00228 }
00229
00230 static int sig_ss7_set_echocanceller(struct sig_ss7_chan *p, int enable)
00231 {
00232 if (p->calls->set_echocanceller) {
00233 return p->calls->set_echocanceller(p->chan_pvt, enable);
00234 }
00235 return -1;
00236 }
00237
00238 static void sig_ss7_loopback(struct sig_ss7_chan *p, int enable)
00239 {
00240 if (p->loopedback != enable) {
00241 p->loopedback = enable;
00242 if (p->calls->set_loopback) {
00243 p->calls->set_loopback(p->chan_pvt, enable);
00244 }
00245 }
00246 }
00247
00248 static struct ast_channel *sig_ss7_new_ast_channel(struct sig_ss7_chan *p, int state, int ulaw, int transfercapability, char *exten, const struct ast_channel *requestor)
00249 {
00250 struct ast_channel *ast;
00251
00252 if (p->calls->new_ast_channel) {
00253 ast = p->calls->new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
00254 } else {
00255 return NULL;
00256 }
00257 if (!ast) {
00258 return NULL;
00259 }
00260
00261 if (!p->owner) {
00262 p->owner = ast;
00263 }
00264 p->alreadyhungup = 0;
00265 ast->transfercapability = transfercapability;
00266 pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY",
00267 ast_transfercapability2str(transfercapability));
00268 if (transfercapability & AST_TRANS_CAP_DIGITAL) {
00269 sig_ss7_set_digital(p, 1);
00270 }
00271
00272 return ast;
00273 }
00274
00275 static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
00276 {
00277 if (linkset->calls->handle_link_exception) {
00278 linkset->calls->handle_link_exception(linkset, which);
00279 }
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 static int sig_ss7_is_chan_available(struct sig_ss7_chan *pvt)
00291 {
00292 if (!pvt->inalarm && !pvt->owner && !pvt->ss7call
00293 && pvt->call_level == SIG_SS7_CALL_LEVEL_IDLE
00294 && !pvt->locallyblocked && !pvt->remotelyblocked) {
00295 return 1;
00296 }
00297 return 0;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 static void sig_ss7_lock_owner(struct sig_ss7_linkset *ss7, int chanpos)
00314 {
00315 for (;;) {
00316 if (!ss7->pvts[chanpos]->owner) {
00317
00318 break;
00319 }
00320 if (!ast_channel_trylock(ss7->pvts[chanpos]->owner)) {
00321
00322 break;
00323 }
00324
00325
00326 sig_ss7_unlock_private(ss7->pvts[chanpos]);
00327 DEADLOCK_AVOIDANCE(&ss7->lock);
00328 sig_ss7_lock_private(ss7->pvts[chanpos]);
00329 }
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 static void sig_ss7_queue_frame(struct sig_ss7_linkset *ss7, int chanpos, struct ast_frame *frame)
00347 {
00348 sig_ss7_lock_owner(ss7, chanpos);
00349 if (ss7->pvts[chanpos]->owner) {
00350 ast_queue_frame(ss7->pvts[chanpos]->owner, frame);
00351 ast_channel_unlock(ss7->pvts[chanpos]->owner);
00352 }
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 static void sig_ss7_queue_control(struct sig_ss7_linkset *ss7, int chanpos, int subclass)
00370 {
00371 struct ast_frame f = {AST_FRAME_CONTROL, };
00372 struct sig_ss7_chan *p = ss7->pvts[chanpos];
00373
00374 if (p->calls->queue_control) {
00375 p->calls->queue_control(p->chan_pvt, subclass);
00376 }
00377
00378 f.subclass.integer = subclass;
00379 sig_ss7_queue_frame(ss7, chanpos, &f);
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
00394 {
00395 int i;
00396 int winner = -1;
00397 for (i = 0; i < linkset->numchans; i++) {
00398 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
00399 winner = i;
00400 break;
00401 }
00402 }
00403 return winner;
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 static int ss7_find_cic_gripe(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, const char *msg_name)
00419 {
00420 int chanpos;
00421
00422 chanpos = ss7_find_cic(linkset, cic, dpc);
00423 if (chanpos < 0) {
00424 ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d.\n",
00425 linkset->span, msg_name, cic, dpc);
00426 return -1;
00427 }
00428 return chanpos;
00429 }
00430
00431 static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
00432 {
00433 unsigned char status[32];
00434 struct sig_ss7_chan *p = NULL;
00435 int i, offset;
00436
00437 for (i = 0; i < linkset->numchans; i++) {
00438 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
00439 p = linkset->pvts[i];
00440 offset = p->cic - startcic;
00441 status[offset] = 0;
00442 if (p->locallyblocked)
00443 status[offset] |= (1 << 0) | (1 << 4);
00444 if (p->remotelyblocked)
00445 status[offset] |= (1 << 1) | (1 << 5);
00446 if (p->ss7call) {
00447 if (p->outgoing)
00448 status[offset] |= (1 << 3);
00449 else
00450 status[offset] |= (1 << 2);
00451 } else
00452 status[offset] |= 0x3 << 2;
00453 }
00454 }
00455
00456 if (p)
00457 isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
00458 else
00459 ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
00460
00461 }
00462
00463 static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
00464 {
00465 int i;
00466
00467 for (i = 0; i < linkset->numchans; i++) {
00468 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
00469 sig_ss7_lock_private(linkset->pvts[i]);
00470 sig_ss7_lock_owner(linkset, i);
00471 if (linkset->pvts[i]->owner) {
00472 ast_softhangup_nolock(linkset->pvts[i]->owner, AST_SOFTHANGUP_DEV);
00473 ast_channel_unlock(linkset->pvts[i]->owner);
00474 }
00475 sig_ss7_unlock_private(linkset->pvts[i]);
00476 }
00477 }
00478 }
00479
00480 static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
00481 {
00482 int i;
00483
00484
00485 for (i = 0; i < linkset->numchans; i++) {
00486 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
00487 if (state) {
00488 if (state[i])
00489 sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
00490 } else
00491 sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
00492 }
00493 }
00494 }
00495
00496 static void ss7_inservice(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
00497 {
00498 int i;
00499
00500 for (i = 0; i < linkset->numchans; i++) {
00501 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
00502 sig_ss7_set_inservice(linkset->pvts[i], 1);
00503 }
00504 }
00505
00506 static void ss7_reset_linkset(struct sig_ss7_linkset *linkset)
00507 {
00508 int i, startcic = -1, endcic, dpc;
00509
00510 if (linkset->numchans <= 0)
00511 return;
00512
00513 startcic = linkset->pvts[0]->cic;
00514
00515 dpc = linkset->pvts[0]->dpc;
00516
00517 for (i = 0; i < linkset->numchans; i++) {
00518 if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
00519 continue;
00520 } else {
00521 endcic = linkset->pvts[i]->cic;
00522 ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
00523 isup_grs(linkset->ss7, startcic, endcic, dpc);
00524
00525
00526 if (linkset->pvts[i+1]) {
00527 startcic = linkset->pvts[i+1]->cic;
00528 dpc = linkset->pvts[i+1]->dpc;
00529 }
00530 }
00531 }
00532 }
00533
00534
00535 static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *linkset)
00536 {
00537 struct ss7 *ss7 = linkset->ss7;
00538 int law;
00539 struct ast_channel *c;
00540 char tmp[256];
00541
00542 if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
00543 p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
00544 isup_acm(ss7, p->ss7call);
00545 } else {
00546 p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
00547 }
00548
00549
00550 if (linkset->type == SS7_ITU) {
00551 law = SIG_SS7_ALAW;
00552 } else {
00553 law = SIG_SS7_ULAW;
00554 }
00555
00556
00557
00558
00559
00560
00561 ast_mutex_unlock(&linkset->lock);
00562 sig_ss7_unlock_private(p);
00563 c = sig_ss7_new_ast_channel(p, AST_STATE_RING, law, 0, p->exten, NULL);
00564 if (!c) {
00565 ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
00566 ast_mutex_lock(&linkset->lock);
00567 sig_ss7_lock_private(p);
00568 isup_rel(linkset->ss7, p->ss7call, AST_CAUSE_SWITCH_CONGESTION);
00569 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
00570 p->alreadyhungup = 1;
00571 return;
00572 }
00573
00574
00575 ast_channel_lock(c);
00576 sig_ss7_lock_private(p);
00577
00578 sig_ss7_set_echocanceller(p, 1);
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591 if (!ast_strlen_zero(p->charge_number)) {
00592 pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
00593
00594 p->charge_number[0] = 0;
00595 }
00596 if (!ast_strlen_zero(p->gen_add_number)) {
00597 pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
00598
00599 p->gen_add_number[0] = 0;
00600 }
00601 if (!ast_strlen_zero(p->jip_number)) {
00602 pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
00603
00604 p->jip_number[0] = 0;
00605 }
00606 if (!ast_strlen_zero(p->gen_dig_number)) {
00607 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
00608
00609 p->gen_dig_number[0] = 0;
00610 }
00611 if (!ast_strlen_zero(p->orig_called_num)) {
00612 pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
00613
00614 p->orig_called_num[0] = 0;
00615 }
00616
00617 snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
00618 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
00619
00620 p->gen_dig_type = 0;
00621
00622 snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
00623 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
00624
00625 p->gen_dig_scheme = 0;
00626
00627 if (!ast_strlen_zero(p->lspi_ident)) {
00628 pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
00629
00630 p->lspi_ident[0] = 0;
00631 }
00632
00633 snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
00634 pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
00635
00636 p->call_ref_ident = 0;
00637
00638 snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
00639 pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
00640
00641 p->call_ref_pc = 0;
00642
00643 snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
00644 pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
00645
00646 p->calling_party_cat = 0;
00647
00648 if (!ast_strlen_zero(p->redirecting_num)) {
00649 pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
00650
00651 p->redirecting_num[0] = 0;
00652 }
00653 if (!ast_strlen_zero(p->generic_name)) {
00654 pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
00655
00656 p->generic_name[0] = 0;
00657 }
00658
00659 sig_ss7_unlock_private(p);
00660 ast_channel_unlock(c);
00661
00662 if (ast_pbx_start(c)) {
00663 ast_log(LOG_WARNING, "Unable to start PBX on %s (CIC %d)\n", c->name, p->cic);
00664 ast_hangup(c);
00665 } else {
00666 ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
00667 }
00668
00669
00670 ast_mutex_lock(&linkset->lock);
00671 sig_ss7_lock_private(p);
00672 }
00673
00674 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct sig_ss7_linkset *ss7, const char *number, const unsigned nai)
00675 {
00676 if (ast_strlen_zero(number)) {
00677 if (size) {
00678 *buf = '\0';
00679 }
00680 return;
00681 }
00682 switch (nai) {
00683 case SS7_NAI_INTERNATIONAL:
00684 snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
00685 break;
00686 case SS7_NAI_NATIONAL:
00687 snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
00688 break;
00689 case SS7_NAI_SUBSCRIBER:
00690 snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
00691 break;
00692 case SS7_NAI_UNKNOWN:
00693 snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
00694 break;
00695 default:
00696 snprintf(buf, size, "%s", number);
00697 break;
00698 }
00699 }
00700
00701 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
00702 {
00703 return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
00704 }
00705
00706
00707 void *ss7_linkset(void *data)
00708 {
00709 int res, i;
00710 struct timeval *next = NULL, tv;
00711 struct sig_ss7_linkset *linkset = (struct sig_ss7_linkset *) data;
00712 struct ss7 *ss7 = linkset->ss7;
00713 ss7_event *e = NULL;
00714 struct sig_ss7_chan *p;
00715 int chanpos;
00716 struct pollfd pollers[SIG_SS7_NUM_DCHANS];
00717 int nextms;
00718
00719 #define SS7_MAX_POLL 60000
00720
00721 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
00722
00723 ss7_set_debug(ss7, SIG_SS7_DEBUG_DEFAULT);
00724 ast_mutex_lock(&linkset->lock);
00725 ss7_start(ss7);
00726 ast_mutex_unlock(&linkset->lock);
00727
00728 for (;;) {
00729 ast_mutex_lock(&linkset->lock);
00730 if ((next = ss7_schedule_next(ss7))) {
00731 tv = ast_tvnow();
00732 tv.tv_sec = next->tv_sec - tv.tv_sec;
00733 tv.tv_usec = next->tv_usec - tv.tv_usec;
00734 if (tv.tv_usec < 0) {
00735 tv.tv_usec += 1000000;
00736 tv.tv_sec -= 1;
00737 }
00738 if (tv.tv_sec < 0) {
00739 tv.tv_sec = 0;
00740 tv.tv_usec = 0;
00741 }
00742 nextms = tv.tv_sec * 1000;
00743 nextms += tv.tv_usec / 1000;
00744 if (SS7_MAX_POLL < nextms) {
00745 nextms = SS7_MAX_POLL;
00746 }
00747 } else {
00748 nextms = SS7_MAX_POLL;
00749 }
00750
00751 for (i = 0; i < linkset->numsigchans; i++) {
00752 pollers[i].fd = linkset->fds[i];
00753 pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
00754 pollers[i].revents = 0;
00755 }
00756 ast_mutex_unlock(&linkset->lock);
00757
00758 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00759 pthread_testcancel();
00760 res = poll(pollers, linkset->numsigchans, nextms);
00761 pthread_testcancel();
00762 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
00763
00764 if ((res < 0) && (errno != EINTR)) {
00765 ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
00766 } else if (!res) {
00767 ast_mutex_lock(&linkset->lock);
00768 ss7_schedule_run(ss7);
00769 ast_mutex_unlock(&linkset->lock);
00770 continue;
00771 }
00772
00773 ast_mutex_lock(&linkset->lock);
00774 for (i = 0; i < linkset->numsigchans; i++) {
00775 if (pollers[i].revents & POLLPRI) {
00776 sig_ss7_handle_link_exception(linkset, i);
00777 }
00778 if (pollers[i].revents & POLLIN) {
00779 res = ss7_read(ss7, pollers[i].fd);
00780 }
00781 if (pollers[i].revents & POLLOUT) {
00782 res = ss7_write(ss7, pollers[i].fd);
00783 if (res < 0) {
00784 ast_debug(1, "Error in write %s\n", strerror(errno));
00785 }
00786 }
00787 }
00788
00789 while ((e = ss7_check_event(ss7))) {
00790 if (linkset->debug) {
00791 ast_verbose("Linkset %d: Processing event: %s\n",
00792 linkset->span, ss7_event2str(e->e));
00793 }
00794
00795 switch (e->e) {
00796 case SS7_EVENT_UP:
00797 if (linkset->state != LINKSET_STATE_UP) {
00798 ast_verbose("--- SS7 Up ---\n");
00799 ss7_reset_linkset(linkset);
00800 }
00801 linkset->state = LINKSET_STATE_UP;
00802 break;
00803 case SS7_EVENT_DOWN:
00804 ast_verbose("--- SS7 Down ---\n");
00805 linkset->state = LINKSET_STATE_DOWN;
00806 for (i = 0; i < linkset->numchans; i++) {
00807 p = linkset->pvts[i];
00808 if (p) {
00809 sig_ss7_set_alarm(p, 1);
00810 }
00811 }
00812 break;
00813 case MTP2_LINK_UP:
00814 ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
00815 break;
00816 case MTP2_LINK_DOWN:
00817 ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
00818 break;
00819 case ISUP_EVENT_CPG:
00820 chanpos = ss7_find_cic_gripe(linkset, e->cpg.cic, e->cpg.opc, "CPG");
00821 if (chanpos < 0) {
00822 break;
00823 }
00824 p = linkset->pvts[chanpos];
00825 sig_ss7_lock_private(p);
00826 switch (e->cpg.event) {
00827 case CPG_EVENT_ALERTING:
00828 if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
00829 p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
00830 }
00831 sig_ss7_lock_owner(linkset, chanpos);
00832 if (p->owner) {
00833 ast_setstate(p->owner, AST_STATE_RINGING);
00834 ast_channel_unlock(p->owner);
00835 }
00836 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
00837 break;
00838 case CPG_EVENT_PROGRESS:
00839 case CPG_EVENT_INBANDINFO:
00840 {
00841 ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
00842 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROGRESS);
00843 p->progress = 1;
00844 sig_ss7_set_dialing(p, 0);
00845 sig_ss7_open_media(p);
00846 }
00847 break;
00848 default:
00849 ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
00850 break;
00851 }
00852
00853 sig_ss7_unlock_private(p);
00854 break;
00855 case ISUP_EVENT_RSC:
00856 ast_verbose("Resetting CIC %d\n", e->rsc.cic);
00857 chanpos = ss7_find_cic_gripe(linkset, e->rsc.cic, e->rsc.opc, "RSC");
00858 if (chanpos < 0) {
00859 break;
00860 }
00861 p = linkset->pvts[chanpos];
00862 sig_ss7_lock_private(p);
00863 sig_ss7_set_inservice(p, 1);
00864 sig_ss7_set_remotelyblocked(p, 0);
00865 isup_set_call_dpc(e->rsc.call, p->dpc);
00866 sig_ss7_lock_owner(linkset, chanpos);
00867 p->ss7call = NULL;
00868 if (p->owner) {
00869 ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
00870 ast_channel_unlock(p->owner);
00871 }
00872 sig_ss7_unlock_private(p);
00873 isup_rlc(ss7, e->rsc.call);
00874 break;
00875 case ISUP_EVENT_GRS:
00876 ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
00877 chanpos = ss7_find_cic_gripe(linkset, e->grs.startcic, e->grs.opc, "GRS");
00878 if (chanpos < 0) {
00879 break;
00880 }
00881 p = linkset->pvts[chanpos];
00882 isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
00883 ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
00884 ss7_hangup_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc);
00885 break;
00886 case ISUP_EVENT_CQM:
00887 ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
00888 ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
00889 break;
00890 case ISUP_EVENT_GRA:
00891 ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
00892 ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
00893 ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
00894 break;
00895 case ISUP_EVENT_IAM:
00896 ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
00897 chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
00898 if (chanpos < 0) {
00899 isup_rel(ss7, e->iam.call, -1);
00900 break;
00901 }
00902 p = linkset->pvts[chanpos];
00903 sig_ss7_lock_private(p);
00904 sig_ss7_lock_owner(linkset, chanpos);
00905 if (p->call_level != SIG_SS7_CALL_LEVEL_IDLE) {
00906
00907
00908
00909
00910
00911
00912
00913
00914 ast_debug(1,
00915 "Linkset %d: SS7 IAM glare on CIC/DPC %d/%d. Dropping both calls.\n",
00916 linkset->span, e->iam.cic, e->iam.opc);
00917 if (p->call_level == SIG_SS7_CALL_LEVEL_ALLOCATED) {
00918
00919
00920
00921 p->alreadyhungup = 1;
00922 isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
00923 }
00924 p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
00925 if (p->owner) {
00926 p->owner->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
00927 ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
00928 ast_channel_unlock(p->owner);
00929 }
00930 sig_ss7_unlock_private(p);
00931 break;
00932 }
00933
00934
00935
00936
00937 ast_assert(!p->owner);
00938
00939 if (!sig_ss7_is_chan_available(p)) {
00940
00941 isup_rel(ss7, e->iam.call, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
00942 sig_ss7_unlock_private(p);
00943 break;
00944 }
00945
00946
00947 p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
00948 p->ss7call = e->iam.call;
00949
00950 isup_set_call_dpc(p->ss7call, p->dpc);
00951
00952 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
00953 ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
00954 p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
00955 } else
00956 p->cid_num[0] = 0;
00957
00958
00959 if (!ast_strlen_zero(e->iam.called_party_num)) {
00960 ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset,
00961 e->iam.called_party_num, e->iam.called_nai);
00962 } else {
00963 p->exten[0] = '\0';
00964 }
00965 sig_ss7_set_dnid(p, p->exten);
00966
00967 if (p->immediate) {
00968 p->exten[0] = 's';
00969 p->exten[1] = '\0';
00970 } else if (!ast_strlen_zero(e->iam.called_party_num)) {
00971 char *st;
00972 ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
00973 st = strchr(p->exten, '#');
00974 if (st) {
00975 *st = '\0';
00976 }
00977 } else {
00978 p->exten[0] = '\0';
00979 }
00980
00981 p->cid_ani[0] = '\0';
00982 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
00983 ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
00984 else
00985 p->cid_name[0] = '\0';
00986
00987 p->cid_ani2 = e->iam.oli_ani2;
00988 p->cid_ton = 0;
00989 ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
00990 ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
00991 p->gen_add_type = e->iam.gen_add_type;
00992 p->gen_add_nai = e->iam.gen_add_nai;
00993 p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
00994 p->gen_add_num_plan = e->iam.gen_add_num_plan;
00995 ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
00996 p->gen_dig_type = e->iam.gen_dig_type;
00997 p->gen_dig_scheme = e->iam.gen_dig_scheme;
00998 ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
00999 ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
01000 ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
01001 ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
01002 p->calling_party_cat = e->iam.calling_party_cat;
01003
01004 sig_ss7_set_caller_id(p);
01005
01006 if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
01007 if (e->iam.cot_check_required) {
01008 p->call_level = SIG_SS7_CALL_LEVEL_CONTINUITY;
01009 sig_ss7_loopback(p, 1);
01010 } else {
01011 ss7_start_call(p, linkset);
01012 }
01013 } else {
01014 ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
01015 p->alreadyhungup = 1;
01016 isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
01017 }
01018 sig_ss7_unlock_private(p);
01019 break;
01020 case ISUP_EVENT_COT:
01021 chanpos = ss7_find_cic_gripe(linkset, e->cot.cic, e->cot.opc, "COT");
01022 if (chanpos < 0) {
01023 isup_rel(ss7, e->cot.call, -1);
01024 break;
01025 }
01026 p = linkset->pvts[chanpos];
01027
01028 sig_ss7_lock_private(p);
01029 if (p->loopedback) {
01030 sig_ss7_loopback(p, 0);
01031 ss7_start_call(p, linkset);
01032 }
01033 sig_ss7_unlock_private(p);
01034 break;
01035 case ISUP_EVENT_CCR:
01036 ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
01037 chanpos = ss7_find_cic_gripe(linkset, e->ccr.cic, e->ccr.opc, "CCR");
01038 if (chanpos < 0) {
01039 break;
01040 }
01041
01042 p = linkset->pvts[chanpos];
01043
01044 sig_ss7_lock_private(p);
01045 sig_ss7_loopback(p, 1);
01046 sig_ss7_unlock_private(p);
01047
01048 isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
01049 break;
01050 case ISUP_EVENT_CVT:
01051 ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
01052 chanpos = ss7_find_cic_gripe(linkset, e->cvt.cic, e->cvt.opc, "CVT");
01053 if (chanpos < 0) {
01054 break;
01055 }
01056
01057 p = linkset->pvts[chanpos];
01058
01059 sig_ss7_lock_private(p);
01060 sig_ss7_loopback(p, 1);
01061 sig_ss7_unlock_private(p);
01062
01063 isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
01064 break;
01065 case ISUP_EVENT_REL:
01066 chanpos = ss7_find_cic_gripe(linkset, e->rel.cic, e->rel.opc, "REL");
01067 if (chanpos < 0) {
01068
01069 isup_rlc(ss7, e->rel.call);
01070 break;
01071 }
01072 p = linkset->pvts[chanpos];
01073 sig_ss7_lock_private(p);
01074 sig_ss7_lock_owner(linkset, chanpos);
01075 if (p->owner) {
01076 p->owner->hangupcause = e->rel.cause;
01077 ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
01078 ast_channel_unlock(p->owner);
01079 }
01080
01081
01082 sig_ss7_loopback(p, 0);
01083
01084 isup_rlc(ss7, e->rel.call);
01085 p->ss7call = NULL;
01086
01087 sig_ss7_unlock_private(p);
01088 break;
01089 case ISUP_EVENT_ACM:
01090 chanpos = ss7_find_cic_gripe(linkset, e->acm.cic, e->acm.opc, "ACM");
01091 if (chanpos < 0) {
01092 isup_rel(ss7, e->acm.call, -1);
01093 break;
01094 }
01095 {
01096 p = linkset->pvts[chanpos];
01097
01098 ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
01099
01100 if (e->acm.call_ref_ident > 0) {
01101 p->rlt = 1;
01102 }
01103
01104 sig_ss7_lock_private(p);
01105 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
01106 if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
01107 p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
01108 }
01109 sig_ss7_set_dialing(p, 0);
01110
01111 if (e->acm.called_party_status_ind == 1) {
01112 if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
01113 p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
01114 }
01115 sig_ss7_lock_owner(linkset, chanpos);
01116 if (p->owner) {
01117 ast_setstate(p->owner, AST_STATE_RINGING);
01118 ast_channel_unlock(p->owner);
01119 }
01120 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
01121 }
01122 sig_ss7_unlock_private(p);
01123 }
01124 break;
01125 case ISUP_EVENT_CGB:
01126 chanpos = ss7_find_cic_gripe(linkset, e->cgb.startcic, e->cgb.opc, "CGB");
01127 if (chanpos < 0) {
01128 break;
01129 }
01130 p = linkset->pvts[chanpos];
01131 ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
01132 isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
01133 break;
01134 case ISUP_EVENT_CGU:
01135 chanpos = ss7_find_cic_gripe(linkset, e->cgu.startcic, e->cgu.opc, "CGU");
01136 if (chanpos < 0) {
01137 break;
01138 }
01139 p = linkset->pvts[chanpos];
01140 ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
01141 isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
01142 break;
01143 case ISUP_EVENT_UCIC:
01144 chanpos = ss7_find_cic_gripe(linkset, e->ucic.cic, e->ucic.opc, "UCIC");
01145 if (chanpos < 0) {
01146 break;
01147 }
01148 p = linkset->pvts[chanpos];
01149 ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
01150 sig_ss7_lock_private(p);
01151 sig_ss7_set_remotelyblocked(p, 1);
01152 sig_ss7_set_inservice(p, 0);
01153 sig_ss7_unlock_private(p);
01154 break;
01155 case ISUP_EVENT_BLO:
01156 chanpos = ss7_find_cic_gripe(linkset, e->blo.cic, e->blo.opc, "BLO");
01157 if (chanpos < 0) {
01158 break;
01159 }
01160 p = linkset->pvts[chanpos];
01161 ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
01162 sig_ss7_lock_private(p);
01163 sig_ss7_set_remotelyblocked(p, 1);
01164 sig_ss7_unlock_private(p);
01165 isup_bla(linkset->ss7, e->blo.cic, p->dpc);
01166 break;
01167 case ISUP_EVENT_BLA:
01168 chanpos = ss7_find_cic_gripe(linkset, e->bla.cic, e->bla.opc, "BLA");
01169 if (chanpos < 0) {
01170 break;
01171 }
01172 ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
01173 p = linkset->pvts[chanpos];
01174 sig_ss7_lock_private(p);
01175 sig_ss7_set_locallyblocked(p, 1);
01176 sig_ss7_unlock_private(p);
01177 break;
01178 case ISUP_EVENT_UBL:
01179 chanpos = ss7_find_cic_gripe(linkset, e->ubl.cic, e->ubl.opc, "UBL");
01180 if (chanpos < 0) {
01181 break;
01182 }
01183 p = linkset->pvts[chanpos];
01184 ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
01185 sig_ss7_lock_private(p);
01186 sig_ss7_set_remotelyblocked(p, 0);
01187 sig_ss7_unlock_private(p);
01188 isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
01189 break;
01190 case ISUP_EVENT_UBA:
01191 chanpos = ss7_find_cic_gripe(linkset, e->uba.cic, e->uba.opc, "UBA");
01192 if (chanpos < 0) {
01193 break;
01194 }
01195 p = linkset->pvts[chanpos];
01196 ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
01197 sig_ss7_lock_private(p);
01198 sig_ss7_set_locallyblocked(p, 0);
01199 sig_ss7_unlock_private(p);
01200 break;
01201 case ISUP_EVENT_CON:
01202 case ISUP_EVENT_ANM:
01203 if (e->e == ISUP_EVENT_CON) {
01204 chanpos = ss7_find_cic_gripe(linkset, e->con.cic, e->con.opc, "CON");
01205 if (chanpos < 0) {
01206 isup_rel(ss7, e->con.call, -1);
01207 break;
01208 }
01209 } else {
01210 chanpos = ss7_find_cic_gripe(linkset, e->anm.cic, e->anm.opc, "ANM");
01211 if (chanpos < 0) {
01212 isup_rel(ss7, e->anm.call, -1);
01213 break;
01214 }
01215 }
01216
01217 {
01218 p = linkset->pvts[chanpos];
01219 sig_ss7_lock_private(p);
01220 if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
01221 p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
01222 }
01223 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
01224 sig_ss7_set_dialing(p, 0);
01225 sig_ss7_open_media(p);
01226 sig_ss7_set_echocanceller(p, 1);
01227 sig_ss7_unlock_private(p);
01228 }
01229 break;
01230 case ISUP_EVENT_RLC:
01231
01232 chanpos = ss7_find_cic_gripe(linkset, e->rlc.cic, e->rlc.opc, "RLC");
01233 if (chanpos < 0) {
01234 break;
01235 }
01236 {
01237 p = linkset->pvts[chanpos];
01238 sig_ss7_lock_private(p);
01239 if (p->alreadyhungup) {
01240 if (!p->owner) {
01241 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
01242 }
01243 p->ss7call = NULL;
01244 }
01245 sig_ss7_unlock_private(p);
01246 }
01247 break;
01248 case ISUP_EVENT_FAA:
01249
01250
01251
01252
01253 chanpos = ss7_find_cic_gripe(linkset, e->faa.cic, e->faa.opc, "FAA");
01254 if (chanpos < 0) {
01255 isup_rel(linkset->ss7, e->faa.call, -1);
01256 break;
01257 }
01258 {
01259
01260 p = linkset->pvts[chanpos];
01261 ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
01262 sig_ss7_lock_private(p);
01263 if (p->alreadyhungup){
01264 if (!p->owner) {
01265 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
01266 }
01267
01268 p->ss7call = NULL;
01269 ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR. Ignoring.\n");
01270 }
01271 sig_ss7_unlock_private(p);
01272 }
01273 break;
01274 default:
01275 ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
01276 break;
01277 }
01278 }
01279 ast_mutex_unlock(&linkset->lock);
01280 }
01281
01282 return 0;
01283 }
01284
01285 static inline void ss7_rel(struct sig_ss7_linkset *ss7)
01286 {
01287 ast_mutex_unlock(&ss7->lock);
01288 }
01289
01290 static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
01291 {
01292
01293 while (ast_mutex_trylock(&ss7->lock)) {
01294
01295 sig_ss7_unlock_private(pvt);
01296 sched_yield();
01297 sig_ss7_lock_private(pvt);
01298 }
01299
01300 if (ss7->master != AST_PTHREADT_NULL) {
01301 pthread_kill(ss7->master, SIGURG);
01302 }
01303 }
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314 void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which)
01315 {
01316 linkset->linkstate[which] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
01317 linkset->linkstate[which] &= ~LINKSTATE_UP;
01318 ss7_link_alarm(linkset->ss7, linkset->fds[which]);
01319 }
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
01331 {
01332 linkset->linkstate[which] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
01333 linkset->linkstate[which] |= LINKSTATE_STARTING;
01334 ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353 int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode)
01354 {
01355 if (!linkset->ss7) {
01356 linkset->type = ss7type;
01357 linkset->ss7 = ss7_new(ss7type);
01358 if (!linkset->ss7) {
01359 ast_log(LOG_ERROR, "Can't create new SS7!\n");
01360 return -1;
01361 }
01362 }
01363
01364 ss7_set_network_ind(linkset->ss7, networkindicator);
01365 ss7_set_pc(linkset->ss7, pointcode);
01366
01367 if (ss7_add_link(linkset->ss7, transport, linkset->fds[which])) {
01368 ast_log(LOG_WARNING, "Could not add SS7 link!\n");
01369 }
01370
01371 if (inalarm) {
01372 linkset->linkstate[which] = LINKSTATE_DOWN | LINKSTATE_INALARM;
01373 ss7_link_alarm(linkset->ss7, linkset->fds[which]);
01374 } else {
01375 linkset->linkstate[which] = LINKSTATE_DOWN;
01376 ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
01377 }
01378
01379 ss7_set_adjpc(linkset->ss7, linkset->fds[which], adjpointcode);
01380
01381 return 0;
01382 }
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392 int sig_ss7_available(struct sig_ss7_chan *p)
01393 {
01394 int available;
01395
01396 if (!p->ss7) {
01397
01398 return 0;
01399 }
01400
01401
01402 ast_mutex_lock(&p->ss7->lock);
01403 available = sig_ss7_is_chan_available(p);
01404 if (available) {
01405 p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
01406 }
01407 ast_mutex_unlock(&p->ss7->lock);
01408
01409 return available;
01410 }
01411
01412 static unsigned char cid_pres2ss7pres(int cid_pres)
01413 {
01414 return (cid_pres >> 5) & 0x03;
01415 }
01416
01417 static unsigned char cid_pres2ss7screen(int cid_pres)
01418 {
01419 return cid_pres & 0x03;
01420 }
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, char *rdest)
01434 {
01435 char ss7_called_nai;
01436 int called_nai_strip;
01437 char ss7_calling_nai;
01438 int calling_nai_strip;
01439 const char *charge_str = NULL;
01440 const char *gen_address = NULL;
01441 const char *gen_digits = NULL;
01442 const char *gen_dig_type = NULL;
01443 const char *gen_dig_scheme = NULL;
01444 const char *gen_name = NULL;
01445 const char *jip_digits = NULL;
01446 const char *lspi_ident = NULL;
01447 const char *rlt_flag = NULL;
01448 const char *call_ref_id = NULL;
01449 const char *call_ref_pc = NULL;
01450 const char *send_far = NULL;
01451 char *c;
01452 char *l;
01453 char dest[256];
01454
01455 ast_copy_string(dest, rdest, sizeof(dest));
01456
01457 c = strchr(dest, '/');
01458 if (c) {
01459 c++;
01460 } else {
01461 c = "";
01462 }
01463 if (strlen(c) < p->stripmsd) {
01464 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
01465 return -1;
01466 }
01467
01468 if (!p->hidecallerid) {
01469 l = ast->connected.id.number.valid ? ast->connected.id.number.str : NULL;
01470 } else {
01471 l = NULL;
01472 }
01473
01474 ss7_grab(p, p->ss7);
01475
01476 if (p->call_level != SIG_SS7_CALL_LEVEL_ALLOCATED) {
01477
01478 ss7_rel(p->ss7);
01479 return -1;
01480 }
01481
01482 p->ss7call = isup_new_call(p->ss7->ss7);
01483 if (!p->ss7call) {
01484 ss7_rel(p->ss7);
01485 ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
01486 return -1;
01487 }
01488
01489 called_nai_strip = 0;
01490 ss7_called_nai = p->ss7->called_nai;
01491 if (ss7_called_nai == SS7_NAI_DYNAMIC) {
01492 if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
01493 called_nai_strip = strlen(p->ss7->internationalprefix);
01494 ss7_called_nai = SS7_NAI_INTERNATIONAL;
01495 } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
01496 called_nai_strip = strlen(p->ss7->nationalprefix);
01497 ss7_called_nai = SS7_NAI_NATIONAL;
01498 } else {
01499 ss7_called_nai = SS7_NAI_SUBSCRIBER;
01500 }
01501 }
01502 isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
01503
01504 calling_nai_strip = 0;
01505 ss7_calling_nai = p->ss7->calling_nai;
01506 if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) {
01507 if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
01508 calling_nai_strip = strlen(p->ss7->internationalprefix);
01509 ss7_calling_nai = SS7_NAI_INTERNATIONAL;
01510 } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
01511 calling_nai_strip = strlen(p->ss7->nationalprefix);
01512 ss7_calling_nai = SS7_NAI_NATIONAL;
01513 } else {
01514 ss7_calling_nai = SS7_NAI_SUBSCRIBER;
01515 }
01516 }
01517 isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
01518 p->use_callingpres ? cid_pres2ss7pres(ast->connected.id.number.presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
01519 p->use_callingpres ? cid_pres2ss7screen(ast->connected.id.number.presentation) : SS7_SCREENING_USER_PROVIDED);
01520
01521 isup_set_oli(p->ss7call, ast->connected.ani2);
01522 isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
01523
01524
01525 charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
01526 if (charge_str)
01527 isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
01528
01529 gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
01530 if (gen_address)
01531 isup_set_gen_address(p->ss7call, gen_address, p->gen_add_nai,p->gen_add_pres_ind, p->gen_add_num_plan,p->gen_add_type);
01532
01533 gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
01534 gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
01535 gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
01536 if (gen_digits)
01537 isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme));
01538
01539 gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
01540 if (gen_name)
01541 isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
01542
01543 jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
01544 if (jip_digits)
01545 isup_set_jip_digits(p->ss7call, jip_digits);
01546
01547 lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
01548 if (lspi_ident)
01549 isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00);
01550
01551 rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
01552 if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
01553 isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00);
01554 }
01555
01556 call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
01557 call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
01558 if (call_ref_id && call_ref_pc) {
01559 isup_set_callref(p->ss7call, atoi(call_ref_id),
01560 call_ref_pc ? atoi(call_ref_pc) : 0);
01561 }
01562
01563 send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
01564 if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
01565 (isup_far(p->ss7->ss7, p->ss7call));
01566
01567 p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
01568 isup_iam(p->ss7->ss7, p->ss7call);
01569 sig_ss7_set_dialing(p, 1);
01570 ast_setstate(ast, AST_STATE_DIALING);
01571 ss7_rel(p->ss7);
01572 return 0;
01573 }
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585 int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
01586 {
01587 int res = 0;
01588
01589 if (!ast->tech_pvt) {
01590 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
01591 return 0;
01592 }
01593
01594 p->owner = NULL;
01595 sig_ss7_set_dialing(p, 0);
01596 sig_ss7_set_outgoing(p, 0);
01597 p->progress = 0;
01598 p->rlt = 0;
01599 p->exten[0] = '\0';
01600
01601 ss7_grab(p, p->ss7);
01602 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
01603 if (p->ss7call) {
01604 if (!p->alreadyhungup) {
01605 const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
01606 int icause = ast->hangupcause ? ast->hangupcause : -1;
01607
01608 if (cause) {
01609 if (atoi(cause)) {
01610 icause = atoi(cause);
01611 }
01612 }
01613 isup_rel(p->ss7->ss7, p->ss7call, icause);
01614 p->alreadyhungup = 1;
01615 }
01616 }
01617 ss7_rel(p->ss7);
01618
01619 return res;
01620 }
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632 int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
01633 {
01634 int res;
01635
01636 ss7_grab(p, p->ss7);
01637 if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
01638 p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
01639 }
01640 sig_ss7_open_media(p);
01641 res = isup_anm(p->ss7->ss7, p->ss7call);
01642 ss7_rel(p->ss7);
01643 return res;
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656 void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan)
01657 {
01658 if (pchan->owner == oldchan) {
01659 pchan->owner = newchan;
01660 }
01661 }
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676 int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
01677 {
01678 int res = -1;
01679
01680 switch (condition) {
01681 case AST_CONTROL_BUSY:
01682 if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
01683 chan->hangupcause = AST_CAUSE_USER_BUSY;
01684 ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
01685 res = 0;
01686 break;
01687 }
01688 res = sig_ss7_play_tone(p, SIG_SS7_TONE_BUSY);
01689 break;
01690 case AST_CONTROL_RINGING:
01691 ss7_grab(p, p->ss7);
01692 if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
01693 p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
01694 if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
01695 p->rlt = 1;
01696 }
01697
01698
01699 if (p->rlt != 1) {
01700 isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
01701 }
01702 }
01703 ss7_rel(p->ss7);
01704
01705 res = sig_ss7_play_tone(p, SIG_SS7_TONE_RINGTONE);
01706
01707 if (chan->_state != AST_STATE_UP && chan->_state != AST_STATE_RING) {
01708 ast_setstate(chan, AST_STATE_RINGING);
01709 }
01710 break;
01711 case AST_CONTROL_PROCEEDING:
01712 ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
01713 ss7_grab(p, p->ss7);
01714
01715 if (chan->_state == AST_STATE_UP && (p->rlt != 1)){
01716 if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
01717 p->rlt = 1;
01718 }
01719 }
01720
01721 if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && !p->outgoing) {
01722 p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
01723 isup_acm(p->ss7->ss7, p->ss7call);
01724 }
01725 ss7_rel(p->ss7);
01726
01727 res = 0;
01728 break;
01729 case AST_CONTROL_PROGRESS:
01730 ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
01731 ss7_grab(p, p->ss7);
01732 if (!p->progress && p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
01733 p->progress = 1;
01734 isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
01735 ss7_rel(p->ss7);
01736
01737
01738 sig_ss7_set_echocanceller(p, 1);
01739 } else {
01740 ss7_rel(p->ss7);
01741 }
01742
01743 res = 0;
01744 break;
01745 case AST_CONTROL_INCOMPLETE:
01746 if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
01747 chan->hangupcause = AST_CAUSE_INVALID_NUMBER_FORMAT;
01748 ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
01749 res = 0;
01750 break;
01751 }
01752
01753 res = 0;
01754 break;
01755 case AST_CONTROL_CONGESTION:
01756 if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
01757 chan->hangupcause = AST_CAUSE_CONGESTION;
01758 ast_softhangup_nolock(chan, AST_SOFTHANGUP_DEV);
01759 res = 0;
01760 break;
01761 }
01762 res = sig_ss7_play_tone(p, SIG_SS7_TONE_CONGESTION);
01763 break;
01764 case AST_CONTROL_HOLD:
01765 ast_moh_start(chan, data, p->mohinterpret);
01766 break;
01767 case AST_CONTROL_UNHOLD:
01768 ast_moh_stop(chan);
01769 break;
01770 case AST_CONTROL_SRCUPDATE:
01771 res = 0;
01772 break;
01773 case -1:
01774 res = sig_ss7_play_tone(p, -1);
01775 break;
01776 }
01777 return res;
01778 }
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792 struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_channel *requestor, int transfercapability)
01793 {
01794 struct ast_channel *ast;
01795
01796
01797 if (p->ss7->type == SS7_ITU) {
01798 law = SIG_SS7_ALAW;
01799 } else {
01800 law = SIG_SS7_ULAW;
01801 }
01802
01803 sig_ss7_set_outgoing(p, 1);
01804 ast = sig_ss7_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
01805 if (!ast) {
01806 sig_ss7_set_outgoing(p, 0);
01807
01808
01809 ast_mutex_lock(&p->ss7->lock);
01810 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
01811 ast_mutex_unlock(&p->ss7->lock);
01812 }
01813 return ast;
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824 void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
01825 {
01826 ast_free(doomed);
01827 }
01828
01829 #define SIG_SS7_SC_HEADER "%-4s %4s %-4s %-3s %-3s %-10s %-4s %s\n"
01830 #define SIG_SS7_SC_LINE "%4d %4d %-4s %-3s %-3s %-10s %-4s %s"
01831 void sig_ss7_cli_show_channels_header(int fd)
01832 {
01833 ast_cli(fd, SIG_SS7_SC_HEADER, "link", "", "Chan", "Lcl", "Rem", "Call", "SS7", "Channel");
01834 ast_cli(fd, SIG_SS7_SC_HEADER, "set", "Chan", "Idle", "Blk", "Blk", "Level", "Call", "Name");
01835 }
01836
01837 void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset)
01838 {
01839 char line[256];
01840 int idx;
01841 struct sig_ss7_chan *pvt;
01842
01843 ast_mutex_lock(&linkset->lock);
01844 for (idx = 0; idx < linkset->numchans; ++idx) {
01845 if (!linkset->pvts[idx]) {
01846 continue;
01847 }
01848 pvt = linkset->pvts[idx];
01849 sig_ss7_lock_private(pvt);
01850 sig_ss7_lock_owner(linkset, idx);
01851
01852 snprintf(line, sizeof(line), SIG_SS7_SC_LINE,
01853 linkset->span,
01854 pvt->channel,
01855 sig_ss7_is_chan_available(pvt) ? "Yes" : "No",
01856 pvt->locallyblocked ? "Yes" : "No",
01857 pvt->remotelyblocked ? "Yes" : "No",
01858 sig_ss7_call_level2str(pvt->call_level),
01859 pvt->ss7call ? "Yes" : "No",
01860 pvt->owner ? pvt->owner->name : "");
01861
01862 if (pvt->owner) {
01863 ast_channel_unlock(pvt->owner);
01864 }
01865 sig_ss7_unlock_private(pvt);
01866
01867 ast_mutex_unlock(&linkset->lock);
01868 ast_cli(fd, "%s\n", line);
01869 ast_mutex_lock(&linkset->lock);
01870 }
01871 ast_mutex_unlock(&linkset->lock);
01872 }
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885 struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_callback *callback, struct sig_ss7_linkset *ss7)
01886 {
01887 struct sig_ss7_chan *pvt;
01888
01889 pvt = ast_calloc(1, sizeof(*pvt));
01890 if (!pvt) {
01891 return pvt;
01892 }
01893
01894 pvt->calls = callback;
01895 pvt->chan_pvt = pvt_data;
01896 pvt->ss7 = ss7;
01897
01898 return pvt;
01899 }
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909 void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7)
01910 {
01911 int idx;
01912
01913 memset(ss7, 0, sizeof(*ss7));
01914
01915 ast_mutex_init(&ss7->lock);
01916
01917 ss7->master = AST_PTHREADT_NULL;
01918 for (idx = 0; idx < ARRAY_LEN(ss7->fds); ++idx) {
01919 ss7->fds[idx] = -1;
01920 }
01921 }
01922
01923
01924
01925 #endif
01926