include "logger.h" and errno.h from asterisk.h - usage shows that they
[asterisk/asterisk.git] / channels / chan_zap.c
index 4a0bd71..633d7b9 100644 (file)
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-#include <stdio.h>
-#include <string.h>
 #ifdef __NetBSD__
 #include <pthread.h>
 #include <signal.h>
 #else
 #include <sys/signal.h>
 #endif
-#include <errno.h>
-#include <stdlib.h>
-#if !defined(SOLARIS) && !defined(__FreeBSD__)
-#include <stdint.h>
-#endif
-#include <unistd.h>
 #include <sys/ioctl.h>
 #include <math.h>
 #include <ctype.h>
@@ -80,7 +72,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
 #include "asterisk/config.h"
-#include "asterisk/logger.h"
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
 #include "asterisk/options.h"
@@ -586,6 +577,7 @@ static struct zt_pvt {
 #if defined(PRI_ANI) || defined(HAVE_SS7)
        char cid_ani[AST_MAX_EXTENSION];
 #endif
+       int cid_ani2;
        char cid_num[AST_MAX_EXTENSION];
        int cid_ton;                                    /*!< Type Of Number (TON) */
        char cid_name[AST_MAX_EXTENSION];
@@ -663,9 +655,16 @@ static struct zt_pvt {
 #ifdef HAVE_SS7
        struct zt_ss7 *ss7;
        struct isup_call *ss7call;
+       char charge_number[50];
+       char gen_add_number[50];
+       unsigned char gen_add_num_plan;
+       unsigned char gen_add_nai;
+       unsigned char gen_add_pres_ind;
+       unsigned char gen_add_type;
        int transcap;
        int cic;                                                        /*!< CIC associated with channel */
        unsigned int dpc;                                               /*!< CIC's DPC */
+       unsigned int loopedback:1;
 #endif
        char begindigit;
 } *iflist = NULL, *ifend = NULL;
@@ -716,8 +715,7 @@ static struct zt_chan_conf zt_chan_conf_default(void) {
                        .localprefix = "",
                        .privateprefix = "",
                        .unknownprefix = "",
-
-                       .resetinterval = 3600
+                       .resetinterval = -1,
                },
 #endif
 #ifdef HAVE_SS7
@@ -1071,7 +1069,13 @@ static int zt_open(char *fn)
                }
        }
        bs = READ_SIZE;
-       if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs) == -1) return -1;
+       if (ioctl(fd, ZT_SET_BLOCKSIZE, &bs) == -1) {
+               ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs,  strerror(errno));
+               x = errno;
+               close(fd);
+               errno = x;
+               return -1;
+       }
        return fd;
 }
 
@@ -2240,6 +2244,10 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                int called_nai_strip;
                char ss7_calling_nai;
                int calling_nai_strip;
+               const char *charge_str = NULL;
+#if 0
+               const char *gen_address = NULL;
+#endif
 
                c = strchr(dest, '/');
                if (c)
@@ -2300,8 +2308,21 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
                        p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
 
+               isup_set_oli(p->ss7call, ast->cid.cid_ani2);
                isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
 
+               /* Set the charge number if it is set */
+               charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
+               if (charge_str)
+                       isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
+               
+#if 0
+               /* Set the generic address if it is set */
+               gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
+               if (gen_address)
+                       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 */
+#endif
+               
                isup_iam(p->ss7->ss7, p->ss7call);
                ast_setstate(ast, AST_STATE_DIALING);
                ss7_rel(p->ss7);
@@ -2326,17 +2347,17 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                        c++;
                else
                        c = dest;
-               if (!p->hidecalleridname)
-                       n = ast->cid.cid_name;
-               else
-                       n = NULL;
+
+               l = NULL;
+               n = NULL;
+
                if (!p->hidecallerid) {
                        l = ast->cid.cid_num;
-                       n = ast->cid.cid_name;
-               } else {
-                       l = NULL;
-                       n = NULL;
+                       if (!p->hidecalleridname) {
+                               n = ast->cid.cid_name;
+                       }
                }
+
                if (strlen(c) < p->stripmsd) {
                        ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
                        ast_mutex_unlock(&p->lock);
@@ -2417,6 +2438,56 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                                pridialplan = PRI_LOCAL_ISDN;
                        }
                }
