Sat Apr 26 2014 22:01:42

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