From 4d3bb147313787e3acf2d6a125b03ec02a7f5c1e Mon Sep 17 00:00:00 2001 From: Matthew Fredrickson Date: Wed, 13 Jan 2010 19:37:59 +0000 Subject: [PATCH] Merge of Q.921 rewrite branch for wider testing. git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1406 2fbb986a-6c06-0410-b554-c9c1f0a7f128 --- Makefile | 2 +- pri.c | 29 +- pri_internal.h | 56 +- pri_q921.h | 33 +- pri_q931.h | 2 +- q921.c | 1922 +++++++++++++++++++++++++++++++++--------------- q931.c | 26 +- 7 files changed, 1413 insertions(+), 657 deletions(-) diff --git a/Makefile b/Makefile index 6428bf2..bfc8a10 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ install: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) ifneq (${OSARCH},SunOS) install -m 644 libpri.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) - if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(libdir)/$(DYNAMIC_LIBRARY); fi + #if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(libdir)/$(DYNAMIC_LIBRARY); fi ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf libpri.so.$(SONAME) libpri.so) install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) if test $$(id -u) = 0; then $(LDCONFIG) $(LDCONFIG_FLAGS) $(INSTALL_PREFIX)$(libdir); fi diff --git a/pri.c b/pri.c index 5243c8e..bfdf6dc 100644 --- a/pri.c +++ b/pri.c @@ -144,7 +144,12 @@ static void pri_default_timers(struct pri *ctrl, int switchtype) /* Set timer values to standard defaults. Time is in ms. */ ctrl->timers[PRI_TIMER_N200] = 3; /* Max numer of Q.921 retransmissions */ ctrl->timers[PRI_TIMER_N202] = 3; /* Max numer of transmissions of the TEI identity request message */ - ctrl->timers[PRI_TIMER_K] = 7; /* Max number of outstanding I-frames */ + + if (ctrl->bri == 1) + ctrl->timers[PRI_TIMER_K] = 1; /* Max number of outstanding I-frames */ + else + ctrl->timers[PRI_TIMER_K] = 7; /* Max number of outstanding I-frames */ + ctrl->timers[PRI_TIMER_T200] = 1000; /* Time between SABME's */ ctrl->timers[PRI_TIMER_T202] = 10 * 1000; /* Min time between transmission of TEI Identity request messages */ ctrl->timers[PRI_TIMER_T203] = 10 * 1000; /* Max time without exchanging packets */ @@ -154,6 +159,7 @@ static void pri_default_timers(struct pri *ctrl, int switchtype) ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */ ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */ ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */ + ctrl->timers[PRI_TIMER_T309] = 6000; /* Time to wait before clearing calls in case of D-channel transient event. Q.931 specifies 6-90 seconds */ ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */ ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */ @@ -343,9 +349,16 @@ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, default: break; } - /* Start Q.921 layer, Wait if we're the network */ - if (p) - q921_start(p, p->localtype == PRI_CPE); + p->k = p->timers[PRI_TIMER_K]; + + if (p->tei == Q921_TEI_GROUP && p->sapi == Q921_SAPI_LAYER2_MANAGEMENT && p->localtype == PRI_CPE) { + p->subchannel = __pri_new_tei(-1, p->localtype, p->switchtype, p, NULL, NULL, NULL, Q921_TEI_PRI, 1); + if (!p->subchannel) { + free(p); + return NULL; + } + } else + q921_start(p); return p; } @@ -363,11 +376,15 @@ void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars) int pri_restart(struct pri *pri) { +#if 0 /* Restart Q.921 layer */ if (pri) { q921_reset(pri, 1); q921_start(pri, pri->localtype == PRI_CPE); } +#else + pri_error(pri, "pri_restart should never be called !!!!\n"); +#endif return 0; } @@ -1303,12 +1320,14 @@ char *pri_dump_info_str(struct pri *ctrl) } used = pri_snprintf(buf, used, buf_size, "Q921 Outstanding: %u\n", q921outstanding); #endif - used = pri_snprintf(buf, used, buf_size, "Window Length: %d/%d\n", ctrl->windowlen, +#if 0 + used = pri_snprintf(buf, used, buf_size, "Window Length: %d/%d\n", ctrl->k, ctrl->window); used = pri_snprintf(buf, used, buf_size, "Sentrej: %d\n", ctrl->sentrej); used = pri_snprintf(buf, used, buf_size, "SolicitFbit: %d\n", ctrl->solicitfbit); used = pri_snprintf(buf, used, buf_size, "Retrans: %d\n", ctrl->retrans); used = pri_snprintf(buf, used, buf_size, "Busy: %d\n", ctrl->busy); +#endif used = pri_snprintf(buf, used, buf_size, "Overlap Dial: %d\n", ctrl->overlapdial); used = pri_snprintf(buf, used, buf_size, "Logical Channel Mapping: %d\n", ctrl->chan_mapping_logical); diff --git a/pri_internal.h b/pri_internal.h index 6bc03af..94c82f9 100644 --- a/pri_internal.h +++ b/pri_internal.h @@ -89,25 +89,30 @@ struct pri { unsigned int hold_support:1;/* TRUE if upper layer supports call hold. */ unsigned int deflection_support:1;/* TRUE if upper layer supports call deflection/rerouting. */ + /* MDL variables */ + int mdl_error; + int mdl_error_state; + int mdl_timer; + int mdl_free_me; + /* Q.921 State */ int q921_state; - int window; /* Max window size */ - int windowlen; /* Fullness of window */ + int k; + int RC; + int peer_rx_busy:1; + int own_rx_busy:1; + int acknowledge_pending:1; + int reject_exception:1; + int v_s; /* Next N(S) for transmission */ int v_a; /* Last acknowledged frame */ int v_r; /* Next frame expected to be received */ - 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 */ int cref; /* Next call reference value */ - int busy; /* Peer is busy */ + int l3initiated; /* Various timers */ - int sabme_timer; /* SABME retransmit */ - int sabme_count; /* SABME retransmit counter for BRI */ int t203_timer; /* Max idle time */ int t202_timer; int n202_counter; @@ -515,6 +520,8 @@ struct q931_call { -1 - No reverse charging 1 - Reverse charging 0,2-7 - Reserved for future use */ + /*! \brief TEI associated with call */ + int tei; int t303_timer; int t303_expirycnt; @@ -627,13 +634,40 @@ static inline int BRI_TE_PTMP(struct pri *mypri) return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP)); } -static inline int PRI_PTP(struct pri *mypri) +static inline int NT_MODE(struct pri *mypri) { struct pri *pri; pri = PRI_MASTER(mypri); - return !pri->bri; + return pri->localtype == PRI_NETWORK; +} + +static inline int TE_MODE(struct pri *mypri) +{ + struct pri *pri; + + pri = PRI_MASTER(mypri); + + return pri->localtype == PRI_CPE; +} + +static inline int PTP_MODE(struct pri *mypri) +{ + struct pri *pri; + + pri = PRI_MASTER(mypri); + + return pri->tei == Q921_TEI_PRI; +} + +static inline int PTMP_MODE(struct pri *mypri) +{ + struct pri *pri; + + pri = PRI_MASTER(mypri); + + return pri->tei == Q921_TEI_GROUP; } #define Q931_DUMMY_CALL_REFERENCE -1 diff --git a/pri_q921.h b/pri_q921.h index e220cad..865a805 100644 --- a/pri_q921.h +++ b/pri_q921.h @@ -166,36 +166,41 @@ typedef struct q921_frame { } q921_frame; #define Q921_INC(j) (j) = (((j) + 1) % 128) +#define Q921_DEC(j) (j) = (((j) - 1) % 128) typedef enum q921_state { - Q921_DOWN = 0, - Q921_TEI_UNASSIGNED, - Q921_TEI_AWAITING_ESTABLISH, - Q921_TEI_AWAITING_ASSIGN, - Q921_TEI_ASSIGNED, - Q921_NEGOTIATION, - Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */ - Q921_LINK_CONNECTION_ESTABLISHED, - Q921_AWAITING_ESTABLISH, - Q921_AWAITING_RELEASE + /* All states except Q921_DOWN are defined in Q.921 SDL diagrams */ + Q921_TEI_UNASSIGNED = 1, + Q921_ASSIGN_AWAITING_TEI = 2, + Q921_ESTABLISH_AWAITING_TEI = 3, + Q921_TEI_ASSIGNED = 4, + Q921_AWAITING_ESTABLISHMENT = 5, + Q921_AWAITING_RELEASE = 6, + Q921_MULTI_FRAME_ESTABLISHED = 7, + Q921_TIMER_RECOVERY = 8, } q921_state; +static inline int Q921_ADD(int a, int b) +{ + return (a + b) % 128; +} + /* Dumps a *known good* Q.921 packet */ extern void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx); /* Bring up the D-channel */ -extern void q921_start(struct pri *pri, int now); +extern void q921_start(struct pri *pri); -extern void q921_reset(struct pri *pri, int reset_iqueue); +//extern void q921_reset(struct pri *pri, int reset_iqueue); extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len); -extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr); +extern int q921_transmit_iframe(struct pri *pri, int tei, void *buf, int len, int cr); extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len); extern pri_event *q921_dchannel_up(struct pri *pri); -extern pri_event *q921_dchannel_down(struct pri *pri); +//extern pri_event *q921_dchannel_down(struct pri *pri); #endif diff --git a/pri_q931.h b/pri_q931.h index b1e1800..b27e659 100644 --- a/pri_q931.h +++ b/pri_q931.h @@ -452,7 +452,7 @@ extern int maintenance_service_ack(struct pri *pri, q931_call *call); /* Q.SIG specific */ #define QSIG_IE_TRANSIT_COUNT 0x31 -extern int q931_receive(struct pri *pri, q931_h *h, int len); +extern int q931_receive(struct pri *pri, int tei, q931_h *h, int len); extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info); diff --git a/q921.c b/q921.c index a653927..ef4e853 100644 --- a/q921.c +++ b/q921.c @@ -56,10 +56,21 @@ (hf).h.tei = (pri)->tei; \ } while(0) -static void reschedule_t203(struct pri *pri); +//static void reschedule_t203(struct pri *pri); static void reschedule_t200(struct pri *pri); -static void q921_restart(struct pri *pri, int now); -static void q921_tei_release_and_reacquire(struct pri *master); +//static void q921_restart(struct pri *pri, int now); +//static void q921_tei_release_and_reacquire(struct pri *master); +static void q921_dump_pri(struct pri *pri); +static void q921_establish_data_link(struct pri *pri); +static void q921_mdl_error(struct pri *pri, char error); +static void q921_mdl_remove(struct pri *pri); + +static void q921_setstate(struct pri *pri, int newstate) +{ + if ((pri->q921_state != newstate) && (newstate != 7) && (newstate != 8)) + pri_error(pri, "Changing from state %d to %d\n", pri->q921_state, newstate); + pri->q921_state = newstate; +} static void q921_discard_retransmissions(struct pri *pri) { @@ -74,6 +85,11 @@ static void q921_discard_retransmissions(struct pri *pri) pri->txqueue = NULL; } +static void q921_discard_iqueue(struct pri *pri) +{ + q921_discard_retransmissions(pri); +} + static int q921_transmit(struct pri *pri, q921_h *h, int len) { int res; @@ -126,20 +142,14 @@ static void q921_send_tei(struct pri *pri, int message, int ri, int ai, int isco static void q921_tei_request(void *vpri) { struct pri *pri = (struct pri *)vpri; - - if (pri->subchannel) { - pri_error(pri, "Cannot request TEI while its already assigned\n"); - return; - } pri->n202_counter++; -#if 0 if (pri->n202_counter > pri->timers[PRI_TIMER_N202]) { - pri_error(pri, "Unable to assign TEI from network\n"); + pri_error(pri, "Unable to receive TEI from network!\n"); + pri->n202_counter = 0; return; } -#endif pri->ri = random() % 65535; - q921_send_tei(pri, Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1); + q921_send_tei(PRI_MASTER(pri), Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1); pri_schedule_del(pri, pri->t202_timer); pri->t202_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_tei_request, pri); } @@ -168,17 +178,10 @@ static void q921_send_ua(struct pri *pri, int pfbit) q921_transmit(pri, &h, 3); } -static void q921_send_sabme_now(void *vpri); - -static void q921_send_sabme(void *vpri, int now) +static void q921_send_sabme(struct pri *pri) { - struct pri *pri = vpri; q921_h h; - pri_schedule_del(pri, pri->sabme_timer); - pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri); - if (!now) - return; Q921_INIT(pri, h); h.u.m3 = 3; /* M3 = 3 */ h.u.m2 = 3; /* M2 = 3 */ @@ -195,33 +198,21 @@ static void q921_send_sabme(void *vpri, int now) pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); return; } - if (pri->bri && (pri->state == Q921_AWAITING_ESTABLISH)) { - if (pri->sabme_count >= pri->timers[PRI_TIMER_N200]) { - pri_schedule_del(pri, pri->sabme_timer); - pri->sabme_timer = 0; - q921_tei_release_and_reacquire(pri->master); - } else { - pri->sabme_count++; - } - } - if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) - pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n"); q921_transmit(pri, &h, 3); - if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_AWAITING_ESTABLISH) - pri_message(pri, DBGHEAD "q921_state now is Q921_AWAITING_ESTABLISH\n", DBGINFO); - pri->q921_state = Q921_AWAITING_ESTABLISH; } +#if 0 static void q921_send_sabme_now(void *vpri) { q921_send_sabme(vpri, 1); } +#endif static int q921_ack_packet(struct pri *pri, int num) { struct q921_frame *f, *prev = NULL; f = pri->txqueue; - while(f) { + while (f) { if (f->h.n_s == num) { /* Cancel each packet as necessary */ /* That's our packet */ @@ -232,12 +223,7 @@ static int q921_ack_packet(struct pri *pri, int num) if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "-- 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; - /* Decrement window size */ - pri->windowlen--; return 1; } prev = f; @@ -257,6 +243,9 @@ static void reschedule_t200(struct pri *pri) pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); } +#define restart_t200(pri) reschedule_t200((pri)) + +#if 0 static void reschedule_t203(struct pri *pri) { if (pri->debug & PRI_DEBUG_Q921_DUMP) @@ -264,77 +253,113 @@ static void reschedule_t203(struct pri *pri) pri_schedule_del(pri, pri->t203_timer); pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); } +#endif -static void q921_send_queued_iframes(struct pri *pri) +#if 0 +static int q921_unacked_iframes(struct pri *pri) { - struct q921_frame *f; + struct q921_frame *f = pri->txqueue; + int cnt = 0; - f = pri->txqueue; - while(f && (pri->windowlen < pri->window)) { - if (!f->transmitted) { - /* Send it now... */ - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen); - f->transmitted++; - pri->windowlen++; - f->h.n_r = pri->v_r; - f->h.p_f = 0; - q921_transmit(pri, (q921_h *)(&f->h), f->len); - } + while(f) { + if (f->transmitted) + cnt++; f = f->next; } + + return cnt; +} +#endif + +static void start_t203(struct pri *pri) +{ + if (pri->t203_timer) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "T203 requested to start without stopping first\n"); + pri_schedule_del(pri, pri->t203_timer); + } + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Starting T203 timer\n"); + pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); +} + +static void stop_t203(struct pri *pri) +{ + if (pri->t203_timer) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Stopping T203 timer\n"); + pri_schedule_del(pri, pri->t203_timer); + pri->t203_timer = 0; + } else { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- T203 requested to stop when not started\n"); + } } -static pri_event *q921_ack_rx(struct pri *pri, int ack, int send_untransmitted_frames) +static void start_t200(struct pri *pri) { - 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(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a, pri->v_s); - 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_DUMP) - pri_message(pri, "-- 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->t200_timer) { if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n"); - /* Something was ACK'd. Stop T200 counter */ + pri_message(pri, "T200 requested to start without stopping first\n"); + pri_schedule_del(pri, pri->t200_timer); + } + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Starting T200 timer\n"); + pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); +} + +static void stop_t200(struct pri *pri) +{ + if (pri->t200_timer) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Stopping T200 timer\n"); pri_schedule_del(pri, pri->t200_timer); pri->t200_timer = 0; - } - if (pri->t203_timer) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- 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->busy && send_untransmitted_frames) { - pri->retrans = 0; - /* Search for something to send */ - q921_send_queued_iframes(pri); - } - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Waiting for acknowledge, restarting T200 counter\n"); - reschedule_t200(pri); } else { if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Nothing left, starting T203 counter\n"); - /* Nothing to transmit, start the T203 counter instead */ - pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); + pri_message(pri, "-- T200 requested to stop when not started\n"); } - return NULL; +} + +/* This is the equivalent of the I-Frame queued up path in Figure B.7 in MULTI_FRAME_ESTABLISHED */ +static int q921_send_queued_iframes(struct pri *pri) +{ + struct q921_frame *f; + int frames_txd = 0; + + if (pri->peer_rx_busy || (pri->v_s == Q921_ADD(pri->v_a, pri->k))) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "Couldn't transmit I frame at this time due to peer busy condition or window shut\n"); + return 0; + } + + f = pri->txqueue; + while (f && (pri->v_s != Q921_ADD(pri->v_a, pri->k))) { + if (!f->transmitted) { + /* Send it now... */ + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->k); + f->transmitted++; + f->h.n_s = pri->v_s; + f->h.n_r = pri->v_r; + f->h.ft = 0; + f->h.p_f = 0; + q921_transmit(pri, (q921_h *)(&f->h), f->len); + Q921_INC(pri->v_s); + frames_txd++; + pri->acknowledge_pending = 0; + } + f = f->next; + } + + if (frames_txd) { + if (!pri->t200_timer) { + stop_t203(pri); + start_t200(pri); + } + } + + return frames_txd; } static void q921_reject(struct pri *pri, int pf) @@ -359,7 +384,6 @@ static void q921_reject(struct pri *pri, int pf) } if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "Sending Reject (%d)\n", pri->v_r); - pri->sentrej = 1; q921_transmit(pri, &h, 4); } @@ -388,96 +412,82 @@ static void q921_rr(struct pri *pri, int pbit, int cmd) { pri_error(pri, "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_DUMP) pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r); q921_transmit(pri, &h, 4); } -static void t200_expire(void *vpri) +static void transmit_enquiry(struct pri *pri) { - struct pri *pri = vpri; - q921_frame *f, *lastframe=NULL; - - if (pri->txqueue) { - /* Retransmit first packet in the queue, setting the poll bit */ - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- T200 counter expired, What to do...\n"); - pri->solicitfbit = 1; - /* Up to three retransmissions */ - if (pri->retrans < pri->timers[PRI_TIMER_N200]) { - pri->retrans++; - /* Reschedule t200_timer */ - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len); - if (pri->busy) - q921_rr(pri, 1, 1); - else { - if (!pri->txqueue->transmitted) - pri_error(pri, "!! Not good - head of queue has not been transmitted yet\n"); - /*Actually we need to retransmit the last transmitted packet, setting the poll bit */ - for (f=pri->txqueue; f; f = f->next) { - if (f->transmitted) - lastframe = f; - } - if (lastframe) { - /* Force Poll bit */ - lastframe->h.p_f = 1; - /* Update nr */ - lastframe->h.n_r = pri->v_r; - pri->v_na = pri->v_r; - q921_transmit(pri, (q921_h *)&lastframe->h, lastframe->len); - } - } - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans); - pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); - } else { - if (pri->debug & PRI_DEBUG_Q921_STATE) - pri_message(pri, "-- Timeout occured, restarting PRI\n"); - if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) - pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n",DBGINFO); - pri->q921_state = Q921_LINK_CONNECTION_RELEASED; - pri->t200_timer = 0; - if (pri->bri && pri->master) { - q921_tei_release_and_reacquire(pri->master); - return; - } else { - q921_dchannel_down(pri); - q921_start(pri, 1); - pri->schedev = 1; - } - } - } else if (pri->solicitfbit) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Retrying poll with f-bit\n"); - if (pri->retrans < pri->timers[PRI_TIMER_N200]) { - pri->retrans++; - pri->solicitfbit = 1; - q921_rr(pri, 1, 1); - pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); - } else { - if (pri->debug & PRI_DEBUG_Q921_STATE) - pri_message(pri, "-- Timeout occured, restarting PRI\n"); - if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) - pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO); - pri->q921_state = Q921_LINK_CONNECTION_RELEASED; - pri->t200_timer = 0; - if (pri->bri && pri->master) { - q921_tei_release_and_reacquire(pri->master); - return; - } else { - q921_dchannel_down(pri); - q921_start(pri, 1); - pri->schedev = 1; - } - } + if (!pri->own_rx_busy) { + q921_rr(pri, 1, 1); + pri->acknowledge_pending = 0; + start_t200(pri); } else { - pri_error(pri, "T200 counter expired, nothing to send...\n"); - pri->t200_timer = 0; + /* XXX: Implement me... */ } } +static void t200_expire(void *vpri) +{ + struct pri *pri = vpri; + + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "%s\n", __FUNCTION__); + + q921_dump_pri(pri); + + pri->t200_timer = 0; + + switch (pri->q921_state) { + case Q921_MULTI_FRAME_ESTABLISHED: + pri->RC = 0; + transmit_enquiry(pri); + pri->RC++; + q921_setstate(pri, Q921_TIMER_RECOVERY); + break; + case Q921_TIMER_RECOVERY: + /* SDL Flow Figure B.8/Q.921 Page 81 */ + if (pri->RC != pri->timers[PRI_TIMER_N200]) { +#if 0 + if (pri->v_s == pri->v_a) { + transmit_enquiry(pri); + } +#else + /* We are chosing to enquiry by default (to reduce risk of T200 timer errors at the other + * side, instead of retransmission of the last I frame we sent */ + transmit_enquiry(pri); +#endif + pri->RC++; + } else { + //pri_error(pri, "MDL-ERROR (I): T200 = N200 in timer recovery state\n"); + q921_mdl_error(pri, 'I'); + q921_establish_data_link(pri); + pri->l3initiated = 0; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + } + break; + case Q921_AWAITING_ESTABLISHMENT: + if (pri->RC != pri->timers[PRI_TIMER_N200]) { + pri->RC++; + q921_send_sabme(pri); + start_t200(pri); + } else { + q921_discard_iqueue(pri); + //pri_error(pri, "MDL-ERROR (G) : T200 expired N200 times in state %d\n", pri->q921_state); + q921_mdl_error(pri, 'G'); + q921_setstate(pri, Q921_TEI_ASSIGNED); + /* DL-RELEASE indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + } + break; + default: + pri_error(pri, "Cannot handle T200 expire in state %d\n", pri->q921_state); + } + +} + +/* This is sending a DL-UNIT-DATA request */ int q921_transmit_uiframe(struct pri *pri, void *buf, int len) { uint8_t ubuf[512]; @@ -517,74 +527,108 @@ int q921_transmit_uiframe(struct pri *pri, void *buf, int len) return 0; } -int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr) +static struct pri * pri_find_tei(struct pri *vpri, int sapi, int tei) +{ + struct pri *pri; + for (pri = PRI_MASTER(vpri); pri; pri = pri->subchannel) { + if (pri->tei == tei && pri->sapi == sapi) + return pri; + } + + return NULL; +} + +/* This is the equivalent of a DL-DATA request, as well as the I frame queued up outcome */ +int q921_transmit_iframe(struct pri *vpri, int tei, void *buf, int len, int cr) { q921_frame *f, *prev=NULL; + struct pri *pri; - for (f=pri->txqueue; f; f = f->next) prev = f; - f = calloc(1, sizeof(q921_frame) + len + 2); - if (f) { - Q921_INIT(pri, f->h); - switch(pri->localtype) { - case PRI_NETWORK: - if (cr) - f->h.h.c_r = 1; - else - f->h.h.c_r = 0; - break; - case PRI_CPE: - if (cr) - f->h.h.c_r = 0; - else - f->h.h.c_r = 1; - break; - } - f->next = NULL; - f->transmitted = 0; - f->len = len + 4; - memcpy(f->h.data, buf, len); - f->h.n_s = pri->v_s; - f->h.n_r = pri->v_r; - pri->v_s++; - pri->v_na = pri->v_r; - f->h.p_f = 0; - f->h.ft = 0; - if (prev) - prev->next = f; - else - pri->txqueue = f; - /* Immediately transmit unless we're in a recovery state, or the window - size is too big */ - if (pri->debug & PRI_DEBUG_Q921_DUMP) { - pri_message(pri, "TEI/SAPI: %d/%d state %d retran %d busy %d\n", - pri->tei, pri->sapi, pri->q921_state, pri->retrans, pri->busy); - } - if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) { - if (pri->windowlen < pri->window) { - q921_send_queued_iframes(pri); - } else { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "Delaying transmission of %d, window is %d/%d long\n", - f->h.n_s, pri->windowlen, pri->window); - } - } - if (pri->t203_timer) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "Stopping T_203 timer\n"); - pri_schedule_del(pri, pri->t203_timer); - pri->t203_timer = 0; + if (BRI_NT_PTMP(vpri)) { + if (tei == Q921_TEI_GROUP) { + pri_error(vpri, "Huh?! For NT-PTMP, we shouldn't be sending I-frames out the group TEI\n"); + return 0; } - /* Check this so that we don't try to send frames while multi frame mode is down */ - if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "Starting T_200 timer\n"); + pri = pri_find_tei(vpri, Q921_SAPI_CALL_CTRL, tei); + if (!pri) { + pri_error(vpri, "Huh?! Unable to locate PRI associated with TEI %d. Did we have to ditch it due to error conditions?\n", tei); + return 0; + } + } else if (BRI_TE_PTMP(vpri)) { + /* We don't care what the tei is, since we only support one sub and one TEI */ + pri = PRI_MASTER(vpri)->subchannel; - reschedule_t200(pri); + if (pri->q921_state == Q921_TEI_UNASSIGNED) { + q921_tei_request(pri); + /* We don't setstate here because the pri with the TEI we need hasn't been created */ + q921_setstate(pri, Q921_ESTABLISH_AWAITING_TEI); } } else { - pri_error(pri, "!! Out of memory for Q.921 transmit\n"); - return -1; + /* Should just be PTP modes, which shouldn't have subs */ + pri = vpri; + } + + /* Figure B.7/Q.921 Page 70 */ + switch (pri->q921_state) { + case Q921_TEI_ASSIGNED: + /* If we aren't in a state compatiable with DL-DATA requests, start getting us there here */ + q921_establish_data_link(pri); + pri->l3initiated = 1; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + /* For all rest, we've done the work to get us up prior to this and fall through */ + case Q921_TEI_UNASSIGNED: + case Q921_ESTABLISH_AWAITING_TEI: + case Q921_ASSIGN_AWAITING_TEI: + case Q921_TIMER_RECOVERY: + case Q921_AWAITING_ESTABLISHMENT: + case Q921_MULTI_FRAME_ESTABLISHED: + for (f=pri->txqueue; f; f = f->next) prev = f; + f = calloc(1, sizeof(q921_frame) + len + 2); + if (f) { + Q921_INIT(pri, f->h); + switch(pri->localtype) { + case PRI_NETWORK: + if (cr) + f->h.h.c_r = 1; + else + f->h.h.c_r = 0; + break; + case PRI_CPE: + if (cr) + f->h.h.c_r = 0; + else + f->h.h.c_r = 1; + break; + } + f->next = NULL; + f->transmitted = 0; + f->len = len + 4; + memcpy(f->h.data, buf, len); + if (prev) + prev->next = f; + else + pri->txqueue = f; + + if (pri->q921_state != Q921_MULTI_FRAME_ESTABLISHED) { + return 0; + } + + if (pri->peer_rx_busy || (pri->v_s == Q921_ADD(pri->v_a, pri->k))) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "Couldn't transmit I frame at this time due to peer busy condition or window shut\n"); + return 0; + } + + q921_send_queued_iframes(pri); + + return 0; + } else { + pri_error(pri, "!! Out of memory for Q.921 transmit\n"); + return -1; + } + default: + pri_error(pri, "Cannot transmit frames in state %d\n", pri->q921_state); } return 0; } @@ -592,73 +636,53 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr) static void t203_expire(void *vpri) { struct pri *pri = vpri; - if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "%s\n", __FUNCTION__); + pri->t203_timer = 0; + switch (pri->q921_state) { + case Q921_MULTI_FRAME_ESTABLISHED: + transmit_enquiry(pri); + pri->RC = 0; + q921_setstate(pri, Q921_TIMER_RECOVERY); + break; + default: if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "T203 counter expired, sending RR and scheduling T203 again\n"); - /* Solicit an F-bit in the other's RR */ - pri->solicitfbit = 1; - pri->retrans = 0; - q921_rr(pri, 1, 1); - /* Start timer T200 to resend our RR if we don't get it */ - pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); - } else { - if (pri->debug & PRI_DEBUG_Q921_DUMP) { - pri_message(pri, - "T203 counter expired in weird state %d on pri with SAPI/TEI of %d/%d\n", - pri->q921_state, pri->sapi, pri->tei); - } + pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state); pri->t203_timer = 0; } } -static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len) +static void q921_dump_iqueue_info(struct pri *pri, int force) { - int res; - pri_event *ev; + struct q921_frame *f; + int pending = 0, unacked = 0; - pri->solicitfbit = 0; - /* 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 */ - pri->sentrej = 0; - ev = q921_ack_rx(pri, i->n_r, 1); - if (ev) - return ev; - if (i->p_f) { - /* If the Poll/Final bit is set, immediate send the RR */ - q921_rr(pri, 1, 0); - } else if (pri->busy || pri->retrans) { - q921_rr(pri, 0, 0); + unacked = pending = 0; + + for (f = pri->txqueue; f && f->next; f = f->next) { + if (f->transmitted) { + unacked++; + } else { + pending++; } - /* 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, 0); - if (res == -1) { - return NULL; - } - if (res & Q931_RES_HAVEEVENT) - return &pri->ev; - } else { - /* 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; + + if (force) + pri_error(pri, "Number of pending packets %d, sent but unacked %d\n", pending, unacked); + + return; } +static void q921_dump_pri_by_h(struct pri *pri, q921_h *h); + void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx) { int x; char *type; char direction_tag; + q921_dump_pri_by_h(pri, h); + direction_tag = txrx ? '>' : '<'; if (showraw) { char *buf = malloc(len * 3 + 1); @@ -831,103 +855,36 @@ void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx) } } -pri_event *q921_dchannel_up(struct pri *pri) +static void q921_dump_pri(struct pri *pri) { - if (pri->tei == Q921_TEI_PRI) { - q921_reset(pri, 1); - } else { - q921_reset(pri, 0); + pri_message(pri, "TEI: %d State %d\n", pri->tei, pri->q921_state); + pri_message(pri, "V(S) %d V(A) %d V(R) %d\n", pri->v_s, pri->v_a, pri->v_r); + pri_message(pri, "K %d, RC %d, l3initiated %d, reject_except %d ack_pend %d\n", pri->k, pri->RC, pri->l3initiated, pri->reject_exception, pri->acknowledge_pending); + pri_message(pri, "T200 %d, N200 %d, T203 %d\n", pri->t200_timer, 3, pri->t203_timer); +} + +static void q921_dump_pri_by_h(struct pri *vpri, q921_h *h) +{ + struct pri *pri = NULL; + + if (BRI_NT_PTMP(vpri)) { + pri = pri_find_tei(vpri, h->h.sapi, h->h.tei); + } else if (BRI_TE_PTMP(vpri)) { + pri = PRI_MASTER(vpri)->subchannel; + } else + pri = vpri; + if (pri) { + q921_dump_pri(pri); + } else if (!PTMP_MODE(vpri)) { + pri_error(vpri, "Huh.... no pri found to dump\n"); } - - /* Stop any SABME retransmissions */ - pri_schedule_del(pri, pri->sabme_timer); - pri->sabme_timer = 0; - - /* Reset any rejects */ - pri->sentrej = 0; - - /* Go into connection established state */ - if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) - pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_ESTABLISHED\n", DBGINFO); - pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED; - - /* Ensure that we do not have T200 or T203 running when the link comes up */ - pri_schedule_del(pri, pri->t200_timer); - pri->t200_timer = 0; - - /* Start the T203 timer */ - pri_schedule_del(pri, pri->t203_timer); - pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); - - /* Notify Layer 3 */ - q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); - - q921_send_queued_iframes(pri); - - /* Report event that D-Channel is now up */ - pri->ev.gen.e = PRI_EVENT_DCHAN_UP; - return &pri->ev; -} - -pri_event *q921_dchannel_down(struct pri *pri) -{ - /* Reset counters, reset sabme timer etc */ - q921_reset(pri, 1); - - /* Notify Layer 3 */ - q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); - - /* Report event that D-Channel is now down */ - pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN; - return &pri->ev; -} - -void q921_reset(struct pri *pri, int reset_iqueue) -{ - /* Having gotten a SABME we MUST reset our entire state */ - if (reset_iqueue) - pri->v_s = 0; - - pri->v_a = 0; - pri->v_r = 0; - pri->v_na = 0; - pri->window = pri->timers[PRI_TIMER_K]; - pri->windowlen = 0; - pri_schedule_del(pri, pri->sabme_timer); - pri_schedule_del(pri, pri->t203_timer); - pri_schedule_del(pri, pri->t200_timer); - pri->sabme_timer = 0; - pri->sabme_count = 0; - pri->t203_timer = 0; - pri->t200_timer = 0; - pri->busy = 0; - pri->solicitfbit = 0; - if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) - pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO); - pri->q921_state = Q921_LINK_CONNECTION_RELEASED; - pri->retrans = 0; - pri->sentrej = 0; - - /* Discard anything waiting to go out */ - if (reset_iqueue) - q921_discard_retransmissions(pri); -} - -static void q921_tei_release_and_reacquire(struct pri *master) -{ - /* Make sure the master is passed into this function */ - q921_dchannel_down(master->subchannel); - __pri_free_tei(master->subchannel); - master->subchannel = NULL; - master->ev.gen.e = PRI_EVENT_DCHAN_DOWN; - master->schedev = 1; - q921_start(master, master->localtype == PRI_CPE); } static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len) { int ri; struct pri *sub = pri; + pri_event *res = NULL; int tei; if (!BRI_NT_PTMP(pri) && !BRI_TE_PTMP(pri)) { @@ -947,6 +904,7 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len) } ri = (h->data[1] << 8) | h->data[2]; tei = (h->data[4] >> 1); + switch(h->data[3]) { case Q921_TEI_IDENTITY_REQUEST: if (!BRI_NT_PTMP(pri)) { @@ -963,44 +921,68 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len) ++tei; sub = sub->subchannel; } + + if (tei >= Q921_TEI_GROUP) { + pri_error(pri, "Reached maximum TEI quota, cannot assign new TEI\n"); + return NULL; + } sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1); + if (!sub->subchannel) { pri_error(pri, "Unable to allocate D-channel for new TEI %d\n", tei); return NULL; } + q921_setstate(sub->subchannel, Q921_TEI_ASSIGNED); + pri_error(pri, "Allocating new TEI %d\n", tei); q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1); break; case Q921_TEI_IDENTITY_ASSIGNED: if (!BRI_TE_PTMP(pri)) return NULL; + /* Assuming we're operating on the sub here */ + pri = pri->subchannel; + + switch (pri->q921_state) { + case Q921_ASSIGN_AWAITING_TEI: + case Q921_ESTABLISH_AWAITING_TEI: + break; + default: + pri_message(pri, "Ignoring unrequested TEI assign message\n"); + return NULL; + } + if (ri != pri->ri) { pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri); return NULL; } + pri_schedule_del(pri, pri->t202_timer); pri->t202_timer = 0; - if (pri->subchannel && (pri->subchannel->tei == tei)) { - pri_error(pri, "TEI already assigned (new is %d, current is %d)\n", tei, pri->subchannel->tei); - q921_tei_release_and_reacquire(pri); + pri->tei = tei; + + switch (pri->q921_state) { + case Q921_ASSIGN_AWAITING_TEI: + q921_setstate(pri, Q921_TEI_ASSIGNED); + pri->ev.gen.e = PRI_EVENT_DCHAN_UP; + res = &pri->ev; + break; + case Q921_ESTABLISH_AWAITING_TEI: + q921_establish_data_link(pri); + pri->l3initiated = 1; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + default: + pri_error(pri, "Error 3\n"); return NULL; } - pri_message(pri, "TEI assiged to %d\n", tei); - pri->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1); - if (!pri->subchannel) { - pri_error(pri, "Unable to allocate D-channel for new TEI %d\n", tei); - return NULL; - } - pri->q921_state = Q921_TEI_ASSIGNED; break; case Q921_TEI_IDENTITY_CHECK_REQUEST: if (!BRI_TE_PTMP(pri)) return NULL; - /* We're assuming one TEI per PRI in TE PTMP mode */ - /* If no subchannel (TEI) ignore */ - if (!pri->subchannel) + if (pri->subchannel->q921_state < Q921_TEI_ASSIGNED) return NULL; /* If it's addressed to the group TEI or to our TEI specifically, we respond */ @@ -1011,162 +993,885 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len) case Q921_TEI_IDENTITY_REMOVE: if (!BRI_TE_PTMP(pri)) return NULL; - /* XXX: Assuming multiframe mode has been disconnected already */ - if (!pri->subchannel) - return NULL; if ((tei == Q921_TEI_GROUP) || (tei == pri->subchannel->tei)) { - q921_tei_release_and_reacquire(pri); + q921_setstate(pri->subchannel, Q921_TEI_UNASSIGNED); + q921_start(pri->subchannel); } } - return NULL; /* Do we need to return something??? */ + return res; /* Do we need to return something??? */ } static int is_command(struct pri *pri, q921_h *h) { - int command =0; + int command = 0; int c_r = h->s.h.c_r; if ((pri->localtype == PRI_NETWORK && c_r == 0) || (pri->localtype == PRI_CPE && c_r == 1)) command = 1; - return( command ); + return command; +} + +static void q921_clear_exception_conditions(struct pri *pri) +{ + pri->own_rx_busy = 0; + pri->peer_rx_busy = 0; + pri->reject_exception = 0; + pri->acknowledge_pending = 0; +} + +static pri_event * q921_sabme_rx(struct pri *pri, q921_h *h) +{ + pri_event *res = NULL; + + switch (pri->q921_state) { + case Q921_TIMER_RECOVERY: + /* Timer recovery state handling is same as multiframe established */ + case Q921_MULTI_FRAME_ESTABLISHED: + /* Send Unnumbered Acknowledgement */ + q921_send_ua(pri, h->u.p_f); + q921_clear_exception_conditions(pri); + //pri_error(pri, "MDL-ERROR (F), SABME in state %d\n", pri->q921_state); + q921_mdl_error(pri, 'F'); + if (pri->v_s != pri->v_a) { + q921_discard_iqueue(pri); + /* DL-ESTABLISH indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); + } + stop_t200(pri); + start_t203(pri); + pri->v_s = pri->v_a = pri->v_r = 0; + q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED); + break; + case Q921_TEI_ASSIGNED: + q921_send_ua(pri, h->u.p_f); + q921_clear_exception_conditions(pri); + pri->v_s = pri->v_a = pri->v_r = 0; + /* DL-ESTABLISH indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); + if (PTP_MODE(pri)) { + pri->ev.gen.e = PRI_EVENT_DCHAN_UP; + res = &pri->ev; + } + start_t203(pri); + q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED); + break; + case Q921_AWAITING_ESTABLISHMENT: + q921_send_ua(pri, h->u.p_f); + break; + case Q921_AWAITING_RELEASE: + default: + pri_error(pri, "Cannot handle SABME in state %d\n", pri->q921_state); + } + + return res; +} + +static pri_event *q921_disc_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + + switch (pri->q921_state) { + case Q921_AWAITING_RELEASE: + q921_send_ua(pri, h->u.p_f); + break; + case Q921_MULTI_FRAME_ESTABLISHED: + case Q921_TIMER_RECOVERY: + q921_discard_iqueue(pri); + q921_send_ua(pri, h->u.p_f); + /* DL-RELEASE Indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + + stop_t200(pri); + if (pri->q921_state == Q921_MULTI_FRAME_ESTABLISHED) + stop_t203(pri); + q921_setstate(pri, Q921_TEI_ASSIGNED); + break; + default: + pri_error(pri, "Don't know what to do with DISC in state %d\n", pri->q921_state); + break; + + } + + return res; +} + +static void q921_mdl_remove(struct pri *pri) +{ + switch (pri->q921_state) { + case Q921_TEI_ASSIGNED: + /* XXX: deviation! Since we don't have a UI queue, we just discard our I-queue */ + q921_discard_iqueue(pri); + q921_setstate(pri, Q921_TEI_UNASSIGNED); + break; + case Q921_AWAITING_ESTABLISHMENT: + q921_discard_iqueue(pri); + /* DL-RELEASE indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + + stop_t200(pri); + q921_setstate(pri, Q921_TEI_UNASSIGNED); + break; + case Q921_AWAITING_RELEASE: + q921_discard_iqueue(pri); + /* DL-RELEASE confirm */ + stop_t200(pri); + break; + case Q921_MULTI_FRAME_ESTABLISHED: + q921_discard_iqueue(pri); + /* DL-RELEASE indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + stop_t200(pri); + stop_t203(pri); + q921_setstate(pri, Q921_TEI_UNASSIGNED); + break; + case Q921_TIMER_RECOVERY: + q921_discard_iqueue(pri); + /* DL-RELEASE indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + stop_t200(pri); + q921_setstate(pri, Q921_TEI_UNASSIGNED); + default: + pri_error(pri, "Cannot handle MDL remove when PRI is in state %d\n", pri->q921_state); + break; + } + + if (BRI_NT_PTMP(pri) && pri->q921_state == Q921_TEI_UNASSIGNED) { + if (pri == PRI_MASTER(pri)) { + pri_error(pri, "Bad bad bad! Asked to free master\n"); + return; + } + pri->mdl_free_me = 1; + } +} + +static int q921_mdl_handle_network_error(struct pri *pri, char error) +{ + int handled = 0; + switch (error) { + case 'C': + case 'D': + case 'G': + case 'H': + q921_mdl_remove(pri); + handled = 1; + break; + case 'A': + case 'B': + case 'E': + case 'F': + case 'I': + default: + pri_error(pri, "Network MDL can't handle error of type %c\n", error); + break; + } + + return handled; +} + +static int q921_mdl_handle_cpe_error(struct pri *pri, char error) +{ + int handled = 0; + + switch (error) { + case 'C': + case 'D': + case 'G': + case 'H': + q921_mdl_remove(pri); + handled = 1; + break; + case 'A': + case 'B': + case 'E': + case 'F': + case 'I': + break; + default: + pri_error(pri, "CPE MDL can't handle error of type %c\n", error); + break; + } + + return handled; +} + +static int q921_mdl_handle_ptp_error(struct pri *pri, char error) +{ + int handled = 0; + /* This is where we act a bit like L3 instead of L2, since we've got an L3 that depends on us + * keeping L2 automatically alive and happy for point to point links */ + switch (error) { + case 'G': + /* We pick it back up and put it back together for this case */ + q921_discard_iqueue(pri); + q921_establish_data_link(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + + pri->schedev = 1; + pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN; + + handled = 1; + break; + default: + pri_error(pri, "PTP MDL can't handle error of type %c\n", error); + } + + return handled; +} + +static void q921_mdl_handle_error(struct pri *pri, char error, int errored_state) +{ + int handled = 0; + if (PTP_MODE(pri)) { + handled = q921_mdl_handle_ptp_error(pri, error); + } else { + if (pri->localtype == PRI_NETWORK) { + handled = q921_mdl_handle_network_error(pri, error); + } else { + handled = q921_mdl_handle_cpe_error(pri, error); + } + } + + if (handled) + return; + + switch (error) { + case 'C': + pri_error(pri, "MDL-ERROR (C): UA in state %d\n", errored_state); + break; + case 'D': + pri_error(pri, "MDL-ERROR (D): UA in state %d\n", errored_state); + break; + case 'A': + pri_error(pri, "MDL-ERROR (A): Got supervisory frame with p_f bit set to 1 in state %d\n", errored_state); + break; + case 'I': + pri_error(pri, "MDL-ERROR (I): T200 = N200 in timer recovery state %d\n", errored_state); + break; + case 'G': + pri_error(pri, "MDL-ERROR (G) : T200 expired N200 times in state %d\n", errored_state); + break; + case 'F': + pri_error(pri, "MDL-ERROR (F), SABME in state %d\n", errored_state); + break; + case 'H': + case 'B': + case 'E': + case 'J': + default: + pri_error(pri, "MDL-ERROR (%c) in state %d\n", error, errored_state); + + } + + return; +} + +static void q921_mdl_handle_error_callback(void *vpri) +{ + struct pri *pri = vpri; + + q921_mdl_handle_error(pri, pri->mdl_error, pri->mdl_error_state); + + pri->mdl_error = 0; + pri->mdl_timer = 0; + + if (pri->mdl_free_me) { + struct pri *master = PRI_MASTER(pri); + struct pri *freep = NULL, *prev, *cur; + prev = master; + cur = master->subchannel; + + while (cur) { + if (cur == pri) { + prev->subchannel = cur->subchannel; + freep = cur; + break; + } + prev = cur; + cur = cur->subchannel; + } + + if (freep == NULL) { + pri_error(pri, "Huh!? no match found in list for TEI %d\n", pri->tei); + return; + } + + pri_error(pri, "Freeing TEI of %d\n", freep->tei); + + free(freep); + } + + return; +} + +static void q921_mdl_error(struct pri *pri, char error) +{ + if (pri->mdl_error) { + pri_error(pri, "Trying to queue an MDL error when one is already scheduled\n"); + return; + } + pri->mdl_error = error; + pri->mdl_error_state = pri->q921_state; + pri->mdl_timer = pri_schedule_event(pri, 0, q921_mdl_handle_error_callback, pri); +} + +static pri_event *q921_ua_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + + switch (pri->q921_state) { + case Q921_TEI_ASSIGNED: + //pri_error(pri, "MDL-ERROR (C, D): UA received in state %d\n", pri->q921_state); + if (h->u.p_f) + q921_mdl_error(pri, 'C'); + else + q921_mdl_error(pri, 'D'); + break; + case Q921_AWAITING_ESTABLISHMENT: + if (!h->u.p_f) { + pri_error(pri, "MDL-ERROR: Received UA with F = 0 while awaiting establishment\n"); + break; + } + + if (!pri->l3initiated) { + if (pri->v_s != pri->v_a) { + q921_discard_iqueue(pri); + /* return DL-ESTABLISH-INDICATION */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); + } + } else { + /* Might not want this... */ + pri->l3initiated = 0; + /* But do want this */ + pri->v_r = 0; + /* return DL-ESTABLISH-CONFIRM */ + } + + if (PTP_MODE(pri)) { + pri->ev.gen.e = PRI_EVENT_DCHAN_UP; + res = &pri->ev; + } + + stop_t200(pri); + start_t203(pri); + + pri->v_s = pri->v_a = 0; + + q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED); + break; + case Q921_AWAITING_RELEASE: + if (!h->u.p_f) { + //pri_error(pri, "MDL-ERROR (D): UA in state %d w with P_F bit 0\n", pri->q921_state); + q921_mdl_error(pri, 'D'); + } else { + /* return DL-RELEASE-CONFIRM */ + stop_t200(pri); + q921_setstate(pri, Q921_TEI_ASSIGNED); + } + break; + case Q921_MULTI_FRAME_ESTABLISHED: + case Q921_TIMER_RECOVERY: + //pri_error(pri, "MDL-ERROR (C, D) UA in state %d\n", pri->q921_state); + q921_mdl_error(pri, 'C'); + break; + default: + pri_error(pri, "Don't know what to do with UA in state %d\n", pri->q921_state); + break; + + } + + return res; +} + +static void q921_enquiry_response(struct pri *pri) +{ + if (pri->own_rx_busy) { + /* XXX : TODO later sometime */ + pri_error(pri, "Implement me %s: own_rx_busy\n", __FUNCTION__); + //q921_rnr(pri); + } else { + q921_rr(pri, 1, 0); + } + + pri->acknowledge_pending = 0; +} + +static void n_r_error_recovery(struct pri *pri) +{ + q921_mdl_error(pri, 'J'); + + q921_establish_data_link(pri); + + pri->l3initiated = 0; +} + +static void update_v_a(struct pri *pri, int n_r) +{ + int idealcnt = 0, realcnt = 0; + int x; + + /* Cancel each packet as necessary */ + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, n_r); + for (x = pri->v_a; x != n_r; Q921_INC(x)) { + idealcnt++; + realcnt += q921_ack_packet(pri, x); + } + if (idealcnt != realcnt) { + pri_error(pri, "Ideally should have ack'd %d frames, but actually ack'd %d. This is not good.\n", idealcnt, realcnt); + q921_dump_iqueue_info(pri, 1); + } + + q921_dump_iqueue_info(pri, 0); + + pri->v_a = n_r; +} + +static int n_r_is_valid(struct pri *pri, int n_r) +{ + int x; + + for (x=pri->v_a; (x != pri->v_s) && (x != n_r); Q921_INC(x)); + if (x != n_r) { + pri_error(pri, "N(R) %d not within ack window! Bad Bad Bad!\n", n_r); + return 0; + } else { + return 1; + } +} + +static int q921_invoke_retransmission(struct pri *pri, int n_r); + +static pri_event * timer_recovery_rr_rej_rx(struct pri *pri, q921_h *h) +{ + /* Figure B.7/Q.921 Page 74 */ + pri->peer_rx_busy = 0; + + if (is_command(pri, h)) { + if (h->s.p_f) { + /* Enquiry response */ + q921_enquiry_response(pri); + } + if (n_r_is_valid(pri, h->s.n_r)) { + update_v_a(pri, h->s.n_r); + } else { + goto n_r_error_out; + } + } else { + if (!h->s.p_f) { + if (n_r_is_valid(pri, h->s.n_r)) { + update_v_a(pri, h->s.n_r); + } else { + goto n_r_error_out; + } + } else { + if (n_r_is_valid(pri, h->s.n_r)) { + update_v_a(pri, h->s.n_r); + stop_t200(pri); + start_t203(pri); + q921_invoke_retransmission(pri, h->s.n_r); + q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED); + } else { + goto n_r_error_out; + } + } + } + return NULL; +n_r_error_out: + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + return NULL; +} + +static pri_event *q921_rr_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + switch (pri->q921_state) { + case Q921_TIMER_RECOVERY: + res = timer_recovery_rr_rej_rx(pri, h); + break; + case Q921_MULTI_FRAME_ESTABLISHED: + /* Figure B.7/Q.921 Page 74 */ + pri->peer_rx_busy = 0; + + if (is_command(pri, h)) { + if (h->s.p_f) { + /* Enquiry response */ + q921_enquiry_response(pri); + } + } else { + if (h->s.p_f) { + //pri_message(pri, "MDL-ERROR (A): Got RR response with p_f bit set to 1 in state %d\n", pri->q921_state); + q921_mdl_error(pri, 'A'); + } + } + + if (!n_r_is_valid(pri, h->s.n_r)) { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + } else { + if (h->s.n_r == pri->v_s) { + update_v_a(pri, h->s.n_r); + stop_t200(pri); + start_t203(pri); + } else { + if (h->s.n_r != pri->v_a) { + /* Need to check the validity of n_r as well.. */ + update_v_a(pri, h->s.n_r); + restart_t200(pri); + } + } + } + break; + default: + pri_error(pri, "Don't know what to do with RR in state %d\n", pri->q921_state); + break; + } + + return res; +} + +/* TODO: Look at this code more... */ +static int q921_invoke_retransmission(struct pri *pri, int n_r) +{ + int frames_txd = 0; + int frames_supposed_to_tx = 0; + q921_frame *f; + unsigned int local_v_s = pri->v_s; + + + for (f = pri->txqueue; f && (f->h.n_s != n_r); f = f->next); + while (f) { + if (f->transmitted) { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", n_r, f->h.n_s); + f->h.n_r = pri->v_r; + f->h.p_f = 0; + q921_transmit(pri, (q921_h *)(&f->h), f->len); + frames_txd++; + } + f = f->next; + } + + while (local_v_s != n_r) { + Q921_DEC(local_v_s); + frames_supposed_to_tx++; + } + + if (frames_supposed_to_tx != frames_txd) { + pri_error(pri, "!!!!!!!!!!!! Should have only transmitted %d frames!\n", frames_supposed_to_tx); + } + + return frames_txd; +} + +static pri_event *q921_rej_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + + pri_message(pri, "!! Got reject for frame %d in state %d\n", h->s.n_r, pri->q921_state); + + switch (pri->q921_state) { + case Q921_TIMER_RECOVERY: + res = timer_recovery_rr_rej_rx(pri, h); + break; + case Q921_MULTI_FRAME_ESTABLISHED: + /* Figure B.7/Q.921 Page 74 */ + pri->peer_rx_busy = 0; + + if (is_command(pri, h)) { + if (h->s.p_f) { + /* Enquiry response */ + q921_enquiry_response(pri); + } + } else { + if (h->s.p_f) { + //pri_message(pri, "MDL-ERROR (A): Got REJ response with p_f bit set to 1 in state %d\n", pri->q921_state); + q921_mdl_error(pri, 'A'); + } + } + + if (!n_r_is_valid(pri, h->s.n_r)) { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + } else { + update_v_a(pri, h->s.n_r); + stop_t200(pri); + start_t203(pri); + q921_invoke_retransmission(pri, h->s.n_r); + } + return NULL; + default: + pri_error(pri, "Don't know what to do with RR in state %d\n", pri->q921_state); + return NULL; + } + + return res; +} + +static pri_event *q921_iframe_rx(struct pri *pri, q921_h *h, int len) +{ + pri_event * eres = NULL; + int res = 0; + + switch (pri->q921_state) { + case Q921_TIMER_RECOVERY: + case Q921_MULTI_FRAME_ESTABLISHED: + /* FIXME: Verify that it's a command ... */ + if (pri->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 == pri->v_r) { + Q921_INC(pri->v_r); + + pri->reject_exception = 0; + + //res = q931_receive(PRI_MASTER(pri), pri->tei, (q931_h *)h->i.data, len - 4); + res = q931_receive(pri, pri->tei, (q931_h *)h->i.data, len - 4); + + if (h->i.p_f) { + q921_rr(pri, 1, 0); + pri->acknowledge_pending = 0; + } else { + if (!pri->acknowledge_pending) { + /* XXX: Fix acknowledge_pending */ + pri->acknowledge_pending = 1; + } + } + + } else { + if (pri->reject_exception) { + if (h->i.p_f) { + q921_rr(pri, 1, 0); + pri->acknowledge_pending = 0; + } + } else { + pri->reject_exception = 1; + q921_reject(pri, h->i.p_f); + pri->acknowledge_pending = 0; + } + } + + if (!n_r_is_valid(pri, h->i.n_r)) { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + } else { + if (pri->q921_state == Q921_TIMER_RECOVERY) { + update_v_a(pri, h->i.n_r); + break; + } else { + if (pri->peer_rx_busy) { + update_v_a(pri, h->i.n_r); + } else { + if (h->i.n_r == pri->v_s) { + update_v_a(pri, h->i.n_r); + stop_t200(pri); + start_t203(pri); + } else { + if (h->i.n_r == pri->v_a) { + update_v_a(pri, h->i.n_r); + stop_t200(pri); + start_t200(pri); + } + } + } + } + } + + if (res == -1) { + return NULL; + } + + if (res & Q931_RES_HAVEEVENT) { + return &pri->ev; + } else { + return NULL; + } + default: + pri_error(pri, "Don't know what to do with an I frame in state %d\n", pri->q921_state); + break; + } + + return eres; +} + +static pri_event *q921_dm_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + + switch (pri->q921_state) { + case Q921_TEI_ASSIGNED: + if (h->u.p_f) + break; + /* else */ + q921_establish_data_link(pri); + pri->l3initiated = 1; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + case Q921_AWAITING_ESTABLISHMENT: + if (!h->u.p_f) + break; + + q921_discard_iqueue(pri); + /* DL-RELEASE indication */ + q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); + stop_t200(pri); + q921_setstate(pri, Q921_TEI_ASSIGNED); + break; + case Q921_AWAITING_RELEASE: + if (!h->u.p_f) + break; + /* DL-RELEASE confirm */ + stop_t200(pri); + q921_setstate(pri, Q921_TEI_ASSIGNED); + break; + case Q921_MULTI_FRAME_ESTABLISHED: + if (h->u.p_f) { + /* MDL-ERROR (B) indication */ + q921_mdl_error(pri, 'B'); + break; + } + + q921_mdl_error(pri, 'E'); + q921_establish_data_link(pri); + pri->l3initiated = 0; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + case Q921_TIMER_RECOVERY: + if (h->u.p_f) { + /* MDL-ERROR (B) indication */ + q921_mdl_error(pri, 'B'); + } else { + /* MDL-ERROR (E) indication */ + q921_mdl_error(pri, 'E'); + } + q921_establish_data_link(pri); + pri->l3initiated = 0; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + default: + pri_error(pri, "Don't know what to do with DM frame in state %d\n", pri->q921_state); + break; + } + + return res; +} + +static pri_event *q921_rnr_rx(struct pri *pri, q921_h *h) +{ + pri_event * res = NULL; + + switch (pri->q921_state) { + case Q921_MULTI_FRAME_ESTABLISHED: + pri->peer_rx_busy = 1; + if (!is_command(pri, h)) { + if (h->s.p_f) { + /* MDL-ERROR (A) indication */ + q921_mdl_error(pri, 'A'); + } + } else { + if (h->s.p_f) { + q921_enquiry_response(pri); + } + } + + if (!n_r_is_valid(pri, h->s.n_r)) { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + } else { + update_v_a(pri, h->s.n_r); + stop_t203(pri); + restart_t200(pri); + } + break; + case Q921_TIMER_RECOVERY: + pri->peer_rx_busy = 1; + if (is_command(pri, h)) { + if (h->s.p_f) { + q921_enquiry_response(pri); + if (n_r_is_valid(pri, h->s.n_r)) { + update_v_a(pri, h->s.n_r); + break; + } else { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + } + } + } else { + if (h->s.p_f) { + if (n_r_is_valid(pri, h->s.n_r)) { + update_v_a(pri, h->s.n_r); + restart_t200(pri); + q921_invoke_retransmission(pri, h->s.n_r); + q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED); + break; + } else { + n_r_error_recovery(pri); + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); + break; + } + } + } + break; + default: + pri_error(pri, "Don't know what to do with RNR in state %d\n", pri->q921_state); + break; + } + + return res; +} + +static void q921_acknowledge_pending_check(struct pri *pri) +{ + if (pri->acknowledge_pending) { + pri->acknowledge_pending = 0; + q921_rr(pri, 0, 0); + } +} + +static void q921_statemachine_check(struct pri *pri) +{ + switch (pri->q921_state) { + case Q921_MULTI_FRAME_ESTABLISHED: + q921_send_queued_iframes(pri); + q921_acknowledge_pending_check(pri); + break; + case Q921_TIMER_RECOVERY: + q921_acknowledge_pending_check(pri); + break; + default: + break; + } } static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len) { - q921_frame *f; - pri_event *ev; - int sendnow; + pri_event *ev = NULL; switch(h->h.data[0] & Q921_FRAMETYPE_MASK) { case 0: case 2: - if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { - pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state); - return NULL; - } - /* Informational frame */ - if (len < 4) { - pri_error(pri, "!! Received short I-frame (expected 4, got %d)\n", len); - break; - } - - /* T203 is rescheduled only on reception of I frames or S frames */ - reschedule_t203(pri); - - return q921_handle_iframe(pri, &h->i, len); + ev = q921_iframe_rx(pri, h, len); break; case 1: - if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { - pri_error(pri, "!! Got S-frame while link down\n"); - return NULL; - } - if (len < 4) { - pri_error(pri, "!! Received short S-frame (expected 4, got %d)\n", len); - break; - } - - /* T203 is rescheduled only on reception of I frames or S frames */ - reschedule_t203(pri); - switch(h->s.ss) { case 0: - /* Receiver Ready */ - pri->busy = 0; - /* Acknowledge frames as necessary */ - ev = q921_ack_rx(pri, h->s.n_r, 1); - if (ev) - return ev; - if (is_command(pri, h)) - pri->solicitfbit = 0; - 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 (!is_command(pri, h)) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Got RR response to our frame\n"); - pri->retrans = 0; - } else { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Unsolicited RR with P/F bit, responding\n"); - q921_rr(pri, 1, 0); - } - } + ev = q921_rr_rx(pri, h); break; case 1: - /* Receiver not ready */ - if (pri->debug & PRI_DEBUG_Q921_STATE) - pri_message(pri, "-- Got receiver not ready\n"); - pri->busy = 1; - ev = q921_ack_rx(pri, h->s.n_r, 0); - if (ev) - return ev; - if (h->s.p_f && is_command(pri, h)) - q921_rr(pri, 1, 0); - pri->solicitfbit = 1; - pri->retrans = 0; - if (pri->t203_timer) { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "Stopping T_203 timer\n"); - pri_schedule_del(pri, pri->t203_timer); - pri->t203_timer = 0; - } - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "Restarting T_200 timer\n"); - reschedule_t200(pri); - break; + ev = q921_rnr_rx(pri, h); + break; case 2: /* Just retransmit */ if (pri->debug & PRI_DEBUG_Q921_STATE) pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r); - if (pri->busy && !is_command(pri, h)) - pri->solicitfbit = 0; - pri->busy = 0; - if (is_command(pri, h) && h->s.p_f) - q921_rr(pri, 1, 0); - q921_ack_rx(pri, h->s.n_r, 0); - /*Resend only if we are in the Multiple Frame Established state or when - we are in the Time Recovery state and received responce with bit F=1*/ - if ((pri->solicitfbit == 0) || (pri->solicitfbit && !is_command(pri, h) && h->s.p_f)) { - pri->solicitfbit = 0; - pri->retrans = 0; - sendnow = 0; - /* Resend I-frames starting from frame where f->h.n_s == h->s.n_r */ - for (f = pri->txqueue; f && (f->h.n_s != h->s.n_r); f = f->next); - while (f) { - sendnow = 1; - if (f->transmitted || (!f->transmitted && (pri->windowlen < pri->window))) { - if (pri->debug & PRI_DEBUG_Q921_STATE) - pri_error(pri, "!! 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; - f->h.p_f = 0; - if (!f->transmitted && (pri->windowlen < pri->window)) - pri->windowlen++; - q921_transmit(pri, (q921_h *)(&f->h), f->len); - } - f = f->next; - } - if (!sendnow) { - if (pri->txqueue) { - /* This should never happen */ - if (!h->s.p_f || h->s.n_r) { - pri_error(pri, "!! 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(pri, "!! 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 */ - pri_schedule_del(pri, pri->t200_timer); - pri->t200_timer = 0; - /* Reset and restart t203 timer */ - reschedule_t203(pri); - } - break; + ev = q921_rej_rx(pri, h); + break; default: pri_error(pri, "!! 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); @@ -1180,50 +1885,29 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len) 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 */ - if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) - pri_message(pri, "-- Got DM Mode from peer.\n"); - /* Disconnected mode, try again after T200 */ - ev = q921_dchannel_down(pri); - q921_restart(pri, 0); - return ev; - - } else { - if (pri->debug & PRI_DEBUG_Q921_DUMP) - pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n"); -#if 0 - /* Requesting that we start */ - q921_restart(pri, 0); -#endif - } + ev = q921_dm_rx(pri, h); break; } else if (!h->u.m2) { - if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP)) + if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP)) { + + pri_error(pri, "I should never be called\n"); q921_receive_MDL(pri, (q921_u *)h, len); - else { + + } else { int res; - res = q931_receive(pri, (q931_h *) h->u.data, len - 3); + res = q931_receive(pri, pri->tei, (q931_h *) h->u.data, len - 3); if (res == -1) { - return NULL; + ev = NULL; } if (res & Q931_RES_HAVEEVENT) - return &pri->ev; + ev = &pri->ev; } } break; case 2: - if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) - pri_message(pri, "-- Got Disconnect from peer.\n"); - /* Acknowledge */ - q921_send_ua(pri, h->u.p_f); - ev = q921_dchannel_down(pri); - if (BRI_TE_PTMP(pri) || PRI_PTP(pri)) { - q921_restart(pri, PRI_PTP(pri) ? 1 : 0); - } - return ev; + ev = q921_disc_rx(pri, h); + break; case 3: if (h->u.m2 == 3) { /* SABME */ @@ -1234,36 +1918,22 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len) pri->remotetype = PRI_NETWORK; if (pri->localtype == PRI_NETWORK) { /* We can't both be networks */ - return pri_mkerror(pri, "We think we're the network, but they think they're the network, too."); + ev = pri_mkerror(pri, "We think we're the network, but they think they're the network, too."); + break; } } else { pri->remotetype = PRI_CPE; if (pri->localtype == PRI_CPE) { /* We can't both be CPE */ - return pri_mkerror(pri, "We think we're the CPE, but they think they're the CPE too.\n"); + ev = pri_mkerror(pri, "We think we're the CPE, but they think they're the CPE too.\n"); + break; } } - /* Send Unnumbered Acknowledgement */ - q921_send_ua(pri, h->u.p_f); - return q921_dchannel_up(pri); + ev = q921_sabme_rx(pri, h); + break; } else if (h->u.m2 == 0) { - /* It's a UA */ - if (pri->q921_state == Q921_AWAITING_ESTABLISH) { - if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) { - pri_message(pri, "-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network"); - } - return q921_dchannel_up(pri); - } else if ((pri->q921_state >= Q921_TEI_ASSIGNED) && pri->bri) { - /* Possible duplicate TEI assignment */ - if (pri->master) - q921_tei_release_and_reacquire(pri->master); - else - pri_error(pri, "Huh!? no master found\n"); - } else { - /* Since we're not in the AWAITING_ESTABLISH STATE, it's unsolicited */ - pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state); - - } + ev = q921_ua_rx(pri, h); + break; } else pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); break; @@ -1279,7 +1949,10 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len) break; } - return NULL; + + q921_statemachine_check(pri); + + return ev; } static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int len) @@ -1296,49 +1969,70 @@ static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int le return NULL; } - if (pri->debug & PRI_DEBUG_Q921_DUMP) { - pri_message(pri, - "Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n", - h->h.sapi, h->h.tei); - pri_message(pri, "Sending TEI release, in order to re-establish TEI state\n"); + /* If we're NT-PTMP, this means an unrecognized TEI that we'll kill */ + if (BRI_NT_PTMP(pri)) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) { + pri_message(pri, + "Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n", + h->h.sapi, h->h.tei); + pri_message(pri, "Sending TEI release, in order to re-establish TEI state\n"); + } + + /* Q.921 says we should send the remove message twice, in case of link corruption */ + q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1); + q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1); } - /* Q.921 says we should send the remove message twice, in case of link corruption */ - q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1); - q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1); - return NULL; } +/* This code assumes that the pri structure is the master pri */ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len) { - pri_event *ev; + pri_event *ev = NULL; + struct pri *tei; /* Discard FCS */ len -= 2; - if (!pri->master && pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) + if (pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0); /* Check some reject conditions -- Start by rejecting improper ea's */ if (h->h.ea1 || !(h->h.ea2)) return NULL; - if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) { - /* Check for SAPIs we don't yet handle */ - /* If it's not us, try any subchannels we have */ - if (pri->subchannel) - return q921_receive(pri->subchannel, h, len + 2); - else { - /* This means we couldn't find a candidate subchannel for it... - * Time for some corrective action */ - - return q921_handle_unmatched_frame(pri, h, len); - } - + if ((h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT)) { + return q921_receive_MDL(pri, (q921_u *)h, len); } + + if ((h->h.tei == Q921_TEI_GROUP) && (h->h.sapi != Q921_SAPI_CALL_CTRL)) { + pri_error(pri, "Do not handle group messages to services other than MDL or CALL CTRL\n"); + return NULL; + } + + if (BRI_TE_PTMP(pri)) { + if (((pri->subchannel->q921_state >= Q921_TEI_ASSIGNED) && (h->h.tei == pri->subchannel->tei)) + || (h->h.tei == Q921_TEI_GROUP)) { + ev = __q921_receive_qualified(pri->subchannel, h, len); + } + /* Only support reception on our single subchannel */ + } else if (BRI_NT_PTMP(pri)) { + tei = pri_find_tei(pri, h->h.sapi, h->h.tei); + + if (tei) + ev = __q921_receive_qualified(tei, h, len); + else + ev = q921_handle_unmatched_frame(pri, h, len); + + } else if (PTP_MODE(pri) && (h->h.sapi == pri->sapi) && (h->h.tei == pri->tei)) { + ev = __q921_receive_qualified(pri, h, len); + } else { + ev = NULL; + } + if (pri->debug & PRI_DEBUG_Q921_DUMP) pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei); - ev = __q921_receive_qualified(pri, h, len); + return ev; } @@ -1352,26 +2046,38 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len) return e; } -static void q921_restart(struct pri *pri, int now) +static void q921_establish_data_link(struct pri *pri) { - if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) { - pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n"); - return; - } - /* Reset our interface */ - q921_reset(pri, 1); - /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */ - q921_send_sabme(pri, now); + q921_clear_exception_conditions(pri); + pri->RC = 0; + stop_t203(pri); + reschedule_t200(pri); + q921_send_sabme(pri); } -void q921_start(struct pri *pri, int isCPE) +static void nt_ptmp_dchannel_up(void *vpri) { - q921_reset(pri, 1); - if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP)) { - pri->q921_state = Q921_DOWN; - if (isCPE) + struct pri *pri = vpri; + + pri->schedev = 1; + pri->ev.gen.e = PRI_EVENT_DCHAN_UP; +} + +void q921_start(struct pri *pri) +{ + if (PTMP_MODE(pri)) { + if (TE_MODE(pri)) { + q921_setstate(pri, Q921_ASSIGN_AWAITING_TEI); q921_tei_request(pri); + } else { + q921_setstate(pri, Q921_TEI_UNASSIGNED); + pri_schedule_event(pri, 0, nt_ptmp_dchannel_up, pri); + } } else { - q921_send_sabme(pri, isCPE); + /* PTP mode, no need for TEI management junk */ + q921_establish_data_link(pri); + pri->l3initiated = 1; + q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT); } } + diff --git a/q931.c b/q931.c index 974d168..ea4fb53 100644 --- a/q931.c +++ b/q931.c @@ -3926,12 +3926,12 @@ static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q *mhb = mh; } -static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr, int uiframe) +static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int uiframe) { if (uiframe) { q921_transmit_uiframe(ctrl, h, len); } else { - q921_transmit_iframe(ctrl, h, len, cr); + q921_transmit_iframe(ctrl, tei, h, len, cr); } /* The transmit operation might dump the q921 header, so logging the q931 message body after the transmit puts the sections of the message in the @@ -3998,14 +3998,6 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[ len = sizeof(buf) - len; ctrl = call->pri; - if (BRI_TE_PTMP(ctrl)) { - /* - * Must use the BRI subchannel structure to send with the correct TEI. - * Note: If the subchannel is NULL then there is no TEI assigned and - * we should not be sending anything out at this time. - */ - ctrl = ctrl->subchannel; - } if (ctrl) { int uiframe; @@ -4054,7 +4046,7 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[ ctrl, ctrl->tei, ctrl->sapi, call->pri, call->pri->tei, call->pri->sapi); } - q931_xmit(ctrl, h, len, 1, uiframe); + q931_xmit(ctrl, ctrl->tei, h, len, 1, uiframe); } call->acked = 1; return 0; @@ -5776,7 +5768,7 @@ static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *ma return cur; } -int q931_receive(struct pri *ctrl, q931_h *h, int len) +int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len) { q931_mh *mh; q931_call *c; @@ -5810,7 +5802,7 @@ int q931_receive(struct pri *ctrl, q931_h *h, int len) KLUDGE this by changing byte 4 from a 0xf (SERVICE) to a 0x7 (SERVICE ACKNOWLEDGE) */ h->raw[h->crlen + 2] -= 0x8; - q931_xmit(ctrl, h, len, 1, 0); + q931_xmit(ctrl, ctrl->tei, h, len, 1, 0); return 0; } @@ -5973,11 +5965,11 @@ static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, stru switch (0x0f & c->changestatus) { case SERVICE_CHANGE_STATUS_INSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_UP; - q921_dchannel_up(ctrl); + //q921_dchannel_up(ctrl); break; case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; - q921_dchannel_down(ctrl); + //q921_dchannel_down(ctrl); break; default: pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus)); @@ -5997,11 +5989,11 @@ static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, stru switch (0x0f & c->changestatus) { case SERVICE_CHANGE_STATUS_INSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_UP; - q921_dchannel_up(ctrl); + //q921_dchannel_up(ctrl); break; case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; - q921_dchannel_down(ctrl); + //q921_dchannel_down(ctrl); break; default: pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus));