mer feb 12 14:56:57 CET 2003

git-svn-id: https://origsvn.digium.com/svn/libpri/trunk@29 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Matteo Brancaleoni 2003-02-12 13:59:23 +00:00
parent 64f6535c65
commit c0ce1c85ed
9 changed files with 552 additions and 196 deletions

View File

@ -60,6 +60,8 @@
#define PRI_EVENT_ANSWER 8 /* Call has been answered */ #define PRI_EVENT_ANSWER 8 /* Call has been answered */
#define PRI_EVENT_HANGUP_ACK 9 /* Call hangup has been acknowledged */ #define PRI_EVENT_HANGUP_ACK 9 /* Call hangup has been acknowledged */
#define PRI_EVENT_RESTART_ACK 10 /* Restart complete on a given channel */ #define PRI_EVENT_RESTART_ACK 10 /* Restart complete on a given channel */
#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility */
#define PRI_EVENT_INFO_RECEIVED 12 /* Additional info (keypad) received */
/* Simple states */ /* Simple states */
#define PRI_STATE_DOWN 0 #define PRI_STATE_DOWN 0
@ -205,14 +207,26 @@ typedef struct pri_event_answer {
q931_call *call; q931_call *call;
} pri_event_answer; } pri_event_answer;
typedef struct pri_event_facname {
int e;
char callingname[256];
char callingnum[256];
int channel;
int cref;
q931_call *call;
} pri_event_facname;
typedef struct pri_event_ring { typedef struct pri_event_ring {
int e; int e;
int channel; /* Channel requested */ int channel; /* Channel requested */
int callingpres; /* Presentation of Calling CallerID */ int callingpres; /* Presentation of Calling CallerID */
int callingplan; /* Dialing plan of Calling entity */ int callingplan; /* Dialing plan of Calling entity */
char callingnum[256]; /* Calling number */ char callingnum[256]; /* Calling number */
char callingname[256]; /* Calling name (if provided) */
int calledplan; /* Dialing plan of Called number */ int calledplan; /* Dialing plan of Called number */
char callednum[256]; /* Called number */ char callednum[256]; /* Called number */
char redirectingnum[256]; /* Redirecting number */
char useruserinfo[256]; /* User->User info */
int flexible; /* Are we flexible with our channel selection? */ int flexible; /* Are we flexible with our channel selection? */
int cref; /* Call Reference Number */ int cref; /* Call Reference Number */
int ctype; /* Call type (see PRI_TRANS_CAP_* */ int ctype; /* Call type (see PRI_TRANS_CAP_* */
@ -238,6 +252,7 @@ typedef union {
pri_event_generic gen; /* Generic view */ pri_event_generic gen; /* Generic view */
pri_event_restart restart; /* Restart view */ pri_event_restart restart; /* Restart view */
pri_event_error err; /* Error view */ pri_event_error err; /* Error view */
pri_event_facname facname; /* Caller*ID Name on Facility */
pri_event_ring ring; /* Ring */ pri_event_ring ring; /* Ring */
pri_event_hangup hangup; /* Hang up */ pri_event_hangup hangup; /* Hang up */
pri_event_ringing ringing; /* Ringing */ pri_event_ringing ringing; /* Ringing */
@ -293,6 +308,10 @@ extern char *pri_cause2str(int cause);
is in-band data available on the channel */ is in-band data available on the channel */
extern int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info); extern int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info);
/* Answer the incomplete(call without called number) call on the given channel.
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
extern int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
/* Answer the call on the given channel (ignored if you called acknowledge already). /* Answer the call on the given channel (ignored if you called acknowledge already).
Set non-isdn to non-zero if you are not connecting to ISDN equipment */ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn); extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
@ -315,6 +334,10 @@ extern struct timeval *pri_schedule_next(struct pri *pri);
extern pri_event *pri_schedule_run(struct pri *pri); extern pri_event *pri_schedule_run(struct pri *pri);
extern int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, extern int pri_call(struct pri *pri, q931_call *c, int transmode, int channel,
int exclusive, int nonisdn, char *caller, int callerplan, int callerpres, int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
char *called,int calledplan, int ulayer1); char *called,int calledplan, int ulayer1);
/* Override message and error stuff */
extern void pri_set_message(void (*__pri_error)(char *));
extern void pri_set_error(void (*__pri_error)(char *));
#endif #endif

73
pri.c
View File

