diff --git a/libpri.h b/libpri.h index 5e1afea..974d0e3 100755 --- a/libpri.h +++ b/libpri.h @@ -60,6 +60,8 @@ #define PRI_EVENT_ANSWER 8 /* Call has been answered */ #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_FACNAME 11 /* Caller*ID Name received on Facility */ +#define PRI_EVENT_INFO_RECEIVED 12 /* Additional info (keypad) received */ /* Simple states */ #define PRI_STATE_DOWN 0 @@ -205,14 +207,26 @@ typedef struct pri_event_answer { q931_call *call; } 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 { int e; int channel; /* Channel requested */ int callingpres; /* Presentation of Calling CallerID */ int callingplan; /* Dialing plan of Calling entity */ char callingnum[256]; /* Calling number */ + char callingname[256]; /* Calling name (if provided) */ int calledplan; /* Dialing plan of 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 cref; /* Call Reference Number */ int ctype; /* Call type (see PRI_TRANS_CAP_* */ @@ -238,6 +252,7 @@ typedef union { pri_event_generic gen; /* Generic view */ pri_event_restart restart; /* Restart view */ pri_event_error err; /* Error view */ + pri_event_facname facname; /* Caller*ID Name on Facility */ pri_event_ring ring; /* Ring */ pri_event_hangup hangup; /* Hang up */ pri_event_ringing ringing; /* Ringing */ @@ -293,6 +308,10 @@ extern char *pri_cause2str(int cause); is in-band data available on the channel */ 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). 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); @@ -315,6 +334,10 @@ extern struct timeval *pri_schedule_next(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, - 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); + +/* Override message and error stuff */ +extern void pri_set_message(void (*__pri_error)(char *)); +extern void pri_set_error(void (*__pri_error)(char *)); #endif diff --git a/pri.c b/pri.c index 8139d84..ff0fc8d 100755 --- a/pri.c +++ b/pri.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "libpri.h" #include "pri_internal.h" #include "pri_q921.h" @@ -64,7 +65,7 @@ struct pri *pri_new(int fd, int node, int switchtype) p->switchtype = switchtype; p->cref = 1; /* Start Q.921 layer */ - q921_start(p); + q921_start(p, 1); } return p; } @@ -95,9 +96,11 @@ pri_event *pri_check_event(struct pri *pri) res = read(pri->fd, buf, sizeof(buf)); if (res < 0) { 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; } + if (!res) + return NULL; /* Receive the q921 packet */ e = q921_receive(pri, (q921_h *)buf, res); 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); } +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) { if (!pri || !call) @@ -217,34 +227,73 @@ void pri_dump_event(struct pri *pri, pri_event *e) { if (!pri || !e) 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) { case PRI_EVENT_DCHAN_UP: case PRI_EVENT_DCHAN_DOWN: break; case PRI_EVENT_CONFIG_ERR: - printf("Error: %s", e->err.err); + pri_message("Error: %s", e->err.err); break; 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: - printf("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)); - printf("Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref); + pri_message("Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres)); + pri_message("Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan)); + pri_message("Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref); break; 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; 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 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) { if (!pri || !c) 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); +} diff --git a/pri_internal.h b/pri_internal.h index aec35fa..1d64617 100755 --- a/pri_internal.h +++ b/pri_internal.h @@ -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 void pri_message(char *fmt, ...); + +extern void pri_error(char *fmt, ...); + #endif diff --git a/pri_q921.h b/pri_q921.h index 2b70df1..3d0f695 100755 --- a/pri_q921.h +++ b/pri_q921.h @@ -137,7 +137,7 @@ typedef struct q921_frame { q921_i h; } q921_frame; -#define Q921_INC(j) (j) = ((j) + 1) % 128 +#define Q921_INC(j) (j) = (((j) + 1) % 128) typedef enum q921_state { 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); /* 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); diff --git a/pri_q931.h b/pri_q931.h index ec0bb04..6069ef9 100755 --- a/pri_q931.h +++ b/pri_q931.h @@ -190,6 +190,7 @@ typedef struct q931_ie { #define Q931_LOW_LAYER_COMPAT 0x7c #define Q931_HIGH_LAYER_COMPAT 0x7d +#define Q931_DISPLAY 0x28 #define Q931_IE_SEGMENTED_MSG 0x00 #define Q931_IE_CHANGE_STATUS 0x01 #define Q931_IE_CONNECTED_NUM 0x0C @@ -197,7 +198,6 @@ typedef struct q931_ie { #define Q931_IE_FACILITY 0x1c #define Q931_IE_ENDPOINT_ID 0x26 #define Q931_IE_NOTIFY_IND 0x27 -#define Q931_IE_DISPLAY 0x28 #define Q931_IE_TIME_DATE 0x29 #define Q931_IE_KEYPAD_FACILITY 0x2c #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_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_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 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); extern void q931_dump(q931_h *h, int len, int txrx); #endif diff --git a/prisched.c b/prisched.c index e4e1431..e96d091 100755 --- a/prisched.c +++ b/prisched.c @@ -38,7 +38,7 @@ int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), vo if (!pri->pri_sched[x].callback) break; if (x == MAX_SCHED) { - fprintf(stderr, "No more room in scheduler\n"); + pri_error("No more room in scheduler\n"); return -1; } if (x > maxsched) @@ -98,6 +98,6 @@ pri_event *pri_schedule_run(struct pri *pri) void pri_schedule_del(struct pri *pri,int id) { 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; } diff --git a/pritest.c b/pritest.c index 58063cf..44b3b75 100755 --- a/pritest.c +++ b/pritest.c @@ -48,6 +48,8 @@ #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2 #define MAX_CHAN 32 +#define DCHANNEL_TIMESLOT 16 + 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) { 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 */ if ((channo >= MAX_CHAN) || (channo < 0)) { 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; /* Answer the line */ - pri_answer(pri, chans[channo].call, channo, 1); + if(flag) { + 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_channel(channo); @@ -222,6 +268,14 @@ static void handle_pri_event(struct pri *pri, pri_event *e) break; case PRI_EVENT_HANGUP_ACK: /* 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; default: fprintf(stderr, "--!! Unknown PRI event %d\n", e->e); diff --git a/q921.c b/q921.c index 09daf78..81ed850 100755 --- a/q921.c +++ b/q921.c @@ -42,6 +42,7 @@ */ #define Q921_INIT(hf) do { \ + memset(&(hf),0,sizeof(hf)); \ (hf).h.sapi = 0; \ (hf).h.ea1 = 0; \ (hf).h.ea2 = 1; \ @@ -65,7 +66,7 @@ static int q921_transmit(struct pri *pri, q921_h *h, int len) { int res; #ifdef RANDOM_DROPS if (!(random() % 3)) { - printf(" === Dropping Packet ===\n"); + pri_message(" === Dropping Packet ===\n"); return 0; } #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 */ res = write(pri->fd, h, 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 0; @@ -98,21 +99,25 @@ static void q921_send_ua(struct pri *pri, int pfbit) h.h.c_r = 1; break; 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; } if (pri->debug & PRI_DEBUG_Q921_STATE) - printf("Sending Unnumbered Acknowledgement\n"); + pri_message("Sending Unnumbered Acknowledgement\n"); 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; q921_h h; pri_schedule_del(pri, pri->sabme_timer); 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); h.u.m3 = 3; /* M3 = 3 */ h.u.m2 = 3; /* M2 = 3 */ @@ -126,31 +131,42 @@ static void q921_send_sabme(void *vpri) h.h.c_r = 0; break; 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; } 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); 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) { struct q921_frame *f, *prev = NULL; f = pri->txqueue; while(f) { if (f->h.n_s == num) { + /* Cancel each packet as necessary */ /* That's our packet */ if (prev) prev->next = f->next; else 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); /* Reset retransmission counter if we actually acked something */ pri->retrans = 0; return 1; } + prev = f; f = f->next; } 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)); if (x != ack) { /* 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; } /* 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)) cnt += q921_ack_packet(pri, x); if (!pri->txqueue) { 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 */ pri_schedule_del(pri, pri->t200_timer); pri->t200_timer = 0; } if (pri->t203_timer) { 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->t203_timer = 0; } if (pri->txqueue) { /* Something left to transmit, Start the T200 counter again if we stopped it */ 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) pri->t200_timer = pri_schedule_event(pri, T_200, t200_expire, pri); } else { 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 */ 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; break; 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; } 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); } @@ -241,12 +259,12 @@ static void q921_rr(struct pri *pri, int pbit) { h.h.c_r = 1; break; 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; } pri->v_na = pri->v_r; /* Make a note that we've already acked this */ 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); } @@ -258,7 +276,7 @@ static void t200_expire(void *vpri) if (pri->txqueue) { /* Retransmit first packet in the queue, setting the poll bit */ 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 */ pri->txqueue->h.p_f = 1; /* Update nr */ @@ -270,22 +288,22 @@ static void t200_expire(void *vpri) if (pri->retrans < N_200) { /* Reschedule t200_timer */ 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); 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); } else { 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->t200_timer = 0; q921_dchannel_down(pri); - q921_start(pri); + q921_start(pri, 1); pri->schedev = 1; } } else { - fprintf(stderr, "T200 counter expired, nothing to send...\n"); + pri_error("T200 counter expired, nothing to send...\n"); 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; for (f=pri->txqueue; f; f = f->next) prev = f; f = malloc(sizeof(q921_frame) + len + 2); + memset(f,0,sizeof(q921_frame) + len + 2); if (f) { Q921_INIT(f->h); 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); if (pri->t203_timer) { 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->t203_timer = 0; } if (!pri->t200_timer) { 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); } else 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 { - fprintf(stderr, "!! Out of memory for Q.921 transmit\n"); + pri_error("!! Out of memory for Q.921 transmit\n"); return -1; } return 0; @@ -352,7 +371,7 @@ static void t203_expire(void *vpri) { struct pri *pri = vpri; 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 */ pri->solicitfbit = 1; q921_rr(pri, 1); @@ -404,26 +423,26 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx) direction_tag = txrx ? '>' : '<'; if (showraw) { - printf("\n%c [", direction_tag); + pri_message("\n%c [", direction_tag); for (x=0;xraw[x]); - printf("]"); + pri_message("%02x ",h->raw[x]); + pri_message("]"); } switch (h->h.data[0] & Q921_FRAMETYPE_MASK) { case 0: case 2: - printf("\n%c Informational frame:\n", direction_tag); + pri_message("\n%c Informational frame:\n", direction_tag); break; case 1: - printf("\n%c Supervisory frame:\n", direction_tag); + pri_message("\n%c Supervisory frame:\n", direction_tag); break; case 3: - printf("\n%c Unnumbered frame:\n", direction_tag); + pri_message("\n%c Unnumbered frame:\n", direction_tag); break; } - printf( + pri_message( "%c SAPI: %02d C/R: %d EA: %d\n" "%c TEI: %03d EA: %d\n", direction_tag, @@ -437,7 +456,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx) case 0: case 2: /* Informational frame */ - printf( + pri_message( "%c N(S): %03d 0: %d\n" "%c N(R): %03d P: %d\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)"; break; } - printf( + pri_message( "%c Zero: %d S: %d 01: %d [ %s ]\n" "%c N(R): %03d P/F: %d\n" "%c %d bytes of data\n", @@ -510,7 +529,7 @@ void q921_dump(q921_h *h, int len, int showraw, int txrx) break; } } - printf( + pri_message( "%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n" "%c %d bytes of data\n", direction_tag, @@ -580,6 +599,7 @@ void q921_reset(struct pri *pri) pri_event *q921_receive(struct pri *pri, q921_h *h, int len) { q921_frame *f; + int sendnow; /* Discard FCS */ len -= 2; @@ -602,23 +622,23 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len) case 0: case 2: 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; } /* Informational frame */ if (len < 4) { - fprintf(stderr, "!! Received short I-frame\n"); + pri_error("!! Received short I-frame (expected 4, got %d)\n", len); break; } return q921_handle_iframe(pri, &h->i, len); break; case 1: 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; } if (len < 4) { - fprintf(stderr, "!! Received short S-frame\n"); + pri_error("!! Received short S-frame (expected 4, got %d)\n", len); break; } 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 (pri->solicitfbit) { 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 { 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); } pri->solicitfbit = 0; @@ -644,36 +664,38 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len) case 1: /* Receiver not ready */ if (pri->debug & PRI_DEBUG_Q921_STATE) - printf("-- Got receiver not ready\n"); + pri_message("-- Got receiver not ready\n"); pri->busy = 1; break; #endif case 2: /* Just retransmit */ 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 it has the poll bit set, send an appropriate supervisory response */ q921_rr(pri, 1); } + sendnow = 0; /* Resend the proper I-frame */ for(f=pri->txqueue;f;f=f->next) { - if (f->h.n_s == h->s.n_r) { - /* Matches the request */ - break; + if (sendnow || (f->h.n_s == h->s.n_r)) { + /* Matches the request, or follows in our window */ + 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; + q921_transmit(pri, (q921_h *)(&f->h), f->len); } } - if (f) { - /* Retransmit the requested frame */ - q921_transmit(pri, (q921_h *)(&f->h), f->len); - } else { + if (!sendnow) { if (pri->txqueue) { /* This should never happen */ 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 { /* 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_s = h->s.n_r; /* 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; 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); } break; case 3: if (len < 3) { - fprintf(stderr, "!! Received short unnumbered frame\n"); + pri_error("!! Received short unnumbered frame\n"); break; } switch(h->u.m3) { case 0: if (h->u.m2 == 3) { 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) - printf("-- Got Unconnected Mode from peer.\n"); - /* Disconnected mode */ - if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) - return q921_dchannel_down(pri); + pri_message("-- Got DM Mode from peer.\n"); + /* Disconnected mode, try again after T200 */ + ev = q921_dchannel_down(pri); + q921_start(pri, 0); + return ev; + } else { 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 */ - q921_start(pri); + q921_start(pri, 0); +#endif } break; } else if (!h->u.m2) { - printf("XXX Unnumbered Information not implemented XXX\n"); + pri_message("XXX Unnumbered Information not implemented XXX\n"); } break; case 2: if (pri->debug & PRI_DEBUG_Q921_STATE) - printf("-- Got Disconnect from peer.\n"); + pri_message("-- Got Disconnect from peer.\n"); /* Acknowledge */ q921_send_ua(pri, h->u.p_f); 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) { /* SABME */ 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) { pri->remotetype = PRI_NETWORK; @@ -750,22 +779,22 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len) /* It's a UA */ if (pri->q921_state == Q921_AWAITING_ESTABLISH) { 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); } 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 - 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; case 4: - fprintf(stderr, "!! Frame got rejected!\n"); + pri_error("!! Frame got rejected!\n"); break; case 5: - fprintf(stderr, "!! XID frames not supported\n"); + pri_error("!! XID frames not supported\n"); break; 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; @@ -773,14 +802,14 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len) return NULL; } -void q921_start(struct pri *pri) +void q921_start(struct pri *pri, int now) { 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; } /* Reset our interface */ q921_reset(pri); /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */ - q921_send_sabme(pri); + q921_send_sabme(pri, now); } diff --git a/q931.c b/q931.c index 0daa632..c2f9142 100755 --- a/q931.c +++ b/q931.c @@ -61,7 +61,7 @@ struct msgtype msgs[] = { { Q931_SEGMENT, "SEGMENT" }, { Q931_CONGESTION_CONTROL, "CONGESTION CONTROL" }, { Q931_INFORMATION, "INFORMATION" }, - { Q931_FACILITY, "FACLITY" }, + { Q931_FACILITY, "FACILITY" }, { Q931_NOTIFY, "NOTIFY" }, /* Call Management */ @@ -192,9 +192,10 @@ struct q931_call { /* Channel flags (0 means none retrieved) */ 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 proc; /* Whether we've sent a call proceeding / alerting */ + int proc; /* Whether we've sent a call proceeding / alerting */ int ri; /* Restart Indicator (Restart Indicator IE) */ @@ -222,10 +223,19 @@ struct q931_call { int callerplan; int callerpres; /* Caller presentation */ char callernum[256]; /* Caller */ + char callername[256]; int calledplan; int nonisdn; char callednum[256]; /* Called Number */ + + int redirectingplan; + int redirectingpres; + int redirectingreason; + char redirectingnum[256]; + + int useruserprotocoldisc; + char useruserinfo[256]; }; struct ie { @@ -278,14 +288,18 @@ static int receive_channel_id(struct pri *pri, q931_call *call, int msgtype, q93 { int x; int pos=0; - if (!ie->data[0] & 0x20) { - fprintf(stderr, "!! Not PRI type!?\n"); - return -1; - } +#ifdef NO_BRI_SUPPORT + if (!ie->data[0] & 0x20) { + pri_error("!! Not PRI type!?\n"); + return -1; + } +#endif +#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT 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; } +#endif if (ie->data[0] & 0x08) call->chanflags = FLAG_EXCLUSIVE; 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; pos++; } - if (pos < len) { + if (pos+2 < len) { /* More coming */ 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; } 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; } 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 */ 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; } @@ -376,30 +390,36 @@ static void dump_channel_id(q931_ie *ie, int len, char prefix) int pos=0; int x; 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", (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] & 0x3); + (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0); + pri_message("%c ChanSel: %s\n", + prefix, msg_chan_sel[(ie->data[0] & 0x3) + ((ie->data[0]>>3) & 0x4)]); pos++; len--; if (ie->data[0] & 0x40) { /* 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++; len--; } else { /* Implicitly defined DS1 */ } - if (pos < len) { + if (pos+2 < len) { /* 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, (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f); if (!(ie->data[pos] & 0x10)) { /* Number specified */ 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); } else { pos++; @@ -408,9 +428,9 @@ static void dump_channel_id(q931_ie *ie, int len, char prefix) res <<= 8; 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) @@ -425,7 +445,7 @@ static char *ri2str(int ri) 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); } @@ -450,7 +470,7 @@ static int transmit_restart_indicator(struct pri *pri, q931_call *call, int msgt ie->data[0] = 0xA0 | (call->ri & 0x7); break; default: - fprintf(stderr, "!! Invalid restart indicator value %d\n", call->ri); + pri_error("!! Invalid restart indicator value %d\n", call->ri); return-1; } return 3; @@ -541,11 +561,11 @@ static char *l32str(int proto) static void dump_bearer_capability(q931_ie *ie, int len, char prefix) { 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)); - 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) { - 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++; } /* Stop here if no more */ @@ -553,15 +573,15 @@ static void dump_bearer_capability(q931_ie *ie, int len, char prefix) return; if ((ie->data[1] & 0x7f) != TRANS_MODE_PACKET) { /* 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) - 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++; } else { /* 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++; - 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++; } } @@ -570,7 +590,7 @@ static int receive_bearer_capability(struct pri* pri, q931_call *call, int msgty { int pos=2; 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; } 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]; 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); } @@ -706,7 +726,7 @@ static void dump_called_party_subaddr(q931_ie *ie, int len, char prefix) { char cnum[256]; 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, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, (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]; 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); - printf("%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, cnum); + 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); + 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) { char cnum[256]; 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, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, (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]; 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); - 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 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 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) { char cnum[256]; 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, subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, (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) { - q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); +#ifdef SKIP_OVERLAP_SUPPORT + /* copy digits to call->callednum */ + 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; 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) { - q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4); - call->callerplan = ie->data[0] & 0x7f; - call->callerpres = ie->data[1] & 0x7f; + int extbit; + + 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; + } 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; } +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 struct msgtype progs[] = { @@ -825,13 +887,33 @@ static char *loc2str(int loc) 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, (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); } +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) { 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; } +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) { 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) { - 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, 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) { int x; - printf("%c Call Identity (len=%2d) [ ", prefix, ie->len); + pri_message("%c Call Identity (len=%2d) [ ", prefix, ie->len); for (x=0;xlen;x++) - printf("0x%02X ", ie->data[x]); - printf(" ]\n"); + pri_message("0x%02X ", ie->data[x]); + pri_message(" ]\n"); } 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) - printf("%02d", ie->data[0]); + pri_message("%02d", ie->data[0]); if (ie->len > 1) - printf("-%02d", ie->data[1]); + pri_message("-%02d", ie->data[1]); if (ie->len > 2) - printf("-%02d", ie->data[2]); + pri_message("-%02d", ie->data[2]); if (ie->len > 3) - printf(" %02d", ie->data[3]); + pri_message(" %02d", ie->data[3]); if (ie->len > 4) - printf(":%02d", ie->data[4]); + pri_message(":%02d", ie->data[4]); if (ie->len > 5) - printf(":%02d", ie->data[5]); - printf(" ]\n"); + pri_message(":%02d", ie->data[5]); + pri_message(" ]\n"); } static void dump_display(q931_ie *ie, int len, char prefix) { int x; - printf("%c Call Identity (len=%2d) [ ", prefix, ie->len); + pri_message("%c Display (len=%2d) [ ", prefix, ie->len); for (x=0;xlen;x++) - printf("%c", ie->data[x] & 0x7f); - printf(" ]\n"); + pri_message("%c", ie->data[x] & 0x7f); + 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) @@ -944,14 +1083,14 @@ static char *pri_causeclass2str(int cause) static void dump_cause(q931_ie *ie, int len, char prefix) { 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, (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, pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4); for (x=4;xdata[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) @@ -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) { - 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) @@ -1015,14 +1154,14 @@ struct ie ies[] = { { 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_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_TRANSIT_NET_SELECT, "Transit Network Selection" }, { Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator }, { Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" }, { Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" }, { 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_SUBADDR, "Redirection Subaddress" }, { Q931_IE_FEATURE_ACTIVATE, "Feature Activation" }, @@ -1032,12 +1171,12 @@ struct ie ies[] = { { Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity }, { Q931_IE_ENDPOINT_ID, "Endpoint Identification" }, { 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_KEYPAD_FACILITY, "Keypad Facility" }, { Q931_IE_SIGNAL, "Signal" }, { 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_CALL_STATUS, "Call Status" }, { Q931_IE_CHANGE_STATUS, "Change Status" }, @@ -1079,7 +1218,7 @@ static inline int q931_cr(q931_h *h) int cr = 0; int x; 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; } for (x=0;xcrlen;x++) { @@ -1097,11 +1236,11 @@ static inline void q931_dumpie(q931_ie *ie, char prefix) if (ies[x].dump) ies[x].dump(ie, ielen(ie), prefix); 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; } - 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) @@ -1117,7 +1256,7 @@ static q931_call *q931_getcall(struct pri *pri, int cr) } /* No call exists, make a new one */ 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)); if (cur) { call_init(cur); @@ -1166,7 +1305,7 @@ static void q931_destroycall(struct pri *pri, int cr) prev = cur; 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) @@ -1186,12 +1325,12 @@ static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie iet->len = res - 2; return res; } 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; } } } - fprintf(stderr, "!! Unknown IE %d (%s)\n", ie, ie2str(ie)); + pri_error("!! Unknown IE %d (%s)\n", ie, ie2str(ie)); return -1; @@ -1212,11 +1351,11 @@ void q931_dump(q931_h *h, int len, int txrx) char c; int x=0, r; c = txrx ? '>' : '<'; - printf("%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 Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); + 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 */ 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 */ len -= (h->crlen + 3); while(x < len) { @@ -1225,26 +1364,26 @@ void q931_dump(q931_h *h, int len, int txrx) x += r; } 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) { int x; 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;xie == ies[x].ie) { if (ies[x].receive) return ies[x].receive(pri, c, msg, ie, ielen(ie)); else { 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; } } } - 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; } @@ -1299,7 +1438,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[]) while(ies[x] > -1) { res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len); 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; } offset += res; @@ -1309,6 +1448,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[]) /* Invert the logic */ len = sizeof(buf) - len; q931_xmit(pri, h, len, 1); + c->acked = 1; return 0; } @@ -1347,6 +1487,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 }; + +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) { @@ -1372,7 +1528,10 @@ int q931_release(struct pri *pri, q931_call *c, int cause) c->cause = cause; c->causecode = CODE_CCITT; c->causeloc = LOC_PRIV_NET_LOCAL_USER; - return send_message(pri, c, Q931_RELEASE, release_ies); + if (c->acked) + 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 return 0; } @@ -1409,11 +1568,11 @@ int q931_disconnect(struct pri *pri, q931_call *c, int cause) 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 }; 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 res; @@ -1438,6 +1597,10 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex if (caller) { strncpy(c->callernum, caller, sizeof(c->callernum) - 1); c->callerplan = callerplan; + if (callername) + strncpy(c->callername, callername, sizeof(c->callername) - 1); + else + strcpy(c->callername, ""); if ((pri->switchtype == PRI_SWITCH_DMS100) || (pri->switchtype == PRI_SWITCH_ATT4ESS)) { /* 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; } else { strcpy(c->callernum, ""); + strcpy(c->callername, ""); c->callerplan = PRI_UNKNOWN; 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; res = send_message(pri, c, Q931_SETUP, setup_ies); - if (!res) + if (!res) { c->alive = 1; + } return res; } @@ -1504,14 +1669,14 @@ int q931_receive(struct pri *pri, q931_h *h, int len) } c = q931_getcall(pri, q931_cr(h)); 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; } /* Preliminary handling */ switch(mh->msg) { case Q931_RESTART: if (pri->debug & PRI_DEBUG_Q931_STATE) - printf("-- Processing Q.931 Restart\n"); + pri_message("-- Processing Q.931 Restart\n"); /* Reset information */ c->channelno = -1; c->slotmap = -1; @@ -1519,9 +1684,12 @@ int q931_receive(struct pri *pri, q931_h *h, int len) c->ds1no = -1; c->ri = -1; break; + case Q931_FACILITY: + strcpy(c->callername, ""); + break; case Q931_SETUP: 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->slotmap = -1; c->chanflags = 0; @@ -1539,6 +1707,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len) c->callerpres = -1; strcpy(c->callernum, ""); 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; case Q931_CONNECT: case Q931_ALERTING: @@ -1565,13 +1740,13 @@ int q931_receive(struct pri *pri, q931_h *h, int len) case Q931_RESTART_ACKNOWLEDGE: c->channelno = -1; break; + case Q931_INFORMATION: + break; case Q931_SETUP_ACKNOWLEDGE: case Q931_STATUS_ENQUIRY: case Q931_USER_INFORMATION: case Q931_SEGMENT: case Q931_CONGESTION_CONTROL: - case Q931_INFORMATION: - case Q931_FACILITY: case Q931_NOTIFY: case Q931_HOLD: 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_ACKNOWLEDGE: 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; 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; } x = 0; @@ -1599,7 +1774,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len) ie = (q931_ie *)(mh->data + x); r = ielen(ie); 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; } 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.callingplan = c->callerplan; 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; 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.cref = c->cr; 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; q931_connect_acknowledge(pri, c); 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_CONNECT_ACKNOWLEDGE: case Q931_STATUS: /* Do nothing */ if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) && (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; case Q931_CALL_PROCEEDING: break; @@ -1693,26 +1882,32 @@ int q931_receive(struct pri *pri, q931_h *h, int len) return res; break; case Q931_DISCONNECT: - /* Send a release with no cause */ - q931_release(pri, c, -1); /* Return such an event */ pri->ev.e = PRI_EVENT_HANGUP; pri->ev.hangup.channel = c->channelno; pri->ev.hangup.cref = c->cr; pri->ev.hangup.cause = c->cause; pri->ev.hangup.call = c; + /* Send a release with no cause */ + q931_release(pri, c, -1); return Q931_RES_HAVEEVENT; case Q931_RESTART_ACKNOWLEDGE: pri->ev.e = PRI_EVENT_RESTART_ACK; pri->ev.restartack.channel = c->channelno; 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_STATUS_ENQUIRY: case Q931_USER_INFORMATION: case Q931_SEGMENT: case Q931_CONGESTION_CONTROL: - case Q931_INFORMATION: - case Q931_FACILITY: case Q931_NOTIFY: case Q931_HOLD: 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_ACKNOWLEDGE: 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; 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 0;