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