date and time created 90/05/11 11:19:34 by sklower
[unix-history] / usr / src / sys / netccitt / hd_input.c
CommitLineData
0f9bb9b6
KS
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
26hdintr ()
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
74process_rxframe (hdp, fbuf)
75register struct hdcb *hdp;
76register 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
272process_iframe (hdp, fbuf, frame)
273register struct hdcb *hdp;
274struct mbuf *fbuf;
275register 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
376bool
377range_check (rear, value, front)
378int 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
398static
399frame_reject (hdp, rejectcode, frame)
400struct hdcb *hdp;
401struct 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
445process_sframe (hdp, frame, frametype)
446register struct hdcb *hdp;
447register struct Hdlc_sframe *frame;
448int 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
496bool
497valid_nr (hdp, nr, finalbit)
498register struct hdcb *hdp;
499register 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
543static
544rej_routine (hdp, rejnr)
545register struct hdcb *hdp;
546register 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
587static
588free_iframes (hdp, nr, finalbit)
589register struct hdcb *hdp;
590int *nr;
591register 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}