Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / net / 802 / llc_sendpdu.c
blobf0c6d116ee64a1813af441423acb97debe279cc8
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.
6 * llc_sendpdu(), llc_sendipdu(), resend() + queue handling code
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.
15 * Changes
16 * Alan Cox : Chainsawed into Linux format, style
17 * Added llc_ to function names
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/malloc.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>
31 static unsigned char cntl_byte_encode[] =
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 */
54 static unsigned char fr_length_encode[] =
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 */
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 */
100 * Sendpdu() constructs an output frame in a new skb and
101 * gives it to the MAC layer for transmision.
102 * This function is not used to send I pdus.
103 * No queues are updated here, nothing is saved for retransmission.
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.
111 void llc_sendpdu(llcptr lp, char type, char pf, int data_len, char *pdu_data)
113 frameptr fr; /* ptr to output pdu buffer */
114 unsigned short int fl; /* frame length == 802.3 "length" value */
115 struct sk_buff *skb;
117 fl = data_len + fr_length_encode[(int)type];
118 skb = alloc_skb(16 + fl, GFP_ATOMIC);
119 if (skb != NULL)
121 skb->dev = lp->dev;
122 skb_reserve(skb, 16);
123 fr = (frameptr) skb_put(skb, fl);
124 memset(fr, 0, fl);
126 * Construct 802.2 header
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];
135 * Fill in pflag and seq nbrs:
137 if (IS_SFRAME(fr))
139 /* case S-frames */
140 if (pf & 0x01)
141 fr->i_hdr.i_pflag = 1;
142 fr->i_hdr.nr = lp->vr;
144 else
146 /* case U frames */
147 if (pf & 0x01)
148 fr->u_hdr.u_pflag = 1;
151 if (data_len > 0)
152 { /* append data if any */
153 if (IS_UFRAME(fr))
155 memcpy(fr->u_hdr.u_info, pdu_data, data_len);
157 else
159 memcpy(fr->i_hdr.is_info, pdu_data, data_len);
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);
167 else
168 printk(KERN_DEBUG "cl2llc: skb_alloc() in llc_sendpdu() failed\n");
171 void llc_xid_request(llcptr lp, char opt, int ll, char * data)
173 llc_sendpdu(lp, XID_CMD, opt, ll, data);
176 void llc_test_request(llcptr lp, int ll, char * data)
178 llc_sendpdu(lp, TEST_CMD, 0, ll, data);
181 void llc_unit_data_request(llcptr lp, int ll, char * data)
183 llc_sendpdu(lp, UI_CMD, 0, ll, data);
188 * llc_sendipdu() Completes an I pdu in an existing skb and gives it
189 * to the MAC layer for transmision.
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.
195 void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb)
197 frameptr fr; /* ptr to output pdu buffer */
198 struct sk_buff *tmp;
200 fr = (frameptr) skb->data;
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];
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)
219 tmp->dev=lp->dev;
220 dev_queue_xmit(tmp);
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
234 int llc_resend_ipdu(llcptr lp, unsigned char ack_nr, unsigned char type, char p)
236 struct sk_buff *skb,*tmp;
237 int resend_count;
238 frameptr fr;
239 unsigned long flags;
242 resend_count = 0;
244 save_flags(flags);
245 cli();
247 skb = skb_peek(&lp->rtq);
249 while(skb && skb != (struct sk_buff *)&lp->rtq)
251 fr = (frameptr) (skb->data + lp->dev->hard_header_len);
252 if (resend_count == 0)
255 * Resending 1st pdu:
258 if (p)
259 fr->i_hdr.i_pflag = 1;
260 else
261 fr->i_hdr.i_pflag = 0;
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;
268 else
271 * Resending pdu 2...n
274 fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
275 fr->i_hdr.i_pflag = 0;
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)
285 tmp->dev = lp->dev;
286 dev_queue_xmit(skb);
288 resend_count++;
289 skb = skb->next;
291 restore_flags(flags);
292 return resend_count;
295 /* ************** internal queue management code ****************** */
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.
304 struct sk_buff *llc_pull_from_atq(llcptr lp)
306 return skb_dequeue(&lp->atq);
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.
315 int llc_free_acknowledged_skbs(llcptr lp, unsigned char pdu_ack)
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;
324 if (pdu_ack > 0)
325 ack = pdu_ack -1;
326 else
327 ack = 127;
329 ack_count = 0;
331 save_flags(flags);
332 cli();
334 pp = skb_dequeue(&lp->rtq);
335 while (pp != NULL)
338 * Locate skb with N(S) == ack
342 * BUG: FIXME - use skb->h.*
344 fr = (frameptr) (pp->data + lp->dev->hard_header_len);
345 ns_save = fr->i_hdr.ns;
347 kfree_skb(pp);
348 ack_count++;
350 if (ns_save == ack)
351 break;
352 pp = skb_dequeue(&lp->rtq);
354 restore_flags(flags);
355 return ack_count;