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