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