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/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>
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 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 */
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 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 */
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
);