2 * NET An implementation of the IEEE 802.2 LLC protocol for the
3 * LINUX operating system. LLC is implemented as a set of
4 * state machines and callbacks for higher networking layers.
6 * Small utilities, Linux timer handling.
8 * Written by Tim Alpaerts, Tim_Alpaerts@toyota-motor-europe.com
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
16 * Alan Cox : Chainsawed into Linux form.
17 * Added llc_ function name prefixes.
18 * Fixed bug in stop/start timer.
19 * Added llc_cancel_timers for closing
23 #include <linux/types.h>
24 #include <linux/kernel.h>
25 #include <linux/netdevice.h>
26 #include <linux/skbuff.h>
27 #include <linux/proc_fs.h>
28 #include <linux/stat.h>
29 #include <net/llc_frame.h>
32 int llc_decode_frametype(frameptr fr)
35 { /* unnumbered cmd/rsp */
36 switch(fr->u_mm.mm & 0x3B)
72 else if (IS_SFRAME(fr))
73 { /* supervisory cmd/rsp */
99 { /* information xfer */
109 * Validate_seq_nos will check N(S) and N(R) to see if they are
110 * invalid or unexpected.
111 * "unexpected" is explained on p44 Send State Variable.
112 * The return value is:
115 * 1 * unexpected N(S)
118 int llc_validate_seq_nos(llcptr lp, frameptr fr)
123 * A U-frame is always good
130 * For S- and I-frames check N(R):
133 if (fr->i_hdr.nr == lp->vs)
134 { /* if N(R) = V(S) */
135 res = 0; /* N(R) is good */
138 { /* lp->k = transmit window size */
140 { /* if window not wrapped around 127 */
141 if ((fr->i_hdr.nr < lp->vs) &&
142 (fr->i_hdr.nr > (lp->vs - lp->k)))
145 res = 4; /* N(R) invalid */
148 { /* window wraps around 127 */
149 if ((fr->i_hdr.nr < lp->vs) ||
150 (fr->i_hdr.nr > (128 + lp->vs - lp->k)))
153 res = 4; /* N(R) invalid */
158 * For an I-frame, must check N(S) also:
163 if (fr->i_hdr.ns == lp->vr)
164 return res; /* N(S) good */
165 if (lp->vr >= lp->rw)
167 /* if receive window not wrapped */
169 if ((fr->i_hdr.ns < lp->vr) &&
170 (fr->i_hdr.ns > (lp->vr - lp->k)))
171 res = res +1; /* N(S) unexpected */
173 res = res +2; /* N(S) invalid */
177 /* Window wraps around 127 */
179 if ((fr->i_hdr.ns < lp->vr) ||
180 (fr->i_hdr.ns > (128 + lp->vr - lp->k)))
181 res = res +1; /* N(S) unexpected */
183 res = res +2; /* N(S) invalid */
189 /* **************** timer management routines ********************* */
191 static void llc_p_timer_expired(unsigned long ulp)
193 llc_timer_expired((llcptr) ulp, P_TIMER);
196 static void llc_rej_timer_expired(unsigned long ulp)
198 llc_timer_expired((llcptr) ulp, REJ_TIMER);
201 static void llc_ack_timer_expired(unsigned long ulp)
203 llc_timer_expired((llcptr) ulp, ACK_TIMER);
206 static void llc_busy_timer_expired(unsigned long ulp)
208 llc_timer_expired((llcptr) ulp, BUSY_TIMER);
211 /* exp_fcn is an array holding the 4 entry points of the
212 timer expiry routines above.
213 It is required to keep start_timer() generic.
217 static void (* exp_fcn[])(unsigned long) =
220 llc_rej_timer_expired,
221 llc_ack_timer_expired,
222 llc_busy_timer_expired
225 void llc_start_timer(llcptr lp, int t)
227 if (lp->timer_state[t] == TIMER_IDLE)
229 lp->tl[t].expires = jiffies + lp->timer_interval[t];
230 lp->tl[t].data = (unsigned long) lp;
231 lp->tl[t].function = exp_fcn[t];
232 add_timer(&lp->tl[t]);
233 lp->timer_state[t] = TIMER_RUNNING;
237 void llc_stop_timer(llcptr lp, int t)
239 if (lp->timer_state[t] == TIMER_RUNNING)
241 del_timer(&lp->tl[t]);
242 lp->timer_state[t] = TIMER_IDLE;
246 void llc_cancel_timers(llcptr lp)
248 llc_stop_timer(lp, P_TIMER);
249 llc_stop_timer(lp, REJ_TIMER);
250 llc_stop_timer(lp, ACK_TIMER);
251 llc_stop_timer(lp, BUSY_TIMER);