From 183cd86a8db7188a716aa573f6ae6d7bece2ec2f Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Mon, 30 Aug 2010 22:34:43 +0000 Subject: [PATCH] Merged revisions 1923,1928-1929 via svnmerge from https://origsvn.digium.com/svn/libpri/branches/1.4 ........ r1923 | rmudgett | 2010-08-30 14:31:46 -0500 (Mon, 30 Aug 2010) | 18 lines Q.921 improvements from comparing Q.921 SDL diagrams with implementation. * Handle sending and receiving DM response frames as needed. * Added handling of received FRMR frames. * Completed implementation of Q921_AWAITING_RELEASE state. (State is currently unreachable since we have no API to initiate sending the DISC message.) * Better NT PTMP TEI allocation. * Reduced more ERROR level severity messages so users will stop panicking when they see ERROR. This is especially true for the Q.921 MDL-ERROR messages. * Added better Q.921 visibility when normal debug message level is enabled. ........ r1928 | rmudgett | 2010-08-30 15:30:59 -0500 (Mon, 30 Aug 2010) | 9 lines Q.921/Q.931 message debug output improvements. The Q.931 message decode debug output now will follow the correct Q.921 header decode if Q.921 message dumping is enabled. Also the Q.931 message decode will happen when the message actually goes out on the line instead of when Q.931 passes the message to Q.921. Q.921 may have to request a TEI, bring the connection up, or retransmit previous frames before it can actually send the new message. ........ r1929 | rmudgett | 2010-08-30 15:49:11 -0500 (Mon, 30 Aug 2010) | 2 lines Reduced fake MDL-ERROR (Z) message severity to be visible only when debugging enabled. ........ git-svn-id: https://origsvn.digium.com/svn/libpri/tags/1.4.11.4@1949 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- q921.c | 854 +++++++++++++++++++++++++++++++++++++-------------------- q931.c | 143 +++++++--- 2 files changed, 657 insertions(+), 340 deletions(-) diff --git a/q921.c b/q921.c index f745265..d1c11c4 100644 --- a/q921.c +++ b/q921.c @@ -43,10 +43,7 @@ * Define RANDOM_DROPS To randomly drop packets in order to simulate loss for testing * retransmission functionality */ - -/* -#define RANDOM_DROPS -*/ +//#define RANDOM_DROPS 1 #define Q921_INIT(ctrl, hf) do { \ memset(&(hf),0,sizeof(hf)); \ @@ -130,11 +127,12 @@ static void q921_setstate(struct pri *ctrl, int newstate) ctrl->q921_state = newstate; } -static void q921_discard_retransmissions(struct pri *ctrl) +static void q921_discard_iqueue(struct pri *ctrl) { struct q921_frame *f, *p; + f = ctrl->txqueue; - while(f) { + while (f) { p = f; f = f->next; /* Free frame */ @@ -143,11 +141,6 @@ static void q921_discard_retransmissions(struct pri *ctrl) ctrl->txqueue = NULL; } -static void q921_discard_iqueue(struct pri *ctrl) -{ - q921_discard_retransmissions(ctrl); -} - static int q921_transmit(struct pri *ctrl, q921_h *h, int len) { int res; @@ -190,8 +183,9 @@ static void q921_send_tei(struct pri *ctrl, int message, int ri, int ai, int isc f->data[2] = ri & 0xff; f->data[3] = message; f->data[4] = (ai << 1) | 1; - if (ctrl->debug & PRI_DEBUG_Q921_STATE) + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { pri_message(ctrl, "Sending TEI management message %d, TEI=%d\n", message, ai); + } q921_transmit(ctrl, (q921_h *)f, 8); free(f); } @@ -241,13 +235,14 @@ static void q921_tei_request(struct pri *ctrl) t202_expire(ctrl); } -static void q921_send_ua(struct pri *ctrl, int pfbit) +static void q921_send_dm(struct pri *ctrl, int fbit) { q921_h h; + Q921_INIT(ctrl, h); - h.u.m3 = 3; /* M3 = 3 */ - h.u.m2 = 0; /* M2 = 0 */ - h.u.p_f = pfbit; /* Final bit on */ + h.u.m3 = 0; /* M3 = 0 */ + h.u.m2 = 3; /* M2 = 3 */ + h.u.p_f = fbit; /* Final set appropriately */ h.u.ft = Q921_FRAMETYPE_U; switch(ctrl->localtype) { case PRI_NETWORK: @@ -257,11 +252,63 @@ static void q921_send_ua(struct pri *ctrl, int pfbit) h.h.c_r = 1; break; default: - pri_error(ctrl, "Don't know how to U/A on a type %d node\n", ctrl->localtype); + pri_error(ctrl, "Don't know how to DM on a type %d node\n", ctrl->localtype); return; } - if (ctrl->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) - pri_message(ctrl, "Sending Unnumbered Acknowledgement\n"); + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending DM\n", ctrl->tei); + } + q921_transmit(ctrl, &h, 4); +} + +static void q921_send_disc(struct pri *ctrl, int pbit) +{ + q921_h h; + + Q921_INIT(ctrl, h); + h.u.m3 = 2; /* M3 = 2 */ + h.u.m2 = 0; /* M2 = 0 */ + h.u.p_f = pbit; /* Poll set appropriately */ + h.u.ft = Q921_FRAMETYPE_U; + switch(ctrl->localtype) { + case PRI_NETWORK: + h.h.c_r = 0; + break; + case PRI_CPE: + h.h.c_r = 1; + break; + default: + pri_error(ctrl, "Don't know how to DISC on a type %d node\n", ctrl->localtype); + return; + } + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending DISC\n", ctrl->tei); + } + q921_transmit(ctrl, &h, 4); +} + +static void q921_send_ua(struct pri *ctrl, int fbit) +{ + q921_h h; + Q921_INIT(ctrl, h); + h.u.m3 = 3; /* M3 = 3 */ + h.u.m2 = 0; /* M2 = 0 */ + h.u.p_f = fbit; /* Final set appropriately */ + h.u.ft = Q921_FRAMETYPE_U; + switch(ctrl->localtype) { + case PRI_NETWORK: + h.h.c_r = 0; + break; + case PRI_CPE: + h.h.c_r = 1; + break; + default: + pri_error(ctrl, "Don't know how to UA on a type %d node\n", ctrl->localtype); + return; + } + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending UA\n", ctrl->tei); + } q921_transmit(ctrl, &h, 3); } @@ -282,9 +329,12 @@ static void q921_send_sabme(struct pri *ctrl) h.h.c_r = 0; break; default: - pri_error(ctrl, "Don't know how to U/A on a type %d node\n", ctrl->localtype); + pri_error(ctrl, "Don't know how to SABME on a type %d node\n", ctrl->localtype); return; } + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending SABME\n", ctrl->tei); + } q921_transmit(ctrl, &h, 3); } @@ -297,9 +347,13 @@ static void q921_send_sabme_now(void *vpri) static int q921_ack_packet(struct pri *ctrl, int num) { - struct q921_frame *f, *prev = NULL; - f = ctrl->txqueue; - while (f) { + struct q921_frame *f; + struct q921_frame *prev; + + for (prev = NULL, f = ctrl->txqueue; f; prev = f, f = f->next) { + if (!f->transmitted) { + break; + } if (f->h.n_s == num) { /* Cancel each packet as necessary */ /* That's our packet */ @@ -307,14 +361,20 @@ static int q921_ack_packet(struct pri *ctrl, int num) prev->next = f->next; else ctrl->txqueue = f->next; - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, ctrl->txqueue ? ctrl->txqueue->h.n_s : -1); + if (ctrl->debug & PRI_DEBUG_Q921_DUMP) { + pri_message(ctrl, + "-- ACKing N(S)=%d, txqueue head is N(S)=%d (-1 is empty, -2 is not transmitted)\n", + f->h.n_s, + ctrl->txqueue + ? ctrl->txqueue->transmitted + ? ctrl->txqueue->h.n_s + : -2 + : -1); + } /* Update v_a */ free(f); return 1; } - prev = f; - f = f->next; } return 0; } @@ -414,40 +474,73 @@ static int q921_send_queued_iframes(struct pri *ctrl) struct q921_frame *f; int frames_txd = 0; - if (ctrl->peer_rx_busy || (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) { - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "Couldn't transmit I-frame at this time due to peer busy condition or window shut\n"); + for (f = ctrl->txqueue; f; f = f->next) { + if (!f->transmitted) { + /* This frame has not been sent yet. */ + break; + } + } + if (!f) { + /* The Tx queue has no pending frames. */ return 0; } - f = ctrl->txqueue; - while (f && (ctrl->v_s != Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) { - if (!f->transmitted) { - /* Send it now... */ - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, ctrl->timers[PRI_TIMER_K]); - f->transmitted++; - - /* - * Send the frame out on the assigned TEI. - * Done now because the frame may have been queued before we - * had an assigned TEI. - */ - f->h.h.tei = ctrl->tei; - - f->h.n_s = ctrl->v_s; - f->h.n_r = ctrl->v_r; - f->h.ft = 0; - f->h.p_f = 0; - q921_transmit(ctrl, (q921_h *)(&f->h), f->len); - Q921_INC(ctrl->v_s); - frames_txd++; - ctrl->acknowledge_pending = 0; + if (ctrl->peer_rx_busy + || (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) { + /* Don't flood debug trace if not really looking at Q.921 layer. */ + if (ctrl->debug & (/* PRI_DEBUG_Q921_STATE | */ PRI_DEBUG_Q921_DUMP)) { + pri_message(ctrl, + "TEI=%d Couldn't transmit I-frame at this time due to peer busy condition or window shut\n", + ctrl->tei); + } + return 0; + } + + /* Send all pending frames that fit in the window. */ + for (; f; f = f->next) { + if (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K])) { + /* The window is no longer open. */ + break; + } + + /* Send it now... */ + ++f->transmitted; + + /* + * Send the frame out on the assigned TEI. + * Done now because the frame may have been queued before we + * had an assigned TEI. + */ + f->h.h.tei = ctrl->tei; + + f->h.n_s = ctrl->v_s; + f->h.n_r = ctrl->v_r; + f->h.ft = 0; + f->h.p_f = 0; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, + "TEI=%d Transmitting N(S)=%d, window is open V(A)=%d K=%d\n", + ctrl->tei, f->h.n_s, ctrl->v_a, ctrl->timers[PRI_TIMER_K]); + } + q921_transmit(ctrl, (q921_h *)(&f->h), f->len); + Q921_INC(ctrl->v_s); + ++frames_txd; + + if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { + /* + * The transmit operation might dump the Q.921 header, so logging + * the Q.931 message body after the transmit puts the sections of + * the message in the right order in the log. + * + * Also the dump is done here so the Q.931 part is decoded only + * once instead of for every retransmission. + */ + q931_dump(ctrl, ctrl->tei, (q931_h *) f->h.data, f->len - 4, 1); } - f = f->next; } if (frames_txd) { + ctrl->acknowledge_pending = 0; if (!ctrl->t200_timer) { stop_t203(ctrl); start_t200(ctrl); @@ -460,6 +553,7 @@ static int q921_send_queued_iframes(struct pri *ctrl) static void q921_reject(struct pri *ctrl, int pf) { q921_h h; + Q921_INIT(ctrl, h); h.s.x0 = 0; /* Always 0 */ h.s.ss = 2; /* Reject */ @@ -474,16 +568,19 @@ static void q921_reject(struct pri *ctrl, int pf) h.h.c_r = 1; break; default: - pri_error(ctrl, "Don't know how to U/A on a type %d node\n", ctrl->localtype); + pri_error(ctrl, "Don't know how to REJ on a type %d node\n", ctrl->localtype); return; } - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "Sending Reject (%d)\n", ctrl->v_r); + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending REJ N(R)=%d\n", ctrl->tei, ctrl->v_r); + } q921_transmit(ctrl, &h, 4); } -static void q921_rr(struct pri *ctrl, int pbit, int cmd) { +static void q921_rr(struct pri *ctrl, int pbit, int cmd) +{ q921_h h; + Q921_INIT(ctrl, h); h.s.x0 = 0; /* Always 0 */ h.s.ss = 0; /* Receive Ready */ @@ -504,11 +601,14 @@ static void q921_rr(struct pri *ctrl, int pbit, int cmd) { h.h.c_r = 1; break; default: - pri_error(ctrl, "Don't know how to U/A on a type %d node\n", ctrl->localtype); + pri_error(ctrl, "Don't know how to RR on a type %d node\n", ctrl->localtype); return; } - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "Sending Receiver Ready (%d)\n", ctrl->v_r); +#if 0 /* Don't flood debug trace with RR if not really looking at Q.921 layer. */ + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Sending RR N(R)=%d\n", ctrl->tei, ctrl->v_r); + } +#endif q921_transmit(ctrl, &h, 4); } @@ -555,7 +655,6 @@ static void t200_expire(void *vpri) #endif ctrl->RC++; } else { - //pri_error(ctrl, "MDL-ERROR (I): T200 = N200 in timer recovery state\n"); q921_mdl_error(ctrl, 'I'); q921_establish_data_link(ctrl); ctrl->l3initiated = 0; @@ -569,16 +668,26 @@ static void t200_expire(void *vpri) start_t200(ctrl); } else { q921_discard_iqueue(ctrl); - //pri_error(ctrl, "MDL-ERROR (G) : T200 expired N200 times in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); q921_mdl_error(ctrl, 'G'); q921_setstate(ctrl, Q921_TEI_ASSIGNED); /* DL-RELEASE indication */ q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); } break; + case Q921_AWAITING_RELEASE: + if (ctrl->RC != ctrl->timers[PRI_TIMER_N200]) { + ++ctrl->RC; + q921_send_disc(ctrl, 1); + start_t200(ctrl); + } else { + q921_mdl_error(ctrl, 'H'); + /* DL-RELEASE confirm */ + q921_setstate(ctrl, Q921_TEI_ASSIGNED); + } + break; default: - pri_error(ctrl, "Cannot handle T200 expire in state %d(%s)\n", + /* Looks like someone forgot to stop the T200 timer. */ + pri_error(ctrl, "T200 expired in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); break; } @@ -614,7 +723,7 @@ int q921_transmit_uiframe(struct pri *ctrl, void *buf, int len) h->h.c_r = 0; break; default: - pri_error(ctrl, "Don't know how to U/A on a type %d node\n", ctrl->localtype); + pri_error(ctrl, "Don't know how to UI-frame on a type %d node\n", ctrl->localtype); return -1; } @@ -719,17 +828,20 @@ int q921_transmit_iframe(struct pri *vpri, int tei, void *buf, int len, int cr) ctrl->txqueue = f; if (ctrl->q921_state != Q921_MULTI_FRAME_ESTABLISHED) { - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) { + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { pri_message(ctrl, - "Just queued I-frame since not in state %d(%s)\n", - Q921_MULTI_FRAME_ESTABLISHED, q921_state2str(Q921_MULTI_FRAME_ESTABLISHED)); + "TEI=%d Just queued I-frame since in state %d(%s)\n", + ctrl->tei, + ctrl->q921_state, q921_state2str(ctrl->q921_state)); } return 0; } if (ctrl->peer_rx_busy || (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) { - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) { - pri_message(ctrl, "Just queued I-frame due to peer busy condition or window shut\n"); + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, + "TEI=%d Just queued I-frame due to peer busy condition or window shut\n", + ctrl->tei); } return 0; } @@ -755,9 +867,12 @@ int q921_transmit_iframe(struct pri *vpri, int tei, void *buf, int len, int cr) static void t203_expire(void *vpri) { struct pri *ctrl = vpri; + if (ctrl->debug & PRI_DEBUG_Q921_DUMP) pri_message(ctrl, "%s\n", __FUNCTION__); + ctrl->t203_timer = 0; + switch (ctrl->q921_state) { case Q921_MULTI_FRAME_ESTABLISHED: transmit_enquiry(ctrl); @@ -765,22 +880,21 @@ static void t203_expire(void *vpri) q921_setstate(ctrl, Q921_TIMER_RECOVERY); break; default: - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "T203 counter expired in weird state %d(%s)\n", - ctrl->q921_state, q921_state2str(ctrl->q921_state)); - ctrl->t203_timer = 0; + /* Looks like someone forgot to stop the T203 timer. */ + pri_error(ctrl, "T203 expired in state %d(%s)\n", + ctrl->q921_state, q921_state2str(ctrl->q921_state)); break; } } -static void q921_dump_iqueue_info(struct pri *ctrl, int force) +static void q921_dump_iqueue_info(struct pri *ctrl) { struct q921_frame *f; int pending = 0, unacked = 0; unacked = pending = 0; - for (f = ctrl->txqueue; f && f->next; f = f->next) { + for (f = ctrl->txqueue; f; f = f->next) { if (f->transmitted) { unacked++; } else { @@ -788,10 +902,7 @@ static void q921_dump_iqueue_info(struct pri *ctrl, int force) } } - if (force) - pri_error(ctrl, "Number of pending packets %d, sent but unacked %d\n", pending, unacked); - - return; + pri_error(ctrl, "Number of pending packets %d, sent but unacked %d\n", pending, unacked); } static void q921_dump_pri_by_h(struct pri *ctrl, char direction_tag, q921_h *h); @@ -972,8 +1083,8 @@ static void q921_dump_pri(struct pri *ctrl, char direction_tag) { pri_message(ctrl, "%c TEI: %d State %d(%s)\n", direction_tag, ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); - pri_message(ctrl, "%c V(S)=%d, V(A)=%d, V(R)=%d\n", - direction_tag, ctrl->v_s, ctrl->v_a, ctrl->v_r); + pri_message(ctrl, "%c V(A)=%d, V(S)=%d, V(R)=%d\n", + direction_tag, ctrl->v_a, ctrl->v_s, ctrl->v_r); pri_message(ctrl, "%c K=%d, RC=%d, l3initiated=%d, reject_except=%d, ack_pend=%d\n", direction_tag, ctrl->timers[PRI_TIMER_K], ctrl->RC, ctrl->l3initiated, ctrl->reject_exception, ctrl->acknowledge_pending); @@ -1004,17 +1115,18 @@ static void q921_dump_pri_by_h(struct pri *vpri, char direction_tag, q921_h *h) static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len) { int ri; - struct pri *sub = ctrl; + struct pri *sub; pri_event *res = NULL; int tei; if (!BRI_NT_PTMP(ctrl) && !BRI_TE_PTMP(ctrl)) { - pri_error(ctrl, "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n"); - return NULL; + return pri_mkerror(ctrl, + "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n"); } - if (ctrl->debug & PRI_DEBUG_Q921_STATE) + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { pri_message(ctrl, "Received MDL message\n"); + } if (h->data[0] != 0x0f) { pri_error(ctrl, "Received MDL with unsupported management entity %02x\n", h->data[0]); return NULL; @@ -1032,31 +1144,38 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len) return NULL; } - if (tei != 127) { + if (tei != Q921_TEI_GROUP) { pri_error(ctrl, "Received TEI identity request with invalid TEI %d\n", tei); q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1); - } - tei = 64; - while (sub->subchannel) { - if (sub->subchannel->tei == tei) - ++tei; - sub = sub->subchannel; - } - - if (tei >= Q921_TEI_GROUP) { - pri_error(ctrl, "Reached maximum TEI quota, cannot assign new TEI\n"); return NULL; } + + /* Find a TEI that is not allocated. */ + tei = 64; + do { + for (sub = ctrl; sub->subchannel; sub = sub->subchannel) { + if (sub->subchannel->tei == tei) { + /* This TEI is already assigned, try next one. */ + ++tei; + if (tei < Q921_TEI_GROUP) { + break; + } + /* XXX : TODO later sometime: Implement the TEI check procedure to reclaim some dead TEIs. */ + pri_error(ctrl, "Reached maximum TEI quota, cannot assign new TEI\n"); + return NULL; + } + } + } while (sub->subchannel); + + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "Allocating new TEI %d\n", tei); + } sub->subchannel = __pri_new_tei(-1, ctrl->localtype, ctrl->switchtype, ctrl, NULL, NULL, NULL, tei, 1); - if (!sub->subchannel) { pri_error(ctrl, "Unable to allocate D-channel for new TEI %d\n", tei); return NULL; } q921_setstate(sub->subchannel, Q921_TEI_ASSIGNED); - if (ctrl->debug & PRI_DEBUG_Q921_STATE) { - pri_message(ctrl, "Allocating new TEI %d\n", tei); - } q921_send_tei(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1); break; case Q921_TEI_IDENTITY_ASSIGNED: @@ -1082,7 +1201,11 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len) pri_schedule_del(ctrl, ctrl->t202_timer); ctrl->t202_timer = 0; + ctrl->tei = tei; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "Got assigned TEI %d\n", tei); + } switch (ctrl->q921_state) { case Q921_ASSIGN_AWAITING_TEI: @@ -1098,22 +1221,22 @@ static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len) res = &ctrl->ev; break; default: - pri_error(ctrl, "Error 3\n"); - return NULL; + break; } - break; case Q921_TEI_IDENTITY_CHECK_REQUEST: if (!BRI_TE_PTMP(ctrl)) return NULL; - if (ctrl->subchannel->q921_state < Q921_TEI_ASSIGNED) + if (ctrl->subchannel->q921_state < Q921_TEI_ASSIGNED) { + /* We do not have a TEI. */ return NULL; + } /* If it's addressed to the group TEI or to our TEI specifically, we respond */ - if ((tei == Q921_TEI_GROUP) || (tei == ctrl->subchannel->tei)) + if ((tei == Q921_TEI_GROUP) || (tei == ctrl->subchannel->tei)) { q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, ctrl->subchannel->tei, 1); - + } break; case Q921_TEI_IDENTITY_REMOVE: if (!BRI_TE_PTMP(ctrl)) @@ -1165,8 +1288,6 @@ static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h) /* Send Unnumbered Acknowledgement */ q921_send_ua(ctrl, h->u.p_f); q921_clear_exception_conditions(ctrl); - //pri_error(ctrl, "MDL-ERROR (F), SABME in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); q921_mdl_error(ctrl, 'F'); if (ctrl->v_s != ctrl->v_a) { q921_discard_iqueue(ctrl); @@ -1195,6 +1316,8 @@ static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h) q921_send_ua(ctrl, h->u.p_f); break; case Q921_AWAITING_RELEASE: + q921_send_dm(ctrl, h->u.p_f); + break; default: pri_error(ctrl, "Cannot handle SABME in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); @@ -1208,7 +1331,15 @@ static pri_event *q921_disc_rx(struct pri *ctrl, q921_h *h) { pri_event * res = NULL; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got DISC\n", ctrl->tei); + } + switch (ctrl->q921_state) { + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + q921_send_dm(ctrl, h->u.p_f); + break; case Q921_AWAITING_RELEASE: q921_send_ua(ctrl, h->u.p_f); break; @@ -1218,7 +1349,6 @@ static pri_event *q921_disc_rx(struct pri *ctrl, q921_h *h) q921_send_ua(ctrl, h->u.p_f); /* DL-RELEASE Indication */ q931_dl_indication(ctrl, PRI_EVENT_DCHAN_DOWN); - stop_t200(ctrl); if (ctrl->q921_state == Q921_MULTI_FRAME_ESTABLISHED) stop_t203(ctrl); @@ -1238,6 +1368,9 @@ static void q921_mdl_remove(struct pri *ctrl) { int mdl_free_me; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "MDL-REMOVE: Removing TEI %d\n", ctrl->tei); + } if (BRI_NT_PTMP(ctrl)) { if (ctrl == PRI_MASTER(ctrl)) { pri_error(ctrl, "Bad bad bad! Cannot MDL-REMOVE master\n"); @@ -1288,6 +1421,12 @@ static void q921_mdl_remove(struct pri *ctrl) return; } + /* + * Negate the TEI value so debug messages will display a + * negated TEI when it is actually unassigned. + */ + ctrl->tei = -ctrl->tei; + ctrl->mdl_free_me = mdl_free_me; } @@ -1307,6 +1446,9 @@ static int q921_mdl_handle_network_error(struct pri *ctrl, char error) case 'E': case 'F': case 'I': + case 'J': + case 'K': + break; default: pri_error(ctrl, "Network MDL can't handle error of type %c\n", error); break; @@ -1332,6 +1474,8 @@ static int q921_mdl_handle_cpe_error(struct pri *ctrl, char error) case 'E': case 'F': case 'I': + case 'J': + case 'K': break; default: pri_error(ctrl, "CPE MDL can't handle error of type %c\n", error); @@ -1363,6 +1507,17 @@ static int q921_mdl_handle_ptp_error(struct pri *ctrl, char error) handled = 1; break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'H': + case 'I': + case 'J': + case 'K': + break; default: pri_error(ctrl, "PTP MDL can't handle error of type %c\n", error); break; @@ -1380,56 +1535,15 @@ static void q921_restart_ptp_link_if_needed(struct pri *ctrl) static void q921_mdl_handle_error(struct pri *ctrl, char error, int errored_state) { - int handled = 0; if (PTP_MODE(ctrl)) { - handled = q921_mdl_handle_ptp_error(ctrl, error); + q921_mdl_handle_ptp_error(ctrl, error); } else { if (ctrl->localtype == PRI_NETWORK) { - handled = q921_mdl_handle_network_error(ctrl, error); + q921_mdl_handle_network_error(ctrl, error); } else { - handled = q921_mdl_handle_cpe_error(ctrl, error); + q921_mdl_handle_cpe_error(ctrl, error); } } - - if (handled) - return; - - switch (error) { - case 'C': - pri_error(ctrl, "MDL-ERROR (C): UA in state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'D': - pri_error(ctrl, "MDL-ERROR (D): UA in state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'A': - pri_error(ctrl, "MDL-ERROR (A): Got supervisory frame with p_f bit set to 1 in state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'I': - pri_error(ctrl, "MDL-ERROR (I): T200 = N200 in timer recovery state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'G': - pri_error(ctrl, "MDL-ERROR (G) : T200 expired N200 times in state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'F': - pri_error(ctrl, "MDL-ERROR (F), SABME in state %d(%s)\n", - errored_state, q921_state2str(errored_state)); - break; - case 'H': - case 'B': - case 'E': - case 'J': - default: - pri_error(ctrl, "MDL-ERROR (%c) in state %d(%s)\n", error, - errored_state, q921_state2str(errored_state)); - break; - } - - return; } static void q921_mdl_handle_error_callback(void *vpri) @@ -1458,12 +1572,12 @@ static void q921_mdl_handle_error_callback(void *vpri) } if (freep == NULL) { - pri_error(ctrl, "Huh!? no match found in list for TEI %d\n", ctrl->tei); + pri_error(ctrl, "Huh!? no match found in list for TEI %d\n", -ctrl->tei); return; } if (ctrl->debug & PRI_DEBUG_Q921_STATE) { - pri_message(ctrl, "Freeing TEI of %d\n", freep->tei); + pri_message(ctrl, "Freeing TEI of %d\n", -freep->tei); } __pri_free_tei(freep); @@ -1474,8 +1588,105 @@ static void q921_mdl_handle_error_callback(void *vpri) static void q921_mdl_error(struct pri *ctrl, char error) { + int is_debug_q921_state; + + /* Log the MDL-ERROR event when detected. */ + is_debug_q921_state = (ctrl->debug & PRI_DEBUG_Q921_STATE); + switch (error) { + case 'A': + pri_message(ctrl, + "TEI=%d MDL-ERROR (A): Got supervisory frame with F=1 in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; + case 'B': + case 'E': + pri_message(ctrl, "TEI=%d MDL-ERROR (%c): DM (F=%c) in state %d(%s)\n", + ctrl->tei, error, (error == 'B') ? '1' : '0', + ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; + case 'C': + case 'D': + if (is_debug_q921_state || PTP_MODE(ctrl)) { + pri_message(ctrl, "TEI=%d MDL-ERROR (%c): UA (F=%c) in state %d(%s)\n", + ctrl->tei, error, (error == 'C') ? '1' : '0', + ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + case 'F': + /* + * The peer is restarting the link. + * Some reasons this might happen: + * 1) Our link establishment requests collided. + * 2) They got reset. + * 3) They could not talk to us for some reason because + * their T200 timer expired N200 times. + * 4) They got an MDL-ERROR (J). + */ + if (is_debug_q921_state) { + /* + * This message is rather annoying and is normal for + * reasons 1-3 above. + */ + pri_message(ctrl, "TEI=%d MDL-ERROR (F): SABME in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + case 'G': + /* We could not get a response from the peer. */ + if (is_debug_q921_state) { + pri_message(ctrl, + "TEI=%d MDL-ERROR (G): T200 expired N200 times sending SABME in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + case 'H': + /* We could not get a response from the peer. */ + if (is_debug_q921_state) { + pri_message(ctrl, + "TEI=%d MDL-ERROR (H): T200 expired N200 times sending DISC in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + case 'I': + /* We could not get a response from the peer. */ + if (is_debug_q921_state) { + pri_message(ctrl, + "TEI=%d MDL-ERROR (I): T200 expired N200 times sending RR/RNR in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + case 'J': + /* N(R) not within ack window. */ + pri_error(ctrl, "TEI=%d MDL-ERROR (J): N(R) error in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; + case 'K': + /* + * Received a frame reject frame. + * The other end does not like what we are doing at all for some reason. + */ + pri_error(ctrl, "TEI=%d MDL-ERROR (K): FRMR in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; + case 'Z': + if (is_debug_q921_state) { + /* Fake MDL-ERROR to kick start PTP L2 link back up. */ + pri_message(ctrl, + "TEI=%d MDL-ERROR (Z): Kick starting L2 link in state %d(%s)\n", + ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + } + break; + default: + pri_message(ctrl, "TEI=%d MDL-ERROR (%c): in state %d(%s)\n", + ctrl->tei, error, ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; + } + if (ctrl->mdl_error) { - pri_error(ctrl, "Trying to queue an MDL error when one is already scheduled\n"); + /* This should not happen. */ + pri_error(ctrl, + "Trying to queue MDL-ERROR (%c) when MDL-ERROR (%c) is already scheduled\n", + error, ctrl->mdl_error); return; } ctrl->mdl_error = error; @@ -1487,18 +1698,23 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h) { pri_event * res = NULL; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got UA\n", ctrl->tei); + } + switch (ctrl->q921_state) { case Q921_TEI_ASSIGNED: - //pri_error(ctrl, "MDL-ERROR (C, D): UA received in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); - if (h->u.p_f) + case Q921_MULTI_FRAME_ESTABLISHED: + case Q921_TIMER_RECOVERY: + if (h->u.p_f) { q921_mdl_error(ctrl, 'C'); - else + } else { q921_mdl_error(ctrl, 'D'); + } break; case Q921_AWAITING_ESTABLISHMENT: if (!h->u.p_f) { - pri_error(ctrl, "MDL-ERROR: Received UA with F = 0 while awaiting establishment\n"); + q921_mdl_error(ctrl, 'D'); break; } @@ -1509,7 +1725,6 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h) q931_dl_indication(ctrl, PRI_EVENT_DCHAN_UP); } } else { - /* Might not want this... */ ctrl->l3initiated = 0; /* return DL-ESTABLISH-CONFIRM */ } @@ -1528,8 +1743,6 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h) break; case Q921_AWAITING_RELEASE: if (!h->u.p_f) { - //pri_error(ctrl, "MDL-ERROR (D): UA in state %d(%s) w with P_F bit 0\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); q921_mdl_error(ctrl, 'D'); } else { /* return DL-RELEASE-CONFIRM */ @@ -1537,12 +1750,6 @@ static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h) q921_setstate(ctrl, Q921_TEI_ASSIGNED); } break; - case Q921_MULTI_FRAME_ESTABLISHED: - case Q921_TIMER_RECOVERY: - //pri_error(ctrl, "MDL-ERROR (C, D) UA in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); - q921_mdl_error(ctrl, 'C'); - break; default: pri_error(ctrl, "Don't know what to do with UA in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); @@ -1581,16 +1788,14 @@ static void update_v_a(struct pri *ctrl, int n_r) /* Cancel each packet as necessary */ if (ctrl->debug & PRI_DEBUG_Q921_DUMP) - pri_message(ctrl, "-- ACKing all packets from %d to (but not including) %d\n", ctrl->v_a, n_r); + pri_message(ctrl, "-- Got ACK for N(S)=%d to (but not including) N(S)=%d\n", ctrl->v_a, n_r); for (x = ctrl->v_a; x != n_r; Q921_INC(x)) { idealcnt++; realcnt += q921_ack_packet(ctrl, x); } if (idealcnt != realcnt) { pri_error(ctrl, "Ideally should have ack'd %d frames, but actually ack'd %d. This is not good.\n", idealcnt, realcnt); - q921_dump_iqueue_info(ctrl, 1); - } else { - q921_dump_iqueue_info(ctrl, 0); + q921_dump_iqueue_info(ctrl); } ctrl->v_a = n_r; @@ -1600,9 +1805,10 @@ static int n_r_is_valid(struct pri *ctrl, int n_r) { int x; - for (x=ctrl->v_a; (x != ctrl->v_s) && (x != n_r); Q921_INC(x)); + /* Is V(A) <= N(R) <= V(S) */ + for (x = ctrl->v_a; x != n_r && x != ctrl->v_s; Q921_INC(x)) { + } if (x != n_r) { - pri_error(ctrl, "N(R) %d not within ack window! Bad Bad Bad!\n", n_r); return 0; } else { return 1; @@ -1655,6 +1861,13 @@ n_r_error_out: static pri_event *q921_rr_rx(struct pri *ctrl, q921_h *h) { pri_event * res = NULL; + +#if 0 /* Don't flood debug trace with RR if not really looking at Q.921 layer. */ + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got RR N(R)=%d\n", ctrl->tei, h->s.n_r); + } +#endif + switch (ctrl->q921_state) { case Q921_TIMER_RECOVERY: res = timer_recovery_rr_rej_rx(ctrl, h); @@ -1670,8 +1883,6 @@ static pri_event *q921_rr_rx(struct pri *ctrl, q921_h *h) } } else { if (h->s.p_f) { - //pri_message(ctrl, "MDL-ERROR (A): Got RR response with p_f bit set to 1 in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); q921_mdl_error(ctrl, 'A'); } } @@ -1693,6 +1904,14 @@ static pri_event *q921_rr_rx(struct pri *ctrl, q921_h *h) } } break; + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_AWAITING_RELEASE: + /* + * Ignore this frame. + * We likely got reset and the other end has not realized it yet. + */ + break; default: pri_error(ctrl, "Don't know what to do with RR in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); @@ -1702,7 +1921,6 @@ static pri_event *q921_rr_rx(struct pri *ctrl, q921_h *h) return res; } -/* TODO: Look at this code more... */ static int q921_invoke_retransmission(struct pri *ctrl, int n_r) { int frames_txd = 0; @@ -1710,25 +1928,24 @@ static int q921_invoke_retransmission(struct pri *ctrl, int n_r) q921_frame *f; unsigned int local_v_s = ctrl->v_s; - - for (f = ctrl->txqueue; f && (f->h.n_s != n_r); f = f->next); - while (f) { - if (f->transmitted) { - if (ctrl->debug & PRI_DEBUG_Q921_STATE) - pri_error(ctrl, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", n_r, f->h.n_s); - f->h.n_r = ctrl->v_r; - f->h.p_f = 0; - q921_transmit(ctrl, (q921_h *)(&f->h), f->len); - frames_txd++; + /* All acked frames should already have been removed from the queue. */ + for (f = ctrl->txqueue; f && f->transmitted; f = f->next) { + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Retransmitting frame N(S)=%d now!\n", + ctrl->tei, f->h.n_s); } - f = f->next; + + /* Give the other side our current N(R) */ + f->h.n_r = ctrl->v_r; + f->h.p_f = 0; + q921_transmit(ctrl, (q921_h *)(&f->h), f->len); + frames_txd++; } while (local_v_s != n_r) { Q921_DEC(local_v_s); frames_supposed_to_tx++; } - if (frames_supposed_to_tx != frames_txd) { pri_error(ctrl, "!!!!!!!!!!!! Should have only transmitted %d frames!\n", frames_supposed_to_tx); } @@ -1741,8 +1958,7 @@ static pri_event *q921_rej_rx(struct pri *ctrl, q921_h *h) pri_event * res = NULL; if (ctrl->debug & PRI_DEBUG_Q921_STATE) { - pri_message(ctrl, "!! Got reject for frame %d in state %d(%s)\n", h->s.n_r, - ctrl->q921_state, q921_state2str(ctrl->q921_state)); + pri_message(ctrl, "TEI=%d Got REJ N(R)=%d\n", ctrl->tei, h->s.n_r); } switch (ctrl->q921_state) { @@ -1760,8 +1976,6 @@ static pri_event *q921_rej_rx(struct pri *ctrl, q921_h *h) } } else { if (h->s.p_f) { - //pri_message(ctrl, "MDL-ERROR (A): Got REJ response with p_f bit set to 1 in state %d(%s)\n", - // ctrl->q921_state, q921_state2str(ctrl->q921_state)); q921_mdl_error(ctrl, 'A'); } } @@ -1775,11 +1989,55 @@ static pri_event *q921_rej_rx(struct pri *ctrl, q921_h *h) start_t203(ctrl); q921_invoke_retransmission(ctrl, h->s.n_r); } - return NULL; + break; + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_AWAITING_RELEASE: + /* + * Ignore this frame. + * We likely got reset and the other end has not realized it yet. + */ + break; default: - pri_error(ctrl, "Don't know what to do with RR in state %d(%s)\n", + pri_error(ctrl, "Don't know what to do with REJ in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); - return NULL; + break; + } + + return res; +} + +static pri_event *q921_frmr_rx(struct pri *ctrl, q921_h *h) +{ + pri_event *res = NULL; + + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got FRMR\n", ctrl->tei); + } + + switch (ctrl->q921_state) { + case Q921_TIMER_RECOVERY: + case Q921_MULTI_FRAME_ESTABLISHED: + q921_mdl_error(ctrl, 'K'); + q921_establish_data_link(ctrl); + ctrl->l3initiated = 0; + q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT); + break; + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_AWAITING_RELEASE: + /* + * Ignore this frame. + * We likely got reset and the other end has not realized it yet. + */ + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Ignoring FRMR.\n", ctrl->tei); + } + break; + default: + pri_error(ctrl, "Don't know what to do with FRMR in state %d(%s)\n", + ctrl->q921_state, q921_state2str(ctrl->q921_state)); + break; } return res; @@ -1797,9 +2055,7 @@ static pri_event *q921_iframe_rx(struct pri *ctrl, q921_h *h, int len) if (ctrl->own_rx_busy) { /* XXX: Note: There's a difference in th P/F between both states */ /* DEVIATION: Handle own rx busy */ - } - - if (h->i.n_s == ctrl->v_r) { + } else if (h->i.n_s == ctrl->v_r) { Q921_INC(ctrl->v_r); ctrl->reject_exception = 0; @@ -1815,11 +2071,9 @@ static pri_event *q921_iframe_rx(struct pri *ctrl, q921_h *h, int len) ctrl->acknowledge_pending = 0; } else { if (!ctrl->acknowledge_pending) { - /* XXX: Fix acknowledge_pending */ ctrl->acknowledge_pending = 1; } } - } else { if (ctrl->reject_exception) { if (h->i.p_f) { @@ -1850,14 +2104,20 @@ static pri_event *q921_iframe_rx(struct pri *ctrl, q921_h *h, int len) } else { if (h->i.n_r != ctrl->v_a) { update_v_a(ctrl, h->i.n_r); - stop_t200(ctrl); - start_t200(ctrl); + reschedule_t200(ctrl); } } } } } - + break; + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_AWAITING_RELEASE: + /* + * Ignore this frame. + * We likely got reset and the other end has not realized it yet. + */ break; default: pri_error(ctrl, "Don't know what to do with an I-frame in state %d(%s)\n", @@ -1872,6 +2132,10 @@ static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h) { pri_event * res = NULL; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got DM\n", ctrl->tei); + } + switch (ctrl->q921_state) { case Q921_TEI_ASSIGNED: if (h->u.p_f) @@ -1901,7 +2165,6 @@ static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h) break; case Q921_MULTI_FRAME_ESTABLISHED: if (h->u.p_f) { - /* MDL-ERROR (B) indication */ q921_mdl_error(ctrl, 'B'); break; } @@ -1913,10 +2176,8 @@ static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h) break; case Q921_TIMER_RECOVERY: if (h->u.p_f) { - /* MDL-ERROR (B) indication */ q921_mdl_error(ctrl, 'B'); } else { - /* MDL-ERROR (E) indication */ q921_mdl_error(ctrl, 'E'); } q921_establish_data_link(ctrl); @@ -1936,12 +2197,15 @@ static pri_event *q921_rnr_rx(struct pri *ctrl, q921_h *h) { pri_event * res = NULL; + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got RNR N(R)=%d\n", ctrl->tei, h->s.n_r); + } + switch (ctrl->q921_state) { case Q921_MULTI_FRAME_ESTABLISHED: ctrl->peer_rx_busy = 1; if (!is_command(ctrl, h)) { if (h->s.p_f) { - /* MDL-ERROR (A) indication */ q921_mdl_error(ctrl, 'A'); } } else { @@ -1965,23 +2229,14 @@ static pri_event *q921_rnr_rx(struct pri *ctrl, q921_h *h) if (is_command(ctrl, h)) { if (h->s.p_f) { q921_enquiry_response(ctrl); - if (n_r_is_valid(ctrl, h->s.n_r)) { - update_v_a(ctrl, h->s.n_r); - break; - } else { - n_r_error_recovery(ctrl); - q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT); - break; - } + } + if (n_r_is_valid(ctrl, h->s.n_r)) { + update_v_a(ctrl, h->s.n_r); + break; } else { - if (n_r_is_valid(ctrl, h->s.n_r)) { - update_v_a(ctrl, h->s.n_r); - break; - } else { - n_r_error_recovery(ctrl); - q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT); - break; - } + n_r_error_recovery(ctrl); + q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT); + break; } } else { if (h->s.p_f) { @@ -2008,6 +2263,14 @@ static pri_event *q921_rnr_rx(struct pri *ctrl, q921_h *h) } } break; + case Q921_TEI_ASSIGNED: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_AWAITING_RELEASE: + /* + * Ignore this frame. + * We likely got reset and the other end has not realized it yet. + */ + break; default: pri_error(ctrl, "Don't know what to do with RNR in state %d(%s)\n", ctrl->q921_state, q921_state2str(ctrl->q921_state)); @@ -2042,6 +2305,7 @@ static void q921_statemachine_check(struct pri *ctrl) static pri_event *__q921_receive_qualified(struct pri *ctrl, q921_h *h, int len) { + int res; pri_event *ev = NULL; switch(h->h.data[0] & Q921_FRAMETYPE_MASK) { @@ -2050,22 +2314,20 @@ static pri_event *__q921_receive_qualified(struct pri *ctrl, q921_h *h, int len) ev = q921_iframe_rx(ctrl, h, len); break; case 1: - switch(h->s.ss) { - case 0: - ev = q921_rr_rx(ctrl, h); + switch ((h->s.x0 << 2) | h->s.ss) { + case 0x00: + ev = q921_rr_rx(ctrl, h); break; - case 1: + case 0x01: ev = q921_rnr_rx(ctrl, h); break; - case 2: - /* Just retransmit */ - if (ctrl->debug & PRI_DEBUG_Q921_STATE) - pri_message(ctrl, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r); + case 0x02: ev = q921_rej_rx(ctrl, h); break; default: - pri_error(ctrl, "!! 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, - ctrl->v_s, ctrl->v_a); + pri_error(ctrl, + "!! XXX Unknown Supervisory frame x0=%d ss=%d, pf=%d, N(R)=%d, V(A)=%d, V(S)=%d XXX\n", + h->s.x0, h->s.ss, h->s.p_f, h->s.n_r, ctrl->v_a, ctrl->v_s); break; } break; @@ -2074,69 +2336,58 @@ static pri_event *__q921_receive_qualified(struct pri *ctrl, q921_h *h, int len) pri_error(ctrl, "!! Received short unnumbered frame\n"); break; } - switch(h->u.m3) { - case 0: - if (h->u.m2 == 3) { - ev = q921_dm_rx(ctrl, h); - break; - } else if (!h->u.m2) { - if ((ctrl->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (ctrl->tei == Q921_TEI_GROUP)) { - pri_error(ctrl, "I should never be called\n"); - ev = q921_receive_MDL(ctrl, (q921_u *)h, len); - } else { - int res; - - res = q931_receive(ctrl, ctrl->tei, (q931_h *) h->u.data, len - 3); - if (res != -1 && (res & Q931_RES_HAVEEVENT)) { - ev = &ctrl->ev; - } - } + switch ((h->u.m3 << 2) | h->u.m2) { + case 0x03: + ev = q921_dm_rx(ctrl, h); + break; + case 0x00: + /* UI-frame */ + res = q931_receive(ctrl, ctrl->tei, (q931_h *) h->u.data, len - 3); + if (res != -1 && (res & Q931_RES_HAVEEVENT)) { + ev = &ctrl->ev; } break; - case 2: + case 0x08: ev = q921_disc_rx(ctrl, h); break; - case 3: - if (h->u.m2 == 3) { - /* SABME */ - if (ctrl->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) { - pri_message(ctrl, "-- Got SABME from %s peer.\n", h->h.c_r ? "network" : "cpe"); + case 0x0F: + /* SABME */ + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { + pri_message(ctrl, "TEI=%d Got SABME from %s peer.\n", + ctrl->tei, h->h.c_r ? "network" : "cpe"); + } + if (h->h.c_r) { + ctrl->remotetype = PRI_NETWORK; + if (ctrl->localtype == PRI_NETWORK) { + /* We can't both be networks */ + ev = pri_mkerror(ctrl, "We think we're the network, but they think they're the network, too."); + break; } - if (h->h.c_r) { - ctrl->remotetype = PRI_NETWORK; - if (ctrl->localtype == PRI_NETWORK) { - /* We can't both be networks */ - ev = pri_mkerror(ctrl, "We think we're the network, but they think they're the network, too."); - break; - } - } else { - ctrl->remotetype = PRI_CPE; - if (ctrl->localtype == PRI_CPE) { - /* We can't both be CPE */ - ev = pri_mkerror(ctrl, "We think we're the CPE, but they think they're the CPE too.\n"); - break; - } + } else { + ctrl->remotetype = PRI_CPE; + if (ctrl->localtype == PRI_CPE) { + /* We can't both be CPE */ + ev = pri_mkerror(ctrl, "We think we're the CPE, but they think they're the CPE too.\n"); + break; } - ev = q921_sabme_rx(ctrl, h); - break; - } else if (h->u.m2 == 0) { - ev = q921_ua_rx(ctrl, h); - break; - } else - pri_error(ctrl, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); + } + ev = q921_sabme_rx(ctrl, h); break; - case 4: - pri_error(ctrl, "!! Frame got rejected!\n"); + case 0x0C: + ev = q921_ua_rx(ctrl, h); break; - case 5: + case 0x11: + ev = q921_frmr_rx(ctrl, h); + break; + case 0x17: pri_error(ctrl, "!! XID frames not supported\n"); break; default: - pri_error(ctrl, "!! Don't know what to do with M3=%d u-frames\n", h->u.m3); + pri_error(ctrl, "!! Don't know what to do with u-frame (m3=%d, m2=%d)\n", + h->u.m3, h->u.m2); break; } break; - } q921_statemachine_check(ctrl); @@ -2160,7 +2411,7 @@ static pri_event *q921_handle_unmatched_frame(struct pri *ctrl, q921_h *h, int l /* If we're NT-PTMP, this means an unrecognized TEI that we'll kill */ if (BRI_NT_PTMP(ctrl)) { - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) { + if (ctrl->debug & PRI_DEBUG_Q921_STATE) { pri_message(ctrl, "Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n", h->h.sapi, h->h.tei); @@ -2180,47 +2431,52 @@ static pri_event *__q921_receive(struct pri *ctrl, q921_h *h, int len) { pri_event *ev = NULL; struct pri *tei; + /* Discard FCS */ len -= 2; - if (ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) + if (ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) { q921_dump(ctrl, h, len, ctrl->debug & PRI_DEBUG_Q921_RAW, 0); + } /* Check some reject conditions -- Start by rejecting improper ea's */ - if (h->h.ea1 || !(h->h.ea2)) + if (h->h.ea1 || !h->h.ea2) { return NULL; + } - if ((h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT)) { + if (h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT) { return q921_receive_MDL(ctrl, &h->u, len); } - if ((h->h.tei == Q921_TEI_GROUP) && (h->h.sapi != Q921_SAPI_CALL_CTRL)) { + if (h->h.tei == Q921_TEI_GROUP && h->h.sapi != Q921_SAPI_CALL_CTRL) { pri_error(ctrl, "Do not handle group messages to services other than MDL or CALL CTRL\n"); return NULL; } if (BRI_TE_PTMP(ctrl)) { - if (((ctrl->subchannel->q921_state >= Q921_TEI_ASSIGNED) && (h->h.tei == ctrl->subchannel->tei)) - || (h->h.tei == Q921_TEI_GROUP)) { + if (h->h.sapi == ctrl->subchannel->sapi + && ((ctrl->subchannel->q921_state >= Q921_TEI_ASSIGNED + && h->h.tei == ctrl->subchannel->tei) + || h->h.tei == Q921_TEI_GROUP)) { ev = __q921_receive_qualified(ctrl->subchannel, h, len); } /* Only support reception on our single subchannel */ } else if (BRI_NT_PTMP(ctrl)) { tei = pri_find_tei(ctrl, h->h.sapi, h->h.tei); - - if (tei) + if (tei) { ev = __q921_receive_qualified(tei, h, len); - else + } else { ev = q921_handle_unmatched_frame(ctrl, h, len); - + } } else if (PTP_MODE(ctrl) && (h->h.sapi == ctrl->sapi) && (h->h.tei == ctrl->tei)) { ev = __q921_receive_qualified(ctrl, h, len); } else { ev = NULL; } - if (ctrl->debug & PRI_DEBUG_Q921_DUMP) + if (ctrl->debug & PRI_DEBUG_Q921_DUMP) { pri_message(ctrl, "Done handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei); + } return ev; } diff --git a/q931.c b/q931.c index a695deb..31ff207 100644 --- a/q931.c +++ b/q931.c @@ -3924,6 +3924,85 @@ static char *disc2str(int disc) return code2str(disc, discs, sizeof(discs) / sizeof(discs[0])); } +/*! + * \internal + * \brief Dump the Q.931 message header. + * + * \param ctrl D channel controller. + * \param tei TEI the packet is associated with. + * \param h Q.931 packet contents/header. + * \param len Received length of the Q.931 packet. + * \param c Message direction prefix character. + * + * \retval 0 on success. + * \retval -1 on error. + */ +static int q931_dump_header(struct pri *ctrl, int tei, q931_h *h, int len, char c) +{ + q931_mh *mh; + int cref; + + pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); + + if (len < 2 || len < 2 + h->crlen) { + pri_message(ctrl, "%c Message too short for call reference. len=%d\n", + c, len); + return -1; + } + cref = q931_cr(h); + pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n", + c, tei, h->crlen, cref & ~Q931_CALL_REFERENCE_FLAG, + cref & ~Q931_CALL_REFERENCE_FLAG, (cref == Q931_DUMMY_CALL_REFERENCE) + ? "Dummy" + : (cref & Q931_CALL_REFERENCE_FLAG) + ? "Sent to originator" : "Sent from originator"); + + if (len < 3 + h->crlen) { + pri_message(ctrl, "%c Message too short for supported protocols. len=%d\n", + c, len); + return -1; + } + + /* Message header begins at the end of the call reference number */ + mh = (q931_mh *)(h->contents + h->crlen); + switch (h->pd) { + case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: + case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: + pri_message(ctrl, "%c Message Type: %s (%d)\n", c, maintenance_msg2str(mh->msg, h->pd), mh->msg); + break; + default: + /* Unknown protocol discriminator but we will treat it as Q.931 anyway. */ + case GR303_PROTOCOL_DISCRIMINATOR: + case Q931_PROTOCOL_DISCRIMINATOR: + pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); + break; + } + + return 0; +} + +/*! + * \internal + * \brief Q.931 is passing this message to Q.921 debug indication. + * + * \param ctrl D channel controller. + * \param tei TEI the packet is associated with. + * \param h Q.931 packet contents/header. + * \param len Received length of the Q.931 packet + * + * \return Nothing + */ +static void q931_to_q921_passing_dump(struct pri *ctrl, int tei, q931_h *h, int len) +{ + char c; + + c = '>'; + + pri_message(ctrl, "\n"); + pri_message(ctrl, "%c DL-DATA request\n", c); + q931_dump_header(ctrl, tei, h, len, c); +} + /*! * \brief Debug dump the given Q.931 packet. * @@ -3943,46 +4022,19 @@ void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx) int r; int cur_codeset; int codeset; - int cref; c = txrx ? '>' : '<'; - pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); - - if (len < 2 || len < 2 + h->crlen) { - pri_message(ctrl, "%c Message too short for call reference. len=%d\n", - c, len); - return; + if (!(ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))) { + /* Put out a blank line if Q.921 is not dumping. */ + pri_message(ctrl, "\n"); } - cref = q931_cr(h); - pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n", - c, tei, h->crlen, cref & ~Q931_CALL_REFERENCE_FLAG, - cref & ~Q931_CALL_REFERENCE_FLAG, (cref == Q931_DUMMY_CALL_REFERENCE) - ? "Dummy" - : (cref & Q931_CALL_REFERENCE_FLAG) - ? "Sent to originator" : "Sent from originator"); - - if (len < 3 + h->crlen) { - pri_message(ctrl, "%c Message too short for supported protocols. len=%d\n", - c, len); + if (q931_dump_header(ctrl, tei, h, len, c)) { return; } - /* Message header begins at the end of the call reference number */ - mh = (q931_mh *)(h->contents + h->crlen); - switch (h->pd) { - case MAINTENANCE_PROTOCOL_DISCRIMINATOR_1: - case MAINTENANCE_PROTOCOL_DISCRIMINATOR_2: - pri_message(ctrl, "%c Message Type: %s (%d)\n", c, maintenance_msg2str(mh->msg, h->pd), mh->msg); - break; - default: - /* Unknown protocol discriminator but we will treat it as Q.931 anyway. */ - case GR303_PROTOCOL_DISCRIMINATOR: - case Q931_PROTOCOL_DISCRIMINATOR: - pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); - break; - } /* Drop length of header, including call reference */ + mh = (q931_mh *)(h->contents + h->crlen); len -= (h->crlen + 3); codeset = cur_codeset = 0; for (x = 0; x < len; x += r) { @@ -4076,21 +4128,30 @@ static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int uiframe) { - /* - * Dump the Q.931 message first. Q.921 may have to request a TEI or - * bring the connection up before it can actually send the message. - * Therefore, the Q.931 message may actually get sent a few seconds - * later. - */ - if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { - q931_dump(ctrl, tei, h, len, 1); - } #ifdef LIBPRI_COUNTERS ctrl->q931_txcount++; #endif if (uiframe) { q921_transmit_uiframe(ctrl, h, len); + if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { + /* + * The transmit operation might dump the Q.921 header, so logging + * the Q.931 message body after the transmit puts the sections of + * the message in the right order in the log, + */ + q931_dump(ctrl, tei, h, len, 1); + } } else { + /* + * Indicate passing the Q.931 message to Q.921 first. Q.921 may + * have to request a TEI or bring the connection up before it can + * actually send the message. Therefore, the Q.931 message may + * actually get sent a few seconds later. Q.921 will dump the + * Q.931 message as appropriate at that time. + */ + if (ctrl->debug & PRI_DEBUG_Q931_DUMP) { + q931_to_q921_passing_dump(ctrl, tei, h, len); + } q921_transmit_iframe(ctrl, tei, h, len, cr); } return 0;