+               while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
+                       switch (c[p->stripmsd]) {
+                       case 'U':
+                               pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'I':
+                               pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'N':
+                               pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'L':
+                               pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'S':
+                               pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'A':
+                               pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'R':
+                               pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
+                               break;
+                       case 'u':
+                               pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
+                               break;
+                       case 'e':
+                               pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
+                               break;
+                       case 'x':
+                               pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
+                               break;
+                       case 'f':
+                               pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
+                               break;
+                       case 'n':
+                               pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
+                               break;
+                       case 'p':
+                               pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
+                               break;
+                       case 'r':
+                               pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
+                               break;
+                       default:
+                               if (isalpha(*c))
+                                       ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
+                       }
+                       c++;
+               }
                pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
 
                ldp_strip = 0;
@@ -2436,6 +2507,58 @@ static int zt_call(struct ast_channel *ast, char *rdest, int timeout)
                                prilocaldialplan = PRI_LOCAL_ISDN;
                        }
                }
+               if (l != NULL) {
+                       while (*l > '9' && *l != '*' && *l != '#') {
+                               switch (*l) {
+                               case 'U':
+                                       prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'I':
+                                       prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'N':
+                                       prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'L':
+                                       prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'S':
+                                       prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'A':
+                                       prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'R':
+                                       prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
+                                       break;
+                               case 'u':
+                                       prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'e':
+                                       prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'x':
+                                       prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'f':
+                                       prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'n':
+                                       prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'p':
+                                       prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
+                                       break;
+                               case 'r':
+                                       prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
+                                       break;
+                               default:
+                                       if (isalpha(*l))
+                                               ast_log(LOG_WARNING, "Unrecognized prilocaldialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
+                               }
+                               l++;
+                       }
+               }
                pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
                        p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
                if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
@@ -4095,22 +4218,24 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                        break;
                case ZT_EVENT_ALARM:
 #ifdef HAVE_PRI
-                       if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
-                               /* T309 is not enabled : hangup calls when alarm occurs */
-                               if (p->call) {
-                                       if (p->pri && p->pri->pri) {
-                                               if (!pri_grab(p, p->pri)) {
-                                                       pri_hangup(p->pri->pri, p->call, -1);
-                                                       pri_destroycall(p->pri->pri, p->call);
-                                                       p->call = NULL;
-                                                       pri_rel(p->pri);
+                       if (p->sig == SIG_PRI) {
+                               if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
+                                       /* T309 is not enabled : hangup calls when alarm occurs */
+                                       if (p->call) {
+                                               if (p->pri && p->pri->pri) {
+                                                       if (!pri_grab(p, p->pri)) {
+                                                               pri_hangup(p->pri->pri, p->call, -1);
+                                                               pri_destroycall(p->pri->pri, p->call);
+                                                               p->call = NULL;
+                                                               pri_rel(p->pri);
+                                                       } else
+                                                               ast_log(LOG_WARNING, "Failed to grab PRI!\n");
                                                } else
-                                                       ast_log(LOG_WARNING, "Failed to grab PRI!\n");
-                                       } else
-                                               ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
+                                                       ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
+                                       }
+                                       if (p->owner)
+                                               p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
                                }
-                               if (p->owner)
-                                       p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
                        }
                        if (p->bearer)
                                p->bearer->inalarm = 1;
@@ -4130,6 +4255,10 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                break;
                        }
 #endif
+#ifdef HAVE_SS7
+                       if (p->sig == SIG_SS7)
+                               break;
+#endif
                case ZT_EVENT_ONHOOK:
                        if (p->radio) {
                                p->subs[index].f.frametype = AST_FRAME_CONTROL;
@@ -5587,7 +5716,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
                                i->dsp = NULL;
                        if (i->dsp) {
                                i->dsp_features = features & ~DSP_PROGRESS_TALK;
-#ifdef HAVE_PRI
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
                                /* We cannot do progress detection until receives PROGRESS message */
                                if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_SS7))) {
                                        /* Remember requested DSP features, don't treat
@@ -5648,6 +5777,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
 #endif
        tmp->cid.cid_pres = i->callingpres;
        tmp->cid.cid_ton = i->cid_ton;
+       tmp->cid.cid_ani2 = i->cid_ani2;
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
        tmp->transfercapability = transfercapability;
        pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
@@ -7145,8 +7275,10 @@ static void *do_monitor(void *data)
                /* Lock the interface list */
                ast_mutex_lock(&iflock);
                if (!pfds || (lastalloc != ifcount)) {
-                       if (pfds)
+                       if (pfds) {
                                ast_free(pfds);
+                               pfds = NULL;
+                       }
                        if (ifcount) {
                                if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
                                        ast_mutex_unlock(&iflock);
@@ -7457,7 +7589,7 @@ static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
 
 #ifdef HAVE_SS7
 
-static unsigned int parse_pointcode(char *pcstring)
+static unsigned int parse_pointcode(const char *pcstring)
 {
        unsigned int code1, code2, code3;
        int numvals;
@@ -8412,6 +8544,38 @@ static int ss7_find_cic(struct zt_ss7 *linkset, int cic)
        return winner;
 }
 
+static void ss7_handle_cqm(struct zt_ss7 *linkset, int startcic, int endcic)
+{
+       unsigned char status[32];
+       struct zt_pvt *p = NULL;
+       int i, offset;
+
+       for (i = 0; i < linkset->numchans; i++) {
+               if (linkset->pvts[i] && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))) {
+                       p = linkset->pvts[i];
+                       offset = p->cic - startcic;
+                       status[offset] = 0;
+                       if (p->locallyblocked)
+                               status[offset] |= (1 << 0) | (1 << 4);
+                       if (p->remotelyblocked)
+                               status[offset] |= (1 << 1) | (1 << 5);
+                       if (p->ss7call) {
+                               if (p->outgoing)
+                                       status[offset] |= (1 << 3);
+                               else
+                                       status[offset] |= (1 << 2);
+                       } else
+                               status[offset] |= 0x3 << 2;
+               }
+       }
+
+       if (p)
+               isup_cqr(linkset->ss7, startcic, endcic, p->dpc, status);
+       else
+               ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
+       
+}
+
 static inline void ss7_block_cics(struct zt_ss7 *linkset, int startcic, int endcic, unsigned char state[], int block)
 {
        int i;
@@ -8467,9 +8631,12 @@ static void ss7_reset_linkset(struct zt_ss7 *linkset)
 
 static void zt_loopback(struct zt_pvt *p, int enable)
 {
-       if (ioctl(p->subs[SUB_REAL].zfd, ZT_LOOPBACK, &enable)) {
-               ast_log(LOG_WARNING, "Unable to set loopback on channel %d\n", p->channel);
-               return;
+       if (p->loopedback != enable) {
+               if (ioctl(p->subs[SUB_REAL].zfd, ZT_LOOPBACK, &enable)) {
+                       ast_log(LOG_WARNING, "Unable to set loopback on channel %d\n", p->channel);
+                       return;
+               }
+               p->loopedback = enable;
        }
 }
 
@@ -8502,6 +8669,18 @@ static void ss7_start_call(struct zt_pvt *p, struct zt_ss7 *linkset)
                ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
        else
                ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
+
+       if (!ast_strlen_zero(p->charge_number)) {
+               pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
+               /* Clear this after we set it */
+               p->charge_number[0] = 0;
+       }
+       if (!ast_strlen_zero(p->gen_add_number)) {
+               pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
+               /* Clear this after we set it */
+               p->gen_add_number[0] = 0;
+       }
+
 }
 
 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct zt_ss7 *ss7, const char *number, const unsigned nai)
@@ -8615,10 +8794,15 @@ static void *ss7_linkset(void *data)
                                }
                        }
 
-                       if (pollers[i].revents & POLLIN)
+                       if (pollers[i].revents & POLLIN) {
+                               ast_mutex_lock(&linkset->lock);
                                res = ss7_read(ss7, pollers[i].fd);
+                               ast_mutex_unlock(&linkset->lock);
+                       }
                        if (pollers[i].revents & POLLOUT) {
+                               ast_mutex_lock(&linkset->lock);
                                res = ss7_write(ss7, pollers[i].fd);
+                               ast_mutex_unlock(&linkset->lock);
                                if (res < 0) {
                                        ast_log(LOG_ERROR, "Error in write %s", strerror(errno));
                                }
@@ -8671,6 +8855,10 @@ static void *ss7_linkset(void *data)
                                                ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
                                                zap_queue_frame(p, &f, linkset);
                                                p->progress = 1;
+                                               if (p->dsp && p->dsp_features) {
+                                                       ast_dsp_set_features(p->dsp, p->dsp_features);
+                                                       p->dsp_features = 0;
+                                               }
                                        }
                                        break;
                                default:
@@ -8706,6 +8894,10 @@ static void *ss7_linkset(void *data)
                                isup_gra(ss7, e->grs.startcic, e->grs.endcic, p->dpc);
                                ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, NULL, 0);
                                break;
+                       case ISUP_EVENT_CQM:
+                               ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
+                               ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic);
+                               break;
                        case ISUP_EVENT_GRA:
                                ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
                                ss7_inservice(linkset, e->gra.startcic, e->gra.endcic);
