include upstream ip1000a driver version 2.09f
[linux-2.4.git] / net / 802 / llc_utility.c
1 /*
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.
5  *
6  *              Small utilities, Linux timer handling.
7  *
8  *              Written by Tim Alpaerts, Tim_Alpaerts@toyota-motor-europe.com
9  *
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.
14  *
15  *      Changes
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
20  *                                              down an llc
21  */
22
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>
30 #include <net/llc.h>
31
32 int llc_decode_frametype(frameptr fr)
33 {
34         if (IS_UFRAME(fr)) 
35         {      /* unnumbered cmd/rsp */
36                 switch(fr->u_mm.mm & 0x3B)
37                 {
38                         case 0x1B:
39                             return(SABME_CMD);
40                             break;
41                         case 0x10:
42                             return(DISC_CMD);
43                             break;
44                         case 0x18:
45                             return(UA_RSP);
46                             break;
47                         case 0x03:
48                             return(DM_RSP);
49                             break;
50                         case 0x21:
51                             return(FRMR_RSP);
52                             break;
53                         case 0x00:
54                             return(UI_CMD);
55                             break;
56                         case 0x2B:
57                             if (IS_RSP(fr)) 
58                                 return(XID_RSP);
59                             else
60                                 return(XID_CMD);
61                             break;
62                         case 0x38:
63                             if (IS_RSP(fr))
64                                 return(TEST_RSP);
65                             else
66                                 return(TEST_CMD);
67                             break;
68                         default:
69                             return(BAD_FRAME);
70                 }
71         }
72         else if (IS_SFRAME(fr))
73         {  /* supervisory cmd/rsp */
74                 switch(fr->s_hdr.ss)
75                 {
76                         case 0x00:
77                             if (IS_RSP(fr)) 
78                                 return(RR_RSP);
79                             else
80                                 return(RR_CMD);
81                             break;
82                         case 0x02:
83                             if (IS_RSP(fr))
84                                 return(REJ_RSP);
85                             else
86                                 return(REJ_CMD);
87                             break;
88                         case 0x01:
89                             if (IS_RSP(fr))
90                                 return(RNR_RSP);
91                             else
92                                 return(RNR_CMD);
93                             break;
94                         default:
95                             return(BAD_FRAME);
96                 }
97         }
98         else
99         {                         /* information xfer */
100                 if (IS_RSP(fr)) 
101                         return(I_RSP);
102                 else    
103                         return(I_CMD);
104         }
105 }
106
107
108 /*
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:
113  *              4 * invalid N(R) +
114  *              2 * invalid N(S) +
115  *              1 * unexpected N(S)
116  */
117
118 int llc_validate_seq_nos(llcptr lp, frameptr fr)
119 {
120         int res;
121      
122         /*
123          *      A U-frame is always good 
124          */
125
126         if (IS_UFRAME(fr)) 
127                 return(0);      
128
129         /*
130          *      For S- and I-frames check N(R): 
131          */
132
133         if (fr->i_hdr.nr == lp->vs) 
134         {       /* if N(R) = V(S)  */
135                 res = 0;                        /* N(R) is good */
136         }
137         else
138         {                               /* lp->k = transmit window size */
139                 if (lp->vs >= lp->k) 
140                 {       /* if window not wrapped around 127 */
141                         if ((fr->i_hdr.nr < lp->vs) &&
142                                 (fr->i_hdr.nr > (lp->vs - lp->k)))
143                                 res = 0;
144                         else 
145                                 res = 4;                /* N(R) invalid */
146                 }
147                 else
148                 {       /* window wraps around 127 */
149                         if ((fr->i_hdr.nr < lp->vs) ||
150                                 (fr->i_hdr.nr > (128 + lp->vs - lp->k))) 
151                                 res = 0;
152                         else
153                                 res = 4;                /* N(R) invalid */
154                 }
155         }
156
157         /*
158          *      For an I-frame, must check N(S) also:  
159          */
160
161         if (IS_IFRAME(fr)) 
162         {
163                 if (fr->i_hdr.ns == lp->vr) 
164                         return res;   /* N(S) good */
165                 if (lp->vr >= lp->rw) 
166                 {
167                         /* if receive window not wrapped */
168
169                         if ((fr->i_hdr.ns < lp->vr) &&
170                                 (fr->i_hdr.ns > (lp->vr - lp->k)))
171                                 res = res +1;           /* N(S) unexpected */
172                         else  
173                                 res = res +2;         /* N(S) invalid */            
174                 }
175                 else
176                 {
177                         /* Window wraps around 127 */
178
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 */
182                         else
183                                 res = res +2;         /* N(S) invalid */            
184                 }
185         }                                       
186         return(res);
187 }
188
189 /* **************** timer management routines ********************* */
190
191 static void llc_p_timer_expired(unsigned long ulp)
192 {
193         llc_timer_expired((llcptr) ulp, P_TIMER);
194 }
195
196 static void llc_rej_timer_expired(unsigned long ulp)
197 {
198         llc_timer_expired((llcptr) ulp, REJ_TIMER);
199 }
200
201 static void llc_ack_timer_expired(unsigned long ulp)
202 {
203         llc_timer_expired((llcptr) ulp, ACK_TIMER);
204
205
206 static void llc_busy_timer_expired(unsigned long ulp)
207 {
208         llc_timer_expired((llcptr) ulp, BUSY_TIMER);
209 }
210
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.
214    Thank you cdecl.
215  */
216
217 static void (* exp_fcn[])(unsigned long) = 
218 {
219         llc_p_timer_expired,
220         llc_rej_timer_expired,
221         llc_ack_timer_expired,
222         llc_busy_timer_expired
223 };   
224
225 void llc_start_timer(llcptr lp, int t)
226 {
227         if (lp->timer_state[t] == TIMER_IDLE)
228         {
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;
234         }
235 }
236
237 void llc_stop_timer(llcptr lp, int t)
238 {
239         if (lp->timer_state[t] == TIMER_RUNNING)
240         {
241                 del_timer(&lp->tl[t]);
242                 lp->timer_state[t] = TIMER_IDLE;
243         }
244 }
245
246 void llc_cancel_timers(llcptr lp)
247 {
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);
252 }
253