141703Ssklower /*
241703Ssklower * Copyright (c) University of British Columbia, 1984
3*63216Sbostic * Copyright (c) 1990, 1993
4*63216Sbostic * The Regents of the University of California. All rights reserved.
541703Ssklower *
641703Ssklower * This code is derived from software contributed to Berkeley by
741703Ssklower * the Laboratory for Computation Vision and the Computer Science Department
841703Ssklower * of the University of British Columbia.
941703Ssklower *
1041703Ssklower * %sccs.include.redist.c%
1141703Ssklower *
12*63216Sbostic * @(#)hd_input.c 8.1 (Berkeley) 06/10/93
1341703Ssklower */
1441586Ssklower
1556530Sbostic #include <sys/param.h>
1656530Sbostic #include <sys/systm.h>
1756530Sbostic #include <sys/mbuf.h>
1856530Sbostic #include <sys/domain.h>
1956530Sbostic #include <sys/socket.h>
2056530Sbostic #include <sys/protosw.h>
2156530Sbostic #include <sys/errno.h>
2256530Sbostic #include <sys/time.h>
2356530Sbostic #include <sys/kernel.h>
2441586Ssklower
2556530Sbostic #include <net/if.h>
2641586Ssklower
2756530Sbostic #include <netccitt/hdlc.h>
2856530Sbostic #include <netccitt/hd_var.h>
2956530Sbostic #include <netccitt/x25.h>
3041586Ssklower
3157018Ssklower static frame_reject();
3257018Ssklower static rej_routine();
3357018Ssklower static free_iframes();
3441586Ssklower /*
3541586Ssklower * HDLC INPUT INTERFACE
3641586Ssklower *
3741586Ssklower * This routine is called when the HDLC physical device has
3841586Ssklower * completed reading a frame.
3941586Ssklower */
4041586Ssklower
hdintr()4141586Ssklower hdintr ()
4241586Ssklower {
4341586Ssklower register struct mbuf *m;
4441586Ssklower register struct hdcb *hdp;
4541586Ssklower register struct ifnet *ifp;
4641586Ssklower register int s;
4741586Ssklower static struct ifnet *lastifp;
4841586Ssklower static struct hdcb *lasthdp;
4941586Ssklower
5041586Ssklower for (;;) {
5141586Ssklower s = splimp ();
5245296Ssklower IF_DEQUEUE (&hdintrq, m);
5341586Ssklower splx (s);
5441586Ssklower if (m == 0)
5541586Ssklower break;
5641586Ssklower if (m->m_len < HDHEADERLN) {
5741586Ssklower printf ("hdintr: packet too short (len=%d)\n",
5841586Ssklower m->m_len);
5941586Ssklower m_freem (m);
6041586Ssklower continue;
6141586Ssklower }
6245296Ssklower if ((m->m_flags & M_PKTHDR) == 0)
6345296Ssklower panic("hdintr");
6445296Ssklower ifp = m->m_pkthdr.rcvif;
6541586Ssklower
6641586Ssklower /*
6741586Ssklower * look up the appropriate hdlc control block
6841586Ssklower */
6941586Ssklower
7041586Ssklower if (ifp == lastifp)
7141586Ssklower hdp = lasthdp;
7241586Ssklower else {
7341586Ssklower for (hdp = hdcbhead; hdp; hdp = hdp->hd_next)
7441586Ssklower if (hdp->hd_ifp == ifp)
7541586Ssklower break;
7641586Ssklower if (hdp == 0) {
7741586Ssklower printf ("hdintr: unknown interface %x\n", ifp);
7841586Ssklower m_freem (m);
7941586Ssklower continue;
8041586Ssklower }
8141586Ssklower lastifp = ifp;
8241586Ssklower lasthdp = hdp;
8341586Ssklower }
8441586Ssklower
8541586Ssklower /* Process_rxframe returns FALSE if the frame was NOT queued
8641586Ssklower for the next higher layers. */
8741586Ssklower if (process_rxframe (hdp, m) == FALSE)
8841586Ssklower m_freem (m);
8941586Ssklower }
9041586Ssklower }
9141586Ssklower
process_rxframe(hdp,fbuf)9241586Ssklower process_rxframe (hdp, fbuf)
9341586Ssklower register struct hdcb *hdp;
9441586Ssklower register struct mbuf *fbuf;
9541586Ssklower {
9641586Ssklower register int queued = FALSE, frametype, pf;
9741586Ssklower register struct Hdlc_frame *frame;
9841586Ssklower
9941586Ssklower frame = mtod (fbuf, struct Hdlc_frame *);
10041586Ssklower pf = ((struct Hdlc_iframe *) frame) -> pf;
10141586Ssklower
10241586Ssklower hd_trace (hdp, RX, frame);
10341586Ssklower if (frame -> address != ADDRESS_A && frame -> address != ADDRESS_B)
10441586Ssklower return (queued);
10541586Ssklower
10641586Ssklower switch ((frametype = hd_decode (hdp, frame)) + hdp->hd_state) {
10741586Ssklower case DM + DISC_SENT:
10841586Ssklower case UA + DISC_SENT:
10941586Ssklower /*
11041586Ssklower * Link now closed. Leave timer running
11141586Ssklower * so hd_timer() can periodically check the
11241586Ssklower * status of interface driver flag bit IFF_UP.
11341586Ssklower */
11441586Ssklower hdp->hd_state = DISCONNECTED;
11541586Ssklower break;
11641586Ssklower
11741586Ssklower case DM + INIT:
11841586Ssklower case UA + INIT:
11941586Ssklower /*
12041586Ssklower * This is a non-standard state change needed for DCEs
12141586Ssklower * that do dynamic link selection. We can't go into the
12241586Ssklower * usual "SEND DM" state because a DM is a SARM in LAP.
12341586Ssklower */
12441586Ssklower hd_writeinternal (hdp, SABM, POLLOFF);
12541586Ssklower hdp->hd_state = SABM_SENT;
12641586Ssklower SET_TIMER (hdp);
12741586Ssklower break;
12841586Ssklower
12941586Ssklower case SABM + DM_SENT:
13041586Ssklower case SABM + WAIT_SABM:
13141586Ssklower hd_writeinternal (hdp, UA, pf);
13241586Ssklower case UA + SABM_SENT:
13341586Ssklower case UA + WAIT_UA:
13441586Ssklower KILL_TIMER (hdp);
13541586Ssklower hd_initvars (hdp);
13641586Ssklower hdp->hd_state = ABM;
13741586Ssklower hd_message (hdp, "Link level operational");
13841586Ssklower /* Notify the packet level - to send RESTART. */
13949927Ssklower (void) pk_ctlinput (PRC_LINKUP, hdp->hd_pkp);
14041586Ssklower break;
14141586Ssklower
14241586Ssklower case SABM + SABM_SENT:
14341586Ssklower /* Got a SABM collision. Acknowledge the remote's SABM
14441586Ssklower via UA but still wait for UA. */
14541586Ssklower hd_writeinternal (hdp, UA, pf);
14641586Ssklower break;
14741586Ssklower
14841586Ssklower case SABM + ABM:
14941586Ssklower /* Request to reset the link from the remote. */
15041586Ssklower KILL_TIMER (hdp);
15141586Ssklower hd_message (hdp, "Link reset");
15241586Ssklower #ifdef HDLCDEBUG
15341586Ssklower hd_dumptrace (hdp);
15441586Ssklower #endif
15541586Ssklower hd_flush (hdp->hd_ifp);
15641586Ssklower hd_writeinternal (hdp, UA, pf);
15741586Ssklower hd_initvars (hdp);
15849927Ssklower (void) pk_ctlinput (PRC_LINKRESET, hdp->hd_pkp);
15941586Ssklower hdp->hd_resets++;
16041586Ssklower break;
16141586Ssklower
16241586Ssklower case SABM + WAIT_UA:
16341586Ssklower hd_writeinternal (hdp, UA, pf);
16441586Ssklower break;
16541586Ssklower
16641586Ssklower case DM + ABM:
16741586Ssklower hd_message (hdp, "DM received: link down");
16841586Ssklower #ifdef HDLCDEBUG
16941586Ssklower hd_dumptrace (hdp);
17041586Ssklower #endif
17149927Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
17241586Ssklower hd_flush (hdp->hd_ifp);
17341586Ssklower case DM + DM_SENT:
17441586Ssklower case DM + WAIT_SABM:
17541586Ssklower case DM + WAIT_UA:
17641586Ssklower hd_writeinternal (hdp, SABM, pf);
17741586Ssklower hdp->hd_state = SABM_SENT;
17841586Ssklower SET_TIMER (hdp);
17941586Ssklower break;
18041586Ssklower
18141586Ssklower case DISC + INIT:
18241586Ssklower case DISC + DM_SENT:
18341586Ssklower case DISC + SABM_SENT:
18441586Ssklower /* Note: This is a non-standard state change. */
18541586Ssklower hd_writeinternal (hdp, UA, pf);
18641586Ssklower hd_writeinternal (hdp, SABM, POLLOFF);
18741586Ssklower hdp->hd_state = SABM_SENT;
18841586Ssklower SET_TIMER (hdp);
18941586Ssklower break;
19041586Ssklower
19141586Ssklower case DISC + WAIT_UA:
19241586Ssklower hd_writeinternal (hdp, DM, pf);
19341586Ssklower SET_TIMER (hdp);
19441586Ssklower hdp->hd_state = DM_SENT;
19541586Ssklower break;
19641586Ssklower
19741586Ssklower case DISC + ABM:
19841586Ssklower hd_message (hdp, "DISC received: link down");
19949927Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
20041586Ssklower case DISC + WAIT_SABM:
20141586Ssklower hd_writeinternal (hdp, UA, pf);
20241586Ssklower hdp->hd_state = DM_SENT;
20341586Ssklower SET_TIMER (hdp);
20441586Ssklower break;
20541586Ssklower
20641586Ssklower case UA + ABM:
20741586Ssklower hd_message (hdp, "UA received: link down");
20849927Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
20941586Ssklower case UA + WAIT_SABM:
21041586Ssklower hd_writeinternal (hdp, DM, pf);
21141586Ssklower hdp->hd_state = DM_SENT;
21241586Ssklower SET_TIMER (hdp);
21341586Ssklower break;
21441586Ssklower
21541586Ssklower case FRMR + DM_SENT:
21641586Ssklower hd_writeinternal (hdp, SABM, pf);
21741586Ssklower hdp->hd_state = SABM_SENT;
21841586Ssklower SET_TIMER (hdp);
21941586Ssklower break;
22041586Ssklower
22141586Ssklower case FRMR + WAIT_SABM:
22241586Ssklower hd_writeinternal (hdp, DM, pf);
22341586Ssklower hdp->hd_state = DM_SENT;
22441586Ssklower SET_TIMER (hdp);
22541586Ssklower break;
22641586Ssklower
22741586Ssklower case FRMR + ABM:
22841586Ssklower hd_message (hdp, "FRMR received: link down");
22949927Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
23041586Ssklower #ifdef HDLCDEBUG
23141586Ssklower hd_dumptrace (hdp);
23241586Ssklower #endif
23341586Ssklower hd_flush (hdp->hd_ifp);
23441586Ssklower hd_writeinternal (hdp, SABM, pf);
23541586Ssklower hdp->hd_state = WAIT_UA;
23641586Ssklower SET_TIMER (hdp);
23741586Ssklower break;
23841586Ssklower
23941586Ssklower case RR + ABM:
24041586Ssklower case RNR + ABM:
24141586Ssklower case REJ + ABM:
24241586Ssklower process_sframe (hdp, (struct Hdlc_sframe *)frame, frametype);
24341586Ssklower break;
24441586Ssklower
24541586Ssklower case IFRAME + ABM:
24641586Ssklower queued = process_iframe (hdp, fbuf, (struct Hdlc_iframe *)frame);
24741586Ssklower break;
24841586Ssklower
24941586Ssklower case IFRAME + SABM_SENT:
25041586Ssklower case RR + SABM_SENT:
25141586Ssklower case RNR + SABM_SENT:
25241586Ssklower case REJ + SABM_SENT:
25341586Ssklower hd_writeinternal (hdp, DM, POLLON);
25441586Ssklower hdp->hd_state = DM_SENT;
25541586Ssklower SET_TIMER (hdp);
25641586Ssklower break;
25741586Ssklower
25841586Ssklower case IFRAME + WAIT_SABM:
25941586Ssklower case RR + WAIT_SABM:
26041586Ssklower case RNR + WAIT_SABM:
26141586Ssklower case REJ + WAIT_SABM:
26241586Ssklower hd_writeinternal (hdp, FRMR, POLLOFF);
26341586Ssklower SET_TIMER (hdp);
26441586Ssklower break;
26541586Ssklower
26641586Ssklower case ILLEGAL + SABM_SENT:
26741586Ssklower hdp->hd_unknown++;
26841586Ssklower hd_writeinternal (hdp, DM, POLLOFF);
26941586Ssklower hdp->hd_state = DM_SENT;
27041586Ssklower SET_TIMER (hdp);
27141586Ssklower break;
27241586Ssklower
27341586Ssklower case ILLEGAL + ABM:
27441586Ssklower hd_message (hdp, "Unknown frame received: link down");
27549927Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
27641586Ssklower case ILLEGAL + WAIT_SABM:
27741586Ssklower hdp->hd_unknown++;
27841586Ssklower #ifdef HDLCDEBUG
27941586Ssklower hd_dumptrace (hdp);
28041586Ssklower #endif
28141586Ssklower hd_writeinternal (hdp, FRMR, POLLOFF);
28241586Ssklower hdp->hd_state = WAIT_SABM;
28341586Ssklower SET_TIMER (hdp);
28441586Ssklower break;
28541586Ssklower }
28641586Ssklower
28741586Ssklower return (queued);
28841586Ssklower }
28941586Ssklower
process_iframe(hdp,fbuf,frame)29041586Ssklower process_iframe (hdp, fbuf, frame)
29141586Ssklower register struct hdcb *hdp;
29241586Ssklower struct mbuf *fbuf;
29341586Ssklower register struct Hdlc_iframe *frame;
29441586Ssklower {
29541586Ssklower register int nr = frame -> nr,
29641586Ssklower ns = frame -> ns,
29741586Ssklower pf = frame -> pf;
29841586Ssklower register int queued = FALSE;
29941586Ssklower
30041586Ssklower /*
30141586Ssklower * Validate the iframe's N(R) value. It's N(R) value must be in
30241586Ssklower * sync with our V(S) value and our "last received nr".
30341586Ssklower */
30441586Ssklower
30541586Ssklower if (valid_nr (hdp, nr, FALSE) == FALSE) {
30641586Ssklower frame_reject (hdp, Z, frame);
30741586Ssklower return (queued);
30841586Ssklower }
30941586Ssklower
31041586Ssklower
31141586Ssklower /*
31241586Ssklower * This section tests the IFRAME for proper sequence. That is, it's
31341586Ssklower * sequence number N(S) MUST be equal to V(S).
31441586Ssklower */
31541586Ssklower
31641586Ssklower if (ns != hdp->hd_vr) {
31741586Ssklower hdp->hd_invalid_ns++;
31841586Ssklower if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) {
31941586Ssklower hdp->hd_condition |= REJ_CONDITION;
32041586Ssklower /*
32141586Ssklower * Flush the transmit queue. This is ugly but we
32241586Ssklower * have no choice. A reject response must be
32341586Ssklower * immediately sent to the DCE. Failure to do so
32441586Ssklower * may result in another out of sequence iframe
32541586Ssklower * arriving (and thus sending another reject)
32641586Ssklower * before the first reject is transmitted. This
32741586Ssklower * will cause the DCE to receive two or more
32841586Ssklower * rejects back to back, which must never happen.
32941586Ssklower */
33041586Ssklower hd_flush (hdp->hd_ifp);
33141586Ssklower hd_writeinternal (hdp, REJ, pf);
33241586Ssklower }
33341586Ssklower return (queued);
33441586Ssklower }
33541586Ssklower hdp->hd_condition &= ~REJ_CONDITION;
33641586Ssklower
33741586Ssklower /*
33841586Ssklower * This section finally tests the IFRAME's sequence number against
33941586Ssklower * the window size (K) and the sequence number of the last frame
34041586Ssklower * we have acknowledged. If the IFRAME is completely correct then
34141586Ssklower * it is queued for the packet level.
34241586Ssklower */
34341586Ssklower
34449927Ssklower if (ns != (hdp -> hd_lasttxnr + hdp -> hd_xcp -> xc_lwsize) % MODULUS) {
34549927Ssklower hdp -> hd_vr = (hdp -> hd_vr + 1) % MODULUS;
34641586Ssklower if (pf == 1) {
34741586Ssklower /* Must generate a RR or RNR with final bit on. */
34841586Ssklower hd_writeinternal (hdp, RR, POLLON);
34941586Ssklower } else
35041586Ssklower /*
35141586Ssklower * Hopefully we can piggyback the RR, if not we will generate
35241586Ssklower * a RR when T3 timer expires.
35341586Ssklower */
35441586Ssklower if (hdp -> hd_rrtimer == 0)
35541586Ssklower hdp->hd_rrtimer = hd_t3;
35641586Ssklower
35741586Ssklower /* Forward iframe to packet level of X.25. */
35843361Ssklower fbuf -> m_data += HDHEADERLN;
35941586Ssklower fbuf -> m_len -= HDHEADERLN;
36045890Ssklower fbuf -> m_pkthdr.len -= HDHEADERLN;
36149927Ssklower fbuf -> m_pkthdr.rcvif = (struct ifnet *)hdp -> hd_pkp;
36241586Ssklower #ifdef BSD4_3
36341586Ssklower fbuf->m_act = 0; /* probably not necessary */
36441586Ssklower #else
36541586Ssklower {
36641586Ssklower register struct mbuf *m;
36741586Ssklower
36841586Ssklower for (m = fbuf; m -> m_next; m = m -> m_next)
36941586Ssklower m -> m_act = (struct mbuf *) 0;
37041586Ssklower m -> m_act = (struct mbuf *) 1;
37141586Ssklower }
37241586Ssklower #endif
37349927Ssklower pk_input (fbuf);
37441586Ssklower queued = TRUE;
37541586Ssklower hd_start (hdp);
37641586Ssklower } else {
37741586Ssklower /*
37841586Ssklower * Here if the remote station has transmitted more iframes then
37941586Ssklower * the number which have been acknowledged plus K.
38041586Ssklower */
38141586Ssklower hdp->hd_invalid_ns++;
38241586Ssklower frame_reject (hdp, W, frame);
38341586Ssklower }
38441586Ssklower return (queued);
38541586Ssklower }
38641586Ssklower
38741586Ssklower /*
38841586Ssklower * This routine is used to determine if a value (the middle parameter)
38941586Ssklower * is between two other values. The low value is the first parameter
39041586Ssklower * the high value is the last parameter. The routine checks the middle
39141586Ssklower * value to see if it is within the range of the first and last values.
39241586Ssklower * The reason we need this routine is the values are modulo some base
39341586Ssklower * hence a simple test for greater or less than is not sufficient.
39441586Ssklower */
39541586Ssklower
39641586Ssklower bool
range_check(rear,value,front)39741586Ssklower range_check (rear, value, front)
39841586Ssklower int rear,
39941586Ssklower value,
40041586Ssklower front;
40141586Ssklower {
40241586Ssklower register bool result = FALSE;
40341586Ssklower
40441586Ssklower if (front > rear)
40541586Ssklower result = (rear <= value) && (value <= front);
40641586Ssklower else
40741586Ssklower result = (rear <= value) || (value <= front);
40841586Ssklower
40941586Ssklower return (result);
41041586Ssklower }
41141586Ssklower
41241586Ssklower /*
41341586Ssklower * This routine handles all the frame reject conditions which can
41441586Ssklower * arise as a result of secondary processing. The frame reject
41541586Ssklower * condition Y (frame length error) are handled elsewhere.
41641586Ssklower */
41741586Ssklower
41841586Ssklower static
41941586Ssklower frame_reject (hdp, rejectcode, frame)
42041586Ssklower struct hdcb *hdp;
42141586Ssklower struct Hdlc_iframe *frame;
42241586Ssklower {
42341586Ssklower register struct Frmr_frame *frmr = &hd_frmr;
42441586Ssklower
42541586Ssklower frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control;
42641586Ssklower
42741586Ssklower frmr -> frmr_ns = frame -> ns;
42841586Ssklower frmr -> frmr_f1_0 = 0;
42941586Ssklower frmr -> frmr_nr = frame -> nr;
43041586Ssklower frmr -> frmr_f2_0 = 0;
43141586Ssklower
43241586Ssklower frmr -> frmr_0000 = 0;
43341586Ssklower frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y =
43441586Ssklower frmr -> frmr_z = 0;
43541586Ssklower switch (rejectcode) {
43641586Ssklower case Z:
43741586Ssklower frmr -> frmr_z = 1;/* invalid N(R). */
43841586Ssklower break;
43941586Ssklower
44041586Ssklower case Y:
44141586Ssklower frmr -> frmr_y = 1;/* iframe length error. */
44241586Ssklower break;
44341586Ssklower
44441586Ssklower case X:
44541586Ssklower frmr -> frmr_x = 1;/* invalid information field. */
44641586Ssklower frmr -> frmr_w = 1;
44741586Ssklower break;
44841586Ssklower
44941586Ssklower case W:
45041586Ssklower frmr -> frmr_w = 1;/* invalid N(S). */
45141586Ssklower }
45241586Ssklower
45341586Ssklower hd_writeinternal (hdp, FRMR, POLLOFF);
45441586Ssklower
45541586Ssklower hdp->hd_state = WAIT_SABM;
45641586Ssklower SET_TIMER (hdp);
45741586Ssklower }
45841586Ssklower
45941586Ssklower /*
46041586Ssklower * This procedure is invoked when ever we receive a supervisor
46141586Ssklower * frame such as RR, RNR and REJ. All processing for these
46241586Ssklower * frames is done here.
46341586Ssklower */
46441586Ssklower
process_sframe(hdp,frame,frametype)46541586Ssklower process_sframe (hdp, frame, frametype)
46641586Ssklower register struct hdcb *hdp;
46741586Ssklower register struct Hdlc_sframe *frame;
46841586Ssklower int frametype;
46941586Ssklower {
47041586Ssklower register int nr = frame -> nr, pf = frame -> pf, pollbit = 0;
47141586Ssklower
47241586Ssklower if (valid_nr (hdp, nr, pf) == TRUE) {
47341586Ssklower switch (frametype) {
47441586Ssklower case RR:
47541586Ssklower hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
47641586Ssklower break;
47741586Ssklower
47841586Ssklower case RNR:
47941586Ssklower hdp->hd_condition |= REMOTE_RNR_CONDITION;
48041586Ssklower hdp->hd_retxcnt = 0;
48141586Ssklower break;
48241586Ssklower
48341586Ssklower case REJ:
48441586Ssklower hdp->hd_condition &= ~REMOTE_RNR_CONDITION;
48541586Ssklower rej_routine (hdp, nr);
48641586Ssklower }
48741586Ssklower
48841586Ssklower if (pf == 1) {
48941586Ssklower hdp->hd_retxcnt = 0;
49041586Ssklower hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION;
49141586Ssklower
49245296Ssklower if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs
49345296Ssklower && hdp->hd_timer == 0 && hdp->hd_txq.head == 0)
49445296Ssklower hd_writeinternal(hdp, RR, pf);
49545296Ssklower else
49641586Ssklower /* If any iframes have been queued because of the
49741586Ssklower timer condition, transmit then now. */
49841586Ssklower if (hdp->hd_condition & REMOTE_RNR_CONDITION) {
49941586Ssklower /* Remote is busy or timer condition, so only
50041586Ssklower send one. */
50141586Ssklower if (hdp->hd_vs != hdp->hd_retxqi)
50241586Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit);
50341586Ssklower }
50441586Ssklower else /* Flush the retransmit list first. */
50541586Ssklower while (hdp->hd_vs != hdp->hd_retxqi)
50641586Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
50741586Ssklower }
50841586Ssklower
50941586Ssklower hd_start (hdp);
51041586Ssklower } else
51141586Ssklower frame_reject (hdp, Z, (struct Hdlc_iframe *)frame); /* Invalid N(R). */
51241586Ssklower }
51341586Ssklower
51441586Ssklower /*
51541586Ssklower * This routine tests the validity of the N(R) which we have received.
51641586Ssklower * If it is ok, then all the iframes which it acknowledges (if any)
51741586Ssklower * will be freed.
51841586Ssklower */
51941586Ssklower
52041586Ssklower bool
valid_nr(hdp,nr,finalbit)52141586Ssklower valid_nr (hdp, nr, finalbit)
52241586Ssklower register struct hdcb *hdp;
52341586Ssklower register int finalbit;
52441586Ssklower {
52541586Ssklower /* Make sure it really does acknowledge something. */
52641586Ssklower if (hdp->hd_lastrxnr == nr)
52741586Ssklower return (TRUE);
52841586Ssklower
52941586Ssklower /*
53041586Ssklower * This section validates the frame's N(R) value. It's N(R) value
53141586Ssklower * must be in syncronization with our V(S) value and our "last
53241586Ssklower * received nr" variable. If it is correct then we are able to send
53341586Ssklower * more IFRAME's, else frame reject condition is entered.
53441586Ssklower */
53541586Ssklower
53641586Ssklower if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) {
53741586Ssklower if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) &&
53841586Ssklower range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE)
53941586Ssklower hdp->hd_vs = nr;
54041586Ssklower
54141586Ssklower else {
54241586Ssklower hdp->hd_invalid_nr++;
54341586Ssklower return (FALSE);
54441586Ssklower }
54541586Ssklower }
54641586Ssklower
54741586Ssklower /*
54841586Ssklower * If we get to here, we do have a valid frame but it might be out
54941586Ssklower * of sequence. However, we should still accept the receive state
55041586Ssklower * number N(R) since it has already passed our previous test and it
55141586Ssklower * does acknowledge frames which we are sending.
55241586Ssklower */
55341586Ssklower
55441586Ssklower KILL_TIMER (hdp);
55541586Ssklower free_iframes (hdp, &nr, finalbit);/* Free all acknowledged iframes */
55641586Ssklower if (nr != hdp->hd_vs)
55741586Ssklower SET_TIMER (hdp);
55841586Ssklower
55941586Ssklower return (TRUE);
56041586Ssklower }
56141586Ssklower
56241586Ssklower /*
56341586Ssklower * This routine determines how many iframes need to be retransmitted.
56441586Ssklower * It then resets the Send State Variable V(S) to accomplish this.
56541586Ssklower */
56641586Ssklower
56741586Ssklower static
rej_routine(hdp,rejnr)56841586Ssklower rej_routine (hdp, rejnr)
56941586Ssklower register struct hdcb *hdp;
57041586Ssklower register int rejnr;
57141586Ssklower {
57241586Ssklower register int anchor;
57341586Ssklower
57441586Ssklower /*
57541586Ssklower * Flush the output queue. Any iframes queued for
57641586Ssklower * transmission will be out of sequence.
57741586Ssklower */
57841586Ssklower
57941586Ssklower hd_flush (hdp->hd_ifp);
58041586Ssklower
58141586Ssklower /*
58241586Ssklower * Determine how many frames should be re-transmitted. In the case
58341586Ssklower * of a normal REJ this should be 1 to K. In the case of a timer
58441586Ssklower * recovery REJ (ie. a REJ with the Final Bit on) this could be 0.
58541586Ssklower */
58641586Ssklower
58741586Ssklower anchor = hdp->hd_vs;
58841586Ssklower if (hdp->hd_condition & TIMER_RECOVERY_CONDITION)
58941586Ssklower anchor = hdp->hd_xx;
59041586Ssklower
59141586Ssklower anchor = (anchor - rejnr + 8) % MODULUS;
59241586Ssklower
59341586Ssklower if (anchor > 0) {
59441586Ssklower
59541586Ssklower /* There is at least one iframe to retransmit. */
59641586Ssklower KILL_TIMER (hdp);
59741586Ssklower hdp->hd_vs = rejnr;
59841586Ssklower
59941586Ssklower while (hdp->hd_vs != hdp->hd_retxqi)
60041586Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF);
60141586Ssklower
60241586Ssklower }
60341586Ssklower hd_start (hdp);
60441586Ssklower }
60541586Ssklower
60641586Ssklower /*
60741586Ssklower * This routine frees iframes from the retransmit queue. It is called
60841586Ssklower * when a previously written iframe is acknowledged.
60941586Ssklower */
61041586Ssklower
61141586Ssklower static
free_iframes(hdp,nr,finalbit)61241586Ssklower free_iframes (hdp, nr, finalbit)
61341586Ssklower register struct hdcb *hdp;
61441586Ssklower int *nr;
61541586Ssklower register int finalbit;
61641586Ssklower
61741586Ssklower {
61841586Ssklower register int i, k;
61941586Ssklower
62041586Ssklower /*
62141586Ssklower * We need to do the following because of a funny quirk in the
62241586Ssklower * protocol. This case occures when in Timer recovery condition
62341586Ssklower * we get a N(R) which acknowledges all the outstanding iframes
62441586Ssklower * but with the Final Bit off. In this case we need to save the last
62541586Ssklower * iframe for possible retransmission even though it has already been
62641586Ssklower * acknowledged!
62741586Ssklower */
62841586Ssklower
62941586Ssklower if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) {
63041586Ssklower *nr = (*nr - 1 + 8) % MODULUS;
63141586Ssklower /* printf ("QUIRK\n"); */
63241586Ssklower }
63341586Ssklower
63441586Ssklower k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS;
63541586Ssklower
63641586Ssklower /* Loop here freeing all acknowledged iframes. */
63741586Ssklower for (i = 0; i < k; ++i) {
63841586Ssklower m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]);
63941586Ssklower hdp->hd_retxq[hdp->hd_lastrxnr] = 0;
64041586Ssklower hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS;
64141586Ssklower }
64241586Ssklower
64341586Ssklower }
644