]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/hd_input.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) University of British Columbia, 1984
24 * Copyright (c) 1990, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * the Laboratory for Computation Vision and the Computer Science Department
29 * of the University of British Columbia.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)hd_input.c 8.1 (Berkeley) 6/10/93
62 #include <sys/param.h>
63 #include <sys/systm.h>
65 #include <sys/domain.h>
66 #include <sys/socket.h>
67 #include <sys/protosw.h>
68 #include <sys/errno.h>
70 #include <sys/kernel.h>
74 #include <netccitt/hdlc.h>
75 #include <netccitt/hd_var.h>
76 #include <netccitt/x25.h>
78 static frame_reject();
80 static free_iframes();
82 * HDLC INPUT INTERFACE
84 * This routine is called when the HDLC physical device has
85 * completed reading a frame.
90 register struct mbuf
*m
;
91 register struct hdcb
*hdp
;
92 register struct ifnet
*ifp
;
94 static struct ifnet
*lastifp
;
95 static struct hdcb
*lasthdp
;
99 IF_DEQUEUE (&hdintrq
, m
);
103 if (m
->m_len
< HDHEADERLN
) {
104 printf ("hdintr: packet too short (len=%d)\n",
109 if ((m
->m_flags
& M_PKTHDR
) == 0)
111 ifp
= m
->m_pkthdr
.rcvif
;
114 * look up the appropriate hdlc control block
120 for (hdp
= hdcbhead
; hdp
; hdp
= hdp
->hd_next
)
121 if (hdp
->hd_ifp
== ifp
)
124 printf ("hdintr: unknown interface %x\n", ifp
);
132 /* Process_rxframe returns FALSE if the frame was NOT queued
133 for the next higher layers. */
134 if (process_rxframe (hdp
, m
) == FALSE
)
139 process_rxframe (hdp
, fbuf
)
140 register struct hdcb
*hdp
;
141 register struct mbuf
*fbuf
;
143 register int queued
= FALSE
, frametype
, pf
;
144 register struct Hdlc_frame
*frame
;
146 frame
= mtod (fbuf
, struct Hdlc_frame
*);
147 pf
= ((struct Hdlc_iframe
*) frame
) -> pf
;
149 hd_trace (hdp
, RX
, frame
);
150 if (frame
-> address
!= ADDRESS_A
&& frame
-> address
!= ADDRESS_B
)
153 switch ((frametype
= hd_decode (hdp
, frame
)) + hdp
->hd_state
) {
157 * Link now closed. Leave timer running
158 * so hd_timer() can periodically check the
159 * status of interface driver flag bit IFF_UP.
161 hdp
->hd_state
= DISCONNECTED
;
167 * This is a non-standard state change needed for DCEs
168 * that do dynamic link selection. We can't go into the
169 * usual "SEND DM" state because a DM is a SARM in LAP.
171 hd_writeinternal (hdp
, SABM
, POLLOFF
);
172 hdp
->hd_state
= SABM_SENT
;
177 case SABM
+ WAIT_SABM
:
178 hd_writeinternal (hdp
, UA
, pf
);
184 hd_message (hdp
, "Link level operational");
185 /* Notify the packet level - to send RESTART. */
186 (void) pk_ctlinput (PRC_LINKUP
, hdp
->hd_pkp
);
189 case SABM
+ SABM_SENT
:
190 /* Got a SABM collision. Acknowledge the remote's SABM
191 via UA but still wait for UA. */
192 hd_writeinternal (hdp
, UA
, pf
);
196 /* Request to reset the link from the remote. */
198 hd_message (hdp
, "Link reset");
202 hd_flush (hdp
->hd_ifp
);
203 hd_writeinternal (hdp
, UA
, pf
);
205 (void) pk_ctlinput (PRC_LINKRESET
, hdp
->hd_pkp
);
210 hd_writeinternal (hdp
, UA
, pf
);
214 hd_message (hdp
, "DM received: link down");
218 (void) pk_ctlinput (PRC_LINKDOWN
, hdp
->hd_pkp
);
219 hd_flush (hdp
->hd_ifp
);
223 hd_writeinternal (hdp
, SABM
, pf
);
224 hdp
->hd_state
= SABM_SENT
;
230 case DISC
+ SABM_SENT
:
231 /* Note: This is a non-standard state change. */
232 hd_writeinternal (hdp
, UA
, pf
);
233 hd_writeinternal (hdp
, SABM
, POLLOFF
);
234 hdp
->hd_state
= SABM_SENT
;
239 hd_writeinternal (hdp
, DM
, pf
);
241 hdp
->hd_state
= DM_SENT
;
245 hd_message (hdp
, "DISC received: link down");
246 (void) pk_ctlinput (PRC_LINKDOWN
, hdp
->hd_pkp
);
247 case DISC
+ WAIT_SABM
:
248 hd_writeinternal (hdp
, UA
, pf
);
249 hdp
->hd_state
= DM_SENT
;
254 hd_message (hdp
, "UA received: link down");
255 (void) pk_ctlinput (PRC_LINKDOWN
, hdp
->hd_pkp
);
257 hd_writeinternal (hdp
, DM
, pf
);
258 hdp
->hd_state
= DM_SENT
;
263 hd_writeinternal (hdp
, SABM
, pf
);
264 hdp
->hd_state
= SABM_SENT
;
268 case FRMR
+ WAIT_SABM
:
269 hd_writeinternal (hdp
, DM
, pf
);
270 hdp
->hd_state
= DM_SENT
;
275 hd_message (hdp
, "FRMR received: link down");
276 (void) pk_ctlinput (PRC_LINKDOWN
, hdp
->hd_pkp
);
280 hd_flush (hdp
->hd_ifp
);
281 hd_writeinternal (hdp
, SABM
, pf
);
282 hdp
->hd_state
= WAIT_UA
;
289 process_sframe (hdp
, (struct Hdlc_sframe
*)frame
, frametype
);
293 queued
= process_iframe (hdp
, fbuf
, (struct Hdlc_iframe
*)frame
);
296 case IFRAME
+ SABM_SENT
:
298 case RNR
+ SABM_SENT
:
299 case REJ
+ SABM_SENT
:
300 hd_writeinternal (hdp
, DM
, POLLON
);
301 hdp
->hd_state
= DM_SENT
;
305 case IFRAME
+ WAIT_SABM
:
307 case RNR
+ WAIT_SABM
:
308 case REJ
+ WAIT_SABM
:
309 hd_writeinternal (hdp
, FRMR
, POLLOFF
);
313 case ILLEGAL
+ SABM_SENT
:
315 hd_writeinternal (hdp
, DM
, POLLOFF
);
316 hdp
->hd_state
= DM_SENT
;
321 hd_message (hdp
, "Unknown frame received: link down");
322 (void) pk_ctlinput (PRC_LINKDOWN
, hdp
->hd_pkp
);
323 case ILLEGAL
+ WAIT_SABM
:
328 hd_writeinternal (hdp
, FRMR
, POLLOFF
);
329 hdp
->hd_state
= WAIT_SABM
;
337 process_iframe (hdp
, fbuf
, frame
)
338 register struct hdcb
*hdp
;
340 register struct Hdlc_iframe
*frame
;
342 register int nr
= frame
-> nr
,
345 register int queued
= FALSE
;
348 * Validate the iframe's N(R) value. It's N(R) value must be in
349 * sync with our V(S) value and our "last received nr".
352 if (valid_nr (hdp
, nr
, FALSE
) == FALSE
) {
353 frame_reject (hdp
, Z
, frame
);
359 * This section tests the IFRAME for proper sequence. That is, it's
360 * sequence number N(S) MUST be equal to V(S).
363 if (ns
!= hdp
->hd_vr
) {
364 hdp
->hd_invalid_ns
++;
365 if (pf
|| (hdp
->hd_condition
& REJ_CONDITION
) == 0) {
366 hdp
->hd_condition
|= REJ_CONDITION
;
368 * Flush the transmit queue. This is ugly but we
369 * have no choice. A reject response must be
370 * immediately sent to the DCE. Failure to do so
371 * may result in another out of sequence iframe
372 * arriving (and thus sending another reject)
373 * before the first reject is transmitted. This
374 * will cause the DCE to receive two or more
375 * rejects back to back, which must never happen.
377 hd_flush (hdp
->hd_ifp
);
378 hd_writeinternal (hdp
, REJ
, pf
);
382 hdp
->hd_condition
&= ~REJ_CONDITION
;
385 * This section finally tests the IFRAME's sequence number against
386 * the window size (K) and the sequence number of the last frame
387 * we have acknowledged. If the IFRAME is completely correct then
388 * it is queued for the packet level.
391 if (ns
!= (hdp
-> hd_lasttxnr
+ hdp
-> hd_xcp
-> xc_lwsize
) % MODULUS
) {
392 hdp
-> hd_vr
= (hdp
-> hd_vr
+ 1) % MODULUS
;
394 /* Must generate a RR or RNR with final bit on. */
395 hd_writeinternal (hdp
, RR
, POLLON
);
398 * Hopefully we can piggyback the RR, if not we will generate
399 * a RR when T3 timer expires.
401 if (hdp
-> hd_rrtimer
== 0)
402 hdp
->hd_rrtimer
= hd_t3
;
404 /* Forward iframe to packet level of X.25. */
405 fbuf
-> m_data
+= HDHEADERLN
;
406 fbuf
-> m_len
-= HDHEADERLN
;
407 fbuf
-> m_pkthdr
.len
-= HDHEADERLN
;
408 fbuf
-> m_pkthdr
.rcvif
= (struct ifnet
*)hdp
-> hd_pkp
;
410 fbuf
->m_act
= 0; /* probably not necessary */
413 register struct mbuf
*m
;
415 for (m
= fbuf
; m
-> m_next
; m
= m
-> m_next
)
416 m
-> m_act
= (struct mbuf
*) 0;
417 m
-> m_act
= (struct mbuf
*) 1;
425 * Here if the remote station has transmitted more iframes then
426 * the number which have been acknowledged plus K.
428 hdp
->hd_invalid_ns
++;
429 frame_reject (hdp
, W
, frame
);
435 * This routine is used to determine if a value (the middle parameter)
436 * is between two other values. The low value is the first parameter
437 * the high value is the last parameter. The routine checks the middle
438 * value to see if it is within the range of the first and last values.
439 * The reason we need this routine is the values are modulo some base
440 * hence a simple test for greater or less than is not sufficient.
444 range_check (rear
, value
, front
)
449 register bool result
= FALSE
;
452 result
= (rear
<= value
) && (value
<= front
);
454 result
= (rear
<= value
) || (value
<= front
);
460 * This routine handles all the frame reject conditions which can
461 * arise as a result of secondary processing. The frame reject
462 * condition Y (frame length error) are handled elsewhere.
466 frame_reject (hdp
, rejectcode
, frame
)
468 struct Hdlc_iframe
*frame
;
470 register struct Frmr_frame
*frmr
= &hd_frmr
;
472 frmr
-> frmr_control
= ((struct Hdlc_frame
*) frame
) -> control
;
474 frmr
-> frmr_ns
= frame
-> ns
;
475 frmr
-> frmr_f1_0
= 0;
476 frmr
-> frmr_nr
= frame
-> nr
;
477 frmr
-> frmr_f2_0
= 0;
479 frmr
-> frmr_0000
= 0;
480 frmr
-> frmr_w
= frmr
-> frmr_x
= frmr
-> frmr_y
=
482 switch (rejectcode
) {
484 frmr
-> frmr_z
= 1;/* invalid N(R). */
488 frmr
-> frmr_y
= 1;/* iframe length error. */
492 frmr
-> frmr_x
= 1;/* invalid information field. */
497 frmr
-> frmr_w
= 1;/* invalid N(S). */
500 hd_writeinternal (hdp
, FRMR
, POLLOFF
);
502 hdp
->hd_state
= WAIT_SABM
;
507 * This procedure is invoked when ever we receive a supervisor
508 * frame such as RR, RNR and REJ. All processing for these
509 * frames is done here.
512 process_sframe (hdp
, frame
, frametype
)
513 register struct hdcb
*hdp
;
514 register struct Hdlc_sframe
*frame
;
517 register int nr
= frame
-> nr
, pf
= frame
-> pf
, pollbit
= 0;
519 if (valid_nr (hdp
, nr
, pf
) == TRUE
) {
522 hdp
->hd_condition
&= ~REMOTE_RNR_CONDITION
;
526 hdp
->hd_condition
|= REMOTE_RNR_CONDITION
;
531 hdp
->hd_condition
&= ~REMOTE_RNR_CONDITION
;
532 rej_routine (hdp
, nr
);
537 hdp
->hd_condition
&= ~TIMER_RECOVERY_CONDITION
;
539 if (frametype
== RR
&& hdp
->hd_lastrxnr
== hdp
->hd_vs
540 && hdp
->hd_timer
== 0 && hdp
->hd_txq
.head
== 0)
541 hd_writeinternal(hdp
, RR
, pf
);
543 /* If any iframes have been queued because of the
544 timer condition, transmit then now. */
545 if (hdp
->hd_condition
& REMOTE_RNR_CONDITION
) {
546 /* Remote is busy or timer condition, so only
548 if (hdp
->hd_vs
!= hdp
->hd_retxqi
)
549 hd_send_iframe (hdp
, hdp
->hd_retxq
[hdp
->hd_vs
], pollbit
);
551 else /* Flush the retransmit list first. */
552 while (hdp
->hd_vs
!= hdp
->hd_retxqi
)
553 hd_send_iframe (hdp
, hdp
->hd_retxq
[hdp
->hd_vs
], POLLOFF
);
558 frame_reject (hdp
, Z
, (struct Hdlc_iframe
*)frame
); /* Invalid N(R). */
562 * This routine tests the validity of the N(R) which we have received.
563 * If it is ok, then all the iframes which it acknowledges (if any)
568 valid_nr (hdp
, nr
, finalbit
)
569 register struct hdcb
*hdp
;
570 register int finalbit
;
572 /* Make sure it really does acknowledge something. */
573 if (hdp
->hd_lastrxnr
== nr
)
577 * This section validates the frame's N(R) value. It's N(R) value
578 * must be in syncronization with our V(S) value and our "last
579 * received nr" variable. If it is correct then we are able to send
580 * more IFRAME's, else frame reject condition is entered.
583 if (range_check (hdp
->hd_lastrxnr
, nr
, hdp
->hd_vs
) == FALSE
) {
584 if ((hdp
->hd_condition
& TIMER_RECOVERY_CONDITION
) &&
585 range_check (hdp
->hd_vs
, nr
, hdp
->hd_xx
) == TRUE
)
589 hdp
->hd_invalid_nr
++;
595 * If we get to here, we do have a valid frame but it might be out
596 * of sequence. However, we should still accept the receive state
597 * number N(R) since it has already passed our previous test and it
598 * does acknowledge frames which we are sending.
602 free_iframes (hdp
, &nr
, finalbit
);/* Free all acknowledged iframes */
603 if (nr
!= hdp
->hd_vs
)
610 * This routine determines how many iframes need to be retransmitted.
611 * It then resets the Send State Variable V(S) to accomplish this.
615 rej_routine (hdp
, rejnr
)
616 register struct hdcb
*hdp
;
622 * Flush the output queue. Any iframes queued for
623 * transmission will be out of sequence.
626 hd_flush (hdp
->hd_ifp
);
629 * Determine how many frames should be re-transmitted. In the case
630 * of a normal REJ this should be 1 to K. In the case of a timer
631 * recovery REJ (ie. a REJ with the Final Bit on) this could be 0.
635 if (hdp
->hd_condition
& TIMER_RECOVERY_CONDITION
)
638 anchor
= (anchor
- rejnr
+ 8) % MODULUS
;
642 /* There is at least one iframe to retransmit. */
646 while (hdp
->hd_vs
!= hdp
->hd_retxqi
)
647 hd_send_iframe (hdp
, hdp
->hd_retxq
[hdp
->hd_vs
], POLLOFF
);
654 * This routine frees iframes from the retransmit queue. It is called
655 * when a previously written iframe is acknowledged.
659 free_iframes (hdp
, nr
, finalbit
)
660 register struct hdcb
*hdp
;
662 register int finalbit
;
668 * We need to do the following because of a funny quirk in the
669 * protocol. This case occures when in Timer recovery condition
670 * we get a N(R) which acknowledges all the outstanding iframes
671 * but with the Final Bit off. In this case we need to save the last
672 * iframe for possible retransmission even though it has already been
676 if ((hdp
->hd_condition
& TIMER_RECOVERY_CONDITION
) && *nr
== hdp
->hd_xx
&& finalbit
== 0) {
677 *nr
= (*nr
- 1 + 8) % MODULUS
;
678 /* printf ("QUIRK\n"); */
681 k
= (*nr
- hdp
->hd_lastrxnr
+ 8) % MODULUS
;
683 /* Loop here freeing all acknowledged iframes. */
684 for (i
= 0; i
< k
; ++i
) {
685 m_freem (hdp
->hd_retxq
[hdp
->hd_lastrxnr
]);
686 hdp
->hd_retxq
[hdp
->hd_lastrxnr
] = 0;
687 hdp
->hd_lastrxnr
= (hdp
->hd_lastrxnr
+ 1) % MODULUS
;