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 
llc_sendpdu(llcptr lp,char type,char pf,int data_len,char * pdu_data)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 
llc_xid_request(llcptr lp,char opt,int ll,char * data)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 
llc_test_request(llcptr lp,int ll,char * data)176 void llc_test_request(llcptr lp, int ll, char * data)
177 {
178 	llc_sendpdu(lp, TEST_CMD, 0, ll, data);
179 }
180 
llc_unit_data_request(llcptr lp,int ll,char * data)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 
llc_sendipdu(llcptr lp,char type,char pf,struct sk_buff * skb)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 
llc_resend_ipdu(llcptr lp,unsigned char ack_nr,unsigned char type,char p)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 
llc_pull_from_atq(llcptr lp)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 
llc_free_acknowledged_skbs(llcptr lp,unsigned char pdu_ack)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 
358