[libpri-commits] mattf: branch 1.4 r1406 - /branches/1.4/

SVN commits to the libpri project libpri-commits at lists.digium.com
Wed Jan 13 13:38:01 CST 2010


Author: mattf
Date: Wed Jan 13 13:37:59 2010
New Revision: 1406

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1406
Log:
Merge of Q.921 rewrite branch for wider testing.

Modified:
    branches/1.4/Makefile
    branches/1.4/pri.c
    branches/1.4/pri_internal.h
    branches/1.4/pri_q921.h
    branches/1.4/pri_q931.h
    branches/1.4/q921.c
    branches/1.4/q931.c

Modified: branches/1.4/Makefile
URL: http://svnview.digium.com/svn/libpri/branches/1.4/Makefile?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/Makefile (original)
+++ branches/1.4/Makefile Wed Jan 13 13:37:59 2010
@@ -144,7 +144,7 @@
 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

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Wed Jan 13 13:37:59 2010
@@ -144,7 +144,12 @@
 	/* 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 @@
 	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 @@
 	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 @@
 
 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 @@
 	}
 	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);

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Wed Jan 13 13:37:59 2010
@@ -89,25 +89,30 @@
 	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 @@
 							   -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 @@
 	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

Modified: branches/1.4/pri_q921.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_q921.h?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/pri_q921.h (original)
+++ branches/1.4/pri_q921.h Wed Jan 13 13:37:59 2010
@@ -166,36 +166,41 @@
 } 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_reset(struct pri *pri, int reset_iqueue);
+extern void q921_start(struct pri *pri);
+
+//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);
-
-#endif
+//extern pri_event *q921_dchannel_down(struct pri *pri);
+
+#endif

Modified: branches/1.4/pri_q931.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_q931.h?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/pri_q931.h (original)
+++ branches/1.4/pri_q931.h Wed Jan 13 13:37:59 2010
@@ -452,7 +452,7 @@
 /* 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);
 

Modified: branches/1.4/q921.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q921.c?view=diff&rev=1406&r1=1405&r2=1406
==============================================================================
--- branches/1.4/q921.c (original)
+++ branches/1.4/q921.c Wed Jan 13 13:37:59 2010
@@ -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)
 {
@@ -72,6 +83,11 @@
 		free(p);
 	}
 	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) 
@@ -126,20 +142,14 @@
 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");
+	pri->n202_counter++;
+	if (pri->n202_counter > pri->timers[PRI_TIMER_N202]) {
+		pri_error(pri, "Unable to receive TEI from network!\n");
+		pri->n202_counter = 0;
 		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");
-		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 @@
 	q921_transmit(pri, &h, 3);
 }
 
-static void q921_send_sabme_now(void *vpri);
-
-static void q921_send_sabme(void *vpri, int now)
-{
-	struct pri *pri = vpri;
+static void q921_send_sabme(struct pri *pri)
+{
 	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 @@
 		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 @@
 			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 @@
 	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 @@
 	pri_schedule_del(pri, pri->t203_timer);
 	pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
 }
-
-static void q921_send_queued_iframes(struct pri *pri)
+#endif
+
+#if 0
+static int q921_unacked_iframes(struct pri *pri)
+{
+	struct q921_frame *f = pri->txqueue;
+	int cnt = 0;
+
+	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 void start_t200(struct pri *pri)
+{
+	if (pri->t200_timer) {
+		if (pri->debug & PRI_DEBUG_Q921_DUMP)
+			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;
+	} else {
+		if (pri->debug & PRI_DEBUG_Q921_DUMP)
+			pri_message(pri, "-- T200 requested to stop when not started\n");
+	}
+}
+
+/* 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->windowlen < pri->window)) {
+	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->windowlen);
+				pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->k);
 			f->transmitted++;
-			pri->windowlen++;
+			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;
 	}
-}
-
-static pri_event *q921_ack_rx(struct pri *pri, int ack, int send_untransmitted_frames)
-{
-	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->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_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);
-	}
-	return NULL;
+
+	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 @@
 	}
 	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 @@
 		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 transmit_enquiry(struct pri *pri)
+{
+	if (!pri->own_rx_busy) {
+		q921_rr(pri, 1, 1);
+		pri->acknowledge_pending = 0;
+		start_t200(pri);
+	} else {
+		/* XXX: Implement me... */
+	}
+}
+
 static void t200_expire(void *vpri)
 {
 	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);
+
+	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 {
-			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);
+			//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 {
-			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 {
-		pri_error(pri, "T200 counter expired, nothing to send...\n");
-	   	pri->t200_timer = 0;
-	}
-}
-
+			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 @@
 	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;
-
-	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;
+	struct pri *pri;
+
+	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;
+		}
+
+		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;
+
+		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 {
+		/* 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
-				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 {
+				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, "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;
-		}
-
-		/* 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");
-
-			reschedule_t200(pri);		
-		}
-	} else {
-		pri_error(pri, "!! Out of memory for Q.921 transmit\n");
-		return -1;
+					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,66 +636,44 @@
 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)
-{
-	int res;
-	pri_event *ev;
-
-	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); 
-		}
-		/* 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;
-}
+static void q921_dump_iqueue_info(struct pri *pri, int force)
+{
+	struct q921_frame *f;
+	int pending = 0, unacked = 0;
+
+	unacked = pending = 0;
+
+	for (f = pri->txqueue; f && f->next; f = f->next) {
+		if (f->transmitted) {
+			unacked++;
+		} else {
+			pending++;
+		}
+	}
+
+	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)
 {
@@ -659,6 +681,8 @@
         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 @@
 	}
 }
 
-pri_event *q921_dchannel_up(struct pri *pri)
-{
-	if (pri->tei == Q921_TEI_PRI) {
-		q921_reset(pri, 1);
-	} else {
-		q921_reset(pri, 0);
-	}
-
-	/* 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 void q921_dump_pri(struct pri *pri)
+{
+	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");
+	}
 }
 
 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 @@
 	}
 	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 @@
 				++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 @@
 	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);
-		}
-	}

[... 1368 lines stripped ...]



More information about the libpri-commits mailing list