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