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