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.
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/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>
31 static unsigned char cntl_byte_encode[] =
54 static unsigned char fr_length_encode[] =
77 static unsigned char cr_bit_encode[] = {
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.
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 */
117 fl = data_len + fr_length_encode[(int)type];
118 skb = alloc_skb(16 + fl, GFP_ATOMIC);
122 skb_reserve(skb, 16);
123 fr = (frameptr) skb_put(skb, fl);
126 * Construct 802.2 header
129 fr->pdu_hdr.dsap = 0;
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:
141 fr->i_hdr.i_pflag = 1;
142 fr->i_hdr.nr = lp->vr;
148 fr->u_hdr.u_pflag = 1;
152 { /* append data if any */
155 memcpy(fr->u_hdr.u_info, pdu_data, data_len);
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);
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 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.
195 void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb)
197 frameptr fr; /* ptr to output pdu buffer */
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];
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;
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);
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;
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)
259 fr->i_hdr.i_pflag = 1;
261 fr->i_hdr.i_pflag = 0;
264 fr->pdu_hdr.ssap = fr->pdu_hdr.ssap & 0xfe;
266 fr->pdu_hdr.ssap = fr->pdu_hdr.ssap | 0x01;
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;
282 tmp=skb_clone(skb, GFP_ATOMIC);
291 restore_flags(flags);
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
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)
320 unsigned char ack; /* N(S) of most recently ack'ed pdu */
321 unsigned char ns_save;
334 pp = skb_dequeue(&lp->rtq);
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;
352 pp = skb_dequeue(&lp->rtq);
354 restore_flags(flags);