Initial, incomplete support for D-channel backup
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@3163 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
562f2c1805
commit
38acf295cc
|
@ -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));
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
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 (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;
|
||||
}
|
||||
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);
|
||||
|
|
Reference in New Issue