@@ -8754,13 +8946,21 @@ static void *ss7_linkset(void *data)
                                        st = strchr(p->exten, '#');
                                        if (st)
                                                *st = '\0';
-                               } else
-                                       p->exten[0] = '\0';
+                                       } else
+                                               p->exten[0] = '\0';
 
-                               /* Need to fill these fields */
                                p->cid_ani[0] = '\0';
                                p->cid_name[0] = '\0';
+                               p->cid_ani2 = e->iam.oli_ani2;
                                p->cid_ton = 0;
+                               ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
+
+                               ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
+                               p->gen_add_type = e->iam.gen_add_type;
+                               p->gen_add_nai = e->iam.gen_add_nai;
+                               p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
+                               p->gen_add_num_plan = e->iam.gen_add_num_plan;
+                                       
                                /* Set DNID */
                                if (!ast_strlen_zero(e->iam.called_party_num))
                                        ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
@@ -8790,6 +8990,22 @@ static void *ss7_linkset(void *data)
                                
                                ss7_start_call(p, linkset);
                                break;
+                       case ISUP_EVENT_CCR:
+                               ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
+                               chanpos = ss7_find_cic(linkset, e->ccr.cic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
+                                       break;
+                               }
+
+                               p = linkset->pvts[chanpos];
+
+                               ast_mutex_lock(&p->lock);
+                               zt_loopback(p, 1);
+                               ast_mutex_unlock(&p->lock);
+
+                               isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
+                               break;
                        case ISUP_EVENT_REL:
                                chanpos = ss7_find_cic(linkset, e->rel.cic);
                                if (chanpos < 0) {
@@ -8804,6 +9020,9 @@ static void *ss7_linkset(void *data)
                                } else
                                        ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
 
+                               /* End the loopback if we have one */
+                               zt_loopback(p, 0);
+
                                isup_rlc(ss7, e->rel.call);
                                p->ss7call = NULL;
 
@@ -8850,7 +9069,6 @@ static void *ss7_linkset(void *data)
                                isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, p->dpc, e->cgu.status, e->cgu.type);
                                break;
                        case ISUP_EVENT_UCIC:
