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