Sun May 20 06:34:01 2012

Asterisk developer's documentation


sig_ss7.c

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

Generated on Sun May 20 06:34:01 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6