xref: /csrg-svn/sys/netccitt/hd_input.c (revision 41586)
1*41586Ssklower /* Copyright (c) University of British Columbia, 1984 */
2*41586Ssklower 
3*41586Ssklower #include "../h/param.h"
4*41586Ssklower #include "../h/systm.h"
5*41586Ssklower #include "../h/mbuf.h"
6*41586Ssklower #include "../h/domain.h"
7*41586Ssklower #include "../h/socket.h"
8*41586Ssklower #include "../h/protosw.h"
9*41586Ssklower #include "../h/errno.h"
10*41586Ssklower #include "../h/time.h"
11*41586Ssklower #include "../h/kernel.h"
12*41586Ssklower 
13*41586Ssklower #include "../net/if.h"
14*41586Ssklower 
15*41586Ssklower #include "../netccitt/hdlc.h"
16*41586Ssklower #include "../netccitt/hd_var.h"
17*41586Ssklower #include "../netccitt/x25.h"
18*41586Ssklower 
19*41586Ssklower /*
20*41586Ssklower  *      HDLC INPUT INTERFACE
21*41586Ssklower  *
22*41586Ssklower  *      This routine is called when the HDLC physical device has
23*41586Ssklower  *      completed reading a frame.
24*41586Ssklower  */
25*41586Ssklower 
26*41586Ssklower hdintr ()
27*41586Ssklower {
28*41586Ssklower 	register struct mbuf *m;
29*41586Ssklower 	register struct hdcb *hdp;
30*41586Ssklower 	register struct ifnet *ifp;
31*41586Ssklower 	register int s;
32*41586Ssklower 	static struct ifnet *lastifp;
33*41586Ssklower 	static struct hdcb *lasthdp;
34*41586Ssklower 
35*41586Ssklower 	for (;;) {
36*41586Ssklower 		s = splimp ();
37*41586Ssklower 		IF_DEQUEUEIF(&hdintrq, m, ifp);
38*41586Ssklower 		splx (s);
39*41586Ssklower 		if (m == 0)
40*41586Ssklower 			break;
41*41586Ssklower 		if (m->m_len < HDHEADERLN) {
42*41586Ssklower 			printf ("hdintr: packet too short (len=%d)\n",
43*41586Ssklower 				m->m_len);
44*41586Ssklower 			m_freem (m);
45*41586Ssklower 			continue;
46*41586Ssklower 		}
47*41586Ssklower 
48*41586Ssklower 		/*
49*41586Ssklower 		 * look up the appropriate hdlc control block
50*41586Ssklower 		 */
51*41586Ssklower 
52*41586Ssklower 		if (ifp == lastifp)
53*41586Ssklower 			hdp = lasthdp;
54*41586Ssklower 		else {
55*41586Ssklower 			for (hdp = hdcbhead; hdp; hdp = hdp->hd_next)
56*41586Ssklower 				if (hdp->hd_ifp == ifp)
57*41586Ssklower 					break;
58*41586Ssklower 			if (hdp == 0) {
59*41586Ssklower 				printf ("hdintr: unknown interface %x\n", ifp);
60*41586Ssklower 				m_freem (m);
61*41586Ssklower 				continue;
62*41586Ssklower 			}
63*41586Ssklower 			lastifp = ifp;
64*41586Ssklower 			lasthdp = hdp;
65*41586Ssklower 		}
66*41586Ssklower 
67*41586Ssklower 		/* Process_rxframe returns FALSE if the frame was NOT queued
68*41586Ssklower 		   for the next higher layers. */
69*41586Ssklower 		if (process_rxframe (hdp, m) == FALSE)
70*41586Ssklower 			m_freem (m);
71*41586Ssklower 	}
72*41586Ssklower }
73*41586Ssklower 
74*41586Ssklower process_rxframe (hdp, fbuf)
75*41586Ssklower register struct hdcb *hdp;
76*41586Ssklower register struct mbuf *fbuf;
77*41586Ssklower {
78*41586Ssklower 	register int queued = FALSE, frametype, pf;
79*41586Ssklower 	register struct Hdlc_frame *frame;
80*41586Ssklower 
81*41586Ssklower 	frame = mtod (fbuf, struct Hdlc_frame *);
82*41586Ssklower 	pf = ((struct Hdlc_iframe *) frame) -> pf;
83*41586Ssklower 
84*41586Ssklower 	hd_trace (hdp, RX, frame);
85*41586Ssklower 	if (frame -> address != ADDRESS_A && frame -> address != ADDRESS_B)
86*41586Ssklower 		return (queued);
87*41586Ssklower 
88*41586Ssklower 	switch ((frametype = hd_decode (hdp, frame)) + hdp->hd_state) {
89*41586Ssklower 	case DM + DISC_SENT:
90*41586Ssklower 	case UA + DISC_SENT:
91*41586Ssklower 		/*
92*41586Ssklower 		 * Link now closed.  Leave timer running
93*41586Ssklower 		 * so hd_timer() can periodically check the
94*41586Ssklower 		 * status of interface driver flag bit IFF_UP.
95*41586Ssklower 		 */
96*41586Ssklower 		hdp->hd_state = DISCONNECTED;
97*41586Ssklower 		break;
98*41586Ssklower 
99*41586Ssklower 	case DM + INIT:
100*41586Ssklower 	case UA + INIT:
101*41586Ssklower 		/*
102*41586Ssklower 		 * This is a non-standard state change needed for DCEs
103*41586Ssklower 		 * that do dynamic link selection.  We can't go into the
104*41586Ssklower 		 * usual "SEND DM" state because a DM is a SARM in LAP.
105*41586Ssklower 		 */
106*41586Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
107*41586Ssklower 		hdp->hd_state = SABM_SENT;
108*41586Ssklower 		SET_TIMER (hdp);
109*41586Ssklower 		break;
110*41586Ssklower 
111*41586Ssklower 	case SABM + DM_SENT:
112*41586Ssklower 	case SABM + WAIT_SABM:
113*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
114*41586Ssklower 	case UA + SABM_SENT:
115*41586Ssklower 	case UA + WAIT_UA:
116*41586Ssklower 		KILL_TIMER (hdp);
117*41586Ssklower 		hd_initvars (hdp);
118*41586Ssklower 		hdp->hd_state = ABM;
119*41586Ssklower 		hd_message (hdp, "Link level operational");
120*41586Ssklower 		/* Notify the packet level - to send RESTART. */
121*41586Ssklower 		(void) pk_ctlinput (PRC_LINKUP, hdp->hd_xcp);
122*41586Ssklower 		break;
123*41586Ssklower 
124*41586Ssklower 	case SABM + SABM_SENT:
125*41586Ssklower 		/* Got a SABM collision. Acknowledge the remote's SABM
126*41586Ssklower 		   via UA but still wait for UA. */
127*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
128*41586Ssklower 		break;
129*41586Ssklower 
130*41586Ssklower 	case SABM + ABM:
131*41586Ssklower 		/* Request to reset the link from the remote. */
132*41586Ssklower 		KILL_TIMER (hdp);
133*41586Ssklower 		hd_message (hdp, "Link reset");
134*41586Ssklower #ifdef HDLCDEBUG
135*41586Ssklower 		hd_dumptrace (hdp);
136*41586Ssklower #endif
137*41586Ssklower 		hd_flush (hdp->hd_ifp);
138*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
139*41586Ssklower 		hd_initvars (hdp);
140*41586Ssklower 		(void) pk_ctlinput (PRC_LINKRESET, hdp->hd_xcp);
141*41586Ssklower 		hdp->hd_resets++;
142*41586Ssklower 		break;
143*41586Ssklower 
144*41586Ssklower 	case SABM + WAIT_UA:
145*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
146*41586Ssklower 		break;
147*41586Ssklower 
148*41586Ssklower 	case DM + ABM:
149*41586Ssklower 		hd_message (hdp, "DM received: link down");
150*41586Ssklower #ifdef HDLCDEBUG
151*41586Ssklower 		hd_dumptrace (hdp);
152*41586Ssklower #endif
153*41586Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
154*41586Ssklower 		hd_flush (hdp->hd_ifp);
155*41586Ssklower 	case DM + DM_SENT:
156*41586Ssklower 	case DM + WAIT_SABM:
157*41586Ssklower 	case DM + WAIT_UA:
158*41586Ssklower 		hd_writeinternal (hdp, SABM, pf);
159*41586Ssklower 		hdp->hd_state = SABM_SENT;
160*41586Ssklower 		SET_TIMER (hdp);
161*41586Ssklower 		break;
162*41586Ssklower 
163*41586Ssklower 	case DISC + INIT:
164*41586Ssklower 	case DISC + DM_SENT:
165*41586Ssklower 	case DISC + SABM_SENT:
166*41586Ssklower 		/* Note: This is a non-standard state change. */
167*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
168*41586Ssklower 		hd_writeinternal (hdp, SABM, POLLOFF);
169*41586Ssklower 		hdp->hd_state = SABM_SENT;
170*41586Ssklower 		SET_TIMER (hdp);
171*41586Ssklower 		break;
172*41586Ssklower 
173*41586Ssklower 	case DISC + WAIT_UA:
174*41586Ssklower 		hd_writeinternal (hdp, DM, pf);
175*41586Ssklower 		SET_TIMER (hdp);
176*41586Ssklower 		hdp->hd_state = DM_SENT;
177*41586Ssklower 		break;
178*41586Ssklower 
179*41586Ssklower 	case DISC + ABM:
180*41586Ssklower 		hd_message (hdp, "DISC received: link down");
181*41586Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
182*41586Ssklower 	case DISC + WAIT_SABM:
183*41586Ssklower 		hd_writeinternal (hdp, UA, pf);
184*41586Ssklower 		hdp->hd_state = DM_SENT;
185*41586Ssklower 		SET_TIMER (hdp);
186*41586Ssklower 		break;
187*41586Ssklower 
188*41586Ssklower 	case UA + ABM:
189*41586Ssklower 		hd_message (hdp, "UA received: link down");
190*41586Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
191*41586Ssklower 	case UA + WAIT_SABM:
192*41586Ssklower 		hd_writeinternal (hdp, DM, pf);
193*41586Ssklower 		hdp->hd_state = DM_SENT;
194*41586Ssklower 		SET_TIMER (hdp);
195*41586Ssklower 		break;
196*41586Ssklower 
197*41586Ssklower 	case FRMR + DM_SENT:
198*41586Ssklower 		hd_writeinternal (hdp, SABM, pf);
199*41586Ssklower 		hdp->hd_state = SABM_SENT;
200*41586Ssklower 		SET_TIMER (hdp);
201*41586Ssklower 		break;
202*41586Ssklower 
203*41586Ssklower 	case FRMR + WAIT_SABM:
204*41586Ssklower 		hd_writeinternal (hdp, DM, pf);
205*41586Ssklower 		hdp->hd_state = DM_SENT;
206*41586Ssklower 		SET_TIMER (hdp);
207*41586Ssklower 		break;
208*41586Ssklower 
209*41586Ssklower 	case FRMR + ABM:
210*41586Ssklower 		hd_message (hdp, "FRMR received: link down");
211*41586Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
212*41586Ssklower #ifdef HDLCDEBUG
213*41586Ssklower 		hd_dumptrace (hdp);
214*41586Ssklower #endif
215*41586Ssklower 		hd_flush (hdp->hd_ifp);
216*41586Ssklower 		hd_writeinternal (hdp, SABM, pf);
217*41586Ssklower 		hdp->hd_state = WAIT_UA;
218*41586Ssklower 		SET_TIMER (hdp);
219*41586Ssklower 		break;
220*41586Ssklower 
221*41586Ssklower 	case RR + ABM:
222*41586Ssklower 	case RNR + ABM:
223*41586Ssklower 	case REJ + ABM:
224*41586Ssklower 		process_sframe (hdp, (struct Hdlc_sframe *)frame, frametype);
225*41586Ssklower 		break;
226*41586Ssklower 
227*41586Ssklower 	case IFRAME + ABM:
228*41586Ssklower 		queued = process_iframe (hdp, fbuf, (struct Hdlc_iframe *)frame);
229*41586Ssklower 		break;
230*41586Ssklower 
231*41586Ssklower 	case IFRAME + SABM_SENT:
232*41586Ssklower 	case RR + SABM_SENT:
233*41586Ssklower 	case RNR + SABM_SENT:
234*41586Ssklower 	case REJ + SABM_SENT:
235*41586Ssklower 		hd_writeinternal (hdp, DM, POLLON);
236*41586Ssklower 		hdp->hd_state = DM_SENT;
237*41586Ssklower 		SET_TIMER (hdp);
238*41586Ssklower 		break;
239*41586Ssklower 
240*41586Ssklower 	case IFRAME + WAIT_SABM:
241*41586Ssklower 	case RR + WAIT_SABM:
242*41586Ssklower 	case RNR + WAIT_SABM:
243*41586Ssklower 	case REJ + WAIT_SABM:
244*41586Ssklower 		hd_writeinternal (hdp, FRMR, POLLOFF);
245*41586Ssklower 		SET_TIMER (hdp);
246*41586Ssklower 		break;
247*41586Ssklower 
248*41586Ssklower 	case ILLEGAL + SABM_SENT:
249*41586Ssklower 		hdp->hd_unknown++;
250*41586Ssklower 		hd_writeinternal (hdp, DM, POLLOFF);
251*41586Ssklower 		hdp->hd_state = DM_SENT;
252*41586Ssklower 		SET_TIMER (hdp);
253*41586Ssklower 		break;
254*41586Ssklower 
255*41586Ssklower 	case ILLEGAL + ABM:
256*41586Ssklower 		hd_message (hdp, "Unknown frame received: link down");
257*41586Ssklower 		(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp);
258*41586Ssklower 	case ILLEGAL + WAIT_SABM:
259*41586Ssklower 		hdp->hd_unknown++;
260*41586Ssklower #ifdef HDLCDEBUG
261*41586Ssklower 		hd_dumptrace (hdp);
262*41586Ssklower #endif
263*41586Ssklower 		hd_writeinternal (hdp, FRMR, POLLOFF);
264*41586Ssklower 		hdp->hd_state = WAIT_SABM;
265*41586Ssklower 		SET_TIMER (hdp);
266*41586Ssklower 		break;
267*41586Ssklower 	}
268*41586Ssklower 
269*41586Ssklower 	return (queued);
270*41586Ssklower }
271*41586Ssklower 
272*41586Ssklower process_iframe (hdp, fbuf, frame)
273*41586Ssklower register struct hdcb *hdp;
274*41586Ssklower struct mbuf *fbuf;
275*41586Ssklower register struct Hdlc_iframe *frame;
276*41586Ssklower {
277*41586Ssklower 	register int    nr = frame -> nr,
278*41586Ssklower 	                ns = frame -> ns,
279*41586Ssklower 	                pf = frame -> pf;
280*41586Ssklower 	register int    queued = FALSE;
281*41586Ssklower 
282*41586Ssklower 	/*
283*41586Ssklower 	 *  Validate the iframe's N(R) value. It's N(R) value must be in
284*41586Ssklower 	 *   sync with our V(S) value and our "last received nr".
285*41586Ssklower 	 */
286*41586Ssklower 
287*41586Ssklower 	if (valid_nr (hdp, nr, FALSE) == FALSE) {
288*41586Ssklower 		frame_reject (hdp, Z, frame);
289*41586Ssklower 		return (queued);
290*41586Ssklower 	}
291*41586Ssklower 
292*41586Ssklower 
293*41586Ssklower 	/*
294*41586Ssklower 	 *  This section tests the IFRAME for proper sequence. That is, it's
295*41586Ssklower 	 *  sequence number N(S) MUST be equal to V(S).
296*41586Ssklower 	 */
297*41586Ssklower 
298*41586Ssklower 	if (ns != hdp->hd_vr) {
299*41586Ssklower 		hdp->hd_invalid_ns++;
300*41586Ssklower 		if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) {
301*41586Ssklower 			hdp->hd_condition |= REJ_CONDITION;
302*41586Ssklower 			/*
303*41586Ssklower 			 * Flush the transmit queue. This is ugly but we
304*41586Ssklower 			 * have no choice.  A reject response must be
305*41586Ssklower 			 * immediately sent to the DCE.  Failure to do so
306*41586Ssklower 			 * may result in another out of sequence iframe
307*41586Ssklower 			 * arriving (and thus sending another reject)
308*41586Ssklower 			 * before the first reject is transmitted. This
309*41586Ssklower 			 * will cause the DCE to receive two or more
310*41586Ssklower 			 * rejects back to back, which must never happen.
311*41586Ssklower 			 */
312*41586Ssklower 			hd_flush (hdp->hd_ifp);
313*41586Ssklower 			hd_writeinternal (hdp, REJ, pf);
314*41586Ssklower 		}
315*41586Ssklower 		return (queued);
316*41586Ssklower 	}
317*41586Ssklower 	hdp->hd_condition &= ~REJ_CONDITION;
318*41586Ssklower 
319*41586Ssklower 	/*
320*41586Ssklower 	 *  This section finally tests the IFRAME's sequence number against
321*41586Ssklower 	 *  the window size (K)  and the sequence number of the  last frame
322*41586Ssklower 	 *  we have acknowledged.  If the IFRAME is completely correct then
323*41586Ssklower 	 *  it is queued for the packet level.
324*41586Ssklower 	 */
325*41586Ssklower 
326*41586Ssklower 	if (ns != (hdp->hd_lasttxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
327*41586Ssklower 		hdp->hd_vr = (hdp->hd_vr + 1) % MODULUS;
328*41586Ssklower 		if (pf == 1) {
329*41586Ssklower 			/* Must generate a RR or RNR with final bit on. */
330*41586Ssklower 			hd_writeinternal (hdp, RR, POLLON);
331*41586Ssklower 		} else
332*41586Ssklower 			/*
333*41586Ssklower 			 *  Hopefully we can piggyback the RR, if not we will generate
334*41586Ssklower 			 *  a RR when T3 timer expires.
335*41586Ssklower 			 */
336*41586Ssklower 			if (hdp -> hd_rrtimer == 0)
337*41586Ssklower 				hdp->hd_rrtimer = hd_t3;
338*41586Ssklower 
339*41586Ssklower 		/* Forward iframe to packet level of X.25. */
340*41586Ssklower 		fbuf -> m_off += HDHEADERLN;
341*41586Ssklower 		fbuf -> m_len -= HDHEADERLN;
342*41586Ssklower #ifdef BSD4_3
343*41586Ssklower 		fbuf->m_act = 0;	/* probably not necessary */
344*41586Ssklower #else
345*41586Ssklower 		{
346*41586Ssklower 			register struct mbuf *m;
347*41586Ssklower 
348*41586Ssklower 			for (m = fbuf; m -> m_next; m = m -> m_next)
349*41586Ssklower 				m -> m_act = (struct mbuf *) 0;
350*41586Ssklower 			m -> m_act = (struct mbuf *) 1;
351*41586Ssklower 		}
352*41586Ssklower #endif
353*41586Ssklower 		pk_input (fbuf, hdp->hd_xcp);
354*41586Ssklower 		queued = TRUE;
355*41586Ssklower 		hd_start (hdp);
356*41586Ssklower 	} else {
357*41586Ssklower 		/*
358*41586Ssklower 		 *  Here if the remote station has transmitted more iframes then
359*41586Ssklower 		 *  the number which have been acknowledged plus K.
360*41586Ssklower 		 */
361*41586Ssklower 		hdp->hd_invalid_ns++;
362*41586Ssklower 		frame_reject (hdp, W, frame);
363*41586Ssklower 	}
364*41586Ssklower 	return (queued);
365*41586Ssklower }
366*41586Ssklower 
367*41586Ssklower /*
368*41586Ssklower  *  This routine is used to determine if a value (the middle parameter)
369*41586Ssklower  *  is between two other values. The low value is  the first  parameter
370*41586Ssklower  *  the high value is the last parameter. The routine checks the middle
371*41586Ssklower  *  value to see if it is within the range of the first and last values.
372*41586Ssklower  *  The reason we need this routine is the values are modulo some  base
373*41586Ssklower  *  hence a simple test for greater or less than is not sufficient.
374*41586Ssklower  */
375*41586Ssklower 
376*41586Ssklower bool
377*41586Ssklower range_check (rear, value, front)
378*41586Ssklower int     rear,
379*41586Ssklower         value,
380*41586Ssklower         front;
381*41586Ssklower {
382*41586Ssklower 	register bool result = FALSE;
383*41586Ssklower 
384*41586Ssklower 	if (front > rear)
385*41586Ssklower 		result = (rear <= value) && (value <= front);
386*41586Ssklower 	else
387*41586Ssklower 		result = (rear <= value) || (value <= front);
388*41586Ssklower 
389*41586Ssklower 	return (result);
390*41586Ssklower }
391*41586Ssklower 
392*41586Ssklower /*
393*41586Ssklower  *  This routine handles all the frame reject conditions which can
394*41586Ssklower  *  arise as a result  of secondary  processing.  The frame reject
395*41586Ssklower  *  condition Y (frame length error) are handled elsewhere.
396*41586Ssklower  */
397*41586Ssklower 
398*41586Ssklower static
399*41586Ssklower frame_reject (hdp, rejectcode, frame)
400*41586Ssklower struct hdcb *hdp;
401*41586Ssklower struct Hdlc_iframe *frame;
402*41586Ssklower {
403*41586Ssklower 	register struct Frmr_frame *frmr = &hd_frmr;
404*41586Ssklower 
405*41586Ssklower 	frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control;
406*41586Ssklower 
407*41586Ssklower 	frmr -> frmr_ns = frame -> ns;
408*41586Ssklower 	frmr -> frmr_f1_0 = 0;
409*41586Ssklower 	frmr -> frmr_nr = frame -> nr;
410*41586Ssklower 	frmr -> frmr_f2_0 = 0;
411*41586Ssklower 
412*41586Ssklower 	frmr -> frmr_0000 = 0;
413*41586Ssklower 	frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y =
414*41586Ssklower 		frmr -> frmr_z = 0;
415*41586Ssklower 	switch (rejectcode) {
416*41586Ssklower 	case Z:
417*41586Ssklower 		frmr -> frmr_z = 1;/* invalid N(R). */
418*41586Ssklower 		break;
419*41586Ssklower 
420*41586Ssklower 	case Y:
421*41586Ssklower 		frmr -> frmr_y = 1;/* iframe length error. */
422*41586Ssklower 		break;
423*41586Ssklower 
424*41586Ssklower 	case X:
425*41586Ssklower 		frmr -> frmr_x = 1;/* invalid information field. */
426*41586Ssklower 		frmr -> frmr_w = 1;
427*41586Ssklower 		break;
428*41586Ssklower 
429*41586Ssklower 	case W:
430*41586Ssklower 		frmr -> frmr_w = 1;/* invalid N(S). */
431*41586Ssklower 	}
432*41586Ssklower 
433*41586Ssklower 	hd_writeinternal (hdp, FRMR, POLLOFF);
434*41586Ssklower 
435*41586Ssklower 	hdp->hd_state = WAIT_SABM;
436*41586Ssklower 	SET_TIMER (hdp);
437*41586Ssklower }
438*41586Ssklower 
439*41586Ssklower /*
440*41586Ssklower  *  This procedure is invoked when ever we receive a supervisor
441*41586Ssklower  *  frame such as RR, RNR and REJ. All processing for these
442*41586Ssklower  *  frames is done here.
443*41586Ssklower  */
444*41586Ssklower 
445*41586Ssklower process_sframe (hdp, frame, frametype)
446*41586Ssklower register struct hdcb *hdp;
447*41586Ssklower register struct Hdlc_sframe *frame;
448*41586Ssklower int frametype;
449*41586Ssklower {
450*41586Ssklower 	register int nr = frame -> nr, pf = frame -> pf, pollbit = 0;
451*41586Ssklower 
452*41586Ssklower 	if (valid_nr (hdp, nr, pf) == TRUE) {
453*41586Ssklower 		switch (frametype) {
454*41586Ssklower 		case RR:
455*41586Ssklower 			hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
456*41586Ssklower 			break;
457*41586Ssklower 
458*41586Ssklower 		case RNR:
459*41586Ssklower 			hdp->hd_condition |= REMOTE_RNR_CONDITION;
460*41586Ssklower 			hdp->hd_retxcnt = 0;
461*41586Ssklower 			break;
462*41586Ssklower 
463*41586Ssklower 		case REJ:
464*41586Ssklower 			hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
465*41586Ssklower 			rej_routine (hdp, nr);
466*41586Ssklower 		}
467*41586Ssklower 
468*41586Ssklower 		if (pf == 1) {
469*41586Ssklower 			hdp->hd_retxcnt = 0;
470*41586Ssklower 			hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION;
471*41586Ssklower 
472*41586Ssklower 			/* If any iframes have been queued because of the
473*41586Ssklower 			   timer condition, transmit then now. */
474*41586Ssklower 			if (hdp->hd_condition & REMOTE_RNR_CONDITION) {
475*41586Ssklower 				/* Remote is busy or timer condition, so only
476*41586Ssklower 				   send one. */
477*41586Ssklower 				if (hdp->hd_vs != hdp->hd_retxqi)
478*41586Ssklower 					hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit);
479*41586Ssklower 			}
480*41586Ssklower 			else	/* Flush the retransmit list first. */
481*41586Ssklower 				while (hdp->hd_vs != hdp->hd_retxqi)
482*41586Ssklower 					hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
483*41586Ssklower 		}
484*41586Ssklower 
485*41586Ssklower 		hd_start (hdp);
486*41586Ssklower 	} else
487*41586Ssklower 		frame_reject (hdp, Z, (struct Hdlc_iframe *)frame);	/* Invalid N(R). */
488*41586Ssklower }
489*41586Ssklower 
490*41586Ssklower /*
491*41586Ssklower  *  This routine tests the validity of the N(R) which we have received.
492*41586Ssklower  *  If it is ok,  then all the  iframes which it acknowledges  (if any)
493*41586Ssklower  *  will be freed.
494*41586Ssklower  */
495*41586Ssklower 
496*41586Ssklower bool
497*41586Ssklower valid_nr (hdp, nr, finalbit)
498*41586Ssklower register struct hdcb *hdp;
499*41586Ssklower register int finalbit;
500*41586Ssklower {
501*41586Ssklower 	/* Make sure it really does acknowledge something. */
502*41586Ssklower 	if (hdp->hd_lastrxnr == nr)
503*41586Ssklower 		return (TRUE);
504*41586Ssklower 
505*41586Ssklower 	/*
506*41586Ssklower 	 *  This section validates the frame's  N(R) value.  It's N(R) value
507*41586Ssklower 	 *  must be  in syncronization  with  our V(S)  value and  our "last
508*41586Ssklower 	 *  received nr" variable. If it is correct then we are able to send
509*41586Ssklower 	 *  more IFRAME's, else frame reject condition is entered.
510*41586Ssklower 	 */
511*41586Ssklower 
512*41586Ssklower 	if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) {
513*41586Ssklower 		if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) &&
514*41586Ssklower 				range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE)
515*41586Ssklower 			hdp->hd_vs = nr;
516*41586Ssklower 
517*41586Ssklower 		else {
518*41586Ssklower 			hdp->hd_invalid_nr++;
519*41586Ssklower 			return (FALSE);
520*41586Ssklower 		}
521*41586Ssklower 	}
522*41586Ssklower 
523*41586Ssklower 	/*
524*41586Ssklower 	 *  If we get to here, we do have a valid frame  but it might be out
525*41586Ssklower 	 *  of sequence.  However, we should  still accept the receive state
526*41586Ssklower 	 *  number N(R) since it has already passed our previous test and it
527*41586Ssklower 	 *  does acknowledge frames which we are sending.
528*41586Ssklower 	 */
529*41586Ssklower 
530*41586Ssklower 	KILL_TIMER (hdp);
531*41586Ssklower 	free_iframes (hdp, &nr, finalbit);/* Free all acknowledged iframes */
532*41586Ssklower 	if (nr != hdp->hd_vs)
533*41586Ssklower 		SET_TIMER (hdp);
534*41586Ssklower 
535*41586Ssklower 	return (TRUE);
536*41586Ssklower }
537*41586Ssklower 
538*41586Ssklower /*
539*41586Ssklower  *  This routine determines how many iframes need to be retransmitted.
540*41586Ssklower  *  It then resets the Send State Variable V(S) to accomplish this.
541*41586Ssklower  */
542*41586Ssklower 
543*41586Ssklower static
544*41586Ssklower rej_routine (hdp, rejnr)
545*41586Ssklower register struct hdcb *hdp;
546*41586Ssklower register int rejnr;
547*41586Ssklower {
548*41586Ssklower 	register int anchor;
549*41586Ssklower 
550*41586Ssklower 	/*
551*41586Ssklower 	 * Flush the output queue.  Any iframes queued for
552*41586Ssklower 	 * transmission will be out of sequence.
553*41586Ssklower 	 */
554*41586Ssklower 
555*41586Ssklower 	hd_flush (hdp->hd_ifp);
556*41586Ssklower 
557*41586Ssklower 	/*
558*41586Ssklower 	 *  Determine how many frames should be re-transmitted. In the case
559*41586Ssklower 	 *  of a normal REJ this  should be 1 to K.  In the case of a timer
560*41586Ssklower 	 *  recovery REJ (ie. a REJ with the Final Bit on) this could be 0.
561*41586Ssklower 	 */
562*41586Ssklower 
563*41586Ssklower 	anchor = hdp->hd_vs;
564*41586Ssklower 	if (hdp->hd_condition & TIMER_RECOVERY_CONDITION)
565*41586Ssklower 		anchor = hdp->hd_xx;
566*41586Ssklower 
567*41586Ssklower 	anchor = (anchor - rejnr + 8) % MODULUS;
568*41586Ssklower 
569*41586Ssklower 	if (anchor > 0) {
570*41586Ssklower 
571*41586Ssklower 		/* There is at least one iframe to retransmit. */
572*41586Ssklower 		KILL_TIMER (hdp);
573*41586Ssklower 		hdp->hd_vs = rejnr;
574*41586Ssklower 
575*41586Ssklower 		while (hdp->hd_vs != hdp->hd_retxqi)
576*41586Ssklower 			hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
577*41586Ssklower 
578*41586Ssklower 	}
579*41586Ssklower 	hd_start (hdp);
580*41586Ssklower }
581*41586Ssklower 
582*41586Ssklower /*
583*41586Ssklower  *  This routine frees iframes from the retransmit queue. It is called
584*41586Ssklower  *  when a previously written iframe is acknowledged.
585*41586Ssklower  */
586*41586Ssklower 
587*41586Ssklower static
588*41586Ssklower free_iframes (hdp, nr, finalbit)
589*41586Ssklower register struct hdcb *hdp;
590*41586Ssklower int *nr;
591*41586Ssklower register int finalbit;
592*41586Ssklower 
593*41586Ssklower {
594*41586Ssklower 	register int    i, k;
595*41586Ssklower 
596*41586Ssklower 	/*
597*41586Ssklower 	 *  We  need to do the  following  because  of a  funny quirk  in  the
598*41586Ssklower 	 *  protocol.  This case  occures  when  in Timer  recovery  condition
599*41586Ssklower 	 *  we get  a  N(R)  which  acknowledges all  the outstanding  iframes
600*41586Ssklower 	 *  but with  the Final Bit off. In this case we need to save the last
601*41586Ssklower 	 *  iframe for possible retransmission even though it has already been
602*41586Ssklower 	 *  acknowledged!
603*41586Ssklower 	 */
604*41586Ssklower 
605*41586Ssklower 	if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) {
606*41586Ssklower 		*nr = (*nr - 1 + 8) % MODULUS;
607*41586Ssklower /*		printf ("QUIRK\n"); */
608*41586Ssklower 	}
609*41586Ssklower 
610*41586Ssklower 	k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS;
611*41586Ssklower 
612*41586Ssklower 	/* Loop here freeing all acknowledged iframes. */
613*41586Ssklower 	for (i = 0; i < k; ++i) {
614*41586Ssklower 		m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]);
615*41586Ssklower 		hdp->hd_retxq[hdp->hd_lastrxnr] = 0;
616*41586Ssklower 		hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS;
617*41586Ssklower 	}
618*41586Ssklower 
619*41586Ssklower }
620