import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / net / 802 / llc_sendpdu.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  *              llc_sendpdu(), llc_sendipdu(), resend() + queue handling code
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 format, style
17  *                                      Added llc_ to function names
18  */
19
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/slab.h>
23 #include <linux/netdevice.h>
24 #include <linux/skbuff.h>
25 #include <net/p8022.h>
26 #include <linux/stat.h>
27 #include <asm/byteorder.h>
28 #include <net/llc_frame.h>
29 #include <net/llc.h>
30
31 static unsigned char cntl_byte_encode[] = 
32 {
33         0x00,   /* I_CMD */
34         0x01,   /* RR_CMD */
35         0x05,   /* RNR_CMD */
36         0x09,   /* REJ_CMD */
37         0x43,   /* DISC_CMD */
38         0x7F,   /* SABME_CMD */
39         0x00,   /* I_RSP */
40         0x01,   /* RR_RSP */
41         0x05,   /* RNR_RSP */
42         0x09,   /* REJ_RSP */
43         0x63,   /* UA_RSP */
44         0x0F,   /* DM_RSP */
45         0x87,   /* FRMR_RSP */
46         0xFF,   /* BAD_FRAME */
47         0x03,   /* UI_CMD */
48         0xBF,   /* XID_CMD */
49         0xE3,   /* TEST_CMD */
50         0xBF,   /* XID_RSP */
51         0xE3    /* TEST_RSP */
52 };
53
54 static unsigned char fr_length_encode[] = 
55 {
56         0x04,   /* I_CMD */
57         0x04,   /* RR_CMD */
58         0x04,   /* RNR_CMD */
59         0x04,   /* REJ_CMD */
60         0x03,   /* DISC_CMD */
61         0x03,   /* SABME_CMD */
62         0x04,   /* I_RSP */
63         0x04,   /* RR_RSP */
64         0x04,   /* RNR_RSP */
65         0x04,   /* REJ_RSP */
66         0x03,   /* UA_RSP */
67         0x03,   /* DM_RSP */
68         0x03,   /* FRMR_RSP */
69         0x00,   /* BAD_FRAME */
70         0x03,   /* UI_CMD */
71         0x03,   /* XID_CMD */
72         0x03,   /* TEST_CMD */
73         0x03,   /* XID_RSP */
74         0x03    /* TEST_RSP */
75 };
76
77 static unsigned char cr_bit_encode[] = {
78         0x00,   /* I_CMD */
79         0x00,   /* RR_CMD */
80         0x00,   /* RNR_CMD */
81         0x00,   /* REJ_CMD */
82         0x00,   /* DISC_CMD */
83         0x00,   /* SABME_CMD */
84         0x01,   /* I_RSP */
85         0x01,   /* RR_RSP */
86         0x01,   /* RNR_RSP */
87         0x01,   /* REJ_RSP */
88         0x01,   /* UA_RSP */
89         0x01,   /* DM_RSP */
90         0x01,   /* FRMR_RSP */
91         0x00,   /* BAD_FRAME */
92         0x00,   /* UI_CMD */
93         0x00,   /* XID_CMD */
94         0x00,   /* TEST_CMD */
95         0x01,   /* XID_RSP */
96         0x01    /* TEST_RSP */
97 };
98
99 /*
100  *      Sendpdu() constructs an output frame in a new skb and
101  *      gives it to the MAC layer for transmission.
102  *      This function is not used to send I pdus.
103  *      No queues are updated here, nothing is saved for retransmission.
104  *
105  *      Parameter pf controls both the poll/final bit and dsap
106  *      fields in the output pdu. 
107  *      The dsap trick was needed to implement XID_CMD send with
108  *      zero dsap field as described in doc 6.6 item 1 of enum.  
109  */
110
111 void llc_sendpdu(llcptr lp, char type, char pf, int data_len, char *pdu_data)
112 {
113         frameptr fr;                /* ptr to output pdu buffer */
114         unsigned short int fl;      /* frame length == 802.3 "length" value */
115         struct sk_buff *skb;
116
117         fl = data_len + fr_length_encode[(int)type];
118         skb = alloc_skb(16 + fl, GFP_ATOMIC); 
119         if (skb != NULL)
120         {
121                 skb->dev = lp->dev;     
122                 skb_reserve(skb, 16);
123                 fr = (frameptr) skb_put(skb, fl);
124                 memset(fr, 0, fl);
125                 /*
126                  *      Construct 802.2 header 
127                  */
128                 if (pf & 0x02) 
129                         fr->pdu_hdr.dsap = 0;
130                 else
131                         fr->pdu_hdr.dsap = lp->remote_sap;
132                 fr->pdu_hdr.ssap = lp->local_sap + cr_bit_encode[(int)type];
133                 fr->pdu_cntl.byte1 = cntl_byte_encode[(int)type];
134                 /* 
135                  *      Fill in pflag and seq nbrs: 
136                  */
137                 if (IS_SFRAME(fr)) 
138                 {
139                         /* case S-frames */
140                         if (pf & 0x01) 
141                                 fr->i_hdr.i_pflag = 1;
142                         fr->i_hdr.nr = lp->vr;
143                 }
144                 else
145                 {
146                         /* case U frames */ 
147                         if (pf & 0x01) 
148                                 fr->u_hdr.u_pflag = 1;
149                 }
150                        
151                 if (data_len > 0) 
152                 {                       /* append data if any  */ 
153                         if (IS_UFRAME(fr)) 
154                         {
155                                 memcpy(fr->u_hdr.u_info, pdu_data, data_len);
156                         }
157                         else 
158                         {
159                                 memcpy(fr->i_hdr.is_info, pdu_data, data_len);
160                         }
161                 }
162                 lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
163                          lp->remote_mac, NULL, fl);
164                 skb->dev=lp->dev;
165                 dev_queue_xmit(skb);
166         }
167         else
168                 printk(KERN_DEBUG "cl2llc: skb_alloc() in llc_sendpdu() failed\n");     
169 }
170
171 void llc_xid_request(llcptr lp, char opt, int ll, char * data)
172 {
173         llc_sendpdu(lp, XID_CMD, opt, ll, data); 
174 }
175
176 void llc_test_request(llcptr lp, int ll, char * data)
177 {
178         llc_sendpdu(lp, TEST_CMD, 0, ll, data); 
179 }
180
181 void llc_unit_data_request(llcptr lp, int ll, char * data)
182 {
183         llc_sendpdu(lp, UI_CMD, 0, ll, data); 
184 }
185
186
187 /*
188  *      llc_sendipdu() Completes an I pdu in an existing skb and gives it
189  *      to the MAC layer for transmission.
190  *      Parameter "type" must be either I_CMD or I_RSP.
191  *      The skb is not freed after xmit, it is kept in case a retransmission
192  *      is requested. If needed it can be picked up again from the rtq.
193  */
194
195 void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb)
196 {
197         frameptr fr;                /* ptr to output pdu buffer */
198         struct sk_buff *tmp;
199         
200         fr = (frameptr) skb->data;
201
202         fr->pdu_hdr.dsap = lp->remote_sap;
203         fr->pdu_hdr.ssap = lp->local_sap + cr_bit_encode[(int)type];
204         fr->pdu_cntl.byte1 = cntl_byte_encode[(int)type];
205                         
206         if (pf)
207                 fr->i_hdr.i_pflag = 1; /* p/f and seq numbers */  
208         fr->i_hdr.nr = lp->vr;
209         fr->i_hdr.ns = lp->vs;
210         lp->vs++;
211         if (lp->vs > 127) 
212                 lp->vs = 0;
213         lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
214                 lp->remote_mac, NULL, skb->len);
215         ADD_TO_RTQ(skb);                /* add skb to the retransmit queue */
216         tmp=skb_clone(skb, GFP_ATOMIC);
217         if(tmp!=NULL)
218         {
219                 tmp->dev=lp->dev;
220                 dev_queue_xmit(tmp);
221         }
222 }
223
224
225 /*
226  *      Resend_ipdu() will resend the pdus in the retransmit queue (rtq)
227  *      the return value is the number of pdus resend.
228  *      ack_nr is N(R) of 1st pdu to resent.
229  *      Type is I_CMD or I_RSP for 1st pdu resent.
230  *      p is p/f flag 0 or 1 for 1st pdu resent.
231  *      All subsequent pdus will be sent as I_CMDs with p/f set to 0
232  */ 
233
234 int llc_resend_ipdu(llcptr lp, unsigned char ack_nr, unsigned char type, char p)
235 {
236         struct sk_buff *skb,*tmp;
237         int resend_count;
238         frameptr fr;
239         unsigned long flags;
240         
241
242         resend_count = 0;
243         
244         save_flags(flags);
245         cli();
246         
247         skb = skb_peek(&lp->rtq);
248
249         while(skb && skb != (struct sk_buff *)&lp->rtq)
250         {
251                 fr = (frameptr) (skb->data + lp->dev->hard_header_len);
252                 if (resend_count == 0) 
253                 {
254                         /* 
255                          *      Resending 1st pdu: 
256                          */
257
258                         if (p) 
259                                 fr->i_hdr.i_pflag = 1;
260                         else
261                                 fr->i_hdr.i_pflag = 0;
262             
263                         if (type == I_CMD)           
264                                 fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
265                         else
266                                 fr->pdu_hdr.ssap = fr->pdu_hdr.ssap | 0x01;
267                 }
268                 else
269                 {
270                         /*
271                          *      Resending pdu 2...n 
272                          */
273
274                         fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
275                         fr->i_hdr.i_pflag = 0;
276                 }
277                 fr->i_hdr.nr = lp->vr;
278                 fr->i_hdr.ns = lp->vs;
279                 lp->vs++;
280                 if (lp->vs > 127) 
281                         lp->vs = 0;
282                 tmp=skb_clone(skb, GFP_ATOMIC);
283                 if(tmp!=NULL)
284                 {
285                         tmp->dev = lp->dev;
286                         dev_queue_xmit(tmp);
287                 }
288                 resend_count++;
289                 skb = skb->next;
290         }
291         restore_flags(flags);
292         return resend_count;
293 }
294
295 /* ************** internal queue management code ****************** */
296
297
298 /*
299  *      Remove one skb from the front of the awaiting transmit queue
300  *      (this is the skb longest on the queue) and return a pointer to 
301  *      that skb. 
302  */ 
303
304 struct sk_buff *llc_pull_from_atq(llcptr lp) 
305 {
306         return skb_dequeue(&lp->atq);
307 }
308  
309 /*
310  *      Free_acknowledged_skbs(), remove from retransmit queue (rtq)
311  *      and free all skbs with an N(S) chronologicaly before 'pdu_ack'.
312  *      The return value is the number of pdus acknowledged.
313  */
314  
315 int llc_free_acknowledged_skbs(llcptr lp, unsigned char pdu_ack)
316 {
317         struct sk_buff *pp;
318         frameptr fr; 
319         int ack_count;
320         unsigned char ack;      /* N(S) of most recently ack'ed pdu */
321         unsigned char ns_save; 
322         unsigned long flags;
323
324         if (pdu_ack > 0) 
325                 ack = pdu_ack -1;
326         else 
327                 ack = 127;
328
329         ack_count = 0;
330
331         save_flags(flags);
332         cli();
333
334         pp = skb_dequeue(&lp->rtq); 
335         while (pp != NULL)
336         {
337                 /* 
338                  *      Locate skb with N(S) == ack 
339                  */
340
341                 /*
342                  *      BUG: FIXME - use skb->h.*
343                  */
344                 fr = (frameptr) (pp->data + lp->dev->hard_header_len);
345                 ns_save = fr->i_hdr.ns;
346
347                 kfree_skb(pp);
348                 ack_count++;
349
350                 if (ns_save == ack) 
351                         break;  
352                 pp = skb_dequeue(&lp->rtq);
353         }
354         restore_flags(flags);
355         return ack_count; 
356 }
357