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

Generated on Mon Oct 8 12:39:05 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7