-                               ast_verb(3,"Got UCIC message on CIC %d\n", e->ucic.cic);
                                chanpos = ss7_find_cic(linkset, e->ucic.cic);
                                if (chanpos < 0) {
                                        ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
@@ -8864,7 +9082,6 @@ static void *ss7_linkset(void *data)
                                ast_mutex_unlock(&p->lock);                     //doesn't require a SS7 acknowledgement
                                break;
                        case ISUP_EVENT_BLO:
-                               ast_verb(3,"Got BLO acknowledgement from CIC %d\n", e->ubl.cic);
                                chanpos = ss7_find_cic(linkset, e->blo.cic);
                                if (chanpos < 0) {
                                        ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
@@ -8874,12 +9091,22 @@ static void *ss7_linkset(void *data)
                                ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
                                ast_mutex_lock(&p->lock);
                                p->remotelyblocked = 1;
-                               p->inservice = 0;
                                ast_mutex_unlock(&p->lock);
                                isup_bla(linkset->ss7, e->blo.cic, p->dpc);
                                break;
+                       case ISUP_EVENT_BLA:
+                               chanpos = ss7_find_cic(linkset, e->bla.cic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
+                                       break;
+                               }
+                               ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
+                               p = linkset->pvts[chanpos];
+                               ast_mutex_lock(&p->lock);
+                               p->locallyblocked = 1;
+                               ast_mutex_unlock(&p->lock);
+                               break;
                        case ISUP_EVENT_UBL:
-                               ast_verb(3,"Got UBL acknowledgement from CIC %d\n", e->ubl.cic);
                                chanpos = ss7_find_cic(linkset, e->ubl.cic);
                                if (chanpos < 0) {
                                        ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
@@ -8889,10 +9116,21 @@ static void *ss7_linkset(void *data)
                                ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
                                ast_mutex_lock(&p->lock);
                                p->remotelyblocked = 0;
-                               p->inservice = 1;
                                ast_mutex_unlock(&p->lock);
                                isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
                                break;
+                       case ISUP_EVENT_UBA:
+                               chanpos = ss7_find_cic(linkset, e->uba.cic);
+                               if (chanpos < 0) {
+                                       ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
+                                       break;
+                               }
+                               p = linkset->pvts[chanpos];
+                               ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
+                               ast_mutex_lock(&p->lock);
+                               p->locallyblocked = 0;
+                               ast_mutex_unlock(&p->lock);
+                               break;
                        case ISUP_EVENT_CON:
                        case ISUP_EVENT_ANM:
                                if (e->e == ISUP_EVENT_CON)
@@ -8909,6 +9147,10 @@ static void *ss7_linkset(void *data)
                                        p = linkset->pvts[chanpos];
                                        ast_mutex_lock(&p->lock);
                                        p->subs[SUB_REAL].needanswer = 1;
+                                       if (p->dsp && p->dsp_features) {
+                                               ast_dsp_set_features(p->dsp, p->dsp_features);
+                                               p->dsp_features = 0;
+                                       }
                                        zt_enable_ec(p);
                                        ast_mutex_unlock(&p->lock);
                                }
@@ -9814,6 +10056,7 @@ static void *pri_dchannel(void *vpri)
                                                        if (e->ring.ani2 >= 0) {
                                                                snprintf(ani2str, 5, "%.2d", e->ring.ani2);
                                                                pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+                                                               pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
                                                        }
 
 #ifdef SUPPORT_USERUSER
@@ -9852,6 +10095,7 @@ static void *pri_dchannel(void *vpri)
                                                                if (e->ring.ani2 >= 0) {
                                                                        snprintf(ani2str, 5, "%d", e->ring.ani2);
                                                                        pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+                                                                       pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
                                                                }
 
 #ifdef SUPPORT_USERUSER
@@ -10775,14 +11019,14 @@ static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_
 }
 
 static struct ast_cli_entry zap_pri_cli[] = {
-       NEW_CLI(handle_pri_debug, "Enables PRI debugging on a span"),
-       NEW_CLI(handle_pri_no_debug, "Disables PRI debugging on a span"),
-       NEW_CLI(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
-       NEW_CLI(handle_pri_show_spans, "Displays PRI Information"),
-       NEW_CLI(handle_pri_show_span, "Displays PRI Information"),
-       NEW_CLI(handle_pri_show_debug, "Displays current PRI debug settings"),
-       NEW_CLI(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
-       NEW_CLI(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
+       AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
+       AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"),
+       AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
+       AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"),
+       AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"),
+       AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
+       AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
+       AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
 };
 
 #endif /* HAVE_PRI */
@@ -10838,6 +11082,8 @@ static char *zap_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                        "       Note that this will STOP any running CALL on zaptel channels.\n"
                        "";
                return NULL;
+       case CLI_GENERATE:
+               return NULL;
        }
        if (a->argc != 2)
                return CLI_SHOWUSAGE;
@@ -10970,7 +11216,7 @@ static char *zap_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_
 
                blockstr[2] = '\0';
 
-               snprintf(statestr, sizeof(statestr), "%s", tmp->inservice ? "In Service" : "Out of Service");
+               snprintf(statestr, sizeof(statestr), "%s", "In Service");
 
                ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
                tmp = tmp->next;
@@ -11297,13 +11543,13 @@ static char *zap_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_a
 }
 
 static struct ast_cli_entry zap_cli[] = {
-       NEW_CLI(handle_zap_show_cadences, "List cadences"),
-       NEW_CLI(zap_show_channels, "Show active zapata channels"),
-       NEW_CLI(zap_show_channel, "Show information on a channel"),
-       NEW_CLI(zap_destroy_channel, "Destroy a channel"),
-       NEW_CLI(zap_restart_cmd, "Fully restart zaptel channels"),
-       NEW_CLI(zap_show_status, "Show all Zaptel cards status"),
-       NEW_CLI(zap_show_version, "Show the Zaptel version in use"),
+       AST_CLI_DEFINE(handle_zap_show_cadences, "List cadences"),
+       AST_CLI_DEFINE(zap_show_channels, "Show active zapata channels"),
+       AST_CLI_DEFINE(zap_show_channel, "Show information on a channel"),
+       AST_CLI_DEFINE(zap_destroy_channel, "Destroy a channel"),
+       AST_CLI_DEFINE(zap_restart_cmd, "Fully restart zaptel channels"),
+       AST_CLI_DEFINE(zap_show_status, "Show all Zaptel cards status"),
+       AST_CLI_DEFINE(zap_show_version, "Show the Zaptel version in use"),
 };
 
 #define TRANSFER       0
@@ -11646,7 +11892,7 @@ static int linkset_addsigchan(int sigchan)
                        return -1;
                }
 
-               ss7_add_link(link->ss7, link->fds[curfd]);
+               ss7_add_link(link->ss7, SS7_TRANSPORT_ZAP, link->fds[curfd]);
                link->numsigchans++;
 
                memset(&si, 0, sizeof(si));
@@ -11789,9 +12035,6 @@ static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_c
                if (linksets[linkset-1].pvts[i]->cic == cic) {
                        blocked = linksets[linkset-1].pvts[i]->locallyblocked;
                        if (!blocked) {
-                               ast_mutex_lock(&linksets[linkset-1].pvts[i]->lock);
-                               linksets[linkset-1].pvts[i]->locallyblocked = 1;
-                               ast_mutex_unlock(&linksets[linkset-1].pvts[i]->lock);
                                ast_mutex_lock(&linksets[linkset-1].lock);
                                isup_blo(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
                                ast_mutex_unlock(&linksets[linkset-1].lock);
@@ -11853,9 +12096,6 @@ static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast
                if (linksets[linkset-1].pvts[i]->cic == cic) {
                        blocked = linksets[linkset-1].pvts[i]->locallyblocked;
                        if (blocked) {
-                               ast_mutex_lock(&linksets[linkset-1].pvts[i]->lock);
-                               linksets[linkset-1].pvts[i]->locallyblocked = 0;
-                               ast_mutex_unlock(&linksets[linkset-1].pvts[i]->lock);
                                ast_mutex_lock(&linksets[linkset-1].lock);
                                isup_ubl(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
                                ast_mutex_unlock(&linksets[linkset-1].lock);
@@ -11903,11 +12143,11 @@ static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct as
 }
 
 static struct ast_cli_entry zap_ss7_cli[] = {
-       NEW_CLI(handle_ss7_debug, "Enables SS7 debugging on a linkset"), 
-       NEW_CLI(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), 
-       NEW_CLI(handle_ss7_block_cic, "Disables SS7 debugging on a linkset"),
-       NEW_CLI(handle_ss7_unblock_cic, "Disables SS7 debugging on a linkset"),
-       NEW_CLI(handle_ss7_show_linkset, "Shows the status of a linkset"),
+       AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), 
+       AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), 
+       AST_CLI_DEFINE(handle_ss7_block_cic, "Disables SS7 debugging on a linkset"),
+       AST_CLI_DEFINE(handle_ss7_unblock_cic, "Disables SS7 debugging on a linkset"),
+       AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
 };
 #endif /* HAVE_SS7 */
 
@@ -12021,7 +12261,7 @@ static int build_channels(struct zt_chan_conf conf, int iscrv, const char *value
 static int process_zap(struct zt_chan_conf *confp, struct ast_variable *v, int reload, int skipchannels)
 {
        struct zt_pvt *tmp;
-       char *ringc; /* temporary string for parsing the dring number. */
+       const char *ringc; /* temporary string for parsing the dring number. */
        int y;
        int found_pseudo = 0;
         char zapchan[MAX_CHANLIST_LEN] = {};
@@ -12560,9 +12800,9 @@ static int process_zap(struct zt_chan_conf *confp, struct ast_variable *v, int r
                                }
                        } else if (!strcasecmp(v->name, "pritimer")) {
 #ifdef PRI_GETSET_TIMERS
-                               char *timerc, *c;
+                               char tmp[20], *timerc, *c = tmp;
                                int timer, timeridx;
-                               c = v->value;
+                               ast_copy_string(tmp, v->value, sizeof(tmp));
                                timerc = strsep(&c, ",");
                                if (timerc) {
                                        timer = atoi(c);
@@ -13003,7 +13243,7 @@ static int load_module(void)
        if (ast_channel_register(&zap_tech)) {
                ast_log(LOG_ERROR, "Unable to register channel class 'Zap'\n");
                __unload_module();
-               return -1;
+               return AST_MODULE_LOAD_FAILURE;
        }
 #ifdef HAVE_PRI
        ast_string_field_init(&inuse, 16);
@@ -13103,8 +13343,10 @@ static int zt_sendtext(struct ast_channel *c, const char *text)
                        continue;
                }
                  /* if got exception */
-               if (fds[0].revents & POLLPRI)
+               if (fds[0].revents & POLLPRI) {
+                       ast_free(mybuf);
                        return -1;
+               }
                if (!(fds[0].revents & POLLOUT)) {
                        ast_debug(1, "write fd not ready on channel %d\n", p->channel);
                        continue;