Index: pri_internal.h
===================================================================
RCS file: /usr/cvsroot/libpri/pri_internal.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- pri_internal.h 15 May 2003 19:35:05 -0000 1.2
+++ pri_internal.h 25 Sep 2003 06:13:14 -0000 1.3
@@ -58,6 +58,7 @@
int v_na; /* What we've told our peer we've acknowledged */
int solicitfbit; /* Have we sent an I or S frame with the F-bit set? */
int retrans; /* Retransmissions */
+ int sentrej; /* Are we in reject state */
-static void q921_ack_rx(struct pri *pri, int ack)
+static void reschedule_t203(struct pri *pri)
+{
+ if (pri->t203_timer) {
+ pri_schedule_del(pri, pri->t203_timer);
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message("-- Restarting T203 counter\n");
+ /* Nothing to transmit, start the T203 counter instead */
+ pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri);
+ }
+}
+
+static pri_event *q921_ack_rx(struct pri *pri, int ack)
{
int x;
int cnt=0;
+ pri_event *ev;
/* Make sure the ACK was within our window */
for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x));
if (x != ack) {
/* ACK was outside of our window --- ignore */
- pri_error("ACK received outside of window, ignoring\n");
- return;
+ pri_error("ACK received outside of window, restarting\n");
+ ev = q921_dchannel_down(pri);
+ q921_start(pri, 1);
+ pri->schedev = 1;
+ return ev;
}
/* Cancel each packet as necessary */
if (pri->debug & PRI_DEBUG_Q921_STATE)
@@ -216,9 +236,10 @@
/* Nothing to transmit, start the T203 counter instead */
pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri);
}
+ return NULL;
}
-static void q921_reject(struct pri *pri)
+static void q921_reject(struct pri *pri, int pf)
{
q921_h h;
Q921_INIT(h);
@@ -226,7 +247,7 @@
h.s.ss = 2; /* Reject */
h.s.ft = 1; /* Frametype (01) */
h.s.n_r = pri->v_r; /* Where to start retransmission */
- h.s.p_f = 1; /* XXX Should it always be set to 1? XXX */
+ h.s.p_f = pf;
switch(pri->localtype) {
case PRI_NETWORK:
h.h.c_r = 0;
@@ -240,10 +261,11 @@
}
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("Sending Reject (%d)\n", pri->v_r);
+ pri->sentrej = 1;
q921_transmit(pri, &h, 4);
}
-static void q921_rr(struct pri *pri, int pbit) {
+static void q921_rr(struct pri *pri, int pbit, int cmd) {
q921_h h;
Q921_INIT(h);
h.s.x0 = 0; /* Always 0 */
@@ -253,10 +275,16 @@
h.s.p_f = pbit; /* Poll/Final set appropriately */
switch(pri->localtype) {
case PRI_NETWORK:
- h.h.c_r = 0;
+ if (cmd)
+ h.h.c_r = 1;
+ else
+ h.h.c_r = 0;
break;
case PRI_CPE:
- h.h.c_r = 1;
+ if (cmd)
+ h.h.c_r = 0;
+ else
+ h.h.c_r = 1;
break;
default:
pri_error("Don't know how to U/A on a type %d node\n", pri->localtype);
@@ -268,8 +296,6 @@
q921_transmit(pri, &h, 4);
}
-static pri_event *q921_dchannel_down(struct pri *pri);
-
static void t200_expire(void *vpri)
{
struct pri *pri = vpri;
@@ -289,14 +315,17 @@
/* Reschedule t200_timer */
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("-- Retransmitting %d bytes\n", pri->txqueue->len);
- q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
+ if (pri->busy)
+ q921_rr(pri, 1, 0);
+ else
+ q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
if (pri->debug & PRI_DEBUG_Q921_STATE)
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)
pri_message("-- Timeout occured, restarting PRI\n");
- pri->state = Q921_LINK_CONNECTION_RELEASED;
+ pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
pri->t200_timer = 0;
q921_dchannel_down(pri);
q921_start(pri, 1);
@@ -344,8 +373,9 @@
else
pri->txqueue = f;
/* Immediately transmit unless we're in a recovery state */
- if (!pri->retrans)
+ if (!pri->retrans && !pri->busy) {
q921_transmit(pri, (q921_h *)(&f->h), f->len);
+ }
if (pri->t203_timer) {
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("Stopping T_203 timer\n");
@@ -370,47 +400,57 @@
static void t203_expire(void *vpri)
{
struct pri *pri = vpri;
- if (pri->debug & PRI_DEBUG_Q921_STATE)
- 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);
- /* Restart ourselves */
- pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri);
+ if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ 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, 1);
+ /* Restart ourselves */
+ pri->t203_timer = pri_schedule_event(pri, T_203, t203_expire, pri);
+ } else {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message("T203 counter expired in weird statd %d\n", pri->q921_state);
+ pri->t203_timer = 0;
+ }
}
static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
{
int res;
+ pri_event *ev;
/* Make sure this is a valid packet */
if (i->n_s == pri->v_r) {
/* Increment next expected I-frame */
Q921_INC(pri->v_r);
/* Handle their ACK */
- q921_ack_rx(pri, i->n_r);
+ pri->sentrej = 0;
+ ev = q921_ack_rx(pri, i->n_r);
+ if (ev)
+ return ev;
if (i->p_f) {
/* If the Poll/Final bit is set, immediate send the RR */
- q921_rr(pri, 1);
+ q921_rr(pri, 1, 0);
+ } else if (pri->busy) {
+ q921_rr(pri, 0, 0);
}
/* Receive Q.931 data */
res = q931_receive(pri, (q931_h *)i->data, len - 4);
/* Send an RR if one wasn't sent already */
if (pri->v_na != pri->v_r)
- q921_rr(pri, 0);
+ q921_rr(pri, 0, 0);
if (res == -1) {
return NULL;
}
if (res & Q931_RES_HAVEEVENT)
return &pri->ev;
} else {
- if (((pri->v_r - i->n_s) & 127) < pri->window) {
- /* It's within our window -- send back an RR */
- q921_rr(pri, 0);
- } else
- q921_reject(pri);
-#if 0
- q931_reject(pri);
-#endif
+ /* If we haven't already sent a reject, send it now, otherwise
+ we are obliged to RR */
+ if (!pri->sentrej)
+ q921_reject(pri, i->p_f);
+ else if (i->p_f)
+ q921_rr(pri, 1, 0);
}
return NULL;
}
@@ -553,6 +593,9 @@
pri_schedule_del(pri, pri->sabme_timer);
pri->sabme_timer = 0;
+ /* Reset any rejects */
+ pri->sentrej = 0;
+
/* Go into connection established state */
pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED;
@@ -592,13 +635,16 @@
pri->solicitfbit = 0;
pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
pri->retrans = 0;
+ pri->sentrej = 0;
+
/* Discard anything waiting to go out */
q921_discard_retransmissions(pri);
}
-pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
+static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
{
q921_frame *f;
+ pri_event *ev;
int sendnow;
/* Discard FCS */
len -= 2;
@@ -646,7 +692,9 @@
/* Receiver Ready */
pri->busy = 0;
/* Acknowledge frames as necessary */
- q921_ack_rx(pri, h->s.n_r);
+ ev = q921_ack_rx(pri, h->s.n_r);
+ if (ev)
+ return ev;
if (h->s.p_f) {
/* If it's a p/f one then send back a RR in return with the p/f bit set */
if (pri->solicitfbit) {
@@ -655,26 +703,28 @@
} else {
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("-- Unsolicited RR with P/F bit, responding\n");
- q921_rr(pri, 1);
+ q921_rr(pri, 1, 0);
}
pri->solicitfbit = 0;
}
break;
-#if 0
case 1:
/* Receiver not ready */
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message("-- Got receiver not ready\n");
+ if(h->s.p_f) {
+ /* Send RR if poll bit set */
+ q921_rr(pri, h->s.p_f, 0);
+ }
pri->busy = 1;
break;
-#endif
case 2:
/* Just retransmit */
if (pri->debug & PRI_DEBUG_Q921_STATE)
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);
+ q921_rr(pri, 1, 0);
}
sendnow = 0;
/* Resend the proper I-frame */
@@ -726,7 +776,6 @@
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)
pri_message("-- Got DM Mode from peer.\n");
/* Disconnected mode, try again after T200 */
@@ -752,7 +801,9 @@
pri_message("-- Got Disconnect from peer.\n");
/* Acknowledge */
q921_send_ua(pri, h->u.p_f);
- return q921_dchannel_down(pri);
+ ev = q921_dchannel_down(pri);
+ q921_start(pri, 0);
+ return ev;
case 3:
if (h->u.m2 == 3) {
/* SABME */
@@ -800,6 +851,14 @@
}
return NULL;
+}
+
+pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
+{
+ pri_event *e;
+ e = __q921_receive(pri, h, len);
+ reschedule_t203(pri);
+ return e;
}
+#define T_308 4000
+#define T_305 30000
+#define T_313 4000
+
struct q931_call {
+ struct pri *pri; /* PRI */
int cr; /* Call Reference */
int forceinvert; /* Force inversion of call number even if 0 */
q931_call *next;
@@ -220,6 +228,7 @@
int peercallstate; /* Call state of peer as reported */
int ourcallstate; /* Our call state */
+ int sugcallstate; /* Status call state */
int callerplan;
int callerpres; /* Caller presentation */
@@ -230,7 +239,10 @@
int nonisdn;
char callednum[256]; /* Called Number */
int complete; /* no more digits coming */
+ int newcall; /* if the received message has a new call reference value */
+ int retranstimer; /* Timer for retransmitting DISC */
+ int t308_timedout; /* Whether t308 timed out once */
int redirectingplan;
int redirectingpres;
int redirectingreason;
@@ -273,6 +285,7 @@
c->chanflags = 0;
c->next = NULL;
c->sentchannel = 0;
+ c->newcall = 1;
c->ourcallstate = Q931_CALL_STATE_NULL;
c->peercallstate = Q931_CALL_STATE_NULL;
}
@@ -908,7 +921,7 @@
static int transmit_display(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
- if (pri->switchtype != PRI_SWITCH_NI1) {
+ if ((pri->switchtype != PRI_SWITCH_NI1) && strlen(call->callername)) {
ie->data[0] = 0xb1;
memcpy(ie->data + 1, call->callername, strlen(call->callername));
return 3 + strlen(call->callername);
@@ -958,7 +971,7 @@
static int receive_call_state(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
{
- call->ourcallstate = ie->data[0] & 0x3f;
+ call->sugcallstate = ie->data[0] & 0x3f;
return 0;
}
@@ -1279,6 +1292,7 @@
call_init(cur);
/* Call reference */
cur->cr = cr;
+ cur->pri = pri;
/* Append to end of list */
if (prev)
prev->next = cur;
@@ -1318,6 +1332,8 @@
pri->calls = cur->next;
if (pri->debug & PRI_DEBUG_Q931_STATE)
pri_message("NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
+ if (cur->retranstimer)
+ pri_schedule_del(pri, cur->retranstimer);
free(cur);
return;
}
@@ -1478,21 +1494,24 @@
static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 };
-static int q931_status(struct pri *pri, q931_call *c)
+static int q931_status(struct pri *pri, q931_call *c, int cause)
{
q931_call *cur = NULL;
+ if (!cause)
+ cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY;
if (c->cr > -1)
cur = pri->calls;
while(cur) {
if (cur->cr == c->cr) {
- cur->cause=PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY;
+ cur->cause=cause;
cur->causecode = CODE_CCITT;
- cur->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ cur->causeloc = LOC_USER;
break;
}
cur = cur->next;
}
if (!cur) {
+ pri_message("YYY Here we get reset YYY\n");
/* something went wrong, respond with "no such call" */
c->ourcallstate = Q931_CALL_STATE_NULL;
c->peercallstate = Q931_CALL_STATE_NULL;
@@ -1575,6 +1594,47 @@
return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
}
+static void pri_connect_timeout(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *pri = c->pri;
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message("Timed out looking for connect acknowledge\n");
+ q931_disconnect(pri, c, PRI_CAUSE_NORMAL_CLEARING);
+
+}
+
+static void pri_release_timeout(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *pri = c->pri;
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message("Timed out looking for release complete\n");
+ c->t308_timedout++;
+ c->alive = 1;
+ q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
+}
+
+static void pri_release_finaltimeout(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *pri = c->pri;
+ c->alive = 1;
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message("Final time-out looking for release complete\n");
+ c->t308_timedout++;
+}
+
+static void pri_disconnect_timeout(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *pri = c->pri;
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message("Timed out looking for release\n");
+ c->alive = 1;
+ q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
+}
+
int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
{
if (channel)
@@ -1590,6 +1650,10 @@
c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
c->peercallstate = Q931_CALL_STATE_ACTIVE;
c->alive = 1;
+ /* Setup timer */
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = pri_schedule_event(pri, T_313, pri_connect_timeout, c);
return send_message(pri, c, Q931_CONNECT, connect_ies);
}
@@ -1604,9 +1668,16 @@
c->cause = cause;
c->causecode = CODE_CCITT;
c->causeloc = LOC_PRIV_NET_LOCAL_USER;
- if (c->acked)
+ if (c->acked) {
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ if (!c->t308_timedout) {
+ c->retranstimer = pri_schedule_event(pri, T_308, pri_release_timeout, c);
+ } else {
+ c->retranstimer = pri_schedule_event(pri, T_308, pri_release_finaltimeout, c);
+ }
return send_message(pri, c, Q931_RELEASE, release_ies);
- else
+ } else
return send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */
} else
return 0;
@@ -1643,6 +1714,9 @@
c->causecode = CODE_CCITT;
c->causeloc = LOC_PRIV_NET_LOCAL_USER;
c->sendhangupack = 1;
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = pri_schedule_event(pri, T_305, pri_disconnect_timeout, c);
return send_message(pri, c, Q931_DISCONNECT, disconnect_ies);
} else
return 0;
@@ -1669,7 +1743,7 @@
c->slotmap = -1;
c->ds1no = -1;
c->nonisdn = nonisdn;
-
+ c->newcall = 0;
if (exclusive)
c->chanflags = FLAG_EXCLUSIVE;
else
@@ -1803,11 +1877,15 @@
break;
case Q931_CALL_STATE_DISCONNECT_REQUEST:
/* sent DISCONNECT */
+ q931_release(pri,c,cause);
break;
case Q931_CALL_STATE_DISCONNECT_INDICATION:
/* received DISCONNECT */
- if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST)
+ if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) {
+ c->alive = 1;
q931_release(pri,c,cause);
+ }
+ break;
case Q931_CALL_STATE_RELEASE_REQUEST:
/* sent RELEASE */
/* don't do anything, waiting for RELEASE_COMPLETE */
@@ -1830,9 +1908,11 @@
q931_mh *mh;
q931_call *c;
q931_ie *ie;
- int x;
+ int x,y;
int res;
int r;
+ int mandies[MAX_MAND_IES];
+ int missingmand;
if (pri->debug & PRI_DEBUG_Q931_DUMP)
q931_dump(h, len, 0);
mh = (q931_mh *)(h->contents + h->crlen);
@@ -1898,8 +1978,12 @@
case Q931_PROGRESS:
c->progress = -1;
break;
- case Q931_CALL_PROCEEDING:
case Q931_CONNECT_ACKNOWLEDGE:
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = 0;
+ /* Fall through */
+ case Q931_CALL_PROCEEDING:
/* Do nothing */
break;
case Q931_RELEASE:
@@ -1907,12 +1991,19 @@
c->cause = -1;
c->causecode = -1;
c->causeloc = -1;
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = 0;
break;
case Q931_RELEASE_COMPLETE:
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = 0;
case Q931_STATUS:
c->cause = -1;
c->causecode = -1;
c->causeloc = -1;
+ c->sugcallstate = -1;
break;
case Q931_RESTART_ACKNOWLEDGE:
c->channelno = -1;
@@ -1923,10 +2014,11 @@
break;
case Q931_SETUP_ACKNOWLEDGE:
break;
+ case Q931_NOTIFY:
+ break;
case Q931_USER_INFORMATION:
case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL:
- case Q931_NOTIFY:
case Q931_HOLD:
case Q931_HOLD_ACKNOWLEDGE:
case Q931_HOLD_REJECT:
@@ -1940,29 +2032,57 @@
case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT:
pri_error("!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
- return -1;
-
+ /* Fall through */
default:
- pri_error("!! Don't know how to pre-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);
+ q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+ if (c->newcall)
+ q931_destroycall(pri,c->cr);
return -1;
}
+ memset(mandies, 0, sizeof(mandies));
+ missingmand = 0;
+ for (x=0;x<sizeof(msgs) / sizeof(msgs[0]); x++) {
+ if (msgs[x].msgnum == mh->msg) {
+ memcpy(mandies, msgs[x].mandies, sizeof(mandies));
+ }
+ }
x = 0;
/* Do real IE processing */
len -= (h->crlen + 3);
while(len) {
ie = (q931_ie *)(mh->data + x);
+ for (y=0;y<MAX_MAND_IES;y++) {
+ if (mandies[y] == ie->ie)
+ mandies[y] = 0;
+ }
r = ielen(ie);
if (r > len) {
pri_error("XXX Message longer than it should be?? XXX\n");
return -1;
}
- q931_handle_ie(pri, c, mh->msg, ie);
+ y = q931_handle_ie(pri, c, mh->msg, ie);
+ if (!(ie->ie & 0xf0) && (y < 0))
+ mandies[MAX_MAND_IES - 1] = ie->ie;
x += r;
len -= r;
}
+ missingmand = 0;
+ for (x=0;x<MAX_MAND_IES;x++) {
+ if (mandies[x]) {
+ pri_error("XXX Missing mandatory IE %d/%s XXX\n", mandies[x], ie2str(mandies[x]));
+ missingmand++;
+ }
+ }
+
/* Post handling */
switch(mh->msg) {
case Q931_RESTART:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ q931_destroycall(pri, c->cr);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_RESTART;
c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
/* Send back the Restart Acknowledge */
@@ -1972,6 +2092,15 @@
pri->ev.restart.channel = c->channelno;
return Q931_RES_HAVEEVENT;
case Q931_SETUP:
+ if (missingmand) {
+ q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ break;
+ }
+ /* Must be new call */
+ if (!c->newcall) {
+ break;
+ }
+ c->newcall = 0;
c->ourcallstate = Q931_CALL_STATE_CALL_PRESENT;
c->peercallstate = Q931_CALL_STATE_CALL_INITIATED;
/* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
@@ -1992,11 +2121,15 @@
pri->ev.ring.layer1 = c->userl1;
pri->ev.ring.complete = c->complete;
if (c->transmoderate != TRANS_MODE_64_CIRCUIT) {
- q931_release(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
+ q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
break;
}
return Q931_RES_HAVEEVENT;
case Q931_ALERTING:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
pri->ev.e = PRI_EVENT_RINGING;
@@ -2005,6 +2138,14 @@
pri->ev.ringing.call = c;
return Q931_RES_HAVEEVENT;
case Q931_CONNECT:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) {
+ q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
pri->ev.e = PRI_EVENT_ANSWER;
@@ -2014,6 +2155,10 @@
q931_connect_acknowledge(pri, c);
return Q931_RES_HAVEEVENT;
case Q931_FACILITY:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
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);
@@ -2025,22 +2170,79 @@
#endif
return Q931_RES_HAVEEVENT;
case Q931_PROGRESS:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ q931_destroycall(pri, c->cr);
+ break;
+ }
+ /* Fall through */
case Q931_CALL_PROCEEDING:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) &&
+ (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING)) {
+ q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
pri->ev.e = PRI_EVENT_PROCEEDING;
pri->ev.proceeding.channel = c->channelno;
- c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
- c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
+ if (mh->msg == Q931_CALL_PROCEEDING) {
+ c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
+ c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
+ }
return Q931_RES_HAVEEVENT;
case Q931_CONNECT_ACKNOWLEDGE:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if (c->ourcallstate != Q931_CALL_STATE_CONNECT_REQUEST) {
+ q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
c->peercallstate = Q931_CALL_STATE_ACTIVE;
break;
case Q931_STATUS:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ q931_destroycall(pri, c->cr);
+ break;
+ }
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
/* Do nothing */
- /* FIXME if the callstate != ourcallstate send RELEASE */
+ /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */
if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) &&
- (c->cause != PRI_CAUSE_INTERWORKING))
+ (c->cause != PRI_CAUSE_INTERWORKING))
pri_error("Received unsolicited status: %s\n", pri_cause2str(c->cause));
+ if (!c->sugcallstate) {
+ pri->ev.hangup.channel = c->channelno;
+ pri->ev.hangup.cref = c->cr;
+ pri->ev.hangup.cause = c->cause;
+ pri->ev.hangup.call = c;
+ /* Free resources */
+ c->ourcallstate = Q931_CALL_STATE_NULL;
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ if (c->alive) {
+ pri->ev.e = PRI_EVENT_HANGUP;
+ res = Q931_RES_HAVEEVENT;
+ c->alive = 0;
+ } else if (c->sendhangupack) {
+ res = Q931_RES_HAVEEVENT;
+ pri->ev.e = PRI_EVENT_HANGUP_ACK;
+ q931_hangup(pri, c, c->cause);
+ } else {
+ q931_hangup(pri, c, c->cause);
+ res = 0;
+ }
+ if (res)
+ return res;
+ }
break;
case Q931_RELEASE_COMPLETE:
c->ourcallstate = Q931_CALL_STATE_NULL;
@@ -2066,15 +2268,37 @@
q931_hangup(pri,c,c->cause);
break;
case Q931_RELEASE:
+ if (missingmand) {
+ q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ break;
+ }
+ if (c->ourcallstate == Q931_CALL_STATE_RELEASE_REQUEST)
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ else {
+ c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST;
+ }
c->ourcallstate = Q931_CALL_STATE_NULL;
- c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST;
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;
- return Q931_RES_HAVEEVENT;
+ /* Don't send release complete if they send us release
+ while we sent it, assume a NULL state */
+ if (c->newcall)
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ else
+ return Q931_RES_HAVEEVENT;
+ break;
case Q931_DISCONNECT:
+ if (missingmand) {
+ q931_release(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ break;
+ }
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
c->sendhangupack = 1;
@@ -2084,10 +2308,6 @@
pri->ev.hangup.cref = c->cr;
pri->ev.hangup.cause = c->cause;
pri->ev.hangup.call = c;
-#if 0 /* Require the user app to call release */
- /* Send a release with no cause */
- q931_release(pri, c, -1);
-#endif
if (c->alive)
return Q931_RES_HAVEEVENT;
else
@@ -2104,6 +2324,10 @@
overlap dialing received digit
+ the "Complete" msg which is basically an EOF on further digits
XXX */
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
if (c->ourcallstate!=Q931_CALL_STATE_OVERLAP_RECEIVING)
break;
pri->ev.e = PRI_EVENT_INFO_RECEIVED;
@@ -2112,19 +2336,29 @@
strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
return Q931_RES_HAVEEVENT;
+ break;
case Q931_STATUS_ENQUIRY:
- q931_status(pri,c);
+ if (c->newcall) {
+ q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
+ } else
+ q931_status(pri,c, 0);
break;
case Q931_SETUP_ACKNOWLEDGE:
+ if (c->newcall) {
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
c->ourcallstate = Q931_CALL_STATE_OVERLAP_SENDING;
c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
pri->ev.e = PRI_EVENT_SETUP_ACK;
pri->ev.setup_ack.channel = c->channelno;
return Q931_RES_HAVEEVENT;
+ case Q931_NOTIFY:
+ /* Do nothing */
+ break;
case Q931_USER_INFORMATION:
case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL:
- case Q931_NOTIFY:
case Q931_HOLD:
case Q931_HOLD_ACKNOWLEDGE:
case Q931_HOLD_REJECT:
@@ -2138,10 +2372,13 @@
case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT:
pri_error("!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
- return -1;
-
+ /* Fall through */
default:
+
pri_error("!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+ if (c->newcall)
+ q931_destroycall(pri,c->cr);
return -1;
}
return 0;
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum