9edb04bbb7d2bf4fe9681fd56078f473e0e20601
[asterisk/asterisk.git] / channels / sig_ss7.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010 Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief SS7 signaling module.
22  *
23  * \author Matthew Fredrickson <creslin@digium.com>
24  * \author Richard Mudgett <rmudgett@digium.com>
25  *
26  * See Also:
27  * \arg \ref AstCREDITS
28  */
29
30
31 #include "asterisk.h"
32
33 #if defined(HAVE_SS7)
34
35 #include <signal.h>
36
37 #include "asterisk/pbx.h"
38 #include "asterisk/causes.h"
39 #include "asterisk/musiconhold.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/transcap.h"
42
43 #include "sig_ss7.h"
44
45 /* ------------------------------------------------------------------- */
46
47 static const char *sig_ss7_call_level2str(enum sig_ss7_call_level level)
48 {
49         switch (level) {
50         case SIG_SS7_CALL_LEVEL_IDLE:
51                 return "Idle";
52         case SIG_SS7_CALL_LEVEL_ALLOCATED:
53                 return "Allocated";
54         case SIG_SS7_CALL_LEVEL_CONTINUITY:
55                 return "Continuity";
56         case SIG_SS7_CALL_LEVEL_SETUP:
57                 return "Setup";
58         case SIG_SS7_CALL_LEVEL_PROCEEDING:
59                 return "Proceeding";
60         case SIG_SS7_CALL_LEVEL_ALERTING:
61                 return "Alerting";
62         case SIG_SS7_CALL_LEVEL_CONNECT:
63                 return "Connect";
64         case SIG_SS7_CALL_LEVEL_GLARE:
65                 return "Glare";
66         }
67         return "Unknown";
68 }
69
70 #define SIG_SS7_DEADLOCK_AVOIDANCE(p) \
71         do { \
72                 sig_ss7_unlock_private(p); \
73                 usleep(1); \
74                 sig_ss7_lock_private(p); \
75         } while (0)
76
77 static void sig_ss7_unlock_private(struct sig_ss7_chan *p)
78 {
79         if (p->calls->unlock_private) {
80                 p->calls->unlock_private(p->chan_pvt);
81         }
82 }
83
84 static void sig_ss7_lock_private(struct sig_ss7_chan *p)
85 {
86         if (p->calls->lock_private) {
87                 p->calls->lock_private(p->chan_pvt);
88         }
89 }
90
91 static void sig_ss7_deadlock_avoidance_private(struct sig_ss7_chan *p)
92 {
93         if (p->calls->deadlock_avoidance_private) {
94                 p->calls->deadlock_avoidance_private(p->chan_pvt);
95         } else {
96                 /* Fallback to the old way if callback not present. */
97                 SIG_SS7_DEADLOCK_AVOIDANCE(p);
98         }
99 }
100
101 void sig_ss7_set_alarm(struct sig_ss7_chan *p, int in_alarm)
102 {
103         p->inalarm = in_alarm;
104         if (p->calls->set_alarm) {
105                 p->calls->set_alarm(p->chan_pvt, in_alarm);
106         }
107 }
108
109 static void sig_ss7_set_dialing(struct sig_ss7_chan *p, int is_dialing)
110 {
111         if (p->calls->set_dialing) {
112                 p->calls->set_dialing(p->chan_pvt, is_dialing);
113         }
114 }
115
116 static void sig_ss7_set_digital(struct sig_ss7_chan *p, int is_digital)
117 {
118         if (p->calls->set_digital) {
119                 p->calls->set_digital(p->chan_pvt, is_digital);
120         }
121 }
122
123 static void sig_ss7_set_outgoing(struct sig_ss7_chan *p, int is_outgoing)
124 {
125         p->outgoing = is_outgoing;
126         if (p->calls->set_outgoing) {
127                 p->calls->set_outgoing(p->chan_pvt, is_outgoing);
128         }
129 }
130
131 static void sig_ss7_set_inservice(struct sig_ss7_chan *p, int is_inservice)
132 {
133         if (p->calls->set_inservice) {
134                 p->calls->set_inservice(p->chan_pvt, is_inservice);
135         }
136 }
137
138 static void sig_ss7_set_locallyblocked(struct sig_ss7_chan *p, int is_blocked)
139 {
140         p->locallyblocked = is_blocked;
141         if (p->calls->set_locallyblocked) {
142                 p->calls->set_locallyblocked(p->chan_pvt, is_blocked);
143         }
144 }
145
146 static void sig_ss7_set_remotelyblocked(struct sig_ss7_chan *p, int is_blocked)
147 {
148         p->remotelyblocked = is_blocked;
149         if (p->calls->set_remotelyblocked) {
150                 p->calls->set_remotelyblocked(p->chan_pvt, is_blocked);
151         }
152 }
153
154 /*!
155  * \internal
156  * \brief Set the caller id information in the parent module.
157  * \since 1.8
158  *
159  * \param p sig_ss7 channel structure.
160  *
161  * \return Nothing
162  */
163 static void sig_ss7_set_caller_id(struct sig_ss7_chan *p)
164 {
165         struct ast_party_caller caller;
166
167         if (p->calls->set_callerid) {
168                 ast_party_caller_init(&caller);
169
170                 caller.id.name.str = p->cid_name;
171                 caller.id.name.presentation = p->callingpres;
172                 caller.id.name.valid = 1;
173
174                 caller.id.number.str = p->cid_num;
175                 caller.id.number.plan = p->cid_ton;
176                 caller.id.number.presentation = p->callingpres;
177                 caller.id.number.valid = 1;
178
179                 if (!ast_strlen_zero(p->cid_subaddr)) {
180                         caller.id.subaddress.valid = 1;
181                         //caller.id.subaddress.type = 0;/* nsap */
182                         //caller.id.subaddress.odd_even_indicator = 0;
183                         caller.id.subaddress.str = p->cid_subaddr;
184                 }
185
186                 caller.ani.number.str = p->cid_ani;
187                 //caller.ani.number.plan = p->xxx;
188                 //caller.ani.number.presentation = p->xxx;
189                 caller.ani.number.valid = 1;
190
191                 caller.ani2 = p->cid_ani2;
192                 p->calls->set_callerid(p->chan_pvt, &caller);
193         }
194 }
195
196 /*!
197  * \internal
198  * \brief Set the Dialed Number Identifier.
199  * \since 1.8
200  *
201  * \param p sig_ss7 channel structure.
202  * \param dnid Dialed Number Identifier string.
203  *
204  * \return Nothing
205  */
206 static void sig_ss7_set_dnid(struct sig_ss7_chan *p, const char *dnid)
207 {
208         if (p->calls->set_dnid) {
209                 p->calls->set_dnid(p->chan_pvt, dnid);
210         }
211 }
212
213 static int sig_ss7_play_tone(struct sig_ss7_chan *p, enum sig_ss7_tone tone)
214 {
215         int res;
216
217         if (p->calls->play_tone) {
218                 res = p->calls->play_tone(p->chan_pvt, tone);
219         } else {
220                 res = -1;
221         }
222         return res;
223 }
224
225 static int sig_ss7_set_echocanceller(struct sig_ss7_chan *p, int enable)
226 {
227         if (p->calls->set_echocanceller) {
228                 return p->calls->set_echocanceller(p->chan_pvt, enable);
229         }
230         return -1;
231 }
232
233 static void sig_ss7_loopback(struct sig_ss7_chan *p, int enable)
234 {
235         if (p->loopedback != enable) {
236                 p->loopedback = enable;
237                 if (p->calls->set_loopback) {
238                         p->calls->set_loopback(p->chan_pvt, enable);
239                 }
240         }
241 }
242
243 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)
244 {
245         struct ast_channel *ast;
246
247         if (p->calls->new_ast_channel) {
248                 ast = p->calls->new_ast_channel(p->chan_pvt, state, ulaw, exten, requestor);
249         } else {
250                 return NULL;
251         }
252         if (!ast) {
253                 return NULL;
254         }
255
256         if (!p->owner) {
257                 p->owner = ast;
258         }
259         p->alreadyhungup = 0;
260         ast->transfercapability = transfercapability;
261         pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY",
262                 ast_transfercapability2str(transfercapability));
263         if (transfercapability & AST_TRANS_CAP_DIGITAL) {
264                 sig_ss7_set_digital(p, 1);
265         }
266
267         return ast;
268 }
269
270 static void sig_ss7_handle_link_exception(struct sig_ss7_linkset *linkset, int which)
271 {
272         if (linkset->calls->handle_link_exception) {
273                 linkset->calls->handle_link_exception(linkset, which);
274         }
275 }
276
277 /*!
278  * \internal
279  * \brief Obtain the sig_ss7 owner channel lock if the owner exists.
280  * \since 1.8
281  *
282  * \param ss7 SS7 linkset control structure.
283  * \param chanpos Channel position in the span.
284  *
285  * \note Assumes the ss7->lock is already obtained.
286  * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
287  *
288  * \return Nothing
289  */
290 static void sig_ss7_lock_owner(struct sig_ss7_linkset *ss7, int chanpos)
291 {
292         for (;;) {
293                 if (!ss7->pvts[chanpos]->owner) {
294                         /* There is no owner lock to get. */
295                         break;
296                 }
297                 if (!ast_channel_trylock(ss7->pvts[chanpos]->owner)) {
298                         /* We got the lock */
299                         break;
300                 }
301                 /* We must unlock the SS7 to avoid the possibility of a deadlock */
302                 ast_mutex_unlock(&ss7->lock);
303                 sig_ss7_deadlock_avoidance_private(ss7->pvts[chanpos]);
304                 ast_mutex_lock(&ss7->lock);
305         }
306 }
307
308 /*!
309  * \internal
310  * \brief Queue the given frame onto the owner channel.
311  * \since 1.8
312  *
313  * \param ss7 SS7 linkset control structure.
314  * \param chanpos Channel position in the span.
315  * \param frame Frame to queue onto the owner channel.
316  *
317  * \note Assumes the ss7->lock is already obtained.
318  * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
319  *
320  * \return Nothing
321  */
322 static void sig_ss7_queue_frame(struct sig_ss7_linkset *ss7, int chanpos, struct ast_frame *frame)
323 {
324         sig_ss7_lock_owner(ss7, chanpos);
325         if (ss7->pvts[chanpos]->owner) {
326                 ast_queue_frame(ss7->pvts[chanpos]->owner, frame);
327                 ast_channel_unlock(ss7->pvts[chanpos]->owner);
328         }
329 }
330
331 /*!
332  * \internal
333  * \brief Queue a control frame of the specified subclass onto the owner channel.
334  * \since 1.8
335  *
336  * \param ss7 SS7 linkset control structure.
337  * \param chanpos Channel position in the span.
338  * \param subclass Control frame subclass to queue onto the owner channel.
339  *
340  * \note Assumes the ss7->lock is already obtained.
341  * \note Assumes the sig_ss7_lock_private(ss7->pvts[chanpos]) is already obtained.
342  *
343  * \return Nothing
344  */
345 static void sig_ss7_queue_control(struct sig_ss7_linkset *ss7, int chanpos, int subclass)
346 {
347         struct ast_frame f = {AST_FRAME_CONTROL, };
348         struct sig_ss7_chan *p = ss7->pvts[chanpos];
349
350         if (p->calls->queue_control) {
351                 p->calls->queue_control(p->chan_pvt, subclass);
352         }
353
354         f.subclass.integer = subclass;
355         sig_ss7_queue_frame(ss7, chanpos, &f);
356 }
357
358 /*!
359  * \internal
360  * \brief Find the channel position by CIC/DPC.
361  *
362  * \param linkset SS7 linkset control structure.
363  * \param cic Circuit Identification Code
364  * \param dpc Destination Point Code
365  *
366  * \retval chanpos on success.
367  * \retval -1 on error.
368  */
369 static int ss7_find_cic(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc)
370 {
371         int i;
372         int winner = -1;
373         for (i = 0; i < linkset->numchans; i++) {
374                 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
375                         winner = i;
376                         break;
377                 }
378         }
379         return winner;
380 }
381
382 /*!
383  * \internal
384  * \brief Find the channel position by CIC/DPC and gripe if not found.
385  *
386  * \param linkset SS7 linkset control structure.
387  * \param cic Circuit Identification Code
388  * \param dpc Destination Point Code
389  * \param msg_name Message type name that failed.
390  *
391  * \retval chanpos on success.
392  * \retval -1 on error.
393  */
394 static int ss7_find_cic_gripe(struct sig_ss7_linkset *linkset, int cic, unsigned int dpc, const char *msg_name)
395 {
396         int chanpos;
397
398         chanpos = ss7_find_cic(linkset, cic, dpc);
399         if (chanpos < 0) {
400                 ast_log(LOG_WARNING, "Linkset %d: SS7 %s requested unconfigured CIC/DPC %d/%d.\n",
401                         linkset->span, msg_name, cic, dpc);
402                 return -1;
403         }
404         return chanpos;
405 }
406
407 static void ss7_handle_cqm(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
408 {
409         unsigned char status[32];
410         struct sig_ss7_chan *p = NULL;
411         int i, offset;
412
413         for (i = 0; i < linkset->numchans; i++) {
414                 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
415                         p = linkset->pvts[i];
416                         offset = p->cic - startcic;
417                         status[offset] = 0;
418                         if (p->locallyblocked)
419                                 status[offset] |= (1 << 0) | (1 << 4);
420                         if (p->remotelyblocked)
421                                 status[offset] |= (1 << 1) | (1 << 5);
422                         if (p->ss7call) {
423                                 if (p->outgoing)
424                                         status[offset] |= (1 << 3);
425                                 else
426                                         status[offset] |= (1 << 2);
427                         } else
428                                 status[offset] |= 0x3 << 2;
429                 }
430         }
431
432         if (p)
433                 isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
434         else
435                 ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
436
437 }
438
439 static inline void ss7_hangup_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
440 {
441         int i;
442
443         for (i = 0; i < linkset->numchans; i++) {
444                 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
445                         sig_ss7_lock_private(linkset->pvts[i]);
446                         if (linkset->pvts[i]->owner)
447                                 linkset->pvts[i]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
448                         sig_ss7_unlock_private(linkset->pvts[i]);
449                 }
450         }
451 }
452
453 static inline void ss7_block_cics(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
454 {
455         int i;
456
457         /* XXX the use of state here seems questionable about matching up with the linkset channels */
458         for (i = 0; i < linkset->numchans; i++) {
459                 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
460                         if (state) {
461                                 if (state[i])
462                                         sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
463                         } else
464                                 sig_ss7_set_remotelyblocked(linkset->pvts[i], block);
465                 }
466         }
467 }
468
469 static void ss7_inservice(struct sig_ss7_linkset *linkset, int startcic, int endcic, unsigned int dpc)
470 {
471         int i;
472
473         for (i = 0; i < linkset->numchans; i++) {
474                 if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
475                         sig_ss7_set_inservice(linkset->pvts[i], 1);
476         }
477 }
478
479 static void ss7_reset_linkset(struct sig_ss7_linkset *linkset)
480 {
481         int i, startcic = -1, endcic, dpc;
482
483         if (linkset->numchans <= 0)
484                 return;
485
486         startcic = linkset->pvts[0]->cic;
487         /* DB: CIC's DPC fix */
488         dpc = linkset->pvts[0]->dpc;
489
490         for (i = 0; i < linkset->numchans; i++) {
491                 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)) {
492                         continue;
493                 } else {
494                         endcic = linkset->pvts[i]->cic;
495                         ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
496                         isup_grs(linkset->ss7, startcic, endcic, dpc);
497
498                         /* DB: CIC's DPC fix */
499                         if (linkset->pvts[i+1]) {
500                                 startcic = linkset->pvts[i+1]->cic;
501                                 dpc = linkset->pvts[i+1]->dpc;
502                         }
503                 }
504         }
505 }
506
507 /* This function is assumed to be called with the private channel lock and linkset lock held */
508 static void ss7_start_call(struct sig_ss7_chan *p, struct sig_ss7_linkset *linkset)
509 {
510         struct ss7 *ss7 = linkset->ss7;
511         int law;
512         struct ast_channel *c;
513         char tmp[256];
514
515         if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
516                 p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
517                 isup_acm(ss7, p->ss7call);
518         } else {
519                 p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
520         }
521
522         if (linkset->type == SS7_ITU) {
523                 law = SIG_SS7_ALAW;
524         } else {
525                 law = SIG_SS7_ULAW;
526         }
527
528         /*
529          * Release the SS7 lock while we create the channel so other
530          * threads can send messages.  We must also release the private
531          * lock to prevent deadlock while creating the channel.
532          */
533         ast_mutex_unlock(&linkset->lock);
534         sig_ss7_unlock_private(p);
535         c = sig_ss7_new_ast_channel(p, AST_STATE_RING, law, 0, p->exten, NULL);
536         if (!c) {
537                 ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
538                 ast_mutex_lock(&linkset->lock);
539                 sig_ss7_lock_private(p);
540                 isup_rel(linkset->ss7, p->ss7call, -1);
541                 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
542                 p->alreadyhungup = 1;
543                 return;
544         }
545
546         /* Hold the channel and private lock while we setup the channel. */
547         ast_channel_lock(c);
548         sig_ss7_lock_private(p);
549
550         sig_ss7_set_echocanceller(p, 1);
551
552         /*
553          * It is reasonably safe to set the following
554          * channel variables while the channel private
555          * structure is locked.  The PBX has not been
556          * started yet and it is unlikely that any other task
557          * will do anything with the channel we have just
558          * created.
559          *
560          * We only reference these variables in the context of the ss7_linkset function
561          * when receiving either and IAM or a COT message.
562          */
563         if (!ast_strlen_zero(p->charge_number)) {
564                 pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
565                 /* Clear this after we set it */
566                 p->charge_number[0] = 0;
567         }
568         if (!ast_strlen_zero(p->gen_add_number)) {
569                 pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
570                 /* Clear this after we set it */
571                 p->gen_add_number[0] = 0;
572         }
573         if (!ast_strlen_zero(p->jip_number)) {
574                 pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
575                 /* Clear this after we set it */
576                 p->jip_number[0] = 0;
577         }
578         if (!ast_strlen_zero(p->gen_dig_number)) {
579                 pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
580                 /* Clear this after we set it */
581                 p->gen_dig_number[0] = 0;
582         }
583         if (!ast_strlen_zero(p->orig_called_num)) {
584                 pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
585                 /* Clear this after we set it */
586                 p->orig_called_num[0] = 0;
587         }
588
589         snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
590         pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
591         /* Clear this after we set it */
592         p->gen_dig_type = 0;
593
594         snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
595         pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
596         /* Clear this after we set it */
597         p->gen_dig_scheme = 0;
598
599         if (!ast_strlen_zero(p->lspi_ident)) {
600                 pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
601                 /* Clear this after we set it */
602                 p->lspi_ident[0] = 0;
603         }
604
605         snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
606         pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
607         /* Clear this after we set it */
608         p->call_ref_ident = 0;
609
610         snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
611         pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
612         /* Clear this after we set it */
613         p->call_ref_pc = 0;
614
615         snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
616         pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
617         /* Clear this after we set it */
618         p->calling_party_cat = 0;
619
620         if (!ast_strlen_zero(p->redirecting_num)) {
621                 pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
622                 /* Clear this after we set it */
623                 p->redirecting_num[0] = 0;
624         }
625         if (!ast_strlen_zero(p->generic_name)) {
626                 pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
627                 /* Clear this after we set it */
628                 p->generic_name[0] = 0;
629         }
630
631         sig_ss7_unlock_private(p);
632         ast_channel_unlock(c);
633
634         if (ast_pbx_start(c)) {
635                 ast_log(LOG_WARNING, "Unable to start PBX on %s (CIC %d)\n", ast_channel_name(c), p->cic);
636                 ast_hangup(c);
637         } else {
638                 ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
639         }
640
641         /* Must return with linkset and private lock. */
642         ast_mutex_lock(&linkset->lock);
643         sig_ss7_lock_private(p);
644 }
645
646 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct sig_ss7_linkset *ss7, const char *number, const unsigned nai)
647 {
648         if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
649                 if (size) {
650                         *buf = '\0';
651                 }
652                 return;
653         }
654         switch (nai) {
655         case SS7_NAI_INTERNATIONAL:
656                 snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
657                 break;
658         case SS7_NAI_NATIONAL:
659                 snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
660                 break;
661         case SS7_NAI_SUBSCRIBER:
662                 snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
663                 break;
664         case SS7_NAI_UNKNOWN:
665                 snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
666                 break;
667         default:
668                 snprintf(buf, size, "%s", number);
669                 break;
670         }
671 }
672
673 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
674 {
675         return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
676 }
677
678 /* This is a thread per linkset that handles all received events from libss7. */
679 void *ss7_linkset(void *data)
680 {
681         int res, i;
682         struct timeval *next = NULL, tv;
683         struct sig_ss7_linkset *linkset = (struct sig_ss7_linkset *) data;
684         struct ss7 *ss7 = linkset->ss7;
685         ss7_event *e = NULL;
686         struct sig_ss7_chan *p;
687         int chanpos;
688         struct pollfd pollers[SIG_SS7_NUM_DCHANS];
689         int nextms = 0;
690
691         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
692
693         ss7_set_debug(ss7, SIG_SS7_DEBUG_DEFAULT);
694         ast_mutex_lock(&linkset->lock);
695         ss7_start(ss7);
696         ast_mutex_unlock(&linkset->lock);
697
698         for (;;) {
699                 ast_mutex_lock(&linkset->lock);
700                 if ((next = ss7_schedule_next(ss7))) {
701                         tv = ast_tvnow();
702                         tv.tv_sec = next->tv_sec - tv.tv_sec;
703                         tv.tv_usec = next->tv_usec - tv.tv_usec;
704                         if (tv.tv_usec < 0) {
705                                 tv.tv_usec += 1000000;
706                                 tv.tv_sec -= 1;
707                         }
708                         if (tv.tv_sec < 0) {
709                                 tv.tv_sec = 0;
710                                 tv.tv_usec = 0;
711                         }
712                         nextms = tv.tv_sec * 1000;
713                         nextms += tv.tv_usec / 1000;
714                 }
715
716                 for (i = 0; i < linkset->numsigchans; i++) {
717                         pollers[i].fd = linkset->fds[i];
718                         pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
719                         pollers[i].revents = 0;
720                 }
721                 ast_mutex_unlock(&linkset->lock);
722
723                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
724                 pthread_testcancel();
725                 res = poll(pollers, linkset->numsigchans, nextms);
726                 pthread_testcancel();
727                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
728
729                 if ((res < 0) && (errno != EINTR)) {
730                         ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
731                 } else if (!res) {
732                         ast_mutex_lock(&linkset->lock);
733                         ss7_schedule_run(ss7);
734                         ast_mutex_unlock(&linkset->lock);
735                         continue;
736                 }
737
738                 ast_mutex_lock(&linkset->lock);
739                 for (i = 0; i < linkset->numsigchans; i++) {
740                         if (pollers[i].revents & POLLPRI) {
741                                 sig_ss7_handle_link_exception(linkset, i);
742                         }
743                         if (pollers[i].revents & POLLIN) {
744                                 res = ss7_read(ss7, pollers[i].fd);
745                         }
746                         if (pollers[i].revents & POLLOUT) {
747                                 res = ss7_write(ss7, pollers[i].fd);
748                                 if (res < 0) {
749                                         ast_debug(1, "Error in write %s\n", strerror(errno));
750                                 }
751                         }
752                 }
753
754                 while ((e = ss7_check_event(ss7))) {
755                         if (linkset->debug) {
756                                 ast_verbose("Linkset %d: Processing event: %s\n",
757                                         linkset->span, ss7_event2str(e->e));
758                         }
759
760                         switch (e->e) {
761                         case SS7_EVENT_UP:
762                                 if (linkset->state != LINKSET_STATE_UP) {
763                                         ast_verbose("--- SS7 Up ---\n");
764                                         ss7_reset_linkset(linkset);
765                                 }
766                                 linkset->state = LINKSET_STATE_UP;
767                                 break;
768                         case SS7_EVENT_DOWN:
769                                 ast_verbose("--- SS7 Down ---\n");
770                                 linkset->state = LINKSET_STATE_DOWN;
771                                 for (i = 0; i < linkset->numchans; i++) {
772                                         p = linkset->pvts[i];
773                                         if (p) {
774                                                 sig_ss7_set_alarm(p, 1);
775                                         }
776                                 }
777                                 break;
778                         case MTP2_LINK_UP:
779                                 ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
780                                 break;
781                         case MTP2_LINK_DOWN:
782                                 ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
783                                 break;
784                         case ISUP_EVENT_CPG:
785                                 chanpos = ss7_find_cic_gripe(linkset, e->cpg.cic, e->cpg.opc, "CPG");
786                                 if (chanpos < 0) {
787                                         break;
788                                 }
789                                 p = linkset->pvts[chanpos];
790                                 sig_ss7_lock_private(p);
791                                 switch (e->cpg.event) {
792                                 case CPG_EVENT_ALERTING:
793                                         if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
794                                                 p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
795                                         }
796                                         sig_ss7_lock_owner(linkset, chanpos);
797                                         if (p->owner) {
798                                                 ast_setstate(p->owner, AST_STATE_RINGING);
799                                                 ast_channel_unlock(p->owner);
800                                         }
801                                         sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
802                                         break;
803                                 case CPG_EVENT_PROGRESS:
804                                 case CPG_EVENT_INBANDINFO:
805                                         {
806                                                 ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
807                                                 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROGRESS);
808                                                 p->progress = 1;
809                                                 sig_ss7_set_dialing(p, 0);
810 #if 0   /* This code no longer seems to be necessary so I did not convert it. */
811                                                 if (p->dsp && p->dsp_features) {
812                                                         ast_dsp_set_features(p->dsp, p->dsp_features);
813                                                         p->dsp_features = 0;
814                                                 }
815 #endif
816                                         }
817                                         break;
818                                 default:
819                                         ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
820                                         break;
821                                 }
822
823                                 sig_ss7_unlock_private(p);
824                                 break;
825                         case ISUP_EVENT_RSC:
826                                 ast_verbose("Resetting CIC %d\n", e->rsc.cic);
827                                 chanpos = ss7_find_cic_gripe(linkset, e->rsc.cic, e->rsc.opc, "RSC");
828                                 if (chanpos < 0) {
829                                         break;
830                                 }
831                                 p = linkset->pvts[chanpos];
832                                 sig_ss7_lock_private(p);
833                                 sig_ss7_set_inservice(p, 1);
834                                 sig_ss7_set_remotelyblocked(p, 0);
835                                 isup_set_call_dpc(e->rsc.call, p->dpc);
836                                 sig_ss7_lock_owner(linkset, chanpos);
837                                 p->ss7call = NULL;
838                                 if (p->owner) {
839                                         ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
840                                         ast_channel_unlock(p->owner);
841                                 }
842                                 sig_ss7_unlock_private(p);
843                                 isup_rlc(ss7, e->rsc.call);
844                                 break;
845                         case ISUP_EVENT_GRS:
846                                 ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
847                                 chanpos = ss7_find_cic_gripe(linkset, e->grs.startcic, e->grs.opc, "GRS");
848                                 if (chanpos < 0) {
849                                         break;
850                                 }
851                                 p = linkset->pvts[chanpos];
852                                 isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
853                                 ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
854                                 ss7_hangup_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc);
855                                 break;
856                         case ISUP_EVENT_CQM:
857                                 ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
858                                 ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
859                                 break;
860                         case ISUP_EVENT_GRA:
861                                 ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
862                                 ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
863                                 ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
864                                 break;
865                         case ISUP_EVENT_IAM:
866                                 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);
867                                 chanpos = ss7_find_cic_gripe(linkset, e->iam.cic, e->iam.opc, "IAM");
868                                 if (chanpos < 0) {
869                                         isup_rel(ss7, e->iam.call, -1);
870                                         break;
871                                 }
872                                 p = linkset->pvts[chanpos];
873                                 sig_ss7_lock_private(p);
874                                 sig_ss7_lock_owner(linkset, chanpos);
875                                 if (p->call_level != SIG_SS7_CALL_LEVEL_IDLE) {
876                                         /*
877                                          * Detected glare/dual-seizure
878                                          *
879                                          * Always abort both calls since we can't implement the dual
880                                          * seizure procedures due to our channel assignment architecture
881                                          * and the fact that we cannot tell libss7 to discard its call
882                                          * structure to ignore the incoming IAM.
883                                          */
884                                         ast_debug(1,
885                                                 "Linkset %d: SS7 IAM glare on CIC/DPC %d/%d.  Dropping both calls.\n",
886                                                 linkset->span, e->iam.cic, e->iam.opc);
887                                         if (p->call_level == SIG_SS7_CALL_LEVEL_ALLOCATED) {
888                                                 /*
889                                                  * We have not sent our IAM yet and we never will at this point.
890                                                  */
891                                                 p->alreadyhungup = 1;
892                                                 isup_rel(ss7, e->iam.call, -1);
893                                         }
894                                         p->call_level = SIG_SS7_CALL_LEVEL_GLARE;
895                                         if (p->owner) {
896                                                 p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
897                                                 ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
898                                                 ast_channel_unlock(p->owner);
899                                         }
900                                         sig_ss7_unlock_private(p);
901                                         break;
902                                 }
903                                 /*
904                                  * The channel should not have an owner at this point since we
905                                  * are in the process of creating an owner for it.
906                                  */
907                                 ast_assert(!p->owner);
908
909                                 /* Mark channel as in use so no outgoing call will steal it. */
910                                 p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
911                                 p->ss7call = e->iam.call;
912
913                                 isup_set_call_dpc(p->ss7call, p->dpc);
914
915                                 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
916                                         ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
917                                         p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
918                                 } else
919                                         p->cid_num[0] = 0;
920
921                                 /* Set DNID */
922                                 if (!ast_strlen_zero(e->iam.called_party_num)) {
923                                         ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset,
924                                                 e->iam.called_party_num, e->iam.called_nai);
925                                 } else {
926                                         p->exten[0] = '\0';
927                                 }
928                                 sig_ss7_set_dnid(p, p->exten);
929
930                                 if (p->immediate) {
931                                         p->exten[0] = 's';
932                                         p->exten[1] = '\0';
933                                 } else if (!ast_strlen_zero(e->iam.called_party_num)) {
934                                         char *st;
935                                         ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
936                                         st = strchr(p->exten, '#');
937                                         if (st) {
938                                                 *st = '\0';
939                                         }
940                                 } else {
941                                         p->exten[0] = '\0';
942                                 }
943
944                                 p->cid_ani[0] = '\0';
945                                 if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
946                                         ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
947                                 else
948                                         p->cid_name[0] = '\0';
949
950                                 p->cid_ani2 = e->iam.oli_ani2;
951                                 p->cid_ton = 0;
952                                 ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
953                                 ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
954                                 p->gen_add_type = e->iam.gen_add_type;
955                                 p->gen_add_nai = e->iam.gen_add_nai;
956                                 p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
957                                 p->gen_add_num_plan = e->iam.gen_add_num_plan;
958                                 ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
959                                 p->gen_dig_type = e->iam.gen_dig_type;
960                                 p->gen_dig_scheme = e->iam.gen_dig_scheme;
961                                 ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
962                                 ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
963                                 ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
964                                 ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
965                                 p->calling_party_cat = e->iam.calling_party_cat;
966
967                                 sig_ss7_set_caller_id(p);
968
969                                 if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
970                                         if (e->iam.cot_check_required) {
971                                                 p->call_level = SIG_SS7_CALL_LEVEL_CONTINUITY;
972                                                 sig_ss7_loopback(p, 1);
973                                         } else {
974                                                 ss7_start_call(p, linkset);
975                                         }
976                                 } else {
977                                         ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
978                                         p->alreadyhungup = 1;
979                                         isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
980                                 }
981                                 sig_ss7_unlock_private(p);
982                                 break;
983                         case ISUP_EVENT_COT:
984                                 chanpos = ss7_find_cic_gripe(linkset, e->cot.cic, e->cot.opc, "COT");
985                                 if (chanpos < 0) {
986                                         isup_rel(ss7, e->cot.call, -1);
987                                         break;
988                                 }
989                                 p = linkset->pvts[chanpos];
990
991                                 sig_ss7_lock_private(p);
992                                 if (p->loopedback) {
993                                         sig_ss7_loopback(p, 0);
994                                         ss7_start_call(p, linkset);
995                                 }
996                                 sig_ss7_unlock_private(p);
997                                 break;
998                         case ISUP_EVENT_CCR:
999                                 ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
1000                                 chanpos = ss7_find_cic_gripe(linkset, e->ccr.cic, e->ccr.opc, "CCR");
1001                                 if (chanpos < 0) {
1002                                         break;
1003                                 }
1004
1005                                 p = linkset->pvts[chanpos];
1006
1007                                 sig_ss7_lock_private(p);
1008                                 sig_ss7_loopback(p, 1);
1009                                 sig_ss7_unlock_private(p);
1010
1011                                 isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
1012                                 break;
1013                         case ISUP_EVENT_CVT:
1014                                 ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
1015                                 chanpos = ss7_find_cic_gripe(linkset, e->cvt.cic, e->cvt.opc, "CVT");
1016                                 if (chanpos < 0) {
1017                                         break;
1018                                 }
1019
1020                                 p = linkset->pvts[chanpos];
1021
1022                                 sig_ss7_lock_private(p);
1023                                 sig_ss7_loopback(p, 1);
1024                                 sig_ss7_unlock_private(p);
1025
1026                                 isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
1027                                 break;
1028                         case ISUP_EVENT_REL:
1029                                 chanpos = ss7_find_cic_gripe(linkset, e->rel.cic, e->rel.opc, "REL");
1030                                 if (chanpos < 0) {
1031                                         /* Continue hanging up the call anyway. */
1032                                         isup_rlc(ss7, e->rel.call);
1033                                         break;
1034                                 }
1035                                 p = linkset->pvts[chanpos];
1036                                 sig_ss7_lock_private(p);
1037                                 sig_ss7_lock_owner(linkset, chanpos);
1038                                 if (p->owner) {
1039                                         p->owner->hangupcause = e->rel.cause;
1040                                         ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
1041                                         ast_channel_unlock(p->owner);
1042                                 }
1043
1044                                 /* End the loopback if we have one */
1045                                 sig_ss7_loopback(p, 0);
1046
1047                                 isup_rlc(ss7, e->rel.call);
1048                                 p->ss7call = NULL;
1049
1050                                 sig_ss7_unlock_private(p);
1051                                 break;
1052                         case ISUP_EVENT_ACM:
1053                                 chanpos = ss7_find_cic_gripe(linkset, e->acm.cic, e->acm.opc, "ACM");
1054                                 if (chanpos < 0) {
1055                                         isup_rel(ss7, e->acm.call, -1);
1056                                         break;
1057                                 }
1058                                 {
1059                                         p = linkset->pvts[chanpos];
1060
1061                                         ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
1062
1063                                         if (e->acm.call_ref_ident > 0) {
1064                                                 p->rlt = 1; /* Setting it but not using it here*/
1065                                         }
1066
1067                                         sig_ss7_lock_private(p);
1068                                         sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_PROCEEDING);
1069                                         if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING) {
1070                                                 p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
1071                                         }
1072                                         sig_ss7_set_dialing(p, 0);
1073                                         /* Send alerting if subscriber is free */
1074                                         if (e->acm.called_party_status_ind == 1) {
1075                                                 if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
1076                                                         p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
1077                                                 }
1078                                                 sig_ss7_lock_owner(linkset, chanpos);
1079                                                 if (p->owner) {
1080                                                         ast_setstate(p->owner, AST_STATE_RINGING);
1081                                                         ast_channel_unlock(p->owner);
1082                                                 }
1083                                                 sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
1084                                         }
1085                                         sig_ss7_unlock_private(p);
1086                                 }
1087                                 break;
1088                         case ISUP_EVENT_CGB:
1089                                 chanpos = ss7_find_cic_gripe(linkset, e->cgb.startcic, e->cgb.opc, "CGB");
1090                                 if (chanpos < 0) {
1091                                         break;
1092                                 }
1093                                 p = linkset->pvts[chanpos];
1094                                 ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
1095                                 isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
1096                                 break;
1097                         case ISUP_EVENT_CGU:
1098                                 chanpos = ss7_find_cic_gripe(linkset, e->cgu.startcic, e->cgu.opc, "CGU");
1099                                 if (chanpos < 0) {
1100                                         break;
1101                                 }
1102                                 p = linkset->pvts[chanpos];
1103                                 ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
1104                                 isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
1105                                 break;
1106                         case ISUP_EVENT_UCIC:
1107                                 chanpos = ss7_find_cic_gripe(linkset, e->ucic.cic, e->ucic.opc, "UCIC");
1108                                 if (chanpos < 0) {
1109                                         break;
1110                                 }
1111                                 p = linkset->pvts[chanpos];
1112                                 ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
1113                                 sig_ss7_lock_private(p);
1114                                 sig_ss7_set_remotelyblocked(p, 1);
1115                                 sig_ss7_set_inservice(p, 0);
1116                                 sig_ss7_unlock_private(p);/* doesn't require a SS7 acknowledgement */
1117                                 break;
1118                         case ISUP_EVENT_BLO:
1119                                 chanpos = ss7_find_cic_gripe(linkset, e->blo.cic, e->blo.opc, "BLO");
1120                                 if (chanpos < 0) {
1121                                         break;
1122                                 }
1123                                 p = linkset->pvts[chanpos];
1124                                 ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
1125                                 sig_ss7_lock_private(p);
1126                                 sig_ss7_set_remotelyblocked(p, 1);
1127                                 sig_ss7_unlock_private(p);
1128                                 isup_bla(linkset->ss7, e->blo.cic, p->dpc);
1129                                 break;
1130                         case ISUP_EVENT_BLA:
1131                                 chanpos = ss7_find_cic_gripe(linkset, e->bla.cic, e->bla.opc, "BLA");
1132                                 if (chanpos < 0) {
1133                                         break;
1134                                 }
1135                                 ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
1136                                 p = linkset->pvts[chanpos];
1137                                 sig_ss7_lock_private(p);
1138                                 sig_ss7_set_locallyblocked(p, 1);
1139                                 sig_ss7_unlock_private(p);
1140                                 break;
1141                         case ISUP_EVENT_UBL:
1142                                 chanpos = ss7_find_cic_gripe(linkset, e->ubl.cic, e->ubl.opc, "UBL");
1143                                 if (chanpos < 0) {
1144                                         break;
1145                                 }
1146                                 p = linkset->pvts[chanpos];
1147                                 ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
1148                                 sig_ss7_lock_private(p);
1149                                 sig_ss7_set_remotelyblocked(p, 0);
1150                                 sig_ss7_unlock_private(p);
1151                                 isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
1152                                 break;
1153                         case ISUP_EVENT_UBA:
1154                                 chanpos = ss7_find_cic_gripe(linkset, e->uba.cic, e->uba.opc, "UBA");
1155                                 if (chanpos < 0) {
1156                                         break;
1157                                 }
1158                                 p = linkset->pvts[chanpos];
1159                                 ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
1160                                 sig_ss7_lock_private(p);
1161                                 sig_ss7_set_locallyblocked(p, 0);
1162                                 sig_ss7_unlock_private(p);
1163                                 break;
1164                         case ISUP_EVENT_CON:
1165                         case ISUP_EVENT_ANM:
1166                                 if (e->e == ISUP_EVENT_CON) {
1167                                         chanpos = ss7_find_cic_gripe(linkset, e->con.cic, e->con.opc, "CON");
1168                                         if (chanpos < 0) {
1169                                                 isup_rel(ss7, e->con.call, -1);
1170                                                 break;
1171                                         }
1172                                 } else {
1173                                         chanpos = ss7_find_cic_gripe(linkset, e->anm.cic, e->anm.opc, "ANM");
1174                                         if (chanpos < 0) {
1175                                                 isup_rel(ss7, e->anm.call, -1);
1176                                                 break;
1177                                         }
1178                                 }
1179
1180                                 {
1181                                         p = linkset->pvts[chanpos];
1182                                         sig_ss7_lock_private(p);
1183                                         if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
1184                                                 p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
1185                                         }
1186                                         sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_ANSWER);
1187 #if 0   /* This code no longer seems to be necessary so I did not convert it. */
1188                                         if (p->dsp && p->dsp_features) {
1189                                                 ast_dsp_set_features(p->dsp, p->dsp_features);
1190                                                 p->dsp_features = 0;
1191                                         }
1192 #endif
1193                                         sig_ss7_set_echocanceller(p, 1);
1194                                         sig_ss7_unlock_private(p);
1195                                 }
1196                                 break;
1197                         case ISUP_EVENT_RLC:
1198                                 /* XXX Call ptr should be passed up from libss7! */
1199                                 chanpos = ss7_find_cic_gripe(linkset, e->rlc.cic, e->rlc.opc, "RLC");
1200                                 if (chanpos < 0) {
1201                                         break;
1202                                 }
1203                                 {
1204                                         p = linkset->pvts[chanpos];
1205                                         sig_ss7_lock_private(p);
1206                                         if (p->alreadyhungup) {
1207                                                 if (!p->owner) {
1208                                                         p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
1209                                                 }
1210                                                 p->ss7call = NULL;
1211                                         }
1212                                         sig_ss7_unlock_private(p);
1213                                 }
1214                                 break;
1215                         case ISUP_EVENT_FAA:
1216                                 /*!
1217                                  * \todo The handling of the SS7 FAA message is not good and I
1218                                  * don't know enough to handle it correctly.
1219                                  */
1220                                 chanpos = ss7_find_cic_gripe(linkset, e->faa.cic, e->faa.opc, "FAA");
1221                                 if (chanpos < 0) {
1222                                         isup_rel(linkset->ss7, e->faa.call, -1);
1223                                         break;
1224                                 }
1225                                 {
1226                                         /* XXX FAR and FAA used for something dealing with transfers? */
1227                                         p = linkset->pvts[chanpos];
1228                                         ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
1229                                         sig_ss7_lock_private(p);
1230                                         if (p->alreadyhungup){
1231                                                 if (!p->owner) {
1232                                                         p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
1233                                                 }
1234                                                 /* XXX We seem to be leaking the isup call structure here. */
1235                                                 p->ss7call = NULL;
1236                                                 ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR.  Ignoring.\n");
1237                                         }
1238                                         sig_ss7_unlock_private(p);
1239                                 }
1240                                 break;
1241                         default:
1242                                 ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
1243                                 break;
1244                         }
1245                 }
1246                 ast_mutex_unlock(&linkset->lock);
1247         }
1248
1249         return 0;
1250 }
1251
1252 static inline void ss7_rel(struct sig_ss7_linkset *ss7)
1253 {
1254         ast_mutex_unlock(&ss7->lock);
1255 }
1256
1257 static void ss7_grab(struct sig_ss7_chan *pvt, struct sig_ss7_linkset *ss7)
1258 {
1259         int res;
1260         /* Grab the lock first */
1261         do {
1262                 res = ast_mutex_trylock(&ss7->lock);
1263                 if (res) {
1264                         sig_ss7_deadlock_avoidance_private(pvt);
1265                 }
1266         } while (res);
1267         /* Then break the poll */
1268         if (ss7->master != AST_PTHREADT_NULL)
1269                 pthread_kill(ss7->master, SIGURG);
1270 }
1271
1272 /*!
1273  * \brief Notify the SS7 layer that the link is in alarm.
1274  * \since 1.8
1275  *
1276  * \param linkset Controlling linkset for the channel.
1277  * \param which Link index of the signaling channel.
1278  *
1279  * \return Nothing
1280  */
1281 void sig_ss7_link_alarm(struct sig_ss7_linkset *linkset, int which)
1282 {
1283         linkset->linkstate[which] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
1284         linkset->linkstate[which] &= ~LINKSTATE_UP;
1285         ss7_link_alarm(linkset->ss7, linkset->fds[which]);
1286 }
1287
1288 /*!
1289  * \brief Notify the SS7 layer that the link is no longer in alarm.
1290  * \since 1.8
1291  *
1292  * \param linkset Controlling linkset for the channel.
1293  * \param which Link index of the signaling channel.
1294  *
1295  * \return Nothing
1296  */
1297 void sig_ss7_link_noalarm(struct sig_ss7_linkset *linkset, int which)
1298 {
1299         linkset->linkstate[which] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
1300         linkset->linkstate[which] |= LINKSTATE_STARTING;
1301         ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
1302 }
1303
1304 /*!
1305  * \brief Setup and add a SS7 link channel.
1306  * \since 1.8
1307  *
1308  * \param linkset Controlling linkset for the channel.
1309  * \param which Link index of the signaling channel.
1310  * \param ss7type Switch type of the linkset
1311  * \param transport Signaling transport of channel.
1312  * \param inalarm Non-zero if the channel is in alarm.
1313  * \param networkindicator User configuration parameter.
1314  * \param pointcode User configuration parameter.
1315  * \param adjpointcode User configuration parameter.
1316  *
1317  * \retval 0 on success.
1318  * \retval -1 on error.
1319  */
1320 int sig_ss7_add_sigchan(struct sig_ss7_linkset *linkset, int which, int ss7type, int transport, int inalarm, int networkindicator, int pointcode, int adjpointcode)
1321 {
1322         if (!linkset->ss7) {
1323                 linkset->type = ss7type;
1324                 linkset->ss7 = ss7_new(ss7type);
1325                 if (!linkset->ss7) {
1326                         ast_log(LOG_ERROR, "Can't create new SS7!\n");
1327                         return -1;
1328                 }
1329         }
1330
1331         ss7_set_network_ind(linkset->ss7, networkindicator);
1332         ss7_set_pc(linkset->ss7, pointcode);
1333
1334         if (ss7_add_link(linkset->ss7, transport, linkset->fds[which])) {
1335                 ast_log(LOG_WARNING, "Could not add SS7 link!\n");
1336         }
1337
1338         if (inalarm) {
1339                 linkset->linkstate[which] = LINKSTATE_DOWN | LINKSTATE_INALARM;
1340                 ss7_link_alarm(linkset->ss7, linkset->fds[which]);
1341         } else {
1342                 linkset->linkstate[which] = LINKSTATE_DOWN;
1343                 ss7_link_noalarm(linkset->ss7, linkset->fds[which]);
1344         }
1345
1346         ss7_set_adjpc(linkset->ss7, linkset->fds[which], adjpointcode);
1347
1348         return 0;
1349 }
1350
1351 /*!
1352  * \internal
1353  * \brief Determine if a private channel structure is available.
1354  *
1355  * \param pvt Channel to determine if available.
1356  *
1357  * \return TRUE if the channel is available.
1358  */
1359 static int sig_ss7_is_chan_available(struct sig_ss7_chan *pvt)
1360 {
1361         if (!pvt->inalarm && !pvt->owner && !pvt->ss7call
1362                 && pvt->call_level == SIG_SS7_CALL_LEVEL_IDLE
1363                 && !pvt->locallyblocked && !pvt->remotelyblocked) {
1364                 return 1;
1365         }
1366         return 0;
1367 }
1368
1369 /*!
1370  * \brief Determine if the specified channel is available for an outgoing call.
1371  * \since 1.8
1372  *
1373  * \param p Signaling private structure pointer.
1374  *
1375  * \retval TRUE if the channel is available.
1376  */
1377 int sig_ss7_available(struct sig_ss7_chan *p)
1378 {
1379         int available;
1380
1381         if (!p->ss7) {
1382                 /* Something is wrong here.  A SS7 channel without the ss7 pointer? */
1383                 return 0;
1384         }
1385
1386         /* Only have to deal with the linkset lock. */
1387         ast_mutex_lock(&p->ss7->lock);
1388         available = sig_ss7_is_chan_available(p);
1389         if (available) {
1390                 p->call_level = SIG_SS7_CALL_LEVEL_ALLOCATED;
1391         }
1392         ast_mutex_unlock(&p->ss7->lock);
1393
1394         return available;
1395 }
1396
1397 static unsigned char cid_pres2ss7pres(int cid_pres)
1398 {
1399          return (cid_pres >> 5) & 0x03;
1400 }
1401
1402 static unsigned char cid_pres2ss7screen(int cid_pres)
1403 {
1404         return cid_pres & 0x03;
1405 }
1406
1407 /*!
1408  * \brief Dial out using the specified SS7 channel.
1409  * \since 1.8
1410  *
1411  * \param p Signaling private structure pointer.
1412  * \param ast Asterisk channel structure pointer.
1413  * \param rdest Dialstring.
1414  *
1415  * \retval 0 on success.
1416  * \retval -1 on error.
1417  */
1418 int sig_ss7_call(struct sig_ss7_chan *p, struct ast_channel *ast, const char *rdest)
1419 {
1420         char ss7_called_nai;
1421         int called_nai_strip;
1422         char ss7_calling_nai;
1423         int calling_nai_strip;
1424         const char *charge_str = NULL;
1425         const char *gen_address = NULL;
1426         const char *gen_digits = NULL;
1427         const char *gen_dig_type = NULL;
1428         const char *gen_dig_scheme = NULL;
1429         const char *gen_name = NULL;
1430         const char *jip_digits = NULL;
1431         const char *lspi_ident = NULL;
1432         const char *rlt_flag = NULL;
1433         const char *call_ref_id = NULL;
1434         const char *call_ref_pc = NULL;
1435         const char *send_far = NULL;
1436         char *c;
1437         char *l;
1438         char dest[256];
1439
1440         ast_copy_string(dest, rdest, sizeof(dest));
1441
1442         c = strchr(dest, '/');
1443         if (c) {
1444                 c++;
1445         } else {
1446                 c = "";
1447         }
1448         if (strlen(c) < p->stripmsd) {
1449                 ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
1450                 return -1;
1451         }
1452
1453         if (!p->hidecallerid) {
1454                 l = ast->connected.id.number.valid ? ast->connected.id.number.str : NULL;
1455         } else {
1456                 l = NULL;
1457         }
1458
1459         ss7_grab(p, p->ss7);
1460
1461         if (p->call_level != SIG_SS7_CALL_LEVEL_ALLOCATED) {
1462                 /* Call collision before sending IAM.  Abort call. */
1463                 ss7_rel(p->ss7);
1464                 return -1;
1465         }
1466
1467         p->ss7call = isup_new_call(p->ss7->ss7);
1468         if (!p->ss7call) {
1469                 ss7_rel(p->ss7);
1470                 ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
1471                 return -1;
1472         }
1473
1474         called_nai_strip = 0;
1475         ss7_called_nai = p->ss7->called_nai;
1476         if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
1477                 if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
1478                         called_nai_strip = strlen(p->ss7->internationalprefix);
1479                         ss7_called_nai = SS7_NAI_INTERNATIONAL;
1480                 } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
1481                         called_nai_strip = strlen(p->ss7->nationalprefix);
1482                         ss7_called_nai = SS7_NAI_NATIONAL;
1483                 } else {
1484                         ss7_called_nai = SS7_NAI_SUBSCRIBER;
1485                 }
1486         }
1487         isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
1488
1489         calling_nai_strip = 0;
1490         ss7_calling_nai = p->ss7->calling_nai;
1491         if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
1492                 if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
1493                         calling_nai_strip = strlen(p->ss7->internationalprefix);
1494                         ss7_calling_nai = SS7_NAI_INTERNATIONAL;
1495                 } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
1496                         calling_nai_strip = strlen(p->ss7->nationalprefix);
1497                         ss7_calling_nai = SS7_NAI_NATIONAL;
1498                 } else {
1499                         ss7_calling_nai = SS7_NAI_SUBSCRIBER;
1500                 }
1501         }
1502         isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
1503                 p->use_callingpres ? cid_pres2ss7pres(ast->connected.id.number.presentation) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
1504                 p->use_callingpres ? cid_pres2ss7screen(ast->connected.id.number.presentation) : SS7_SCREENING_USER_PROVIDED);
1505
1506         isup_set_oli(p->ss7call, ast->connected.ani2);
1507         isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
1508
1509         /* Set the charge number if it is set */
1510         charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
1511         if (charge_str)
1512                 isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
1513
1514         gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
1515         if (gen_address)
1516                 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 */
1517
1518         gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
1519         gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
1520         gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
1521         if (gen_digits)
1522                 isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme));
1523
1524         gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
1525         if (gen_name)
1526                 isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
1527
1528         jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
1529         if (jip_digits)
1530                 isup_set_jip_digits(p->ss7call, jip_digits);
1531
1532         lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
1533         if (lspi_ident)
1534                 isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00);
1535
1536         rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
1537         if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
1538                 isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */
1539         }
1540
1541         call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
1542         call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
1543         if (call_ref_id && call_ref_pc) {
1544                 isup_set_callref(p->ss7call, atoi(call_ref_id),
1545                                  call_ref_pc ? atoi(call_ref_pc) : 0);
1546         }
1547
1548         send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
1549         if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
1550                 (isup_far(p->ss7->ss7, p->ss7call));
1551
1552         p->call_level = SIG_SS7_CALL_LEVEL_SETUP;
1553         isup_iam(p->ss7->ss7, p->ss7call);
1554         sig_ss7_set_dialing(p, 1);
1555         ast_setstate(ast, AST_STATE_DIALING);
1556         ss7_rel(p->ss7);
1557         return 0;
1558 }
1559
1560 /*!
1561  * \brief SS7 hangup channel.
1562  * \since 1.8
1563  *
1564  * \param p Signaling private structure pointer.
1565  * \param ast Asterisk channel structure pointer.
1566  *
1567  * \retval 0 on success.
1568  * \retval -1 on error.
1569  */
1570 int sig_ss7_hangup(struct sig_ss7_chan *p, struct ast_channel *ast)
1571 {
1572         int res = 0;
1573
1574         if (!ast->tech_pvt) {
1575                 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
1576                 return 0;
1577         }
1578
1579         p->owner = NULL;
1580         sig_ss7_set_dialing(p, 0);
1581         sig_ss7_set_outgoing(p, 0);
1582         p->progress = 0;
1583         p->rlt = 0;
1584         p->exten[0] = '\0';
1585         /* Perform low level hangup if no owner left */
1586         ss7_grab(p, p->ss7);
1587         p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
1588         if (p->ss7call) {
1589                 if (!p->alreadyhungup) {
1590                         const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
1591                         int icause = ast->hangupcause ? ast->hangupcause : -1;
1592
1593                         if (cause) {
1594                                 if (atoi(cause)) {
1595                                         icause = atoi(cause);
1596                                 }
1597                         }
1598                         isup_rel(p->ss7->ss7, p->ss7call, icause);
1599                         p->alreadyhungup = 1;
1600                 }
1601         }
1602         ss7_rel(p->ss7);
1603
1604         return res;
1605 }
1606
1607 /*!
1608  * \brief SS7 answer channel.
1609  * \since 1.8
1610  *
1611  * \param p Signaling private structure pointer.
1612  * \param ast Asterisk channel structure pointer.
1613  *
1614  * \retval 0 on success.
1615  * \retval -1 on error.
1616  */
1617 int sig_ss7_answer(struct sig_ss7_chan *p, struct ast_channel *ast)
1618 {
1619         int res;
1620
1621         ss7_grab(p, p->ss7);
1622         if (p->call_level < SIG_SS7_CALL_LEVEL_CONNECT) {
1623                 p->call_level = SIG_SS7_CALL_LEVEL_CONNECT;
1624         }
1625         res = isup_anm(p->ss7->ss7, p->ss7call);
1626         ss7_rel(p->ss7);
1627         return res;
1628 }
1629
1630 /*!
1631  * \brief Fix up a channel:  If a channel is consumed, this is called.  Basically update any ->owner links.
1632  * \since 1.8
1633  *
1634  * \param oldchan Old channel pointer to replace.
1635  * \param newchan New channel pointer to set.
1636  * \param pchan Signaling private structure pointer.
1637  *
1638  * \return Nothing
1639  */
1640 void sig_ss7_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, struct sig_ss7_chan *pchan)
1641 {
1642         if (pchan->owner == oldchan) {
1643                 pchan->owner = newchan;
1644         }
1645 }
1646
1647 /*!
1648  * \brief SS7 answer channel.
1649  * \since 1.8
1650  *
1651  * \param p Signaling private structure pointer.
1652  * \param chan Asterisk channel structure pointer.
1653  * \param condition AST control frame subtype.
1654  * \param data AST control frame payload contents.
1655  * \param datalen Length of payload contents.
1656  *
1657  * \retval 0 on success.
1658  * \retval -1 on error or indication condition not handled.
1659  */
1660 int sig_ss7_indicate(struct sig_ss7_chan *p, struct ast_channel *chan, int condition, const void *data, size_t datalen)
1661 {
1662         int res = -1;
1663
1664         switch (condition) {
1665         case AST_CONTROL_BUSY:
1666                 res = sig_ss7_play_tone(p, SIG_SS7_TONE_BUSY);
1667                 break;
1668         case AST_CONTROL_RINGING:
1669                 ss7_grab(p, p->ss7);
1670                 if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
1671                         p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
1672                         if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
1673                                 p->rlt = 1;
1674                         }
1675
1676                         /* No need to send CPG if call will be RELEASE */
1677                         if (p->rlt != 1) {
1678                                 isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
1679                         }
1680                 }
1681                 ss7_rel(p->ss7);
1682
1683                 res = sig_ss7_play_tone(p, SIG_SS7_TONE_RINGTONE);
1684
1685                 if (chan->_state != AST_STATE_UP && chan->_state != AST_STATE_RING) {
1686                         ast_setstate(chan, AST_STATE_RINGING);
1687                 }
1688                 break;
1689         case AST_CONTROL_PROCEEDING:
1690                 ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",ast_channel_name(chan));
1691                 ss7_grab(p, p->ss7);
1692                 /* This IF sends the FAR for an answered ALEG call */
1693                 if (chan->_state == AST_STATE_UP && (p->rlt != 1)){
1694                         if ((isup_far(p->ss7->ss7, p->ss7call)) != -1) {
1695                                 p->rlt = 1;
1696                         }
1697                 }
1698
1699                 if (p->call_level < SIG_SS7_CALL_LEVEL_PROCEEDING && !p->outgoing) {
1700                         p->call_level = SIG_SS7_CALL_LEVEL_PROCEEDING;
1701                         isup_acm(p->ss7->ss7, p->ss7call);
1702                 }
1703                 ss7_rel(p->ss7);
1704                 /* don't continue in ast_indicate */
1705                 res = 0;
1706                 break;
1707         case AST_CONTROL_PROGRESS:
1708                 ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",ast_channel_name(chan));
1709                 ss7_grab(p, p->ss7);
1710                 if (!p->progress && p->call_level < SIG_SS7_CALL_LEVEL_ALERTING && !p->outgoing) {
1711                         p->progress = 1;/* No need to send inband-information progress again. */
1712                         isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
1713                         ss7_rel(p->ss7);
1714
1715                         /* enable echo canceler here on SS7 calls */
1716                         sig_ss7_set_echocanceller(p, 1);
1717                 } else {
1718                         ss7_rel(p->ss7);
1719                 }
1720                 /* don't continue in ast_indicate */
1721                 res = 0;
1722                 break;
1723         case AST_CONTROL_INCOMPLETE:
1724                 /* If the channel is connected, wait for additional input */
1725                 if (p->call_level == SIG_SS7_CALL_LEVEL_CONNECT) {
1726                         res = 0;
1727                         break;
1728                 }
1729                 chan->hangupcause = AST_CAUSE_INVALID_NUMBER_FORMAT;
1730                 break;
1731         case AST_CONTROL_CONGESTION:
1732                 chan->hangupcause = AST_CAUSE_CONGESTION;
1733                 break;
1734         case AST_CONTROL_HOLD:
1735                 ast_moh_start(chan, data, p->mohinterpret);
1736                 break;
1737         case AST_CONTROL_UNHOLD:
1738                 ast_moh_stop(chan);
1739                 break;
1740         case AST_CONTROL_SRCUPDATE:
1741                 res = 0;
1742                 break;
1743         case -1:
1744                 res = sig_ss7_play_tone(p, -1);
1745                 break;
1746         }
1747         return res;
1748 }
1749
1750 /*!
1751  * \brief SS7 channel request.
1752  * \since 1.8
1753  *
1754  * \param p Signaling private structure pointer.
1755  * \param law Companding law preferred
1756  * \param requestor Asterisk channel requesting a channel to dial (Can be NULL)
1757  * \param transfercapability
1758  *
1759  * \retval ast_channel on success.
1760  * \retval NULL on error.
1761  */
1762 struct ast_channel *sig_ss7_request(struct sig_ss7_chan *p, enum sig_ss7_law law, const struct ast_channel *requestor, int transfercapability)
1763 {
1764         struct ast_channel *ast;
1765
1766         sig_ss7_set_outgoing(p, 1);
1767         ast = sig_ss7_new_ast_channel(p, AST_STATE_RESERVED, law, transfercapability, p->exten, requestor);
1768         if (!ast) {
1769                 sig_ss7_set_outgoing(p, 0);
1770
1771                 /* Release the allocated channel.  Only have to deal with the linkset lock. */
1772                 ast_mutex_lock(&p->ss7->lock);
1773                 p->call_level = SIG_SS7_CALL_LEVEL_IDLE;
1774                 ast_mutex_unlock(&p->ss7->lock);
1775         }
1776         return ast;
1777 }
1778
1779 /*!
1780  * \brief Delete the sig_ss7 private channel structure.
1781  * \since 1.8
1782  *
1783  * \param doomed sig_ss7 private channel structure to delete.
1784  *
1785  * \return Nothing
1786  */
1787 void sig_ss7_chan_delete(struct sig_ss7_chan *doomed)
1788 {
1789         ast_free(doomed);
1790 }
1791
1792 #define SIG_SS7_SC_HEADER       "%-4s %4s %-4s %-3s %-3s %-10s %-4s %s\n"
1793 #define SIG_SS7_SC_LINE          "%4d %4d %-4s %-3s %-3s %-10s %-4s %s"
1794 void sig_ss7_cli_show_channels_header(int fd)
1795 {
1796         ast_cli(fd, SIG_SS7_SC_HEADER, "link", "",     "Chan", "Lcl", "Rem", "Call",  "SS7",  "Channel");
1797         ast_cli(fd, SIG_SS7_SC_HEADER, "set",  "Chan", "Idle", "Blk", "Blk", "Level", "Call", "Name");
1798 }
1799
1800 void sig_ss7_cli_show_channels(int fd, struct sig_ss7_linkset *linkset)
1801 {
1802         char line[256];
1803         int idx;
1804         struct sig_ss7_chan *pvt;
1805
1806         ast_mutex_lock(&linkset->lock);
1807         for (idx = 0; idx < linkset->numchans; ++idx) {
1808                 if (!linkset->pvts[idx]) {
1809                         continue;
1810                 }
1811                 pvt = linkset->pvts[idx];
1812                 sig_ss7_lock_private(pvt);
1813                 sig_ss7_lock_owner(linkset, idx);
1814
1815                 snprintf(line, sizeof(line), SIG_SS7_SC_LINE,
1816                         linkset->span,
1817                         pvt->channel,
1818                         sig_ss7_is_chan_available(pvt) ? "Yes" : "No",
1819                         pvt->locallyblocked ? "Yes" : "No",
1820                         pvt->remotelyblocked ? "Yes" : "No",
1821                         sig_ss7_call_level2str(pvt->call_level),
1822                         pvt->ss7call ? "Yes" : "No",
1823                         pvt->owner ? ast_channel_name(pvt->owner) : "");
1824
1825                 if (pvt->owner) {
1826                         ast_channel_unlock(pvt->owner);
1827                 }
1828                 sig_ss7_unlock_private(pvt);
1829
1830                 ast_mutex_unlock(&linkset->lock);
1831                 ast_cli(fd, "%s\n", line);
1832                 ast_mutex_lock(&linkset->lock);
1833         }
1834         ast_mutex_unlock(&linkset->lock);
1835 }
1836
1837 /*!
1838  * \brief Create a new sig_ss7 private channel structure.
1839  * \since 1.8
1840  *
1841  * \param pvt_data Upper layer private data structure.
1842  * \param callback Callbacks to the upper layer.
1843  * \param ss7 Controlling linkset for the channel.
1844  *
1845  * \retval sig_ss7_chan on success.
1846  * \retval NULL on error.
1847  */
1848 struct sig_ss7_chan *sig_ss7_chan_new(void *pvt_data, struct sig_ss7_callback *callback, struct sig_ss7_linkset *ss7)
1849 {
1850         struct sig_ss7_chan *pvt;
1851
1852         pvt = ast_calloc(1, sizeof(*pvt));
1853         if (!pvt) {
1854                 return pvt;
1855         }
1856
1857         pvt->calls = callback;
1858         pvt->chan_pvt = pvt_data;
1859         pvt->ss7 = ss7;
1860
1861         return pvt;
1862 }
1863
1864 /*!
1865  * \brief Initialize the SS7 linkset control.
1866  * \since 1.8
1867  *
1868  * \param ss7 SS7 linkset control structure.
1869  *
1870  * \return Nothing
1871  */
1872 void sig_ss7_init_linkset(struct sig_ss7_linkset *ss7)
1873 {
1874         int idx;
1875
1876         memset(ss7, 0, sizeof(*ss7));
1877
1878         ast_mutex_init(&ss7->lock);
1879
1880         ss7->master = AST_PTHREADT_NULL;
1881         for (idx = 0; idx < ARRAY_LEN(ss7->fds); ++idx) {
1882                 ss7->fds[idx] = -1;
1883         }
1884 }
1885
1886 /* ------------------------------------------------------------------- */
1887
1888 #endif  /* defined(HAVE_SS7) */
1889 /* end sig_ss7.c */