aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-06-07 03:39:18 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-06-07 03:39:18 +0000
commit38acf295cc2c472e0231f7a309743da6aad0a92d (patch)
tree1d2f0bf568846e77a67837641950c8ece7fed272 /channels
parent562f2c18056936d099579d433cf151ead5d52a69 (diff)
Initial, incomplete support for D-channel backup
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@3163 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rwxr-xr-xchannels/chan_zap.c562
1 files changed, 386 insertions, 176 deletions
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 78ec79d7b..dd217144f 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -55,7 +55,7 @@
#include <ctype.h>
#ifdef ZAPATA_PRI
#include <libpri.h>
-#ifndef PRI_GR303_SUPPORT
+#ifndef PRI_ENSLAVE_SUPPORT
#error "You need newer libpri"
#endif
#endif
@@ -133,11 +133,18 @@ static char *config = "zapata.conf";
#define SIG_GR303FXOKS (0x100000 | ZT_SIG_FXOKS)
#define NUM_SPANS 32
+#define NUM_DCHANS 4 /* No more than 4 d-channels */
#define MAX_CHANNELS 672 /* No more than a DS3 per trunk group */
#define RESET_INTERVAL 3600 /* How often (in seconds) to reset unused channels */
#define CHAN_PSEUDO -2
+#define DCHAN_PROVISIONED (1 << 0)
+#define DCHAN_NOTINALARM (1 << 1)
+#define DCHAN_UP (1 << 2)
+
+#define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
+
static char context[AST_MAX_EXTENSION] = "default";
static char callerid[256] = "";
@@ -310,16 +317,17 @@ struct zt_pri {
int nodetype; /* Node type */
int switchtype; /* Type of switch to emulate */
int dialplan; /* Dialing plan */
- int dchannel; /* What channel the dchannel is on */
+ int dchannels[NUM_DCHANS]; /* What channel are the dchannels on */
int trunkgroup; /* What our trunkgroup is */
int mastertrunkgroup; /* What trunk group is our master */
int prilogicalspan; /* Logical span number within trunk group */
int numchans; /* Num of channels we represent */
int overlapdial; /* In overlap dialing mode */
- struct pri *pri;
+ struct pri *dchans[NUM_DCHANS]; /* Actual d-channels */
+ int dchanavail[NUM_DCHANS]; /* Whether each channel is available */
+ struct pri *pri; /* Currently active D-channel */
int debug;
- int fd;
- int up;
+ int fds[NUM_DCHANS]; /* FD's for d-channels */
int offset;
int span;
int resetting;
@@ -1762,6 +1770,16 @@ static int destroy_channel(struct zt_pvt *prev, struct zt_pvt *cur, int now)
}
#ifdef ZAPATA_PRI
+int pri_is_up(struct zt_pri *pri)
+{
+ int x;
+ for (x=0;x<NUM_DCHANS;x++) {
+ if (pri->dchanavail[x] == DCHAN_AVAILABLE)
+ return 1;
+ }
+ return 0;
+}
+
int pri_assign_bearer(struct zt_pvt *crv, struct zt_pri *pri, struct zt_pvt *bearer)
{
bearer->owner = &inuse;
@@ -1772,6 +1790,48 @@ int pri_assign_bearer(struct zt_pvt *crv, struct zt_pri *pri, struct zt_pvt *bea
crv->pri = pri;
return 0;
}
+
+static char *pri_order(int level)
+{
+ switch(level) {
+ case 0:
+ return "Primary";
+ case 1:
+ return "Secondary";
+ case 2:
+ return "Tertiary";
+ case 3:
+ return "Quaternary";
+ default:
+ return "<Unknown>";
+ }
+}
+
+int pri_find_dchan(struct zt_pri *pri)
+{
+ int oldslot = -1;
+ struct pri *old;
+ int newslot = -1;
+ int x;
+ old = pri->pri;
+ for(x=0;x<NUM_DCHANS;x++) {
+ if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
+ newslot = x;
+ if (pri->dchans[x] == old) {
+ oldslot = x;
+ }
+ }
+ if (newslot < 0) {
+ ast_log(LOG_WARNING, "No D-channels available! Using Primary on channel anyway %d!\n",
+ pri->dchannels[newslot]);
+ newslot = 0;
+ }
+ if (old && (oldslot != newslot))
+ ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
+ pri->dchannels[oldslot], pri->dchannels[newslot]);
+ pri->pri = pri->dchans[newslot];
+ return 0;
+}
#endif
static int zt_hangup(struct ast_channel *ast)
@@ -5478,10 +5538,11 @@ static int pri_resolve_span(int *span, int channel, int offset, struct zt_spanin
*span = -1;
} else {
if (si->totalchans == 31) { /* if it's an E1 */
- pris[*span].dchannel = 16;
+ pris[*span].dchannels[0] = 16 + offset;
} else {
- pris[*span].dchannel = 24;
+ pris[*span].dchannels[0] = 24 + offset;
}
+ pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
pris[*span].offset = offset;
pris[*span].span = *span + 1;
}
@@ -5489,57 +5550,66 @@ static int pri_resolve_span(int *span, int channel, int offset, struct zt_spanin
return 0;
}
-static int pri_create_trunkgroup(int trunkgroup, int channel)
+static int pri_create_trunkgroup(int trunkgroup, int *channels)
{
struct zt_spaninfo si;
ZT_PARAMS p;
int fd;
int span;
- int x;
+ int ospan=0;
+ int x,y;
for (x=0;x<NUM_SPANS;x++) {
if (pris[x].trunkgroup == trunkgroup) {
- ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, channel %d\n", trunkgroup, x + 1, pris[x].dchannel);
+ ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
return -1;
}
}
- memset(&si, 0, sizeof(si));
- memset(&p, 0, sizeof(p));
- fd = open("/dev/zap/channel", O_RDWR);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
- return -1;
- }
- x = channel;
- if (ioctl(fd, ZT_SPECIFY, &x)) {
- ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channel, strerror(errno));
- close(fd);
- return -1;
- }
- if (ioctl(fd, ZT_GET_PARAMS, &p)) {
- ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channel, strerror(errno));
- return -1;
- }
- if (ioctl(fd, ZT_SPANSTAT, &si)) {
- ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d)\n", channel, p.spanno);
- close(fd);
- return -1;
- }
- span = p.spanno - 1;
- if (pris[span].trunkgroup) {
- ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
- close(fd);
- return -1;
- }
- if (pris[span].pvts[0]) {
- ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
+ for (y=0;y<NUM_DCHANS;y++) {
+ if (!channels[y])
+ break;
+ memset(&si, 0, sizeof(si));
+ memset(&p, 0, sizeof(p));
+ fd = open("/dev/zap/channel", O_RDWR);
+ if (fd < 0) {
+ ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
+ return -1;
+ }
+ x = channels[y];
+ if (ioctl(fd, ZT_SPECIFY, &x)) {
+ ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
+ close(fd);
+ return -1;
+ }
+ if (ioctl(fd, ZT_GET_PARAMS, &p)) {
+ ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
+ return -1;
+ }
+ if (ioctl(fd, ZT_SPANSTAT, &si)) {
+ ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d)\n", channels[y], p.spanno);
+ close(fd);
+ return -1;
+ }
+ span = p.spanno - 1;
+ if (pris[span].trunkgroup) {
+ ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
+ close(fd);
+ return -1;
+ }
+ if (pris[span].pvts[0]) {
+ ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
+ close(fd);
+ return -1;
+ }
+ if (!y) {
+ pris[span].trunkgroup = trunkgroup;
+ pris[span].offset = channels[y] - p.chanpos;
+ ospan = span;
+ }
+ pris[ospan].dchannels[y] = channels[y];
+ pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
+ pris[span].span = span + 1;
close(fd);
- return -1;
}
- pris[span].trunkgroup = trunkgroup;
- pris[span].offset = channel - p.chanpos;
- pris[span].dchannel = p.chanpos;
- pris[span].span = span + 1;
- close(fd);
return 0;
}
@@ -5702,6 +5772,8 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
if ((signalling == SIG_PRI) || (signalling == SIG_GR303FXOKS)) {
int offset;
int myswitchtype;
+ int matchesdchan;
+ int x,y;
offset = 0;
if ((signalling == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) {
ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
@@ -5731,8 +5803,18 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
myswitchtype = switchtype;
else
myswitchtype = PRI_SWITCH_GR303_TMC;
+ /* Make sure this isn't a d-channel */
+ matchesdchan=0;
+ for (x=0;x<NUM_SPANS;x++) {
+ for (y=0;y<NUM_DCHANS;y++) {
+ if (pris[x].dchannels[y] == tmp->channel) {
+ matchesdchan = 1;
+ break;
+ }
+ }
+ }
offset = p.chanpos;
- if (offset != pris[span].dchannel) {
+ if (!matchesdchan) {
if (pris[span].nodetype && (pris[span].nodetype != pritype)) {
ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
free(tmp);
@@ -5949,7 +6031,7 @@ static struct zt_pvt *mkintf(int channel, int signalling, int radio, struct zt_p
ioctl(tmp->subs[SUB_REAL].zfd,ZT_SETTONEZONE,&tmp->tonezone);
#ifdef ZAPATA_PRI
/* the dchannel is down so put the channel in alarm */
- if (tmp->pri && tmp->pri->up == 0)
+ if (tmp->pri && !pri_is_up(tmp->pri))
tmp->inalarm = 1;
else
tmp->inalarm = 0;
@@ -6506,7 +6588,7 @@ static void *pri_dchannel(void *vpri)
{
struct zt_pri *pri = vpri;
pri_event *e;
- struct pollfd fds[1];
+ struct pollfd fds[NUM_DCHANS];
int res;
int chanpos = 0;
int x;
@@ -6514,7 +6596,7 @@ static void *pri_dchannel(void *vpri)
int activeidles;
int nextidle = -1;
struct ast_channel *c;
- struct timeval tv, *next;
+ struct timeval tv, lowest, *next;
struct timeval lastidle = { 0, 0 };
int doidling=0;
char *cc;
@@ -6522,7 +6604,8 @@ static void *pri_dchannel(void *vpri)
struct ast_channel *idle;
pthread_t p;
time_t t;
- int i;
+ int i, which=-1;
+ int numdchans;
struct zt_pvt *crv;
pthread_t threadid;
pthread_attr_t attr;
@@ -6549,12 +6632,17 @@ static void *pri_dchannel(void *vpri)
ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
}
for(;;) {
- fds[0].fd = pri->fd;
- fds[0].events = POLLIN | POLLPRI;
+ for (i=0;i<NUM_DCHANS;i++) {
+ if (!pri->dchannels[i])
+ break;
+ fds[i].fd = pri->fds[i];
+ fds[i].events = POLLIN | POLLPRI;
+ }
+ numdchans = i;
time(&t);
ast_mutex_lock(&pri->lock);
if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
- if (pri->resetting && pri->up) {
+ if (pri->resetting && pri_is_up(pri)) {
if (pri->resetpos < 0)
pri_check_restart(pri);
} else {
@@ -6565,7 +6653,7 @@ static void *pri_dchannel(void *vpri)
}
}
/* Look for any idle channels if appropriate */
- if (doidling && pri->up) {
+ if (doidling && pri_is_up(pri)) {
nextidle = -1;
haveidles = 0;
activeidles = 0;
@@ -6624,63 +6712,93 @@ static void *pri_dchannel(void *vpri)
}
}
}
- if ((next = pri_schedule_next(pri->pri))) {
- /* We need relative time here */
- gettimeofday(&tv, NULL);
- tv.tv_sec = next->tv_sec - tv.tv_sec;
- tv.tv_usec = next->tv_usec - tv.tv_usec;
- if (tv.tv_usec < 0) {
- tv.tv_usec += 1000000;
- tv.tv_sec -= 1;
- }
- if (tv.tv_sec < 0) {
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- }
- if (doidling || pri->resetting) {
- if (tv.tv_sec > 1) {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
+ /* Start with reasonable max */
+ lowest.tv_sec = 60;
+ lowest.tv_usec = 0;
+ for (i=0; i<NUM_DCHANS; i++) {
+ /* Find lowest available d-channel */
+ if (!pri->dchannels[i])
+ break;
+ if ((next = pri_schedule_next(pri->pri))) {
+ /* We need relative time here */
+ gettimeofday(&tv, NULL);
+ tv.tv_sec = next->tv_sec - tv.tv_sec;
+ tv.tv_usec = next->tv_usec - tv.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000;
+ tv.tv_sec -= 1;
}
- } else {
- if (tv.tv_sec > 60) {
- tv.tv_sec = 60;
+ if (tv.tv_sec < 0) {
+ tv.tv_sec = 0;
tv.tv_usec = 0;
}
+ if (doidling || pri->resetting) {
+ if (tv.tv_sec > 1) {
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ }
+ } else {
+ if (tv.tv_sec > 60) {
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ }
+ }
+ } else if (doidling || pri->resetting) {
+ /* Make sure we stop at least once per second if we're
+ monitoring idle channels */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ } else {
+ /* Don't poll for more than 60 seconds */
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ }
+ if (!i || (tv.tv_sec < lowest.tv_sec) || ((tv.tv_sec == lowest.tv_sec) && (tv.tv_usec < lowest.tv_usec))) {
+ lowest.tv_sec = tv.tv_sec;
+ lowest.tv_usec = tv.tv_usec;
}
- } else if (doidling || pri->resetting) {
- /* Make sure we stop at least once per second if we're
- monitoring idle channels */
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- } else {
- /* Don't poll for more than 60 seconds */
- tv.tv_sec = 60;
- tv.tv_usec = 0;
}
ast_mutex_unlock(&pri->lock);
e = NULL;
- res = poll(fds, 1, tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
ast_mutex_lock(&pri->lock);
if (!res) {
- /* Just a timeout, run the scheduler */
- e = pri_schedule_run(pri->pri);
+ for (which=0;which<NUM_DCHANS;which++) {
+ if (!pri->dchans[which])
+ break;
+ /* Just a timeout, run the scheduler */
+ e = pri_schedule_run(pri->dchans[which]);
+ if (e)
+ break;
+ }
} else if (res > -1) {
- e = pri_check_event(pri->pri);
+ for (which=0;which<NUM_DCHANS;which++) {
+ if (!pri->dchans[which])
+ break;
+ if (fds[which].revents & (POLLIN | POLLPRI)) {
+ e = pri_check_event(pri->dchans[which]);
+ }
+ if (e)
+ break;
+ }
} else if (errno != EINTR)
ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
if (e) {
if (pri->debug)
- pri_dump_event(pri->pri, e);
+ pri_dump_event(pri->dchans[which], e);
switch(e->e) {
case PRI_EVENT_DCHAN_UP:
if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "D-Channel on span %d up\n", pri->span);
- pri->up = 1;
+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d up\n", pri_order(which), pri->span);
+ pri->dchanavail[which] |= DCHAN_UP;
+ pri_find_dchan(pri);
+
+ /* Note presense of D-channel */
time(&pri->lastreset);
+
/* Restart in 5 seconds */
pri->lastreset -= RESET_INTERVAL;
pri->lastreset += 5;
@@ -6693,26 +6811,29 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_DCHAN_DOWN:
if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "D-Channel on span %d down\n", pri->span);
- pri->up = 0;
- pri->resetting = 0;
- /* Hangup active channels and put them in alarm mode */
- for (i=0; i<pri->numchans; i++) {
- struct zt_pvt *p = pri->pvts[i];
- if (p) {
- if (p->call) {
- if (p->pri && p->pri->pri) {
- pri_hangup(p->pri->pri, p->call, -1);
- pri_destroycall(p->pri->pri, p->call);
- p->call = NULL;
- } else
- ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
+ ast_verbose(VERBOSE_PREFIX_2 "%s D-Channel on span %d down\n", pri_order(which), pri->span);
+ pri->dchanavail[which] &= ~DCHAN_UP;
+ pri_find_dchan(pri);
+ if (!pri_is_up(pri)) {
+ pri->resetting = 0;
+ /* Hangup active channels and put them in alarm mode */
+ for (i=0; i<pri->numchans; i++) {
+ struct zt_pvt *p = pri->pvts[i];
+ if (p) {
+ if (p->call) {
+ if (p->pri && p->pri->pri) {
+ pri_hangup(p->pri->pri, p->call, -1);
+ pri_destroycall(p->pri->pri, p->call);
+ p->call = NULL;
+ } else
+ ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
+ }
+ if (p->master) {
+ pri_hangup_all(p->master);
+ } else if (p->owner)
+ p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+ p->inalarm = 1;
}
- if (p->master) {
- pri_hangup_all(p->master);
- } else if (p->owner)
- p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
- p->inalarm = 1;
}
}
break;
@@ -7231,14 +7352,28 @@ static void *pri_dchannel(void *vpri)
ast_log(LOG_DEBUG, "Event: %d\n", e->e);
}
} else {
- /* Check for an event */
- x = 0;
- res = ioctl(pri->fd, ZT_GETEVENT, &x);
- if (x)
- ast_log(LOG_NOTICE, "PRI got event: %d on span %d\n", x, pri->span);
- if (option_debug)
- ast_log(LOG_DEBUG, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
- }
+ for (i=0;i<NUM_DCHANS;i++) {
+ if (!pri->dchannels[i])
+ break;
+ /* Check for an event */
+ x = 0;
+ res = ioctl(pri->fds[i], ZT_GETEVENT, &x);
+ if (x)
+ ast_log(LOG_NOTICE, "PRI got event: %d on %s D-channel of span %d\n", x, pri_order(x), pri->span);
+
+ /* Keep track of alarm state */
+ if (x == ZT_EVENT_ALARM) {
+ pri->dchanavail[i] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
+ pri_find_dchan(pri);
+ } else if (x == ZT_EVENT_NOALARM) {
+ pri->dchanavail[i] |= DCHAN_NOTINALARM;
+ pri_find_dchan(pri);
+ }
+
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
+ }
+ }
ast_mutex_unlock(&pri->lock);
}
/* Never reached */
@@ -7250,53 +7385,78 @@ static int start_pri(struct zt_pri *pri)
int res, x;
ZT_PARAMS p;
ZT_BUFFERINFO bi;
-
- pri->fd = open("/dev/zap/channel", O_RDWR, 0600);
- x = pri->offset + pri->dchannel;
- if ((pri->fd < 0) || (ioctl(pri->fd,ZT_SPECIFY,&x) == -1)) {
- ast_log(LOG_ERROR, "Unable to open D-channel %d (%d + %d) (%s)\n", x, pri->offset, pri->dchannel, strerror(errno));
- return -1;
- }
-
- res = ioctl(pri->fd, ZT_GET_PARAMS, &p);
- if (res) {
- close(pri->fd);
- pri->fd = -1;
- ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
- return -1;
- }
- if (p.sigtype != ZT_SIG_HDLCFCS) {
- close(pri->fd);
- pri->fd = -1;
- ast_log(LOG_ERROR, "D-channel %d (%d + %d) is not in HDLC/FCS mode. See /etc/zaptel.conf\n", x, pri->offset, pri->dchannel);
- return -1;
- }
- bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.numbufs = 16;
- bi.bufsize = 1024;
- if (ioctl(pri->fd, ZT_SET_BUFINFO, &bi)) {
- ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d\n", x);
- close(pri->fd);
- pri->fd = -1;
- return -1;
- }
- pri->pri = pri_new(pri->fd, pri->nodetype, pri->switchtype);
- if (!pri->pri) {
- close(pri->fd);
- pri->fd = -1;
- ast_log(LOG_ERROR, "Unable to create PRI structure\n");
- return -1;
+ struct zt_spaninfo si;
+ int i;
+
+ for (i=0;i<NUM_DCHANS;i++) {
+ if (!pri->dchannels[i])
+ break;
+ pri->fds[i] = open("/dev/zap/channel", O_RDWR, 0600);
+ x = pri->dchannels[i];
+ if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],ZT_SPECIFY,&x) == -1)) {
+ ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
+ return -1;
+ }
+ res = ioctl(pri->fds[i], ZT_GET_PARAMS, &p);
+ if (res) {
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
+ return -1;
+ }
+ if (p.sigtype != ZT_SIG_HDLCFCS) {
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode. See /etc/zaptel.conf\n", x);
+ return -1;
+ }
+ memset(&si, 0, sizeof(si));
+ res = ioctl(pri->fds[i], ZT_SPANSTAT, &si);
+ if (res) {
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
+ }
+ if (!si.alarms)
+ pri->dchanavail[i] |= DCHAN_NOTINALARM;
+ else
+ pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
+ bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ bi.numbufs = 16;
+ bi.bufsize = 1024;
+ if (ioctl(pri->fds[i], ZT_SET_BUFINFO, &bi)) {
+ ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d\n", x);
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ return -1;
+ }
+ pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
+ /* Force overlap dial if we're doing GR-303! */
+ if (pri->switchtype == PRI_SWITCH_GR303_TMC)
+ pri->overlapdial = 1;
+ pri_set_overlapdial(pri->dchans[i],pri->overlapdial);
+ /* Enslave to master if appropriate */
+ if (i)
+ pri_enslave(pri->dchans[0], pri->dchans[i]);
+ if (!pri->dchans[i]) {
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ ast_log(LOG_ERROR, "Unable to create PRI structure\n");
+ return -1;
+ }
+ pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
}
+ /* Assume primary is the one we use */
+ pri->pri = pri->dchans[0];
pri->resetpos = -1;
- /* Force overlap dial if we're doing GR-303! */
- if (pri->switchtype == PRI_SWITCH_GR303_TMC)
- pri->overlapdial = 1;
- pri_set_overlapdial(pri->pri,pri->overlapdial);
- pri_set_debug(pri->pri, DEFAULT_PRI_DEBUG);
if (pthread_create(&pri->master, NULL, pri_dchannel, pri)) {
- close(pri->fd);
- pri->fd = -1;
+ for (i=0;i<NUM_DCHANS;i++) {
+ if (!pri->dchannels[i])
+ break;
+ close(pri->fds[i]);
+ pri->fds[i] = -1;
+ }
ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
return -1;
}
@@ -7322,6 +7482,7 @@ static char *complete_span(char *line, char *word, int pos, int state)
static int handle_pri_debug(int fd, int argc, char *argv[])
{
int span;
+ int x;
if (argc < 4) {
return RESULT_SHOWUSAGE;
}
@@ -7334,7 +7495,10 @@ static int handle_pri_debug(int fd, int argc, char *argv[])
ast_cli(fd, "No PRI running on span %d\n", span);
return RESULT_SUCCESS;
}
- pri_set_debug(pris[span-1].pri, PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE);
+ for (x=0;x<NUM_DCHANS;x++) {
+ if (pris[span-1].dchans[x])
+ pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE);
+ }
ast_cli(fd, "Enabled debugging on span %d\n", span);
return RESULT_SUCCESS;
}
@@ -7344,6 +7508,7 @@ static int handle_pri_debug(int fd, int argc, char *argv[])
static int handle_pri_no_debug(int fd, int argc, char *argv[])
{
int span;
+ int x;
if (argc < 5)
return RESULT_SHOWUSAGE;
span = atoi(argv[4]);
@@ -7355,7 +7520,10 @@ static int handle_pri_no_debug(int fd, int argc, char *argv[])
ast_cli(fd, "No PRI running on span %d\n", span);
return RESULT_SUCCESS;
}
- pri_set_debug(pris[span-1].pri, 0);
+ for (x=0;x<NUM_DCHANS;x++) {
+ if (pris[span-1].dchans[x])
+ pri_set_debug(pris[span-1].dchans[x], 0);
+ }
ast_cli(fd, "Disabled debugging on span %d\n", span);
return RESULT_SUCCESS;
}
@@ -7363,6 +7531,7 @@ static int handle_pri_no_debug(int fd, int argc, char *argv[])
static int handle_pri_really_debug(int fd, int argc, char *argv[])
{
int span;
+ int x;
if (argc < 5)
return RESULT_SHOWUSAGE;
span = atoi(argv[4]);
@@ -7374,14 +7543,36 @@ static int handle_pri_really_debug(int fd, int argc, char *argv[])
ast_cli(fd, "No PRI running on span %d\n", span);
return RESULT_SUCCESS;
}
- pri_set_debug(pris[span-1].pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+ for (x=0;x<NUM_DCHANS;x++) {
+ if (pris[span-1].dchans[x])
+ pri_set_debug(pris[span-1].dchans[x], (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+ }
ast_cli(fd, "Enabled EXTENSIVE debugging on span %d\n", span);
return RESULT_SUCCESS;
}
+static void build_status(char *s, int status, int active)
+{
+ strcpy(s, "");
+ if (status & DCHAN_PROVISIONED)
+ strcat(s, "Provisioned, ");
+ if (!(status & DCHAN_NOTINALARM))
+ strcat(s, "In Alarm, ");
+ if (status & DCHAN_UP)
+ strcat(s, "Up");
+ else
+ strcat(s, "Down");
+ if (active)
+ strcat(s, ", Active");
+ else
+ strcat(s, ", Standby");
+}
+
static int handle_pri_show_span(int fd, int argc, char *argv[])
{
int span;
+ int x;
+ char status[256];
if (argc < 4)
return RESULT_SHOWUSAGE;
span = atoi(argv[3]);
@@ -7393,7 +7584,15 @@ static int handle_pri_show_span(int fd, int argc, char *argv[])
ast_cli(fd, "No PRI running on span %d\n", span);
return RESULT_SUCCESS;
}
- pri_dump_info(pris[span-1].pri);
+ for(x=0;x<NUM_DCHANS;x++) {
+ if (pris[span-1].dchannels[x]) {
+ ast_cli(fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
+ build_status(status, pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
+ ast_cli(fd, "Status: %s\n", status);
+ pri_dump_info(pris[span-1].pri);
+ ast_cli(fd, "\n");
+ }
+ }
return RESULT_SUCCESS;
}
@@ -7971,7 +8170,7 @@ static int __unload_module(void)
#ifdef ZAPATA_PRI
for(i=0;i<NUM_SPANS;i++) {
pthread_join(pris[i].master, NULL);
- zt_close(pris[i].fd);
+ zt_close(pris[i].fds[i]);
}
#endif
return 0;
@@ -7996,9 +8195,10 @@ static int setup_zap(void)
int cur_radio = 0;
#ifdef ZAPATA_PRI
int spanno;
+ int i;
int logicalspan;
int trunkgroup;
- int dchannel;
+ int dchannels[NUM_DCHANS];
struct zt_pri *pri;
#endif
@@ -8024,14 +8224,23 @@ static int setup_zap(void)
trunkgroup = atoi(v->value);
if (trunkgroup > 0) {
if ((c = strchr(v->value, ','))) {
- dchannel = atoi(c + 1);
- if (dchannel > 0) {
- if (pri_create_trunkgroup(trunkgroup, dchannel)) {
- ast_log(LOG_WARNING, "Unable to create trunk group %d with D-channel %d at line %d of zapata.conf\n", trunkgroup, dchannel, v->lineno);
+ i = 0;
+ memset(dchannels, 0, sizeof(dchannels));
+ while(c && (i < NUM_DCHANS)) {
+ dchannels[i] = atoi(c + 1);
+ if (dchannels[i] < 0) {
+ ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of zapata.conf\n", trunkgroup, v->lineno);
+ } else
+ i++;
+ c = strchr(c + 1, ',');
+ }
+ if (i) {
+ if (pri_create_trunkgroup(trunkgroup, dchannels)) {
+ ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of zapata.conf\n", trunkgroup, dchannels[0], v->lineno);
} else if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Created trunk group %d with D-channel %d\n", trunkgroup, dchannel);
+ ast_verbose(VERBOSE_PREFIX_2 "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
} else
- ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of zapata.conf\n", trunkgroup, v->lineno);
+ ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of zapata.conf\n", trunkgroup, v->lineno);
} else
ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of zapata.conf\n", trunkgroup, v->lineno);
} else
@@ -8572,11 +8781,12 @@ int load_module(void)
int res;
#ifdef ZAPATA_PRI
- int y;
+ int y,i;
memset(pris, 0, sizeof(pris));
for (y=0;y<NUM_SPANS;y++) {
pris[y].offset = -1;
- pris[y].fd = -1;
+ for (i=0;i<NUM_DCHANS;i++)
+ pris[y].fds[i] = -1;
}
pri_set_error(zt_pri_error);
pri_set_message(zt_pri_message);