@ -18,6 +18,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/select.h> #include <sys/select.h>
#include <stdarg.h>
#include "libpri.h" #include "libpri.h"
#include "pri_internal.h" #include "pri_internal.h"
#include "pri_q921.h" #include "pri_q921.h"
@ -64,7 +65,7 @@ struct pri *pri_new(int fd, int node, int switchtype)
p->switchtype = switchtype; p->switchtype = switchtype;
p->cref = 1; p->cref = 1;
/* Start Q.921 layer */ /* Start Q.921 layer */
q921_start(p); q921_start(p, 1);
} }
return p; return p;
} }
@ -95,9 +96,11 @@ pri_event *pri_check_event(struct pri *pri)
res = read(pri->fd, buf, sizeof(buf)); res = read(pri->fd, buf, sizeof(buf));
if (res < 0) { if (res < 0) {
if (errno != EAGAIN) if (errno != EAGAIN)
fprintf(stderr, "Read on %d failed: %s\n", pri->fd, strerror(errno)); pri_error("Read on %d failed: %s\n", pri->fd, strerror(errno));
return NULL; return NULL;
} }
if (!res)
return NULL;
/* Receive the q921 packet */ /* Receive the q921 packet */
e = q921_receive(pri, (q921_h *)buf, res); e = q921_receive(pri, (q921_h *)buf, res);
return e; return e;
@ -178,6 +181,13 @@ int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info)
return q931_alerting(pri, call, channel, info); return q931_alerting(pri, call, channel, info);
} }
int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn)
{
if (!pri || !call)
return -1;
return q931_setup_ack(pri, call, channel, nonisdn);
}
int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn) int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn)
{ {
if (!pri || !call) if (!pri || !call)
@ -217,34 +227,73 @@ void pri_dump_event(struct pri *pri, pri_event *e)
{ {
if (!pri || !e) if (!pri || !e)
return; return;
printf("Event type: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e); pri_message("Event type: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
switch(e->gen.e) { switch(e->gen.e) {
case PRI_EVENT_DCHAN_UP: case PRI_EVENT_DCHAN_UP:
case PRI_EVENT_DCHAN_DOWN: case PRI_EVENT_DCHAN_DOWN:
break; break;
case PRI_EVENT_CONFIG_ERR: case PRI_EVENT_CONFIG_ERR:
printf("Error: %s", e->err.err); pri_message("Error: %s", e->err.err);
break; break;
case PRI_EVENT_RESTART: case PRI_EVENT_RESTART:
printf("Restart on channel %d\n", e->restart.channel); pri_message("Restart on channel %d\n", e->restart.channel);
case PRI_EVENT_RING: case PRI_EVENT_RING:
printf("Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres)); pri_message("Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres));
printf("Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan)); pri_message("Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan));
printf("Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref); pri_message("Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref);
break; break;
case PRI_EVENT_HANGUP: case PRI_EVENT_HANGUP:
printf("Hangup, reference number: %d, reason: %s\n", e->hangup.cref, pri_cause2str(e->hangup.cause)); pri_message("Hangup, reference number: %d, reason: %s\n", e->hangup.cref, pri_cause2str(e->hangup.cause));
break; break;
default: default:
printf("Don't know how to dump events of type %d\n", e->gen.e); pri_message("Don't know how to dump events of type %d\n", e->gen.e);
} }
} }
int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
int nonisdn, char *caller, int callerplan, int callerpres, char *called, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called,
int calledplan,int ulayer1) int calledplan,int ulayer1)
{ {
if (!pri || !c) if (!pri || !c)
return -1; return -1;
return q931_setup(pri, c, transmode, channel, exclusive, nonisdn, caller, callerplan, callerpres, called, calledplan, ulayer1); return q931_setup(pri, c, transmode, channel, exclusive, nonisdn, caller, callerplan, callername, callerpres, called, calledplan, ulayer1);
}
static void (*__pri_error)(char *stuff);
static void (*__pri_message)(char *stuff);
void pri_set_message(void (*func)(char *stuff))
{
__pri_message = func;
}
void pri_set_error(void (*func)(char *stuff))
{
__pri_error = func;
}
void pri_message(char *fmt, ...)
{
char tmp[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
if (__pri_message)
__pri_message(tmp);
else
fprintf(stdout, tmp);
}
void pri_error(char *fmt, ...)
{
char tmp[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
if (__pri_error)
__pri_error(tmp);
else
fprintf(stderr, tmp);
} }

View File

@ -88,4 +88,8 @@ extern void pri_schedule_del(struct pri *pri, int ev);
extern pri_event *pri_mkerror(struct pri *pri, char *errstr); extern pri_event *pri_mkerror(struct pri *pri, char *errstr);
extern void pri_message(char *fmt, ...);
extern void pri_error(char *fmt, ...);
#endif #endif

View File

@ -137,7 +137,7 @@ typedef struct q921_frame {
q921_i h; q921_i h;
} q921_frame; } q921_frame;
#define Q921_INC(j) (j) = ((j) + 1) % 128 #define Q921_INC(j) (j) = (((j) + 1) % 128)
typedef enum q921_state { typedef enum q921_state {
Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */ Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */
@ -150,7 +150,7 @@ typedef enum q921_state {
extern void q921_dump(q921_h *h, int len, int showraw, int txrx); extern void q921_dump(q921_h *h, int len, int showraw, int txrx);
/* Bring up the D-channel */ /* Bring up the D-channel */
extern void q921_start(struct pri *pri); extern void q921_start(struct pri *pri, int now);
extern void q921_reset(struct pri *pri); extern void q921_reset(struct pri *pri);

View File

@ -190,6 +190,7 @@ typedef struct q931_ie {
#define Q931_LOW_LAYER_COMPAT 0x7c #define Q931_LOW_LAYER_COMPAT 0x7c
#define Q931_HIGH_LAYER_COMPAT 0x7d #define Q931_HIGH_LAYER_COMPAT 0x7d
#define Q931_DISPLAY 0x28
#define Q931_IE_SEGMENTED_MSG 0x00 #define Q931_IE_SEGMENTED_MSG 0x00
#define Q931_IE_CHANGE_STATUS 0x01 #define Q931_IE_CHANGE_STATUS 0x01
#define Q931_IE_CONNECTED_NUM 0x0C #define Q931_IE_CONNECTED_NUM 0x0C
@ -197,7 +198,6 @@ typedef struct q931_ie {
#define Q931_IE_FACILITY 0x1c #define Q931_IE_FACILITY 0x1c
#define Q931_IE_ENDPOINT_ID 0x26 #define Q931_IE_ENDPOINT_ID 0x26
#define Q931_IE_NOTIFY_IND 0x27 #define Q931_IE_NOTIFY_IND 0x27
#define Q931_IE_DISPLAY 0x28
#define Q931_IE_TIME_DATE 0x29 #define Q931_IE_TIME_DATE 0x29
#define Q931_IE_KEYPAD_FACILITY 0x2c #define Q931_IE_KEYPAD_FACILITY 0x2c
#define Q931_IE_CALL_STATUS 0x2d #define Q931_IE_CALL_STATUS 0x2d
@ -223,6 +223,8 @@ extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info
extern int q931_call_proceeding(struct pri *pri, q931_call *call); extern int q931_call_proceeding(struct pri *pri, q931_call *call);
extern int q931_setup_ack(struct pri *pri, q931_call *call, int channel, int nonisdn);
extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn); extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
extern int q931_release(struct pri *pri, q931_call *call, int cause); extern int q931_release(struct pri *pri, q931_call *call, int cause);
@ -234,7 +236,7 @@ extern int q931_restart(struct pri *pri, int channel);
extern q931_call *q931_new_call(struct pri *pri); extern q931_call *q931_new_call(struct pri *pri);
extern int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, extern int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
int nonisdn, char *caller, int callerplan, int callerpres, char *called, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called,
int calledplan, int ulay1); int calledplan, int ulay1);
extern void q931_dump(q931_h *h, int len, int txrx); extern void q931_dump(q931_h *h, int len, int txrx);
#endif #endif

View File

@ -38,7 +38,7 @@ int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), vo
if (!pri->pri_sched[x].callback) if (!pri->pri_sched[x].callback)
break; break;
if (x == MAX_SCHED) { if (x == MAX_SCHED) {
fprintf(stderr, "No more room in scheduler\n"); pri_error("No more room in scheduler\n");
return -1; return -1;
} }
if (x > maxsched) if (x > maxsched)
@ -98,6 +98,6 @@ pri_event *pri_schedule_run(struct pri *pri)
void pri_schedule_del(struct pri *pri,int id) void pri_schedule_del(struct pri *pri,int id)
{ {
if ((id >= MAX_SCHED) || (id < 0)) if ((id >= MAX_SCHED) || (id < 0))
fprintf(stderr, "Asked to delete sched id %d???\n", id); pri_error("Asked to delete sched id %d???\n", id);
pri->pri_sched[id].callback = NULL; pri->pri_sched[id].callback = NULL;
} }

View File

@ -48,6 +48,8 @@
#define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2 #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2
#define MAX_CHAN 32 #define MAX_CHAN 32
#define DCHANNEL_TIMESLOT 16
static int offset = 0; static int offset = 0;
@ -162,10 +164,50 @@ static void launch_channel(int channo)
} }
static int get_free_channel(int channo)
{
channo--;
if((channo>MAX_CHAN)||(channo<0)) {
fprintf(stderr, "Invalid Bchannel RANGE <%d", channo);
return 0;
};
while(chans[channo].pid) {
channo--;
}
return channo;
}
/* place here criteria for completion of destination number */
static int number_incommplete(char *number)
{
return strlen(number) < 3;
}
static void start_channel(struct pri *pri, pri_event *e) static void start_channel(struct pri *pri, pri_event *e)
{ {
int channo = e->ring.channel; int channo = e->ring.channel;
int flag = 1;
pri_event_ring *ring = &e->ring;
if(channo == -1) {
channo = e->ring.channel = get_free_channel(MAX_CHAN);
if(channo == DCHANNEL_TIMESLOT)
channo = e->ring.channel = get_free_channel(MAX_CHAN);
fprintf(stdout, "Any channel selected: %d\n", channo);
if(!channo) {
pri_release(pri, ring->call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
fprintf(stdout, "Abort call due to no avl B channels\n");
return;
}
flag = 0;
}
/* Make sure it's a valid number */ /* Make sure it's a valid number */
if ((channo >= MAX_CHAN) || (channo < 0)) { if ((channo >= MAX_CHAN) || (channo < 0)) {
fprintf(stderr, "--!! Channel %d is out of range\n", channo); fprintf(stderr, "--!! Channel %d is out of range\n", channo);
@ -185,7 +227,11 @@ static void start_channel(struct pri *pri, pri_event *e)
chans[channo].call = e->ring.call; chans[channo].call = e->ring.call;
/* Answer the line */ /* Answer the line */
if(flag) {
pri_answer(pri, chans[channo].call, channo, 1); pri_answer(pri, chans[channo].call, channo, 1);
} else {
pri_need_more_info(pri, chans[channo].call, channo, 1);
}
/* Launch a process to handle it */ /* Launch a process to handle it */
launch_channel(channo); launch_channel(channo);
@ -222,6 +268,14 @@ static void handle_pri_event(struct pri *pri, pri_event *e)
break; break;
case PRI_EVENT_HANGUP_ACK: case PRI_EVENT_HANGUP_ACK:
/* Ignore */ /* Ignore */
break;
case PRI_EVENT_INFO_RECEIVED:
fprintf(stdout, "number is: %s\n", e->ring.callednum);
if(!number_incommplete(e->ring.callednum)) {
fprintf(stdout, "final number is: %s\n", e->ring.callednum);
pri_answer(pri, e->ring.call, 0, 1);
}
break; break;
default: default:
fprintf(stderr, "--!! Unknown PRI event %d\n", e->e); fprintf(stderr, "--!! Unknown PRI event %d\n", e->e);

179
q921.c
View File

@ -42,6 +42,7 @@
*/ */
#define Q921_INIT(hf) do { \ #define Q921_INIT(hf) do { \
memset(&(hf),0,sizeof(hf)); \
(hf).h.sapi = 0; \ (hf).h.sapi = 0; \
(hf).h.ea1 = 0; \ (hf).h.ea1 = 0; \
(hf).h.ea2 = 1; \ (hf).h.ea2 = 1; \
@ -65,7 +66,7 @@ static int q921_transmit(struct pri *pri, q921_h *h, int len) {
int res; int res;
#ifdef RANDOM_DROPS #ifdef RANDOM_DROPS
if (!(random() % 3)) { if (!(random() % 3)) {
printf(" === Dropping Packet ===\n"); pri_message(" === Dropping Packet ===\n");
return 0; return 0;
} }
#endif #endif
@ -76,7 +77,7 @@ static int q921_transmit(struct pri *pri, q921_h *h, int len) {
/* Write an extra two bytes for the FCS */ /* Write an extra two bytes for the FCS */
res = write(pri->fd, h, len + 2); res = write(pri->fd, h, len + 2);
if (res != (len + 2)) { if (res != (len + 2)) {
fprintf(stderr, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno)); pri_error("Short write: %d/%d (%s)\n", res, len + 2, strerror(errno));
return -1; return -1;
} }
return 0; return 0;
@ -98,21 +99,25 @@ static void q921_send_ua(struct pri *pri, int pfbit)
h.h.c_r = 1; h.h.c_r = 1;
break; break;
default: default:
fprintf(stderr, "Don't know how to U/A on a type %d node\n", pri->localtype); pri_error("Don't know how to U/A on a type %d node\n", pri->localtype);
return; return;
} }
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Sending Unnumbered Acknowledgement\n"); pri_message("Sending Unnumbered Acknowledgement\n");
q921_transmit(pri, &h, 3); q921_transmit(pri, &h, 3);
} }
static void q921_send_sabme(void *vpri) static void q921_send_sabme_now(void *vpri);
static void q921_send_sabme(void *vpri, int now)
{ {
struct pri *pri = vpri; struct pri *pri = vpri;
q921_h h; q921_h h;
pri_schedule_del(pri, pri->sabme_timer); pri_schedule_del(pri, pri->sabme_timer);
pri->sabme_timer = 0; pri->sabme_timer = 0;
pri->sabme_timer = pri_schedule_event(pri, T_200, q921_send_sabme, pri); pri->sabme_timer = pri_schedule_event(pri, T_200, q921_send_sabme_now, pri);
if (!now)
return;
Q921_INIT(h); Q921_INIT(h);
h.u.m3 = 3; /* M3 = 3 */ h.u.m3 = 3; /* M3 = 3 */
h.u.m2 = 3; /* M2 = 3 */ h.u.m2 = 3; /* M2 = 3 */
@ -126,31 +131,42 @@ static void q921_send_sabme(void *vpri)
h.h.c_r = 0; h.h.c_r = 0;
break; break;
default: default:
fprintf(stderr, "Don't know how to U/A on a type %d node\n", pri->localtype); pri_error("Don't know how to U/A on a type %d node\n", pri->localtype);
return; return;
} }
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Sending Set Asynchronous Balanced Mode Extended\n"); pri_message("Sending Set Asynchronous Balanced Mode Extended\n");
q921_transmit(pri, &h, 3); q921_transmit(pri, &h, 3);
pri->q921_state = Q921_AWAITING_ESTABLISH; pri->q921_state = Q921_AWAITING_ESTABLISH;
} }
static void q921_send_sabme_now(void *vpri)
{
q921_send_sabme(vpri, 1);
}
static int q921_ack_packet(struct pri *pri, int num) static int q921_ack_packet(struct pri *pri, int num)
{ {
struct q921_frame *f, *prev = NULL; struct q921_frame *f, *prev = NULL;
f = pri->txqueue; f = pri->txqueue;
while(f) { while(f) {
if (f->h.n_s == num) { if (f->h.n_s == num) {
/* Cancel each packet as necessary */
/* That's our packet */ /* That's our packet */
if (prev) if (prev)
prev->next = f->next; prev->next = f->next;
else else
pri->txqueue = f->next; pri->txqueue = f->next;
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1);
/* Update v_a */
pri->v_a = num;
free(f); free(f);
/* Reset retransmission counter if we actually acked something */ /* Reset retransmission counter if we actually acked something */
pri->retrans = 0; pri->retrans = 0;
return 1; return 1;
} }
prev = f;
f = f->next; f = f->next;
} }
return 0; return 0;
@ -167,34 +183,36 @@ static void q921_ack_rx(struct pri *pri, int ack)
for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x)); for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x));
if (x != ack) { if (x != ack) {
/* ACK was outside of our window --- ignore */ /* ACK was outside of our window --- ignore */
fprintf(stderr, "ACK received outside of window, ignoring\n"); pri_error("ACK received outside of window, ignoring\n");
return; return;
} }
/* Cancel each packet as necessary */ /* Cancel each packet as necessary */
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, ack);
for (x=pri->v_a; x != ack; Q921_INC(x)) for (x=pri->v_a; x != ack; Q921_INC(x))
cnt += q921_ack_packet(pri, x); cnt += q921_ack_packet(pri, x);
if (!pri->txqueue) { if (!pri->txqueue) {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Since there was nothing left, stopping T200 counter\n"); pri_message("-- Since there was nothing left, stopping T200 counter\n");
/* Something was ACK'd. Stop T200 counter */ /* Something was ACK'd. Stop T200 counter */
pri_schedule_del(pri, pri->t200_timer); pri_schedule_del(pri, pri->t200_timer);
pri->t200_timer = 0; pri->t200_timer = 0;
} }
if (pri->t203_timer) { if (pri->t203_timer) {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Stopping T203 counter since we got an ACK\n"); pri_message("-- Stopping T203 counter since we got an ACK\n");
pri_schedule_del(pri, pri->t203_timer); pri_schedule_del(pri, pri->t203_timer);
pri->t203_timer = 0; pri->t203_timer = 0;
} }
if (pri->txqueue) { if (pri->txqueue) {
/* Something left to transmit, Start the T200 counter again if we stopped it */ /* Something left to transmit, Start the T200 counter again if we stopped it */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Something left to transmit, restarting T200 counter\n"); pri_message("-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue->h.n_s);
if (!pri->t200_timer) if (!pri->t200_timer)
pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri); pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri);
} else { } else {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Nothing left, starting T203 counter\n"); pri_message("-- Nothing left, starting T203 counter\n");
/* Nothing to transmit, start the T203 counter instead */ /* Nothing to transmit, start the T203 counter instead */
pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri); pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri);
} }
@ -217,11 +235,11 @@ static void q921_reject(struct pri *pri)
h.h.c_r = 1; h.h.c_r = 1;
break; break;
default: default:
fprintf(stderr, "Don't know how to U/A on a type %d node\n", pri->localtype); pri_error("Don't know how to U/A on a type %d node\n", pri->localtype);
return; return;
} }
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Sending Reject (%d)\n", pri->v_r); pri_message("Sending Reject (%d)\n", pri->v_r);
q921_transmit(pri, &h, 4); q921_transmit(pri, &h, 4);
} }
@ -241,12 +259,12 @@ static void q921_rr(struct pri *pri, int pbit) {
h.h.c_r = 1; h.h.c_r = 1;
break; break;
default: default:
fprintf(stderr, "Don't know how to U/A on a type %d node\n", pri->localtype); pri_error("Don't know how to U/A on a type %d node\n", pri->localtype);
return; return;
} }
pri->v_na = pri->v_r; /* Make a note that we've already acked this */ pri->v_na = pri->v_r; /* Make a note that we've already acked this */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Sending Receiver Ready (%d)\n", pri->v_r); pri_message("Sending Receiver Ready (%d)\n", pri->v_r);
q921_transmit(pri, &h, 4); q921_transmit(pri, &h, 4);
} }
@ -258,7 +276,7 @@ static void t200_expire(void *vpri)
if (pri->txqueue) { if (pri->txqueue) {
/* Retransmit first packet in the queue, setting the poll bit */ /* Retransmit first packet in the queue, setting the poll bit */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- T200 counter expired, What to do...\n"); pri_message("-- T200 counter expired, What to do...\n");
/* Force Poll bit */ /* Force Poll bit */
pri->txqueue->h.p_f = 1; pri->txqueue->h.p_f = 1;
/* Update nr */ /* Update nr */
@ -270,22 +288,22 @@ static void t200_expire(void *vpri)
if (pri->retrans < N_200) { if (pri->retrans < N_200) {
/* Reschedule t200_timer */ /* Reschedule t200_timer */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Retransmitting %d bytes\n", pri->txqueue->len); pri_message("-- Retransmitting %d bytes\n", pri->txqueue->len);
q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len); q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Rescheduling retransmission (%d)\n", pri->retrans); pri_message("-- Rescheduling retransmission (%d)\n", pri->retrans);
pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri); pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri);
} else { } else {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Timeout occured, restarting PRI\n"); pri_message("-- Timeout occured, restarting PRI\n");
pri->state = Q921_LINK_CONNECTION_RELEASED; pri->state = Q921_LINK_CONNECTION_RELEASED;
pri->t200_timer = 0; pri->t200_timer = 0;
q921_dchannel_down(pri); q921_dchannel_down(pri);
q921_start(pri); q921_start(pri, 1);
pri->schedev = 1; pri->schedev = 1;
} }
} else { } else {
fprintf(stderr, "T200 counter expired, nothing to send...\n"); pri_error("T200 counter expired, nothing to send...\n");
pri->t200_timer = 0; pri->t200_timer = 0;
} }
} }
@ -295,6 +313,7 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
q921_frame *f, *prev=NULL; q921_frame *f, *prev=NULL;
for (f=pri->txqueue; f; f = f->next) prev = f; for (f=pri->txqueue; f; f = f->next) prev = f;
f = malloc(sizeof(q921_frame) + len + 2); f = malloc(sizeof(q921_frame) + len + 2);
memset(f,0,sizeof(q921_frame) + len + 2);
if (f) { if (f) {
Q921_INIT(f->h); Q921_INIT(f->h);
switch(pri->localtype) { switch(pri->localtype) {
@ -329,20 +348,20 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
q921_transmit(pri, (q921_h *)(&f->h), f->len); q921_transmit(pri, (q921_h *)(&f->h), f->len);
if (pri->t203_timer) { if (pri->t203_timer) {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Stopping T_203 timer\n"); pri_message("Stopping T_203 timer\n");
pri_schedule_del(pri, pri->t203_timer); pri_schedule_del(pri, pri->t203_timer);
pri->t203_timer = 0; pri->t203_timer = 0;
} }
if (!pri->t200_timer) { if (!pri->t200_timer) {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("Starting T_200 timer\n"); pri_message("Starting T_200 timer\n");
pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri); pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri);
} else } else
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("T_200 timer already going (%d)\n", pri->t200_timer); pri_message("T_200 timer already going (%d)\n", pri->t200_timer);
} else { } else {
fprintf(stderr, "!! Out of memory for Q.921 transmit\n"); pri_error("!! Out of memory for Q.921 transmit\n");
return -1; return -1;
} }
return 0; return 0;
@ -352,7 +371,7 @@ static void t203_expire(void *vpri)
{ {
struct pri *pri = vpri; struct pri *pri = vpri;
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("T203 counter expired, sending RR and scheduling T203 again\n"); pri_message("T203 counter expired, sending RR and scheduling T203 again\n");
/* Solicit an F-bit in the other's RR */ /* Solicit an F-bit in the other's RR */
pri->solicitfbit = 1; pri->solicitfbit = 1;
q921_rr(pri, 1); q921_rr(pri, 1);
@ -404,26 +423,26 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx)
direction_tag = txrx ? '>' : '<'; direction_tag = txrx ? '>' : '<';
if (showraw) { if (showraw) {
printf("\n%c [", direction_tag); pri_message("\n%c [", direction_tag);
for (x=0;x<len;x++) for (x=0;x<len;x++)
printf("%02x ",h->raw[x]); pri_message("%02x ",h->raw[x]);
printf("]"); pri_message("]");
} }
switch (h->h.data[0] & Q921_FRAMETYPE_MASK) { switch (h->h.data[0] & Q921_FRAMETYPE_MASK) {
case 0: case 0:
case 2: case 2:
printf("\n%c Informational frame:\n", direction_tag); pri_message("\n%c Informational frame:\n", direction_tag);
break; break;
case 1: case 1:
printf("\n%c Supervisory frame:\n", direction_tag); pri_message("\n%c Supervisory frame:\n", direction_tag);
break; break;
case 3: case 3:
printf("\n%c Unnumbered frame:\n", direction_tag); pri_message("\n%c Unnumbered frame:\n", direction_tag);
break; break;
} }
printf( pri_message(
"%c SAPI: %02d C/R: %d EA: %d\n" "%c SAPI: %02d C/R: %d EA: %d\n"
"%c TEI: %03d EA: %d\n", "%c TEI: %03d EA: %d\n",
direction_tag, direction_tag,
@ -437,7 +456,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx)
case 0: case 0:
case 2: case 2:
/* Informational frame */ /* Informational frame */
printf( pri_message(
"%c N(S): %03d 0: %d\n" "%c N(S): %03d 0: %d\n"
"%c N(R): %03d P: %d\n" "%c N(R): %03d P: %d\n"
"%c %d bytes of data\n", "%c %d bytes of data\n",
@ -464,7 +483,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx)
type = "REJ (reject)"; type = "REJ (reject)";
break; break;
} }
printf( pri_message(
"%c Zero: %d S: %d 01: %d [ %s ]\n" "%c Zero: %d S: %d 01: %d [ %s ]\n"
"%c N(R): %03d P/F: %d\n" "%c N(R): %03d P/F: %d\n"
"%c %d bytes of data\n", "%c %d bytes of data\n",
@ -510,7 +529,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx)
break; break;
} }
} }
printf( pri_message(
"%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n" "%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n"
"%c %d bytes of data\n", "%c %d bytes of data\n",
direction_tag, direction_tag,
@ -580,6 +599,7 @@ void q921_reset(struct pri *pri)
pri_event *q921_receive(struct pri *pri, q921_h *h, int len) pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
{ {
q921_frame *f; q921_frame *f;
int sendnow;
/* Discard FCS */ /* Discard FCS */
len -= 2; len -= 2;
@ -602,23 +622,23 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
case 0: case 0:
case 2: case 2:
if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
fprintf(stderr, "!! Got I-frame while link state %d\n", pri->q921_state); pri_error("!! Got I-frame while link state %d\n", pri->q921_state);
return NULL; return NULL;
} }
/* Informational frame */ /* Informational frame */
if (len < 4) { if (len < 4) {
fprintf(stderr, "!! Received short I-frame\n"); pri_error("!! Received short I-frame (expected 4, got %d)\n", len);
break; break;
} }
return q921_handle_iframe(pri, &h->i, len); return q921_handle_iframe(pri, &h->i, len);
break; break;
case 1: case 1:
if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
fprintf(stderr, "!! Got S-frame while link down\n"); pri_error("!! Got S-frame while link down\n");
return NULL; return NULL;
} }
if (len < 4) { if (len < 4) {
fprintf(stderr, "!! Received short S-frame\n"); pri_error("!! Received short S-frame (expected 4, got %d)\n", len);
break; break;
} }
switch(h->s.ss) { switch(h->s.ss) {
@ -631,10 +651,10 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
/* If it's a p/f one then send back a RR in return with the p/f bit set */ /* If it's a p/f one then send back a RR in return with the p/f bit set */
if (pri->solicitfbit) { if (pri->solicitfbit) {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Got RR response to our frame\n"); pri_message("-- Got RR response to our frame\n");
} else { } else {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Unsolicited RR with P/F bit, responding\n"); pri_message("-- Unsolicited RR with P/F bit, responding\n");
q921_rr(pri, 1); q921_rr(pri, 1);
} }
pri->solicitfbit = 0; pri->solicitfbit = 0;
@ -644,36 +664,38 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
case 1: case 1:
/* Receiver not ready */ /* Receiver not ready */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Got receiver not ready\n"); pri_message("-- Got receiver not ready\n");
pri->busy = 1; pri->busy = 1;
break; break;
#endif #endif
case 2: case 2:
/* Just retransmit */ /* Just retransmit */
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r); pri_message("-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r);
if (h->s.p_f) { if (h->s.p_f) {
/* If it has the poll bit set, send an appropriate supervisory response */ /* If it has the poll bit set, send an appropriate supervisory response */
q921_rr(pri, 1); q921_rr(pri, 1);
} }
sendnow = 0;
/* Resend the proper I-frame */ /* Resend the proper I-frame */
for(f=pri->txqueue;f;f=f->next) { for(f=pri->txqueue;f;f=f->next) {
if (f->h.n_s == h->s.n_r) { if (sendnow || (f->h.n_s == h->s.n_r)) {
/* Matches the request */ /* Matches the request, or follows in our window */
break; sendnow = 1;
} pri_error("!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
} f->h.n_r = pri->v_r;
if (f) {
/* Retransmit the requested frame */
q921_transmit(pri, (q921_h *)(&f->h), f->len); q921_transmit(pri, (q921_h *)(&f->h), f->len);
} else { }
}
if (!sendnow) {
if (pri->txqueue) { if (pri->txqueue) {
/* This should never happen */ /* This should never happen */
if (!h->s.p_f || h->s.n_r) { if (!h->s.p_f || h->s.n_r) {
fprintf(stderr, "!! Got reject for frame %d, but we only have others!\n", h->s.n_r); pri_error("!! Got reject for frame %d, but we only have others!\n", h->s.n_r);
} }
} else { } else {
/* Hrm, we have nothing to send, but have been REJ'd. Reset v_a, v_s, etc */ /* Hrm, we have nothing to send, but have been REJ'd. Reset v_a, v_s, etc */
pri_error("!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r);
pri->v_a = h->s.n_r; pri->v_a = h->s.n_r;
pri->v_s = h->s.n_r; pri->v_s = h->s.n_r;
/* Reset t200 timer if it was somehow going */ /* Reset t200 timer if it was somehow going */
@ -689,38 +711,45 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
} }
break; break;
default: default:
fprintf(stderr, "!! XXX Unknown Supervisory frame ss=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", h->s.ss, h->s.p_f, h->s.n_r, pri_error("!! XXX Unknown Supervisory frame ss=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", h->s.ss, h->s.p_f, h->s.n_r,
pri->v_s, pri->v_a); pri->v_s, pri->v_a);
} }
break; break;
case 3: case 3:
if (len < 3) { if (len < 3) {
fprintf(stderr, "!! Received short unnumbered frame\n"); pri_error("!! Received short unnumbered frame\n");
break; break;
} }
switch(h->u.m3) { switch(h->u.m3) {
case 0: case 0:
if (h->u.m2 == 3) { if (h->u.m2 == 3) {
if (h->u.p_f) { if (h->u.p_f) {
/* Section 5.7.1 says we should restart on receiving a DM response with the f-bit set to
one, but we wait T200 first */
pri_event *ev = NULL;
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Got Unconnected Mode from peer.\n"); pri_message("-- Got DM Mode from peer.\n");
/* Disconnected mode */ /* Disconnected mode, try again after T200 */
if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) ev = q921_dchannel_down(pri);
return q921_dchannel_down(pri); q921_start(pri, 0);
return ev;
} else { } else {
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- DM requesting SABME, starting.\n"); pri_message("-- Ignoring unsolicited DM with p/f set to 0\n");
#if 0
/* Requesting that we start */ /* Requesting that we start */
q921_start(pri); q921_start(pri, 0);
#endif
} }
break; break;
} else if (!h->u.m2) { } else if (!h->u.m2) {
printf("XXX Unnumbered Information not implemented XXX\n"); pri_message("XXX Unnumbered Information not implemented XXX\n");
} }
break; break;
case 2: case 2:
if (pri->debug & PRI_DEBUG_Q921_STATE) if (pri->debug & PRI_DEBUG_Q921_STATE)
printf("-- Got Disconnect from peer.\n"); pri_message("-- Got Disconnect from peer.\n");
/* Acknowledge */ /* Acknowledge */
q921_send_ua(pri, h->u.p_f); q921_send_ua(pri, h->u.p_f);
return q921_dchannel_down(pri); return q921_dchannel_down(pri);
@ -728,7 +757,7 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
if (h->u.m2 == 3) { if (h->u.m2 == 3) {
/* SABME */ /* SABME */
if (pri->debug & PRI_DEBUG_Q921_STATE) { if (pri->debug & PRI_DEBUG_Q921_STATE) {
printf("-- Got SABME from %s peer.\n", h->h.c_r ? "network" : "cpe"); pri_message("-- Got SABME from %s peer.\n", h->h.c_r ? "network" : "cpe");
} }
if (h->h.c_r) { if (h->h.c_r) {
pri->remotetype = PRI_NETWORK; pri->remotetype = PRI_NETWORK;
@ -750,22 +779,22 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
/* It's a UA */ /* It's a UA */
if (pri->q921_state == Q921_AWAITING_ESTABLISH) { if (pri->q921_state == Q921_AWAITING_ESTABLISH) {
if (pri->debug & PRI_DEBUG_Q921_STATE) { if (pri->debug & PRI_DEBUG_Q921_STATE) {
printf("-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network"); pri_message("-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network");
} }
return q921_dchannel_up(pri); return q921_dchannel_up(pri);
} else } else
fprintf(stderr, "!! Got a UA, but i'm in state %d\n", pri->q921_state); pri_error("!! Got a UA, but i'm in state %d\n", pri->q921_state);
} else } else
fprintf(stderr, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); pri_error("!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2);
break; break;
case 4: case 4:
fprintf(stderr, "!! Frame got rejected!\n"); pri_error("!! Frame got rejected!\n");
break; break;
case 5: case 5:
fprintf(stderr, "!! XID frames not supported\n"); pri_error("!! XID frames not supported\n");
break; break;
default: default:
fprintf(stderr, "!! Don't know what to do with M3=%d u-frames\n", h->u.m3); pri_error("!! Don't know what to do with M3=%d u-frames\n", h->u.m3);
} }
break; break;
@ -773,14 +802,14 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
return NULL; return NULL;
} }
void q921_start(struct pri *pri) void q921_start(struct pri *pri, int now)
{ {
if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) { if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
fprintf(stderr, "!! q921_start: Not in 'Link Connection Released' state\n"); pri_error("!! q921_start: Not in 'Link Connection Released' state\n");
return; return;
} }
/* Reset our interface */ /* Reset our interface */
q921_reset(pri); q921_reset(pri);
/* Do the SABME XXX Maybe we should implement T_WAIT? XXX */ /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
q921_send_sabme(pri); q921_send_sabme(pri, now);
} }

381
q931.c
View File

@ -61,7 +61,7 @@ struct msgtype msgs[] = {
{ Q931_SEGMENT, "SEGMENT" }, { Q931_SEGMENT, "SEGMENT" },
{ Q931_CONGESTION_CONTROL, "CONGESTION CONTROL" }, { Q931_CONGESTION_CONTROL, "CONGESTION CONTROL" },
{ Q931_INFORMATION, "INFORMATION" }, { Q931_INFORMATION, "INFORMATION" },
{ Q931_FACILITY, "FACLITY" }, { Q931_FACILITY, "FACILITY" },
{ Q931_NOTIFY, "NOTIFY" }, { Q931_NOTIFY, "NOTIFY" },
/* Call Management */ /* Call Management */
@ -193,6 +193,7 @@ struct q931_call {
int chanflags; int chanflags;
int alive; /* Whether or not the call is alive */ int alive; /* Whether or not the call is alive */
int acked; /* Whether setup has been acked or not */
int sendhangupack; /* Whether or not to send a hangup ack */ int sendhangupack; /* Whether or not to send a hangup ack */
int proc; /* Whether we've sent a call proceeding / alerting */ int proc; /* Whether we've sent a call proceeding / alerting */
@ -222,10 +223,19 @@ struct q931_call {
int callerplan; int callerplan;
int callerpres; /* Caller presentation */ int callerpres; /* Caller presentation */
char callernum[256]; /* Caller */ char callernum[256]; /* Caller */
char callername[256];
int calledplan; int calledplan;
int nonisdn; int nonisdn;
char callednum[256]; /* Called Number */ char callednum[256]; /* Called Number */
int redirectingplan;
int redirectingpres;
int redirectingreason;
char redirectingnum[256];
int useruserprotocoldisc;
char useruserinfo[256];
}; };
struct ie { struct ie {
@ -278,14 +288,18 @@ static int receive_channel_id(struct pri *pri, q931_call *call, int msgtype, q93
{ {
int x; int x;
int pos=0; int pos=0;
#ifdef NO_BRI_SUPPORT
if (!ie->data[0] & 0x20) { if (!ie->data[0] & 0x20) {
fprintf(stderr, "!! Not PRI type!?\n"); pri_error("!! Not PRI type!?\n");
return -1; return -1;
} }
#endif
#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
if ((ie->data[0] & 3) != 1) { if ((ie->data[0] & 3) != 1) {
fprintf(stderr, "!! Unexpected Channel selection %d\n", ie->data[0] & 3); pri_error("!! Unexpected Channel selection %d\n", ie->data[0] & 3);
return -1; return -1;
} }
#endif
if (ie->data[0] & 0x08) if (ie->data[0] & 0x08)
call->chanflags = FLAG_EXCLUSIVE; call->chanflags = FLAG_EXCLUSIVE;
else else
@ -296,14 +310,14 @@ static int receive_channel_id(struct pri *pri, q931_call *call, int msgtype, q93
call->ds1no = ie->data[1] & 0x7f; call->ds1no = ie->data[1] & 0x7f;
pos++; pos++;
} }
if (pos < len) { if (pos+2 < len) {
/* More coming */ /* More coming */
if ((ie->data[pos] & 0x0f) != 3) { if ((ie->data[pos] & 0x0f) != 3) {
fprintf(stderr, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f); pri_error("!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f);
return -1; return -1;
} }
if ((ie->data[pos] & 0x60) != 0) { if ((ie->data[pos] & 0x60) != 0) {
fprintf(stderr, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5); pri_error("!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5);
return -1; return -1;
} }
if (ie->data[pos] & 0x10) { if (ie->data[pos] & 0x10) {
@ -367,7 +381,7 @@ static int transmit_channel_id(struct pri *pri, q931_call *call, int msgtype, q9
/* We're done */ /* We're done */
return pos + 2; return pos + 2;
} }
fprintf(stderr, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n"); pri_error("!! No channel map, no channel, and no ds1? What am I supposed to identify?\n");
return -1; return -1;
} }
@ -376,30 +390,36 @@ static void dump_channel_id(q931_ie *ie, int len, char prefix)
int pos=0; int pos=0;
int x; int x;
int res = 0; int res = 0;
printf("%c Channel ID (len=%2d) [ Ext: %d IntID: %s, %s Spare: %d, %s Dchan: %d, ChanSel: %d \n", static const char* msg_chan_sel[] = {
"No channel selected", "B1 channel", "B2 channel","Any channel selected"
"No channel selected", "As indicated in following octets", "Reserved","Any channel selected"
};
pri_message("%c Channel ID (len=%2d) [ Ext: %d IntID: %s, %s Spare: %d, %s Dchan: %d\n",
prefix, len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit", prefix, len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit",
(ie->data[0] & 0x20) ? "PRI" : "Other", (ie->data[0] & 0x10) ? 1 : 0, (ie->data[0] & 0x20) ? "PRI" : "Other", (ie->data[0] & 0x10) ? 1 : 0,
(ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0, (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0);
ie->data[0] & 0x3); pri_message("%c ChanSel: %s\n",
prefix, msg_chan_sel[(ie->data[0] & 0x3) + ((ie->data[0]>>3) & 0x4)]);
pos++; pos++;
len--; len--;
if (ie->data[0] & 0x40) { if (ie->data[0] & 0x40) {
/* Explicitly defined DS1 */ /* Explicitly defined DS1 */
printf("%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f); pri_message("%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
pos++; pos++;
len--; len--;
} else { } else {
/* Implicitly defined DS1 */ /* Implicitly defined DS1 */
} }
if (pos < len) { if (pos+2 < len) {
/* Still more information here */ /* Still more information here */
printf("%c Ext: %d Coding: %d %s Specified Channel Type: %d\n", pri_message("%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5, prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
(ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f); (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f);
if (!(ie->data[pos] & 0x10)) { if (!(ie->data[pos] & 0x10)) {
/* Number specified */ /* Number specified */
pos++; pos++;
printf("%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7, pri_message("%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7,
(ie->data[pos]) & 0x7f); (ie->data[pos]) & 0x7f);
} else { } else {
pos++; pos++;
@ -408,9 +428,9 @@ static void dump_channel_id(q931_ie *ie, int len, char prefix)
res <<= 8; res <<= 8;
res |= ie->data[pos++]; res |= ie->data[pos++];
} }
printf("%c Map: %s ]\n", prefix, binary(res, 24)); pri_message("%c Map: %s ]\n", prefix, binary(res, 24));
} }
} else printf(" ]\n"); } else pri_message(" ]\n");
} }
static char *ri2str(int ri) static char *ri2str(int ri)
@ -425,7 +445,7 @@ static char *ri2str(int ri)
static void dump_restart_indicator(q931_ie *ie, int len, char prefix) static void dump_restart_indicator(q931_ie *ie, int len, char prefix)
{ {
printf("%c Restart Indentifier: [ Ext: %d Spare: %d Resetting %s (%d) ]\n", pri_message("%c Restart Indentifier: [ Ext: %d Spare: %d Resetting %s (%d) ]\n",
prefix, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7); prefix, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7);
} }
@ -450,7 +470,7 @@ static int transmit_restart_indicator(struct pri *pri, q931_call *call, int msgt
ie->data[0] = 0xA0 | (call->ri & 0x7); ie->data[0] = 0xA0 | (call->ri & 0x7);
break; break;
default: default:
fprintf(stderr, "!! Invalid restart indicator value %d\n", call->ri); pri_error("!! Invalid restart indicator value %d\n", call->ri);
return-1; return-1;
} }
return 3; return 3;
@ -541,11 +561,11 @@ static char *l32str(int proto)
static void dump_bearer_capability(q931_ie *ie, int len, char prefix) static void dump_bearer_capability(q931_ie *ie, int len, char prefix)
{ {
int pos=2; int pos=2;
printf("%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n", pri_message("%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n",
prefix, ie->len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f)); prefix, ie->len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f));
printf("%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); pri_message("%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
if ((ie->data[1] & 0x7f) == 0x18) { if ((ie->data[1] & 0x7f) == 0x18) {
printf("%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f); pri_message("%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f);
pos++; pos++;
} }
/* Stop here if no more */ /* Stop here if no more */
@ -553,15 +573,15 @@ static void dump_bearer_capability(q931_ie *ie, int len, char prefix)
return; return;
if ((ie->data[1] & 0x7f) != TRANS_MODE_PACKET) { if ((ie->data[1] & 0x7f) != TRANS_MODE_PACKET) {
/* Look for octets 5 and 5.a if present */ /* Look for octets 5 and 5.a if present */
printf("%c Ext: %d User information layer 1: %s (%d)\n", prefix, (ie->data[pos] >> 7), l12str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f); pri_message("%c Ext: %d User information layer 1: %s (%d)\n", prefix, (ie->data[pos] >> 7), l12str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f);
if ((ie->data[pos] & 0x7f) == PRI_LAYER_1_ITU_RATE_ADAPT) if ((ie->data[pos] & 0x7f) == PRI_LAYER_1_ITU_RATE_ADAPT)
printf("%c Ext: %d Rate adaptatation: %s (%d)\n", prefix, ie->data[pos] >> 7, ra2str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f); pri_message("%c Ext: %d Rate adaptatation: %s (%d)\n", prefix, ie->data[pos] >> 7, ra2str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f);
pos++; pos++;
} else { } else {
/* Look for octets 6 and 7 but not 5 and 5.a */ /* Look for octets 6 and 7 but not 5 and 5.a */
printf("%c Ext: %d User information layer 2: %s (%d)\n", prefix, ie->data[pos] >> 7, l22str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f); pri_message("%c Ext: %d User information layer 2: %s (%d)\n", prefix, ie->data[pos] >> 7, l22str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f);
pos++; pos++;
printf("%c Ext: %d User information layer 3: %s (%d)\n", prefix, ie->data[pos] >> 7, l32str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f); pri_message("%c Ext: %d User information layer 3: %s (%d)\n", prefix, ie->data[pos] >> 7, l32str(ie->data[pos] & 0x7f), ie->data[pos] & 0x7f);
pos++; pos++;
} }
} }
@ -570,7 +590,7 @@ static int receive_bearer_capability(struct pri* pri, q931_call *call, int msgty
{ {
int pos=2; int pos=2;
if (ie->data[0] & 0x60) { if (ie->data[0] & 0x60) {
fprintf(stderr, "!! non-standard Q.931 standard field\n"); pri_error("!! non-standard Q.931 standard field\n");
return -1; return -1;
} }
call->transcapability = ie->data[0] & 0x1f; call->transcapability = ie->data[0] & 0x1f;
@ -698,7 +718,7 @@ static void dump_called_party_number(q931_ie *ie, int len, char prefix)
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
printf("%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", pri_message("%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n",
prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
} }
@ -706,7 +726,7 @@ static void dump_called_party_subaddr(q931_ie *ie, int len, char prefix)
{ {
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
printf("%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", pri_message("%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
prefix, len, ie->data[0] >> 7, prefix, len, ie->data[0] >> 7,
subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
(ie->data[0] & 0x08) >> 3, cnum); (ie->data[0] & 0x08) >> 3, cnum);
@ -717,15 +737,15 @@ static void dump_calling_party_number(q931_ie *ie, int len, char prefix)
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
printf("%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); pri_message("%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
printf("%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, cnum); pri_message("%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, cnum);
} }
static void dump_calling_party_subaddr(q931_ie *ie, int len, char prefix) static void dump_calling_party_subaddr(q931_ie *ie, int len, char prefix)
{ {
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
printf("%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", pri_message("%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
prefix, len, ie->data[0] >> 7, prefix, len, ie->data[0] >> 7,
subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
(ie->data[0] & 0x08) >> 3, cnum); (ie->data[0] & 0x08) >> 3, cnum);
@ -735,15 +755,27 @@ static void dump_redirecting_number(q931_ie *ie, int len, char prefix)
{ {
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 3, len - 5); q931_get_number(cnum, sizeof(cnum), ie->data + 3, len - 5);
printf("%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); pri_message("%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
printf("%c Presentation: %s (%d) Reason: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, redirection_reason2str(ie->data[2]), ie->data[2], cnum); pri_message("%c Presentation: %s (%d) Reason: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, redirection_reason2str(ie->data[2]), ie->data[2], cnum);
} }
static int receive_redirecting_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
call->redirectingplan = ie->data[0] & 0x7f;
call->redirectingpres = ie->data[1] & 0x7f;
call->redirectingreason = ie->data[2] & 0x0f;
q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + 3, len - 5);
return 0;
}
static void dump_redirecting_subaddr(q931_ie *ie, int len, char prefix) static void dump_redirecting_subaddr(q931_ie *ie, int len, char prefix)
{ {
char cnum[256]; char cnum[256];
q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
printf("%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", pri_message("%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
prefix, len, ie->data[0] >> 7, prefix, len, ie->data[0] >> 7,
subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
(ie->data[0] & 0x08) >> 3, cnum); (ie->data[0] & 0x08) >> 3, cnum);
@ -751,7 +783,13 @@ static void dump_redirecting_subaddr(q931_ie *ie, int len, char prefix)
static int receive_called_party_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int receive_called_party_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{ {
#ifdef SKIP_OVERLAP_SUPPORT
/* copy digits to call->callednum */
q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
#else
/* append new digits to call->callednum */
q931_get_number(call->callednum + strlen(call->callednum), sizeof(call->callednum) - strlen(call->callednum), ie->data + 1, len - 3);
#endif
call->calledplan = ie->data[0] & 0x7f; call->calledplan = ie->data[0] & 0x7f;
return 0; return 0;
} }
@ -766,9 +804,19 @@ static int transmit_called_party_number(struct pri *pri, q931_call *call, int ms
static int receive_calling_party_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int receive_calling_party_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{ {
q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4); int extbit;
call->callerplan = ie->data[0] & 0x7f; call->callerplan = ie->data[0] & 0x7f;
extbit = (ie->data[0] >> 7) & 0x01;
if (extbit) {
q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 1, len - 3);
call->callerpres = 0; /* PI presentation allowed
SI user-provided, not screened */
} else {
q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4);
call->callerpres = ie->data[1] & 0x7f; call->callerpres = ie->data[1] & 0x7f;
}
return 0; return 0;
} }
@ -781,6 +829,20 @@ static int transmit_calling_party_number(struct pri *pri, q931_call *call, int m
return strlen(call->callernum) + 4; return strlen(call->callernum) + 4;
} }
static void dump_user_user(q931_ie *ie, int len, char prefix)
{
}
static int receive_user_user(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
call->useruserprotocoldisc = ie->data[0] & 0xff;
if (call->useruserprotocoldisc == 4) /* IA5 */
q931_get_number(call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3);
return 0;
}
static char *prog2str(int prog) static char *prog2str(int prog)
{ {
static struct msgtype progs[] = { static struct msgtype progs[] = {
@ -825,13 +887,33 @@ static char *loc2str(int loc)
static void dump_progress_indicator(q931_ie *ie, int len, char prefix) static void dump_progress_indicator(q931_ie *ie, int len, char prefix)
{ {
printf("%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n", pri_message("%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
(ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
printf("%c Ext: %d Progress Description: %s (%d) ]\n", pri_message("%c Ext: %d Progress Description: %s (%d) ]\n",
prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
} }
static int receive_display(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
unsigned char *data;
data = ie->data;
if (data[0] & 0x80) {
/* Skip over character set */
data++;
len--;
}
q931_get_number(call->callername, sizeof(call->callername), data, len - 2);
return 0;
}
static int transmit_display(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
ie->data[0] = 0xb1;
memcpy(ie->data + 1, call->callername, strlen(call->callername));
return 3 + strlen(call->callername);
}
static int receive_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int receive_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{ {
call->progloc = ie->data[0] & 0xf; call->progloc = ie->data[0] & 0xf;
@ -840,6 +922,18 @@ static int receive_progress_indicator(struct pri *pri, q931_call *call, int msgt
return 0; return 0;
} }
static int receive_facility(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
if (ie->len < 14) {
pri_error("!! Facility message shorter than 14 bytes\n");
return 0;
}
if (ie->data[13] + 14 == ie->len) {
q931_get_number(call->callername, sizeof(call->callername) - 1, ie->data + 14, ie->len - 14);
}
return 0;
}
static int transmit_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int transmit_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{ {
if (call->progress > 0) { if (call->progress > 0) {
@ -880,7 +974,7 @@ static char *callstate2str(int callstate)
static void dump_call_state(q931_ie *ie, int len, char prefix) static void dump_call_state(q931_ie *ie, int len, char prefix)
{ {
printf("%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n", pri_message("%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n",
prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6, prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6,
callstate2str(ie->data[0] & 0x3f), ie->data[0] & 0x3f); callstate2str(ie->data[0] & 0x3f), ie->data[0] & 0x3f);
} }
@ -888,37 +982,82 @@ static void dump_call_state(q931_ie *ie, int len, char prefix)
static void dump_call_identity(q931_ie *ie, int len, char prefix) static void dump_call_identity(q931_ie *ie, int len, char prefix)
{ {
int x; int x;
printf("%c Call Identity (len=%2d) [ ", prefix, ie->len); pri_message("%c Call Identity (len=%2d) [ ", prefix, ie->len);
for (x=0;x<ie->len;x++) for (x=0;x<ie->len;x++)
printf("0x%02X ", ie->data[x]); pri_message("0x%02X ", ie->data[x]);
printf(" ]\n"); pri_message(" ]\n");
} }
static void dump_time_date(q931_ie *ie, int len, char prefix) static void dump_time_date(q931_ie *ie, int len, char prefix)
{ {
printf("%c Time Date (len=%2d) [ ", prefix, ie->len); pri_message("%c Time Date (len=%2d) [ ", prefix, ie->len);
if (ie->len > 0) if (ie->len > 0)
printf("%02d", ie->data[0]); pri_message("%02d", ie->data[0]);
if (ie->len > 1) if (ie->len > 1)
printf("-%02d", ie->data[1]); pri_message("-%02d", ie->data[1]);
if (ie->len > 2) if (ie->len > 2)
printf("-%02d", ie->data[2]); pri_message("-%02d", ie->data[2]);
if (ie->len > 3) if (ie->len > 3)
printf(" %02d", ie->data[3]); pri_message(" %02d", ie->data[3]);
if (ie->len > 4) if (ie->len > 4)
printf(":%02d", ie->data[4]); pri_message(":%02d", ie->data[4]);
if (ie->len > 5) if (ie->len > 5)
printf(":%02d", ie->data[5]); pri_message(":%02d", ie->data[5]);
printf(" ]\n"); pri_message(" ]\n");
} }
static void dump_display(q931_ie *ie, int len, char prefix) static void dump_display(q931_ie *ie, int len, char prefix)
{ {
int x; int x;
printf("%c Call Identity (len=%2d) [ ", prefix, ie->len); pri_message("%c Display (len=%2d) [ ", prefix, ie->len);
for (x=0;x<ie->len;x++) for (x=0;x<ie->len;x++)
printf("%c", ie->data[x] & 0x7f); pri_message("%c", ie->data[x] & 0x7f);
printf(" ]\n"); pri_message(" ]\n");
}
static void dump_ie_data(unsigned char *c, int len)
{
char tmp[1024] = "";
int x=0;
int lastascii = 0;
while(len) {
if (((*c >= 'A') && (*c <= 'Z')) ||
((*c >= 'a') && (*c <= 'z')) ||
((*c >= '0') && (*c <= '9'))) {
if (!lastascii) {
if (strlen(tmp)) {
tmp[x++] = ',';
tmp[x++] = ' ';
}
tmp[x++] = '\'';
}
tmp[x++] = *c;
lastascii = 1;
} else {
if (lastascii) {
tmp[x++] = '\'';
}
if (strlen(tmp)) {
tmp[x++] = ',';
tmp[x++] = ' ';
}
sprintf (tmp + x, "0x%02x", *c);
x += 4;
lastascii = 0;
}
c++;
len--;
}
if (lastascii)
tmp[x++] = '\'';
pri_message(tmp);
}
static void dump_facility(q931_ie *ie, int len, char prefix)
{
pri_message("%c Facility (len=%2d) [ ", prefix, ie->len);
dump_ie_data(ie->data, ie->len);
pri_message(" ]\n");
} }
char *pri_cause2str(int cause) char *pri_cause2str(int cause)
@ -944,14 +1083,14 @@ static char *pri_causeclass2str(int cause)
static void dump_cause(q931_ie *ie, int len, char prefix) static void dump_cause(q931_ie *ie, int len, char prefix)
{ {
int x; int x;
printf("%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n", pri_message("%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, prefix, ie->len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
(ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
printf("%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n", pri_message("%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n",
prefix, (ie->data[1] >> 7), pri_cause2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, prefix, (ie->data[1] >> 7), pri_cause2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f,
pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4); pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4);
for (x=4;x<len;x++) for (x=4;x<len;x++)
printf("%c Cause data %d: %02x (%d)\n", prefix, x-4, ie->data[x], ie->data[x]); pri_message("%c Cause data %d: %02x (%d)\n", prefix, x-4, ie->data[x], ie->data[x]);
} }
static int receive_cause(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int receive_cause(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
@ -976,7 +1115,7 @@ static int transmit_cause(struct pri *pri, q931_call *call, int msgtype, q931_ie
static void dump_sending_complete(q931_ie *ie, int len, char prefix) static void dump_sending_complete(q931_ie *ie, int len, char prefix)
{ {
printf("%c Sending Complete (len=%2d)\n", prefix, ie->len); pri_message("%c Sending Complete (len=%2d)\n", prefix, ie->len);
} }
static int receive_sending_complete(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) static int receive_sending_complete(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
@ -1015,14 +1154,14 @@ struct ie ies[] = {
{ Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr }, { Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr },
{ Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number }, { Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number },
{ Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr }, { Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr },
{ Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number }, { Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number, receive_redirecting_number },
{ Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr }, { Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr },
{ Q931_TRANSIT_NET_SELECT, "Transit Network Selection" }, { Q931_TRANSIT_NET_SELECT, "Transit Network Selection" },
{ Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator }, { Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator },
{ Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" }, { Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" },
{ Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" }, { Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
{ Q931_PACKET_SIZE, "Packet Size" }, { Q931_PACKET_SIZE, "Packet Size" },
{ Q931_IE_FACILITY, "Facility" }, { Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility },
{ Q931_IE_REDIRECTION_NUMBER, "Redirection Number" }, { Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
{ Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" }, { Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" },
{ Q931_IE_FEATURE_ACTIVATE, "Feature Activation" }, { Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
@ -1032,12 +1171,12 @@ struct ie ies[] = {
{ Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity }, { Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
{ Q931_IE_ENDPOINT_ID, "Endpoint Identification" }, { Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
{ Q931_IE_NOTIFY_IND, "Notification Indicator" }, { Q931_IE_NOTIFY_IND, "Notification Indicator" },
{ Q931_IE_DISPLAY, "Display", dump_display }, { Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
{ Q931_IE_TIME_DATE, "Date/Time", dump_time_date }, { Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
{ Q931_IE_KEYPAD_FACILITY, "Keypad Facility" }, { Q931_IE_KEYPAD_FACILITY, "Keypad Facility" },
{ Q931_IE_SIGNAL, "Signal" }, { Q931_IE_SIGNAL, "Signal" },
{ Q931_IE_SWITCHHOOK, "Switch-hook" }, { Q931_IE_SWITCHHOOK, "Switch-hook" },
{ Q931_IE_USER_USER, "User-User" }, { Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user },
{ Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" }, { Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
{ Q931_IE_CALL_STATUS, "Call Status" }, { Q931_IE_CALL_STATUS, "Call Status" },
{ Q931_IE_CHANGE_STATUS, "Change Status" }, { Q931_IE_CHANGE_STATUS, "Change Status" },
@ -1079,7 +1218,7 @@ static inline int q931_cr(q931_h *h)
int cr = 0; int cr = 0;
int x; int x;
if (h->crlen > 3) { if (h->crlen > 3) {
fprintf(stderr, "Call Reference Length Too long: %d\n", h->crlen); pri_error("Call Reference Length Too long: %d\n", h->crlen);
return -1; return -1;
} }
for (x=0;x<h->crlen;x++) { for (x=0;x<h->crlen;x++) {
@ -1097,11 +1236,11 @@ static inline void q931_dumpie(q931_ie *ie, char prefix)
if (ies[x].dump) if (ies[x].dump)
ies[x].dump(ie, ielen(ie), prefix); ies[x].dump(ie, ielen(ie), prefix);
else else
printf("%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie)); pri_message("%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie));
return; return;
} }
fprintf(stderr, "!! %c Unknown IE %d (len = %d)\n", prefix, ie->ie, ielen(ie)); pri_error("!! %c Unknown IE %d (len = %d)\n", prefix, ie->ie, ielen(ie));
} }
static q931_call *q931_getcall(struct pri *pri, int cr) static q931_call *q931_getcall(struct pri *pri, int cr)
@ -1117,7 +1256,7 @@ static q931_call *q931_getcall(struct pri *pri, int cr)
} }
/* No call exists, make a new one */ /* No call exists, make a new one */
if (pri->debug & PRI_DEBUG_Q931_STATE) if (pri->debug & PRI_DEBUG_Q931_STATE)
printf("-- Making new call for cr %d\n", cr); pri_message("-- Making new call for cr %d\n", cr);
cur = malloc(sizeof(struct q931_call)); cur = malloc(sizeof(struct q931_call));
if (cur) { if (cur) {
call_init(cur); call_init(cur);
@ -1166,7 +1305,7 @@ static void q931_destroycall(struct pri *pri, int cr)
prev = cur; prev = cur;
cur = cur->next; cur = cur->next;
} }
fprintf(stderr, "Can't destroy call %d!\n", cr); pri_error("Can't destroy call %d!\n", cr);
} }
static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen) static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen)
@ -1186,12 +1325,12 @@ static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie
iet->len = res - 2; iet->len = res - 2;
return res; return res;
} else { } else {
fprintf(stderr, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie); pri_error("!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie);
return -1; return -1;
} }
} }
} }
fprintf(stderr, "!! Unknown IE %d (%s)\n", ie, ie2str(ie)); pri_error("!! Unknown IE %d (%s)\n", ie, ie2str(ie));
return -1; return -1;
@ -1212,11 +1351,11 @@ void q931_dump(q931_h *h, int len, int txrx)
char c; char c;
int x=0, r; int x=0, r;
c = txrx ? '>' : '<'; c = txrx ? '>' : '<';
printf("%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); pri_message("%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len);
printf("%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, q931_cr(h), q931_cr(h), (h->crv[0] & 0x80) ? "Terminator" : "Originator"); pri_message("%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, q931_cr(h), q931_cr(h), (h->crv[0] & 0x80) ? "Terminator" : "Originator");
/* Message header begins at the end of the call reference number */ /* Message header begins at the end of the call reference number */
mh = (q931_mh *)(h->contents + h->crlen); mh = (q931_mh *)(h->contents + h->crlen);
printf("%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); pri_message("%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg);
/* Drop length of header, including call reference */ /* Drop length of header, including call reference */
len -= (h->crlen + 3); len -= (h->crlen + 3);
while(x < len) { while(x < len) {
@ -1225,26 +1364,26 @@ void q931_dump(q931_h *h, int len, int txrx)
x += r; x += r;
} }
if (x > len) if (x > len)
fprintf(stderr, "XXX Message longer than it should be?? XXX\n"); pri_error("XXX Message longer than it should be?? XXX\n");
} }
static int q931_handle_ie(struct pri *pri, q931_call *c, int msg, q931_ie *ie) static int q931_handle_ie(struct pri *pri, q931_call *c, int msg, q931_ie *ie)
{ {
int x; int x;
if (pri->debug & PRI_DEBUG_Q931_STATE) if (pri->debug & PRI_DEBUG_Q931_STATE)
printf("-- Processing IE %d (%s)\n", ie->ie, ie2str(ie->ie)); pri_message("-- Processing IE %d (%s)\n", ie->ie, ie2str(ie->ie));
for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) { for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
if (ie->ie == ies[x].ie) { if (ie->ie == ies[x].ie) {
if (ies[x].receive) if (ies[x].receive)
return ies[x].receive(pri, c, msg, ie, ielen(ie)); return ies[x].receive(pri, c, msg, ie, ielen(ie));
else { else {
if (pri->debug & PRI_DEBUG_Q931_ANOMALY) if (pri->debug & PRI_DEBUG_Q931_ANOMALY)
fprintf(stderr, "!! No handler for IE %d (%s)\n", ie->ie, ie2str(ie->ie)); pri_error("!! No handler for IE %d (%s)\n", ie->ie, ie2str(ie->ie));
return -1; return -1;
} }
} }
} }
printf("!! Unknown IE %d (%s)\n", ie->ie, ie2str(ie->ie)); pri_message("!! Unknown IE %d (%s)\n", ie->ie, ie2str(ie->ie));
return -1; return -1;
} }
@ -1299,7 +1438,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
while(ies[x] > -1) { while(ies[x] > -1) {
res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len); res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len);
if (res < 0) { if (res < 0) {
fprintf(stderr, "!! Unable to add IE '%s'\n", ie2str(ies[x])); pri_error("!! Unable to add IE '%s'\n", ie2str(ies[x]));
return -1; return -1;
} }
offset += res; offset += res;
@ -1309,6 +1448,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
/* Invert the logic */ /* Invert the logic */
len = sizeof(buf) - len; len = sizeof(buf) - len;
q931_xmit(pri, h, len, 1); q931_xmit(pri, h, len, 1);
c->acked = 1;
return 0; return 0;
} }
@ -1348,6 +1488,22 @@ int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
{
if (channel)
c->channelno = channel;
c->chanflags &= ~FLAG_PREFERRED;
c->chanflags |= FLAG_EXCLUSIVE;
if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
c->progloc = LOC_PRIV_NET_LOCAL_USER;
c->progcode = CODE_CCITT;
c->progress = Q931_PROG_CALLED_NOT_ISDN;
} else
c->progress = -1;
return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
}
int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn) int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
{ {
if (channel) if (channel)
@ -1372,7 +1528,10 @@ int q931_release(struct pri *pri, q931_call *c, int cause)
c->cause = cause; c->cause = cause;
c->causecode = CODE_CCITT; c->causecode = CODE_CCITT;
c->causeloc = LOC_PRIV_NET_LOCAL_USER; c->causeloc = LOC_PRIV_NET_LOCAL_USER;
if (c->acked)
return send_message(pri, c, Q931_RELEASE, release_ies); return send_message(pri, c, Q931_RELEASE, release_ies);
else
return send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */
} else } else
return 0; return 0;
} }
@ -1409,11 +1568,11 @@ int q931_disconnect(struct pri *pri, q931_call *c, int cause)
return 0; return 0;
} }
static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_DISPLAY, Q931_PROGRESS_INDICATOR,
Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 }; Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 };
int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
int nonisdn, char *caller, int callerplan, int callerpres, char *called, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called,
int calledplan, int userl1) int calledplan, int userl1)
{ {
int res; int res;
@ -1438,6 +1597,10 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
if (caller) { if (caller) {
strncpy(c->callernum, caller, sizeof(c->callernum) - 1); strncpy(c->callernum, caller, sizeof(c->callernum) - 1);
c->callerplan = callerplan; c->callerplan = callerplan;
if (callername)
strncpy(c->callername, callername, sizeof(c->callername) - 1);
else
strcpy(c->callername, "");
if ((pri->switchtype == PRI_SWITCH_DMS100) || if ((pri->switchtype == PRI_SWITCH_DMS100) ||
(pri->switchtype == PRI_SWITCH_ATT4ESS)) { (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
/* Doesn't like certain presentation types */ /* Doesn't like certain presentation types */
@ -1447,6 +1610,7 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
c->callerpres = callerpres; c->callerpres = callerpres;
} else { } else {
strcpy(c->callernum, ""); strcpy(c->callernum, "");
strcpy(c->callername, "");
c->callerplan = PRI_UNKNOWN; c->callerplan = PRI_UNKNOWN;
c->callerpres = PRES_NUMBER_NOT_AVAILABLE; c->callerpres = PRES_NUMBER_NOT_AVAILABLE;
} }
@ -1462,8 +1626,9 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
c->progress = -1; c->progress = -1;
res = send_message(pri, c, Q931_SETUP, setup_ies); res = send_message(pri, c, Q931_SETUP, setup_ies);
if (!res) if (!res) {
c->alive = 1; c->alive = 1;
}
return res; return res;
} }
@ -1504,14 +1669,14 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
} }
c = q931_getcall(pri, q931_cr(h)); c = q931_getcall(pri, q931_cr(h));
if (!c) { if (!c) {
fprintf(stderr, "Unable to locate call %d\n", q931_cr(h)); pri_error("Unable to locate call %d\n", q931_cr(h));
return -1; return -1;
} }
/* Preliminary handling */ /* Preliminary handling */
switch(mh->msg) { switch(mh->msg) {
case Q931_RESTART: case Q931_RESTART:
if (pri->debug & PRI_DEBUG_Q931_STATE) if (pri->debug & PRI_DEBUG_Q931_STATE)
printf("-- Processing Q.931 Restart\n"); pri_message("-- Processing Q.931 Restart\n");
/* Reset information */ /* Reset information */
c->channelno = -1; c->channelno = -1;
c->slotmap = -1; c->slotmap = -1;
@ -1519,9 +1684,12 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
c->ds1no = -1; c->ds1no = -1;
c->ri = -1; c->ri = -1;
break; break;
case Q931_FACILITY:
strcpy(c->callername, "");
break;
case Q931_SETUP: case Q931_SETUP:
if (pri->debug & PRI_DEBUG_Q931_STATE) if (pri->debug & PRI_DEBUG_Q931_STATE)
printf("-- Processing Q.931 Call Setup\n"); pri_message("-- Processing Q.931 Call Setup\n");
c->channelno = -1; c->channelno = -1;
c->slotmap = -1; c->slotmap = -1;
c->chanflags = 0; c->chanflags = 0;
@ -1539,6 +1707,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
c->callerpres = -1; c->callerpres = -1;
strcpy(c->callernum, ""); strcpy(c->callernum, "");
strcpy(c->callednum, ""); strcpy(c->callednum, "");
strcpy(c->callername, "");
c->redirectingplan = -1;
c->redirectingpres = -1;
c->redirectingreason = -1;
strcpy(c->redirectingnum, "");
c->useruserprotocoldisc = -1;
strcpy(c->useruserinfo, "");
break; break;
case Q931_CONNECT: case Q931_CONNECT:
case Q931_ALERTING: case Q931_ALERTING:
@ -1565,13 +1740,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
case Q931_RESTART_ACKNOWLEDGE: case Q931_RESTART_ACKNOWLEDGE:
c->channelno = -1; c->channelno = -1;
break; break;
case Q931_INFORMATION:
break;
case Q931_SETUP_ACKNOWLEDGE: case Q931_SETUP_ACKNOWLEDGE:
case Q931_STATUS_ENQUIRY: case Q931_STATUS_ENQUIRY:
case Q931_USER_INFORMATION: case Q931_USER_INFORMATION:
case Q931_SEGMENT: case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL: case Q931_CONGESTION_CONTROL:
case Q931_INFORMATION:
case Q931_FACILITY:
case Q931_NOTIFY: case Q931_NOTIFY:
case Q931_HOLD: case Q931_HOLD:
case Q931_HOLD_ACKNOWLEDGE: case Q931_HOLD_ACKNOWLEDGE:
@ -1585,11 +1760,11 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
case Q931_SUSPEND: case Q931_SUSPEND:
case Q931_SUSPEND_ACKNOWLEDGE: case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT: case Q931_SUSPEND_REJECT:
fprintf(stderr, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); pri_error("!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
return -1; return -1;
default: default:
fprintf(stderr, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); pri_error("!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
return -1; return -1;
} }
x = 0; x = 0;
@ -1599,7 +1774,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
ie = (q931_ie *)(mh->data + x); ie = (q931_ie *)(mh->data + x);
r = ielen(ie); r = ielen(ie);
if (r > len) { if (r > len) {
fprintf(stderr, "XXX Message longer than it should be?? XXX\n"); pri_error("XXX Message longer than it should be?? XXX\n");
return -1; return -1;
} }
q931_handle_ie(pri, c, mh->msg, ie); q931_handle_ie(pri, c, mh->msg, ie);
@ -1623,8 +1798,11 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
pri->ev.ring.callingpres = c->callerpres; pri->ev.ring.callingpres = c->callerpres;
pri->ev.ring.callingplan = c->callerplan; pri->ev.ring.callingplan = c->callerplan;
strncpy(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum) - 1); strncpy(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum) - 1);
strncpy(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname) - 1);
pri->ev.ring.calledplan = c->calledplan; pri->ev.ring.calledplan = c->calledplan;
strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1); strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
strncpy(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum) - 1);
strncpy(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo) - 1);
pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
pri->ev.ring.cref = c->cr; pri->ev.ring.cref = c->cr;
pri->ev.ring.call = c; pri->ev.ring.call = c;
@ -1647,13 +1825,24 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
pri->ev.answer.call = c; pri->ev.answer.call = c;
q931_connect_acknowledge(pri, c); q931_connect_acknowledge(pri, c);
return Q931_RES_HAVEEVENT; return Q931_RES_HAVEEVENT;
case Q931_FACILITY:
pri->ev.e = PRI_EVENT_FACNAME;
strncpy(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname) - 1);
strncpy(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingname) - 1);
pri->ev.facname.channel = c->channelno;
pri->ev.facname.cref = c->cr;
pri->ev.facname.call = c;
#if 0
pri_message("Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum);
#endif
return Q931_RES_HAVEEVENT;
case Q931_PROGRESS: case Q931_PROGRESS:
case Q931_CONNECT_ACKNOWLEDGE: case Q931_CONNECT_ACKNOWLEDGE:
case Q931_STATUS: case Q931_STATUS:
/* Do nothing */ /* Do nothing */
if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) && if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) &&
(c->cause != PRI_CAUSE_INTERWORKING)) (c->cause != PRI_CAUSE_INTERWORKING))
fprintf(stderr, "Received unsolicited status: %s\n", pri_cause2str(c->cause)); pri_error("Received unsolicited status: %s\n", pri_cause2str(c->cause));
break; break;
case Q931_CALL_PROCEEDING: case Q931_CALL_PROCEEDING:
break; break;
@ -1693,26 +1882,32 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
return res; return res;
break; break;
case Q931_DISCONNECT: case Q931_DISCONNECT:
/* Send a release with no cause */
q931_release(pri, c, -1);
/* Return such an event */ /* Return such an event */
pri->ev.e = PRI_EVENT_HANGUP; pri->ev.e = PRI_EVENT_HANGUP;
pri->ev.hangup.channel = c->channelno; pri->ev.hangup.channel = c->channelno;
pri->ev.hangup.cref = c->cr; pri->ev.hangup.cref = c->cr;
pri->ev.hangup.cause = c->cause; pri->ev.hangup.cause = c->cause;
pri->ev.hangup.call = c; pri->ev.hangup.call = c;
/* Send a release with no cause */
q931_release(pri, c, -1);
return Q931_RES_HAVEEVENT; return Q931_RES_HAVEEVENT;
case Q931_RESTART_ACKNOWLEDGE: case Q931_RESTART_ACKNOWLEDGE:
pri->ev.e = PRI_EVENT_RESTART_ACK; pri->ev.e = PRI_EVENT_RESTART_ACK;
pri->ev.restartack.channel = c->channelno; pri->ev.restartack.channel = c->channelno;
return Q931_RES_HAVEEVENT; return Q931_RES_HAVEEVENT;
case Q931_INFORMATION:
pri->ev.e = PRI_EVENT_INFO_RECEIVED;
pri->ev.ring.call = c;
strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
return Q931_RES_HAVEEVENT;
case Q931_SETUP_ACKNOWLEDGE: case Q931_SETUP_ACKNOWLEDGE:
case Q931_STATUS_ENQUIRY: case Q931_STATUS_ENQUIRY:
case Q931_USER_INFORMATION: case Q931_USER_INFORMATION:
case Q931_SEGMENT: case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL: case Q931_CONGESTION_CONTROL:
case Q931_INFORMATION:
case Q931_FACILITY:
case Q931_NOTIFY: case Q931_NOTIFY:
case Q931_HOLD: case Q931_HOLD:
case Q931_HOLD_ACKNOWLEDGE: case Q931_HOLD_ACKNOWLEDGE:
@ -1726,11 +1921,11 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
case Q931_SUSPEND: case Q931_SUSPEND:
case Q931_SUSPEND_ACKNOWLEDGE: case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT: case Q931_SUSPEND_REJECT:
fprintf(stderr, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); pri_error("!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
return -1; return -1;
default: default:
fprintf(stderr, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); pri_error("!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
return -1; return -1;
} }
return 0; return 0;