1 /* $NetBSD: hd_input.c,v 1.20 2003/08/07 16:33:00 agc Exp $ */
2
3 /*
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Laboratory for Computation Vision and the Computer Science Department
9 * of the University of British Columbia.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)hd_input.c 8.1 (Berkeley) 6/10/93
36 */
37
38 /*
39 * Copyright (c) 1984 University of British Columbia.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * the Laboratory for Computation Vision and the Computer Science Department
43 * of the University of British Columbia.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software
54 * must display the following acknowledgement:
55 * This product includes software developed by the University of
56 * California, Berkeley and its contributors.
57 * 4. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * SUCH DAMAGE.
72 *
73 * @(#)hd_input.c 8.1 (Berkeley) 6/10/93
74 */
75
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: hd_input.c,v 1.20 2003/08/07 16:33:00 agc Exp $");
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/mbuf.h>
82 #include <sys/domain.h>
83 #include <sys/socket.h>
84 #include <sys/protosw.h>
85 #include <sys/errno.h>
86 #include <sys/time.h>
87 #include <sys/kernel.h>
88
89 #include <net/if.h>
90
91 #include <netccitt/hdlc.h>
92 #include <netccitt/hd_var.h>
93 #include <netccitt/x25.h>
94 #include <netccitt/pk_extern.h>
95
96 struct hdcb *hdcbhead; /* head of linked list of hdcb's */
97 struct Frmr_frame hd_frmr; /* rejected frame diagnostic info */
98 struct ifqueue hdintrq; /* hdlc packet input queue */
99
100 static void frame_reject __P((struct hdcb *, int, struct Hdlc_iframe *));
101 static void rej_routine __P((struct hdcb *, int));
102 static void free_iframes __P((struct hdcb *, int *, int));
103
104 /*
105 * HDLC INPUT INTERFACE
106 *
107 * This routine is called when the HDLC physical device has
108 * completed reading a frame.
109 */
110
111 void
112 hdintr()
113 {
114 struct mbuf *m;
115 struct hdcb *hdp;
116 struct ifnet *ifp;
117 int s;
118 static struct ifnet *lastifp;
119 static struct hdcb *lasthdp;
120
121 for (;;) {
122 s = splnet();
123 IF_DEQUEUE(&hdintrq, m);
124 splx(s);
125 if (m == 0)
126 break;
127 if (m->m_len < HDHEADERLN) {
128 printf("hdintr: packet too short (len=%d)\n",
129 m->m_len);
130 m_freem(m);
131 continue;
132 }
133 if ((m->m_flags & M_PKTHDR) == 0)
134 panic("hdintr");
135 ifp = m->m_pkthdr.rcvif;
136
137 /*
138 * look up the appropriate hdlc control block
139 */
140
141 if (ifp == lastifp)
142 hdp = lasthdp;
143 else {
144 for (hdp = hdcbhead; hdp; hdp = hdp->hd_next)
145 if (hdp->hd_ifp == ifp)
146 break;
147 if (hdp == 0) {
148 printf("hdintr: unknown interface %p\n", ifp);
149 m_freem(m);
150 continue;
151 }
152 lastifp = ifp;
153 lasthdp = hdp;
154 }
155
156 /*
157 * Process_rxframe returns FALSE if the frame was NOT queued
158 * for the next higher layers.
159 */
160 if (process_rxframe(hdp, m) == FALSE)
161 m_freem(m);
162 }
163 }
164
165 int
166 process_rxframe(hdp, fbuf)
167 struct hdcb *hdp;
168 struct mbuf *fbuf;
169 {
170 int queued = FALSE, frametype, pf;
171 struct Hdlc_frame *frame;
172 struct sockaddr *sa = (struct sockaddr *) hdp->hd_pkp;
173
174 frame = mtod(fbuf, struct Hdlc_frame *);
175 pf = ((struct Hdlc_iframe *) frame)->pf;
176
177 hd_trace(hdp, RX, fbuf);
178 if (frame->address != ADDRESS_A && frame->address != ADDRESS_B)
179 return (queued);
180
181 switch ((frametype = hd_decode(hdp, frame)) + hdp->hd_state) {
182 case DM + DISC_SENT:
183 case UA + DISC_SENT:
184 /*
185 * Link now closed. Leave timer running
186 * so hd_timer() can periodically check the
187 * status of interface driver flag bit IFF_UP.
188 */
189 hdp->hd_state = DISCONNECTED;
190 break;
191
192 case DM + INIT:
193 case UA + INIT:
194 /*
195 * This is a non-standard state change needed for DCEs
196 * that do dynamic link selection. We can't go into the
197 * usual "SEND DM" state because a DM is a SARM in LAP.
198 */
199 hd_writeinternal(hdp, SABM, POLLOFF);
200 hdp->hd_state = SABM_SENT;
201 SET_TIMER(hdp);
202 break;
203
204 case SABM + DM_SENT:
205 case SABM + WAIT_SABM:
206 hd_writeinternal(hdp, UA, pf);
207 case UA + SABM_SENT:
208 case UA + WAIT_UA:
209 KILL_TIMER(hdp);
210 hd_initvars(hdp);
211 hdp->hd_state = ABM;
212 hd_message(hdp, "Link level operational");
213 /* Notify the packet level - to send RESTART. */
214 (void) pk_ctlinput(PRC_LINKUP, sa, NULL);
215 break;
216
217 case SABM + SABM_SENT:
218 /*
219 * Got a SABM collision. Acknowledge the remote's SABM via UA
220 * but still wait for UA.
221 */
222 hd_writeinternal(hdp, UA, pf);
223 break;
224
225 case SABM + ABM:
226 /* Request to reset the link from the remote. */
227 KILL_TIMER(hdp);
228 hd_message(hdp, "Link reset");
229 #ifdef HDLCDEBUG
230 hd_dumptrace(hdp);
231 #endif
232 hd_flush(hdp->hd_ifp);
233 hd_writeinternal(hdp, UA, pf);
234 hd_initvars(hdp);
235 (void) pk_ctlinput(PRC_LINKRESET, sa, NULL);
236 hdp->hd_resets++;
237 break;
238
239 case SABM + WAIT_UA:
240 hd_writeinternal(hdp, UA, pf);
241 break;
242
243 case DM + ABM:
244 hd_message(hdp, "DM received: link down");
245 #ifdef HDLCDEBUG
246 hd_dumptrace(hdp);
247 #endif
248 (void) pk_ctlinput(PRC_LINKDOWN, sa, NULL);
249 hd_flush(hdp->hd_ifp);
250 case DM + DM_SENT:
251 case DM + WAIT_SABM:
252 case DM + WAIT_UA:
253 hd_writeinternal(hdp, SABM, pf);
254 hdp->hd_state = SABM_SENT;
255 SET_TIMER(hdp);
256 break;
257
258 case DISC + INIT:
259 case DISC + DM_SENT:
260 case DISC + SABM_SENT:
261 /* Note: This is a non-standard state change. */
262 hd_writeinternal(hdp, UA, pf);
263 hd_writeinternal(hdp, SABM, POLLOFF);
264 hdp->hd_state = SABM_SENT;
265 SET_TIMER(hdp);
266 break;
267
268 case DISC + WAIT_UA:
269 hd_writeinternal(hdp, DM, pf);
270 SET_TIMER(hdp);
271 hdp->hd_state = DM_SENT;
272 break;
273
274 case DISC + ABM:
275 hd_message(hdp, "DISC received: link down");
276 (void) pk_ctlinput(PRC_LINKDOWN, sa, NULL);
277 case DISC + WAIT_SABM:
278 hd_writeinternal(hdp, UA, pf);
279 hdp->hd_state = DM_SENT;
280 SET_TIMER(hdp);
281 break;
282
283 case UA + ABM:
284 hd_message(hdp, "UA received: link down");
285 (void) pk_ctlinput(PRC_LINKDOWN, sa, NULL);
286 case UA + WAIT_SABM:
287 hd_writeinternal(hdp, DM, pf);
288 hdp->hd_state = DM_SENT;
289 SET_TIMER(hdp);
290 break;
291
292 case FRMR + DM_SENT:
293 hd_writeinternal(hdp, SABM, pf);
294 hdp->hd_state = SABM_SENT;
295 SET_TIMER(hdp);
296 break;
297
298 case FRMR + WAIT_SABM:
299 hd_writeinternal(hdp, DM, pf);
300 hdp->hd_state = DM_SENT;
301 SET_TIMER(hdp);
302 break;
303
304 case FRMR + ABM:
305 hd_message(hdp, "FRMR received: link down");
306 (void) pk_ctlinput(PRC_LINKDOWN, sa, NULL);
307 #ifdef HDLCDEBUG
308 hd_dumptrace(hdp);
309 #endif
310 hd_flush(hdp->hd_ifp);
311 hd_writeinternal(hdp, SABM, pf);
312 hdp->hd_state = WAIT_UA;
313 SET_TIMER(hdp);
314 break;
315
316 case RR + ABM:
317 case RNR + ABM:
318 case REJ + ABM:
319 process_sframe(hdp, (struct Hdlc_sframe *) frame, frametype);
320 break;
321
322 case IFRAME + ABM:
323 queued = process_iframe(hdp, fbuf, (struct Hdlc_iframe *) frame);
324 break;
325
326 case IFRAME + SABM_SENT:
327 case RR + SABM_SENT:
328 case RNR + SABM_SENT:
329 case REJ + SABM_SENT:
330 hd_writeinternal(hdp, DM, POLLON);
331 hdp->hd_state = DM_SENT;
332 SET_TIMER(hdp);
333 break;
334
335 case IFRAME + WAIT_SABM:
336 case RR + WAIT_SABM:
337 case RNR + WAIT_SABM:
338 case REJ + WAIT_SABM:
339 hd_writeinternal(hdp, FRMR, POLLOFF);
340 SET_TIMER(hdp);
341 break;
342
343 case ILLEGAL + SABM_SENT:
344 hdp->hd_unknown++;
345 hd_writeinternal(hdp, DM, POLLOFF);
346 hdp->hd_state = DM_SENT;
347 SET_TIMER(hdp);
348 break;
349
350 case ILLEGAL + ABM:
351 hd_message(hdp, "Unknown frame received: link down");
352 (void) pk_ctlinput(PRC_LINKDOWN, sa, NULL);
353 case ILLEGAL + WAIT_SABM:
354 hdp->hd_unknown++;
355 #ifdef HDLCDEBUG
356 hd_dumptrace(hdp);
357 #endif
358 hd_writeinternal(hdp, FRMR, POLLOFF);
359 hdp->hd_state = WAIT_SABM;
360 SET_TIMER(hdp);
361 break;
362 }
363
364 return (queued);
365 }
366
367 int
368 process_iframe(hdp, fbuf, frame)
369 struct hdcb *hdp;
370 struct mbuf *fbuf;
371 struct Hdlc_iframe *frame;
372 {
373 int nr = frame->nr, ns = frame->ns, pf = frame->pf;
374 int queued = FALSE;
375
376 /*
377 * Validate the iframe's N(R) value. It's N(R) value must be in sync
378 * with our V(S) value and our "last received nr".
379 */
380
381 if (valid_nr(hdp, nr, FALSE) == FALSE) {
382 frame_reject(hdp, Z, frame);
383 return (queued);
384 }
385 /*
386 * This section tests the IFRAME for proper sequence. That is, it's
387 * sequence number N(S) MUST be equal to V(S).
388 */
389
390 if (ns != hdp->hd_vr) {
391 hdp->hd_invalid_ns++;
392 if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) {
393 hdp->hd_condition |= REJ_CONDITION;
394 /*
395 * Flush the transmit queue. This is ugly but we
396 * have no choice. A reject response must be
397 * immediately sent to the DCE. Failure to do so
398 * may result in another out of sequence iframe
399 * arriving (and thus sending another reject)
400 * before the first reject is transmitted. This
401 * will cause the DCE to receive two or more
402 * rejects back to back, which must never happen.
403 */
404 hd_flush(hdp->hd_ifp);
405 hd_writeinternal(hdp, REJ, pf);
406 }
407 return (queued);
408 }
409 hdp->hd_condition &= ~REJ_CONDITION;
410
411 /*
412 * This section finally tests the IFRAME's sequence number against
413 * the window size (K) and the sequence number of the last frame we
414 * have acknowledged. If the IFRAME is completely correct then it is
415 * queued for the packet level.
416 */
417
418 if (ns != (hdp->hd_lasttxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) {
419 hdp->hd_vr = (hdp->hd_vr + 1) % MODULUS;
420 if (pf == 1) {
421 /* Must generate a RR or RNR with final bit on. */
422 hd_writeinternal(hdp, RR, POLLON);
423 } else
424 /*
425 * Hopefully we can piggyback the RR, if not we will
426 * generate a RR when T3 timer expires.
427 */
428 if (hdp->hd_rrtimer == 0)
429 hdp->hd_rrtimer = hd_t3;
430
431 /* Forward iframe to packet level of X.25. */
432 fbuf->m_data += HDHEADERLN;
433 fbuf->m_len -= HDHEADERLN;
434 fbuf->m_pkthdr.len -= HDHEADERLN;
435 fbuf->m_pkthdr.rcvif = (struct ifnet *) hdp->hd_pkp;
436 #ifdef BSD4_3
437 fbuf->m_nextpkt = 0;/* probably not necessary */
438 #else
439 {
440 struct mbuf *m;
441
442 for (m = fbuf; m->m_next; m = m->m_next)
443 m->m_nextpkt = (struct mbuf *) 0;
444 m->m_nextpkt = (struct mbuf *) 1;
445 }
446 #endif
447 pk_input(fbuf);
448 queued = TRUE;
449 hd_start(hdp);
450 } else {
451 /*
452 * Here if the remote station has transmitted more iframes
453 * then the number which have been acknowledged plus K.
454 */
455 hdp->hd_invalid_ns++;
456 frame_reject(hdp, W, frame);
457 }
458 return (queued);
459 }
460
461 /*
462 * This routine is used to determine if a value (the middle parameter) is
463 * between two other values. The low value is the first parameter the high
464 * value is the last parameter. The routine checks the middle value to see if
465 * it is within the range of the first and last values. The reason we need
466 * this routine is the values are modulo some base hence a simple test for
467 * greater or less than is not sufficient.
468 */
469
470 bool
471 range_check(rear, value, front)
472 int rear, value, front;
473 {
474 bool result = FALSE;
475
476 if (front > rear)
477 result = (rear <= value) && (value <= front);
478 else
479 result = (rear <= value) || (value <= front);
480
481 return (result);
482 }
483
484 /*
485 * This routine handles all the frame reject conditions which can arise as a
486 * result of secondary processing. The frame reject condition Y (frame
487 * length error) are handled elsewhere.
488 */
489
490 static void
491 frame_reject(hdp, rejectcode, frame)
492 struct hdcb *hdp;
493 int rejectcode;
494 struct Hdlc_iframe *frame;
495 {
496 struct Frmr_frame *frmr = &hd_frmr;
497
498 frmr->frmr_control = ((struct Hdlc_frame *) frame)->control;
499
500 frmr->frmr_ns = frame->ns;
501 frmr->frmr_f1_0 = 0;
502 frmr->frmr_nr = frame->nr;
503 frmr->frmr_f2_0 = 0;
504
505 frmr->frmr_0000 = 0;
506 frmr->frmr_w = frmr->frmr_x = frmr->frmr_y =
507 frmr->frmr_z = 0;
508 switch (rejectcode) {
509 case Z:
510 frmr->frmr_z = 1; /* invalid N(R). */
511 break;
512
513 case Y:
514 frmr->frmr_y = 1; /* iframe length error. */
515 break;
516
517 case X:
518 frmr->frmr_x = 1; /* invalid information field. */
519 frmr->frmr_w = 1;
520 break;
521
522 case W:
523 frmr->frmr_w = 1; /* invalid N(S). */
524 }
525
526 hd_writeinternal(hdp, FRMR, POLLOFF);
527
528 hdp->hd_state = WAIT_SABM;
529 SET_TIMER(hdp);
530 }
531
532 /*
533 * This procedure is invoked when ever we receive a supervisor frame such as
534 * RR, RNR and REJ. All processing for these frames is done here.
535 */
536
537 void
538 process_sframe(hdp, frame, frametype)
539 struct hdcb *hdp;
540 struct Hdlc_sframe *frame;
541 int frametype;
542 {
543 int nr = frame->nr, pf = frame->pf, pollbit = 0;
544
545 if (valid_nr(hdp, nr, pf) == TRUE) {
546 switch (frametype) {
547 case RR:
548 hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
549 break;
550
551 case RNR:
552 hdp->hd_condition |= REMOTE_RNR_CONDITION;
553 hdp->hd_retxcnt = 0;
554 break;
555
556 case REJ:
557 hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
558 rej_routine(hdp, nr);
559 }
560
561 if (pf == 1) {
562 hdp->hd_retxcnt = 0;
563 hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION;
564
565 if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs
566 && hdp->hd_timer == 0 && hdp->hd_txq.head == 0)
567 hd_writeinternal(hdp, RR, pf);
568 else
569 /*
570 * If any iframes have been queued because of
571 * the timer condition, transmit then now.
572 */
573 if (hdp->hd_condition & REMOTE_RNR_CONDITION) {
574 /*
575 * Remote is busy or timer condition, so only
576 * send one.
577 */
578 if (hdp->hd_vs != hdp->hd_retxqi)
579 hd_send_iframe(hdp,
580 hdp->hd_retxq[(u_char)hdp->hd_vs],
581 pollbit);
582 } else /* Flush the retransmit list first. */
583 while (hdp->hd_vs != hdp->hd_retxqi)
584 hd_send_iframe(hdp,
585 hdp->hd_retxq[(u_char)hdp->hd_vs],
586 POLLOFF);
587 }
588 hd_start(hdp);
589 } else
590 frame_reject(hdp, Z, (struct Hdlc_iframe *) frame); /* Invalid N(R). */
591 }
592
593 /*
594 * This routine tests the validity of the N(R) which we have received. If it
595 * is ok, then all the iframes which it acknowledges (if any) will be
596 * freed.
597 */
598
599 bool
600 valid_nr(hdp, nr, finalbit)
601 struct hdcb *hdp;
602 int nr;
603 int finalbit;
604 {
605 /* Make sure it really does acknowledge something. */
606 if (hdp->hd_lastrxnr == nr)
607 return (TRUE);
608
609 /*
610 * This section validates the frame's N(R) value. It's N(R) value
611 * must be in synchronization with our V(S) value and our "last
612 * received nr" variable. If it is correct then we are able to send
613 * more IFRAME's, else frame reject condition is entered.
614 */
615
616 if (range_check(hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) {
617 if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) &&
618 range_check(hdp->hd_vs, nr, hdp->hd_xx) == TRUE)
619 hdp->hd_vs = nr;
620
621 else {
622 hdp->hd_invalid_nr++;
623 return (FALSE);
624 }
625 }
626 /*
627 * If we get to here, we do have a valid frame but it might be out
628 * of sequence. However, we should still accept the receive state
629 * number N(R) since it has already passed our previous test and it
630 * does acknowledge frames which we are sending.
631 */
632
633 KILL_TIMER(hdp);
634 free_iframes(hdp, &nr, finalbit); /* Free all acknowledged
635 * iframes */
636 if (nr != hdp->hd_vs)
637 SET_TIMER(hdp);
638
639 return (TRUE);
640 }
641
642 /*
643 * This routine determines how many iframes need to be retransmitted. It then
644 * resets the Send State Variable V(S) to accomplish this.
645 */
646
647 static void
648 rej_routine(hdp, rejnr)
649 struct hdcb *hdp;
650 int rejnr;
651 {
652 int anchor;
653
654 /*
655 * Flush the output queue. Any iframes queued for
656 * transmission will be out of sequence.
657 */
658
659 hd_flush(hdp->hd_ifp);
660
661 /*
662 * Determine how many frames should be re-transmitted. In the case of
663 * a normal REJ this should be 1 to K. In the case of a timer
664 * recovery REJ (ie. a REJ with the Final Bit on) this could be 0.
665 */
666
667 anchor = hdp->hd_vs;
668 if (hdp->hd_condition & TIMER_RECOVERY_CONDITION)
669 anchor = hdp->hd_xx;
670
671 anchor = (anchor - rejnr + 8) % MODULUS;
672
673 if (anchor > 0) {
674
675 /* There is at least one iframe to retransmit. */
676 KILL_TIMER(hdp);
677 hdp->hd_vs = rejnr;
678
679 while (hdp->hd_vs != hdp->hd_retxqi)
680 hd_send_iframe(hdp, hdp->hd_retxq[(u_char)hdp->hd_vs],
681 POLLOFF);
682
683 }
684 hd_start(hdp);
685 }
686
687 /*
688 * This routine frees iframes from the retransmit queue. It is called when a
689 * previously written iframe is acknowledged.
690 */
691
692 static void
693 free_iframes(hdp, nr, finalbit)
694 struct hdcb *hdp;
695 int *nr;
696 int finalbit;
697
698 {
699 int i, k;
700
701 /*
702 * We need to do the following because of a funny quirk in the
703 * protocol. This case occures when in Timer recovery condition
704 * we get a N(R) which acknowledges all the outstanding iframes
705 * but with the Final Bit off. In this case we need to save the last
706 * iframe for possible retransmission even though it has already been
707 * acknowledged!
708 */
709
710 if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) {
711 *nr = (*nr - 1 + 8) % MODULUS;
712 #if 0
713 printf ("QUIRK\n");
714 #endif
715 }
716 k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS;
717
718 /* Loop here freeing all acknowledged iframes. */
719 for (i = 0; i < k; ++i) {
720 m_freem(hdp->hd_retxq[(u_char)hdp->hd_lastrxnr]);
721 hdp->hd_retxq[(u_char)hdp->hd_lastrxnr] = 0;
722 hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS;
723 }
724
725 }
Cache object: ff4b370e2bde3802c053d888e9fec29d
|