diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/irda/irlap_frame.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/irda/irlap_frame.c')
-rw-r--r-- | net/irda/irlap_frame.c | 1437 |
1 files changed, 1437 insertions, 0 deletions
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c new file mode 100644 index 000000000000..040abe714aa3 --- /dev/null +++ b/net/irda/irlap_frame.c | |||
@@ -0,0 +1,1437 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlap_frame.c | ||
4 | * Version: 1.0 | ||
5 | * Description: Build and transmit IrLAP frames | ||
6 | * Status: Stable | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Tue Aug 19 10:27:26 1997 | ||
9 | * Modified at: Wed Jan 5 08:59:04 2000 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * | ||
12 | * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, | ||
13 | * All Rights Reserved. | ||
14 | * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License as | ||
18 | * published by the Free Software Foundation; either version 2 of | ||
19 | * the License, or (at your option) any later version. | ||
20 | * | ||
21 | * Neither Dag Brattli nor University of Troms� admit liability nor | ||
22 | * provide warranty for any of this software. This material is | ||
23 | * provided "AS-IS" and at no charge. | ||
24 | * | ||
25 | ********************************************************************/ | ||
26 | |||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/if.h> | ||
29 | #include <linux/if_ether.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/irda.h> | ||
32 | |||
33 | #include <net/pkt_sched.h> | ||
34 | #include <net/sock.h> | ||
35 | |||
36 | #include <asm/byteorder.h> | ||
37 | |||
38 | #include <net/irda/irda.h> | ||
39 | #include <net/irda/irda_device.h> | ||
40 | #include <net/irda/irlap.h> | ||
41 | #include <net/irda/wrapper.h> | ||
42 | #include <net/irda/timer.h> | ||
43 | #include <net/irda/irlap_frame.h> | ||
44 | #include <net/irda/qos.h> | ||
45 | |||
46 | static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
47 | int command); | ||
48 | |||
49 | /* | ||
50 | * Function irlap_insert_info (self, skb) | ||
51 | * | ||
52 | * Insert minimum turnaround time and speed information into the skb. We | ||
53 | * need to do this since it's per packet relevant information. Safe to | ||
54 | * have this function inlined since it's only called from one place | ||
55 | */ | ||
56 | static inline void irlap_insert_info(struct irlap_cb *self, | ||
57 | struct sk_buff *skb) | ||
58 | { | ||
59 | struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; | ||
60 | |||
61 | /* | ||
62 | * Insert MTT (min. turn time) and speed into skb, so that the | ||
63 | * device driver knows which settings to use | ||
64 | */ | ||
65 | cb->magic = LAP_MAGIC; | ||
66 | cb->mtt = self->mtt_required; | ||
67 | cb->next_speed = self->speed; | ||
68 | |||
69 | /* Reset */ | ||
70 | self->mtt_required = 0; | ||
71 | |||
72 | /* | ||
73 | * Delay equals negotiated BOFs count, plus the number of BOFs to | ||
74 | * force the negotiated minimum turnaround time | ||
75 | */ | ||
76 | cb->xbofs = self->bofs_count; | ||
77 | cb->next_xbofs = self->next_bofs; | ||
78 | cb->xbofs_delay = self->xbofs_delay; | ||
79 | |||
80 | /* Reset XBOF's delay (used only for getting min turn time) */ | ||
81 | self->xbofs_delay = 0; | ||
82 | /* Put the correct xbofs value for the next packet */ | ||
83 | self->bofs_count = self->next_bofs; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Function irlap_queue_xmit (self, skb) | ||
88 | * | ||
89 | * A little wrapper for dev_queue_xmit, so we can insert some common | ||
90 | * code into it. | ||
91 | */ | ||
92 | void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) | ||
93 | { | ||
94 | /* Some common init stuff */ | ||
95 | skb->dev = self->netdev; | ||
96 | skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data; | ||
97 | skb->protocol = htons(ETH_P_IRDA); | ||
98 | skb->priority = TC_PRIO_BESTEFFORT; | ||
99 | |||
100 | irlap_insert_info(self, skb); | ||
101 | |||
102 | dev_queue_xmit(skb); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Function irlap_send_snrm_cmd (void) | ||
107 | * | ||
108 | * Transmits a connect SNRM command frame | ||
109 | */ | ||
110 | void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) | ||
111 | { | ||
112 | struct sk_buff *tx_skb; | ||
113 | struct snrm_frame *frame; | ||
114 | int ret; | ||
115 | |||
116 | IRDA_ASSERT(self != NULL, return;); | ||
117 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
118 | |||
119 | /* Allocate frame */ | ||
120 | tx_skb = dev_alloc_skb(64); | ||
121 | if (!tx_skb) | ||
122 | return; | ||
123 | |||
124 | frame = (struct snrm_frame *) skb_put(tx_skb, 2); | ||
125 | |||
126 | /* Insert connection address field */ | ||
127 | if (qos) | ||
128 | frame->caddr = CMD_FRAME | CBROADCAST; | ||
129 | else | ||
130 | frame->caddr = CMD_FRAME | self->caddr; | ||
131 | |||
132 | /* Insert control field */ | ||
133 | frame->control = SNRM_CMD | PF_BIT; | ||
134 | |||
135 | /* | ||
136 | * If we are establishing a connection then insert QoS paramerters | ||
137 | */ | ||
138 | if (qos) { | ||
139 | skb_put(tx_skb, 9); /* 21 left */ | ||
140 | frame->saddr = cpu_to_le32(self->saddr); | ||
141 | frame->daddr = cpu_to_le32(self->daddr); | ||
142 | |||
143 | frame->ncaddr = self->caddr; | ||
144 | |||
145 | ret = irlap_insert_qos_negotiation_params(self, tx_skb); | ||
146 | if (ret < 0) { | ||
147 | dev_kfree_skb(tx_skb); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
151 | irlap_queue_xmit(self, tx_skb); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Function irlap_recv_snrm_cmd (skb, info) | ||
156 | * | ||
157 | * Received SNRM (Set Normal Response Mode) command frame | ||
158 | * | ||
159 | */ | ||
160 | static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, | ||
161 | struct irlap_info *info) | ||
162 | { | ||
163 | struct snrm_frame *frame; | ||
164 | |||
165 | if (pskb_may_pull(skb,sizeof(struct snrm_frame))) { | ||
166 | frame = (struct snrm_frame *) skb->data; | ||
167 | |||
168 | /* Copy the new connection address ignoring the C/R bit */ | ||
169 | info->caddr = frame->ncaddr & 0xFE; | ||
170 | |||
171 | /* Check if the new connection address is valid */ | ||
172 | if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { | ||
173 | IRDA_DEBUG(3, "%s(), invalid connection address!\n", | ||
174 | __FUNCTION__); | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | /* Copy peer device address */ | ||
179 | info->daddr = le32_to_cpu(frame->saddr); | ||
180 | info->saddr = le32_to_cpu(frame->daddr); | ||
181 | |||
182 | /* Only accept if addressed directly to us */ | ||
183 | if (info->saddr != self->saddr) { | ||
184 | IRDA_DEBUG(2, "%s(), not addressed to us!\n", | ||
185 | __FUNCTION__); | ||
186 | return; | ||
187 | } | ||
188 | irlap_do_event(self, RECV_SNRM_CMD, skb, info); | ||
189 | } else { | ||
190 | /* Signal that this SNRM frame does not contain and I-field */ | ||
191 | irlap_do_event(self, RECV_SNRM_CMD, skb, NULL); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Function irlap_send_ua_response_frame (qos) | ||
197 | * | ||
198 | * Send UA (Unnumbered Acknowledgement) frame | ||
199 | * | ||
200 | */ | ||
201 | void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) | ||
202 | { | ||
203 | struct sk_buff *tx_skb; | ||
204 | struct ua_frame *frame; | ||
205 | int ret; | ||
206 | |||
207 | IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies); | ||
208 | |||
209 | IRDA_ASSERT(self != NULL, return;); | ||
210 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
211 | |||
212 | /* Allocate frame */ | ||
213 | tx_skb = dev_alloc_skb(64); | ||
214 | if (!tx_skb) | ||
215 | return; | ||
216 | |||
217 | frame = (struct ua_frame *) skb_put(tx_skb, 10); | ||
218 | |||
219 | /* Build UA response */ | ||
220 | frame->caddr = self->caddr; | ||
221 | frame->control = UA_RSP | PF_BIT; | ||
222 | |||
223 | frame->saddr = cpu_to_le32(self->saddr); | ||
224 | frame->daddr = cpu_to_le32(self->daddr); | ||
225 | |||
226 | /* Should we send QoS negotiation parameters? */ | ||
227 | if (qos) { | ||
228 | ret = irlap_insert_qos_negotiation_params(self, tx_skb); | ||
229 | if (ret < 0) { | ||
230 | dev_kfree_skb(tx_skb); | ||
231 | return; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | irlap_queue_xmit(self, tx_skb); | ||
236 | } | ||
237 | |||
238 | |||
239 | /* | ||
240 | * Function irlap_send_dm_frame (void) | ||
241 | * | ||
242 | * Send disconnected mode (DM) frame | ||
243 | * | ||
244 | */ | ||
245 | void irlap_send_dm_frame( struct irlap_cb *self) | ||
246 | { | ||
247 | struct sk_buff *tx_skb = NULL; | ||
248 | __u8 *frame; | ||
249 | |||
250 | IRDA_ASSERT(self != NULL, return;); | ||
251 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
252 | |||
253 | tx_skb = dev_alloc_skb(32); | ||
254 | if (!tx_skb) | ||
255 | return; | ||
256 | |||
257 | frame = skb_put(tx_skb, 2); | ||
258 | |||
259 | if (self->state == LAP_NDM) | ||
260 | frame[0] = CBROADCAST; | ||
261 | else | ||
262 | frame[0] = self->caddr; | ||
263 | |||
264 | frame[1] = DM_RSP | PF_BIT; | ||
265 | |||
266 | irlap_queue_xmit(self, tx_skb); | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Function irlap_send_disc_frame (void) | ||
271 | * | ||
272 | * Send disconnect (DISC) frame | ||
273 | * | ||
274 | */ | ||
275 | void irlap_send_disc_frame(struct irlap_cb *self) | ||
276 | { | ||
277 | struct sk_buff *tx_skb = NULL; | ||
278 | __u8 *frame; | ||
279 | |||
280 | IRDA_DEBUG(3, "%s()\n", __FUNCTION__); | ||
281 | |||
282 | IRDA_ASSERT(self != NULL, return;); | ||
283 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
284 | |||
285 | tx_skb = dev_alloc_skb(16); | ||
286 | if (!tx_skb) | ||
287 | return; | ||
288 | |||
289 | frame = skb_put(tx_skb, 2); | ||
290 | |||
291 | frame[0] = self->caddr | CMD_FRAME; | ||
292 | frame[1] = DISC_CMD | PF_BIT; | ||
293 | |||
294 | irlap_queue_xmit(self, tx_skb); | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Function irlap_send_discovery_xid_frame (S, s, command) | ||
299 | * | ||
300 | * Build and transmit a XID (eXchange station IDentifier) discovery | ||
301 | * frame. | ||
302 | */ | ||
303 | void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, | ||
304 | __u8 command, discovery_t *discovery) | ||
305 | { | ||
306 | struct sk_buff *tx_skb = NULL; | ||
307 | struct xid_frame *frame; | ||
308 | __u32 bcast = BROADCAST; | ||
309 | __u8 *info; | ||
310 | |||
311 | IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, | ||
312 | s, S, command); | ||
313 | |||
314 | IRDA_ASSERT(self != NULL, return;); | ||
315 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
316 | IRDA_ASSERT(discovery != NULL, return;); | ||
317 | |||
318 | tx_skb = dev_alloc_skb(64); | ||
319 | if (!tx_skb) | ||
320 | return; | ||
321 | |||
322 | skb_put(tx_skb, 14); | ||
323 | frame = (struct xid_frame *) tx_skb->data; | ||
324 | |||
325 | if (command) { | ||
326 | frame->caddr = CBROADCAST | CMD_FRAME; | ||
327 | frame->control = XID_CMD | PF_BIT; | ||
328 | } else { | ||
329 | frame->caddr = CBROADCAST; | ||
330 | frame->control = XID_RSP | PF_BIT; | ||
331 | } | ||
332 | frame->ident = XID_FORMAT; | ||
333 | |||
334 | frame->saddr = cpu_to_le32(self->saddr); | ||
335 | |||
336 | if (command) | ||
337 | frame->daddr = cpu_to_le32(bcast); | ||
338 | else | ||
339 | frame->daddr = cpu_to_le32(discovery->data.daddr); | ||
340 | |||
341 | switch (S) { | ||
342 | case 1: | ||
343 | frame->flags = 0x00; | ||
344 | break; | ||
345 | case 6: | ||
346 | frame->flags = 0x01; | ||
347 | break; | ||
348 | case 8: | ||
349 | frame->flags = 0x02; | ||
350 | break; | ||
351 | case 16: | ||
352 | frame->flags = 0x03; | ||
353 | break; | ||
354 | default: | ||
355 | frame->flags = 0x02; | ||
356 | break; | ||
357 | } | ||
358 | |||
359 | frame->slotnr = s; | ||
360 | frame->version = 0x00; | ||
361 | |||
362 | /* | ||
363 | * Provide info for final slot only in commands, and for all | ||
364 | * responses. Send the second byte of the hint only if the | ||
365 | * EXTENSION bit is set in the first byte. | ||
366 | */ | ||
367 | if (!command || (frame->slotnr == 0xff)) { | ||
368 | int len; | ||
369 | |||
370 | if (discovery->data.hints[0] & HINT_EXTENSION) { | ||
371 | info = skb_put(tx_skb, 2); | ||
372 | info[0] = discovery->data.hints[0]; | ||
373 | info[1] = discovery->data.hints[1]; | ||
374 | } else { | ||
375 | info = skb_put(tx_skb, 1); | ||
376 | info[0] = discovery->data.hints[0]; | ||
377 | } | ||
378 | info = skb_put(tx_skb, 1); | ||
379 | info[0] = discovery->data.charset; | ||
380 | |||
381 | len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb)); | ||
382 | info = skb_put(tx_skb, len); | ||
383 | memcpy(info, discovery->data.info, len); | ||
384 | } | ||
385 | irlap_queue_xmit(self, tx_skb); | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Function irlap_recv_discovery_xid_rsp (skb, info) | ||
390 | * | ||
391 | * Received a XID discovery response | ||
392 | * | ||
393 | */ | ||
394 | static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, | ||
395 | struct sk_buff *skb, | ||
396 | struct irlap_info *info) | ||
397 | { | ||
398 | struct xid_frame *xid; | ||
399 | discovery_t *discovery = NULL; | ||
400 | __u8 *discovery_info; | ||
401 | char *text; | ||
402 | |||
403 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__); | ||
404 | |||
405 | IRDA_ASSERT(self != NULL, return;); | ||
406 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
407 | |||
408 | if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { | ||
409 | IRDA_ERROR("%s: frame to short!\n", __FUNCTION__); | ||
410 | return; | ||
411 | } | ||
412 | |||
413 | xid = (struct xid_frame *) skb->data; | ||
414 | |||
415 | info->daddr = le32_to_cpu(xid->saddr); | ||
416 | info->saddr = le32_to_cpu(xid->daddr); | ||
417 | |||
418 | /* Make sure frame is addressed to us */ | ||
419 | if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { | ||
420 | IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n", | ||
421 | __FUNCTION__); | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) { | ||
426 | IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__); | ||
427 | return; | ||
428 | } | ||
429 | memset(discovery, 0, sizeof(discovery_t)); | ||
430 | |||
431 | discovery->data.daddr = info->daddr; | ||
432 | discovery->data.saddr = self->saddr; | ||
433 | discovery->timestamp = jiffies; | ||
434 | |||
435 | IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__, | ||
436 | discovery->data.daddr); | ||
437 | |||
438 | discovery_info = skb_pull(skb, sizeof(struct xid_frame)); | ||
439 | |||
440 | /* Get info returned from peer */ | ||
441 | discovery->data.hints[0] = discovery_info[0]; | ||
442 | if (discovery_info[0] & HINT_EXTENSION) { | ||
443 | IRDA_DEBUG(4, "EXTENSION\n"); | ||
444 | discovery->data.hints[1] = discovery_info[1]; | ||
445 | discovery->data.charset = discovery_info[2]; | ||
446 | text = (char *) &discovery_info[3]; | ||
447 | } else { | ||
448 | discovery->data.hints[1] = 0; | ||
449 | discovery->data.charset = discovery_info[1]; | ||
450 | text = (char *) &discovery_info[2]; | ||
451 | } | ||
452 | /* | ||
453 | * Terminate info string, should be safe since this is where the | ||
454 | * FCS bytes resides. | ||
455 | */ | ||
456 | skb->data[skb->len] = '\0'; | ||
457 | strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); | ||
458 | discovery->name_len = strlen(discovery->data.info); | ||
459 | |||
460 | info->discovery = discovery; | ||
461 | |||
462 | irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Function irlap_recv_discovery_xid_cmd (skb, info) | ||
467 | * | ||
468 | * Received a XID discovery command | ||
469 | * | ||
470 | */ | ||
471 | static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, | ||
472 | struct sk_buff *skb, | ||
473 | struct irlap_info *info) | ||
474 | { | ||
475 | struct xid_frame *xid; | ||
476 | discovery_t *discovery = NULL; | ||
477 | __u8 *discovery_info; | ||
478 | char *text; | ||
479 | |||
480 | if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { | ||
481 | IRDA_ERROR("%s: frame to short!\n", __FUNCTION__); | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | xid = (struct xid_frame *) skb->data; | ||
486 | |||
487 | info->daddr = le32_to_cpu(xid->saddr); | ||
488 | info->saddr = le32_to_cpu(xid->daddr); | ||
489 | |||
490 | /* Make sure frame is addressed to us */ | ||
491 | if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { | ||
492 | IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n", | ||
493 | __FUNCTION__); | ||
494 | return; | ||
495 | } | ||
496 | |||
497 | switch (xid->flags & 0x03) { | ||
498 | case 0x00: | ||
499 | info->S = 1; | ||
500 | break; | ||
501 | case 0x01: | ||
502 | info->S = 6; | ||
503 | break; | ||
504 | case 0x02: | ||
505 | info->S = 8; | ||
506 | break; | ||
507 | case 0x03: | ||
508 | info->S = 16; | ||
509 | break; | ||
510 | default: | ||
511 | /* Error!! */ | ||
512 | return; | ||
513 | } | ||
514 | info->s = xid->slotnr; | ||
515 | |||
516 | discovery_info = skb_pull(skb, sizeof(struct xid_frame)); | ||
517 | |||
518 | /* | ||
519 | * Check if last frame | ||
520 | */ | ||
521 | if (info->s == 0xff) { | ||
522 | /* Check if things are sane at this point... */ | ||
523 | if((discovery_info == NULL) || | ||
524 | !pskb_may_pull(skb, 3)) { | ||
525 | IRDA_ERROR("%s: discovery frame to short!\n", | ||
526 | __FUNCTION__); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * We now have some discovery info to deliver! | ||
532 | */ | ||
533 | discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC); | ||
534 | if (!discovery) { | ||
535 | IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | discovery->data.daddr = info->daddr; | ||
540 | discovery->data.saddr = self->saddr; | ||
541 | discovery->timestamp = jiffies; | ||
542 | |||
543 | discovery->data.hints[0] = discovery_info[0]; | ||
544 | if (discovery_info[0] & HINT_EXTENSION) { | ||
545 | discovery->data.hints[1] = discovery_info[1]; | ||
546 | discovery->data.charset = discovery_info[2]; | ||
547 | text = (char *) &discovery_info[3]; | ||
548 | } else { | ||
549 | discovery->data.hints[1] = 0; | ||
550 | discovery->data.charset = discovery_info[1]; | ||
551 | text = (char *) &discovery_info[2]; | ||
552 | } | ||
553 | /* | ||
554 | * Terminate string, should be safe since this is where the | ||
555 | * FCS bytes resides. | ||
556 | */ | ||
557 | skb->data[skb->len] = '\0'; | ||
558 | strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); | ||
559 | discovery->name_len = strlen(discovery->data.info); | ||
560 | |||
561 | info->discovery = discovery; | ||
562 | } else | ||
563 | info->discovery = NULL; | ||
564 | |||
565 | irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info); | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * Function irlap_send_rr_frame (self, command) | ||
570 | * | ||
571 | * Build and transmit RR (Receive Ready) frame. Notice that it is currently | ||
572 | * only possible to send RR frames with the poll bit set. | ||
573 | */ | ||
574 | void irlap_send_rr_frame(struct irlap_cb *self, int command) | ||
575 | { | ||
576 | struct sk_buff *tx_skb; | ||
577 | __u8 *frame; | ||
578 | |||
579 | tx_skb = dev_alloc_skb(16); | ||
580 | if (!tx_skb) | ||
581 | return; | ||
582 | |||
583 | frame = skb_put(tx_skb, 2); | ||
584 | |||
585 | frame[0] = self->caddr; | ||
586 | frame[0] |= (command) ? CMD_FRAME : 0; | ||
587 | |||
588 | frame[1] = RR | PF_BIT | (self->vr << 5); | ||
589 | |||
590 | irlap_queue_xmit(self, tx_skb); | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * Function irlap_send_rd_frame (self) | ||
595 | * | ||
596 | * Request disconnect. Used by a secondary station to request the | ||
597 | * disconnection of the link. | ||
598 | */ | ||
599 | void irlap_send_rd_frame(struct irlap_cb *self) | ||
600 | { | ||
601 | struct sk_buff *tx_skb; | ||
602 | __u8 *frame; | ||
603 | |||
604 | tx_skb = dev_alloc_skb(16); | ||
605 | if (!tx_skb) | ||
606 | return; | ||
607 | |||
608 | frame = skb_put(tx_skb, 2); | ||
609 | |||
610 | frame[0] = self->caddr; | ||
611 | frame[1] = RD_RSP | PF_BIT; | ||
612 | |||
613 | irlap_queue_xmit(self, tx_skb); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Function irlap_recv_rr_frame (skb, info) | ||
618 | * | ||
619 | * Received RR (Receive Ready) frame from peer station, no harm in | ||
620 | * making it inline since its called only from one single place | ||
621 | * (irlap_driver_rcv). | ||
622 | */ | ||
623 | static inline void irlap_recv_rr_frame(struct irlap_cb *self, | ||
624 | struct sk_buff *skb, | ||
625 | struct irlap_info *info, int command) | ||
626 | { | ||
627 | info->nr = skb->data[1] >> 5; | ||
628 | |||
629 | /* Check if this is a command or a response frame */ | ||
630 | if (command) | ||
631 | irlap_do_event(self, RECV_RR_CMD, skb, info); | ||
632 | else | ||
633 | irlap_do_event(self, RECV_RR_RSP, skb, info); | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * Function irlap_recv_rnr_frame (self, skb, info) | ||
638 | * | ||
639 | * Received RNR (Receive Not Ready) frame from peer station | ||
640 | * | ||
641 | */ | ||
642 | static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
643 | struct irlap_info *info, int command) | ||
644 | { | ||
645 | info->nr = skb->data[1] >> 5; | ||
646 | |||
647 | IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __FUNCTION__, info->nr, jiffies); | ||
648 | |||
649 | if (command) | ||
650 | irlap_do_event(self, RECV_RNR_CMD, skb, info); | ||
651 | else | ||
652 | irlap_do_event(self, RECV_RNR_RSP, skb, info); | ||
653 | } | ||
654 | |||
655 | static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
656 | struct irlap_info *info, int command) | ||
657 | { | ||
658 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__); | ||
659 | |||
660 | info->nr = skb->data[1] >> 5; | ||
661 | |||
662 | /* Check if this is a command or a response frame */ | ||
663 | if (command) | ||
664 | irlap_do_event(self, RECV_REJ_CMD, skb, info); | ||
665 | else | ||
666 | irlap_do_event(self, RECV_REJ_RSP, skb, info); | ||
667 | } | ||
668 | |||
669 | static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
670 | struct irlap_info *info, int command) | ||
671 | { | ||
672 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__); | ||
673 | |||
674 | info->nr = skb->data[1] >> 5; | ||
675 | |||
676 | /* Check if this is a command or a response frame */ | ||
677 | if (command) | ||
678 | irlap_do_event(self, RECV_SREJ_CMD, skb, info); | ||
679 | else | ||
680 | irlap_do_event(self, RECV_SREJ_RSP, skb, info); | ||
681 | } | ||
682 | |||
683 | static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
684 | struct irlap_info *info, int command) | ||
685 | { | ||
686 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
687 | |||
688 | /* Check if this is a command or a response frame */ | ||
689 | if (command) | ||
690 | irlap_do_event(self, RECV_DISC_CMD, skb, info); | ||
691 | else | ||
692 | irlap_do_event(self, RECV_RD_RSP, skb, info); | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * Function irlap_recv_ua_frame (skb, frame) | ||
697 | * | ||
698 | * Received UA (Unnumbered Acknowledgement) frame | ||
699 | * | ||
700 | */ | ||
701 | static inline void irlap_recv_ua_frame(struct irlap_cb *self, | ||
702 | struct sk_buff *skb, | ||
703 | struct irlap_info *info) | ||
704 | { | ||
705 | irlap_do_event(self, RECV_UA_RSP, skb, info); | ||
706 | } | ||
707 | |||
708 | /* | ||
709 | * Function irlap_send_data_primary(self, skb) | ||
710 | * | ||
711 | * Send I-frames as the primary station but without the poll bit set | ||
712 | * | ||
713 | */ | ||
714 | void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) | ||
715 | { | ||
716 | struct sk_buff *tx_skb; | ||
717 | |||
718 | if (skb->data[1] == I_FRAME) { | ||
719 | |||
720 | /* | ||
721 | * Insert frame sequence number (Vs) in control field before | ||
722 | * inserting into transmit window queue. | ||
723 | */ | ||
724 | skb->data[1] = I_FRAME | (self->vs << 1); | ||
725 | |||
726 | /* | ||
727 | * Insert frame in store, in case of retransmissions | ||
728 | * Increase skb reference count, see irlap_do_event() | ||
729 | */ | ||
730 | skb_get(skb); | ||
731 | skb_queue_tail(&self->wx_list, skb); | ||
732 | |||
733 | /* Copy buffer */ | ||
734 | tx_skb = skb_clone(skb, GFP_ATOMIC); | ||
735 | if (tx_skb == NULL) { | ||
736 | return; | ||
737 | } | ||
738 | |||
739 | self->vs = (self->vs + 1) % 8; | ||
740 | self->ack_required = FALSE; | ||
741 | self->window -= 1; | ||
742 | |||
743 | irlap_send_i_frame( self, tx_skb, CMD_FRAME); | ||
744 | } else { | ||
745 | IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__); | ||
746 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); | ||
747 | self->window -= 1; | ||
748 | } | ||
749 | } | ||
750 | /* | ||
751 | * Function irlap_send_data_primary_poll (self, skb) | ||
752 | * | ||
753 | * Send I(nformation) frame as primary with poll bit set | ||
754 | */ | ||
755 | void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) | ||
756 | { | ||
757 | struct sk_buff *tx_skb; | ||
758 | int transmission_time; | ||
759 | |||
760 | /* Stop P timer */ | ||
761 | del_timer(&self->poll_timer); | ||
762 | |||
763 | /* Is this reliable or unreliable data? */ | ||
764 | if (skb->data[1] == I_FRAME) { | ||
765 | |||
766 | /* | ||
767 | * Insert frame sequence number (Vs) in control field before | ||
768 | * inserting into transmit window queue. | ||
769 | */ | ||
770 | skb->data[1] = I_FRAME | (self->vs << 1); | ||
771 | |||
772 | /* | ||
773 | * Insert frame in store, in case of retransmissions | ||
774 | * Increase skb reference count, see irlap_do_event() | ||
775 | */ | ||
776 | skb_get(skb); | ||
777 | skb_queue_tail(&self->wx_list, skb); | ||
778 | |||
779 | /* Copy buffer */ | ||
780 | tx_skb = skb_clone(skb, GFP_ATOMIC); | ||
781 | if (tx_skb == NULL) { | ||
782 | return; | ||
783 | } | ||
784 | |||
785 | /* | ||
786 | * Set poll bit if necessary. We do this to the copied | ||
787 | * skb, since retransmitted need to set or clear the poll | ||
788 | * bit depending on when they are sent. | ||
789 | */ | ||
790 | tx_skb->data[1] |= PF_BIT; | ||
791 | |||
792 | self->vs = (self->vs + 1) % 8; | ||
793 | self->ack_required = FALSE; | ||
794 | |||
795 | irlap_send_i_frame(self, tx_skb, CMD_FRAME); | ||
796 | } else { | ||
797 | IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__); | ||
798 | |||
799 | if (self->ack_required) { | ||
800 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); | ||
801 | irlap_send_rr_frame(self, CMD_FRAME); | ||
802 | self->ack_required = FALSE; | ||
803 | } else { | ||
804 | skb->data[1] |= PF_BIT; | ||
805 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | /* How much time we took for transmission of all frames. | ||
810 | * We don't know, so let assume we used the full window. Jean II */ | ||
811 | transmission_time = self->final_timeout; | ||
812 | |||
813 | /* Reset parameter so that we can fill next window */ | ||
814 | self->window = self->window_size; | ||
815 | |||
816 | #ifdef CONFIG_IRDA_DYNAMIC_WINDOW | ||
817 | /* Remove what we have not used. Just do a prorata of the | ||
818 | * bytes left in window to window capacity. | ||
819 | * See max_line_capacities[][] in qos.c for details. Jean II */ | ||
820 | transmission_time -= (self->final_timeout * self->bytes_left | ||
821 | / self->line_capacity); | ||
822 | IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __FUNCTION__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time); | ||
823 | |||
824 | /* We are allowed to transmit a maximum number of bytes again. */ | ||
825 | self->bytes_left = self->line_capacity; | ||
826 | #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ | ||
827 | |||
828 | /* | ||
829 | * The network layer has a intermediate buffer between IrLAP | ||
830 | * and the IrDA driver which can contain 8 frames. So, even | ||
831 | * though IrLAP is currently sending the *last* frame of the | ||
832 | * tx-window, the driver most likely has only just started | ||
833 | * sending the *first* frame of the same tx-window. | ||
834 | * I.e. we are always at the very begining of or Tx window. | ||
835 | * Now, we are supposed to set the final timer from the end | ||
836 | * of our tx-window to let the other peer reply. So, we need | ||
837 | * to add extra time to compensate for the fact that we | ||
838 | * are really at the start of tx-window, otherwise the final timer | ||
839 | * might expire before he can answer... | ||
840 | * Jean II | ||
841 | */ | ||
842 | irlap_start_final_timer(self, self->final_timeout + transmission_time); | ||
843 | |||
844 | /* | ||
845 | * The clever amongst you might ask why we do this adjustement | ||
846 | * only here, and not in all the other cases in irlap_event.c. | ||
847 | * In all those other case, we only send a very short management | ||
848 | * frame (few bytes), so the adjustement would be lost in the | ||
849 | * noise... | ||
850 | * The exception of course is irlap_resend_rejected_frame(). | ||
851 | * Jean II */ | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * Function irlap_send_data_secondary_final (self, skb) | ||
856 | * | ||
857 | * Send I(nformation) frame as secondary with final bit set | ||
858 | * | ||
859 | */ | ||
860 | void irlap_send_data_secondary_final(struct irlap_cb *self, | ||
861 | struct sk_buff *skb) | ||
862 | { | ||
863 | struct sk_buff *tx_skb = NULL; | ||
864 | |||
865 | IRDA_ASSERT(self != NULL, return;); | ||
866 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
867 | IRDA_ASSERT(skb != NULL, return;); | ||
868 | |||
869 | /* Is this reliable or unreliable data? */ | ||
870 | if (skb->data[1] == I_FRAME) { | ||
871 | |||
872 | /* | ||
873 | * Insert frame sequence number (Vs) in control field before | ||
874 | * inserting into transmit window queue. | ||
875 | */ | ||
876 | skb->data[1] = I_FRAME | (self->vs << 1); | ||
877 | |||
878 | /* | ||
879 | * Insert frame in store, in case of retransmissions | ||
880 | * Increase skb reference count, see irlap_do_event() | ||
881 | */ | ||
882 | skb_get(skb); | ||
883 | skb_queue_tail(&self->wx_list, skb); | ||
884 | |||
885 | tx_skb = skb_clone(skb, GFP_ATOMIC); | ||
886 | if (tx_skb == NULL) { | ||
887 | return; | ||
888 | } | ||
889 | |||
890 | tx_skb->data[1] |= PF_BIT; | ||
891 | |||
892 | self->vs = (self->vs + 1) % 8; | ||
893 | self->ack_required = FALSE; | ||
894 | |||
895 | irlap_send_i_frame(self, tx_skb, RSP_FRAME); | ||
896 | } else { | ||
897 | if (self->ack_required) { | ||
898 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); | ||
899 | irlap_send_rr_frame(self, RSP_FRAME); | ||
900 | self->ack_required = FALSE; | ||
901 | } else { | ||
902 | skb->data[1] |= PF_BIT; | ||
903 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | self->window = self->window_size; | ||
908 | #ifdef CONFIG_IRDA_DYNAMIC_WINDOW | ||
909 | /* We are allowed to transmit a maximum number of bytes again. */ | ||
910 | self->bytes_left = self->line_capacity; | ||
911 | #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ | ||
912 | |||
913 | irlap_start_wd_timer(self, self->wd_timeout); | ||
914 | } | ||
915 | |||
916 | /* | ||
917 | * Function irlap_send_data_secondary (self, skb) | ||
918 | * | ||
919 | * Send I(nformation) frame as secondary without final bit set | ||
920 | * | ||
921 | */ | ||
922 | void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) | ||
923 | { | ||
924 | struct sk_buff *tx_skb = NULL; | ||
925 | |||
926 | /* Is this reliable or unreliable data? */ | ||
927 | if (skb->data[1] == I_FRAME) { | ||
928 | |||
929 | /* | ||
930 | * Insert frame sequence number (Vs) in control field before | ||
931 | * inserting into transmit window queue. | ||
932 | */ | ||
933 | skb->data[1] = I_FRAME | (self->vs << 1); | ||
934 | |||
935 | /* | ||
936 | * Insert frame in store, in case of retransmissions | ||
937 | * Increase skb reference count, see irlap_do_event() | ||
938 | */ | ||
939 | skb_get(skb); | ||
940 | skb_queue_tail(&self->wx_list, skb); | ||
941 | |||
942 | tx_skb = skb_clone(skb, GFP_ATOMIC); | ||
943 | if (tx_skb == NULL) { | ||
944 | return; | ||
945 | } | ||
946 | |||
947 | self->vs = (self->vs + 1) % 8; | ||
948 | self->ack_required = FALSE; | ||
949 | self->window -= 1; | ||
950 | |||
951 | irlap_send_i_frame(self, tx_skb, RSP_FRAME); | ||
952 | } else { | ||
953 | irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); | ||
954 | self->window -= 1; | ||
955 | } | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * Function irlap_resend_rejected_frames (nr) | ||
960 | * | ||
961 | * Resend frames which has not been acknowledged. Should be safe to | ||
962 | * traverse the list without locking it since this function will only be | ||
963 | * called from interrupt context (BH) | ||
964 | */ | ||
965 | void irlap_resend_rejected_frames(struct irlap_cb *self, int command) | ||
966 | { | ||
967 | struct sk_buff *tx_skb; | ||
968 | struct sk_buff *skb; | ||
969 | int count; | ||
970 | |||
971 | IRDA_ASSERT(self != NULL, return;); | ||
972 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
973 | |||
974 | /* Initialize variables */ | ||
975 | count = skb_queue_len(&self->wx_list); | ||
976 | |||
977 | /* Resend unacknowledged frame(s) */ | ||
978 | skb = skb_peek(&self->wx_list); | ||
979 | while (skb != NULL) { | ||
980 | irlap_wait_min_turn_around(self, &self->qos_tx); | ||
981 | |||
982 | /* We copy the skb to be retransmitted since we will have to | ||
983 | * modify it. Cloning will confuse packet sniffers | ||
984 | */ | ||
985 | /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ | ||
986 | tx_skb = skb_copy(skb, GFP_ATOMIC); | ||
987 | if (!tx_skb) { | ||
988 | IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); | ||
989 | return; | ||
990 | } | ||
991 | /* Unlink tx_skb from list */ | ||
992 | tx_skb->next = tx_skb->prev = NULL; | ||
993 | tx_skb->list = NULL; | ||
994 | |||
995 | /* Clear old Nr field + poll bit */ | ||
996 | tx_skb->data[1] &= 0x0f; | ||
997 | |||
998 | /* | ||
999 | * Set poll bit on the last frame retransmitted | ||
1000 | */ | ||
1001 | if (count-- == 1) | ||
1002 | tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ | ||
1003 | else | ||
1004 | tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ | ||
1005 | |||
1006 | irlap_send_i_frame(self, tx_skb, command); | ||
1007 | |||
1008 | /* | ||
1009 | * If our skb is the last buffer in the list, then | ||
1010 | * we are finished, if not, move to the next sk-buffer | ||
1011 | */ | ||
1012 | if (skb == skb_peek_tail(&self->wx_list)) | ||
1013 | skb = NULL; | ||
1014 | else | ||
1015 | skb = skb->next; | ||
1016 | } | ||
1017 | #if 0 /* Not yet */ | ||
1018 | /* | ||
1019 | * We can now fill the window with additional data frames | ||
1020 | */ | ||
1021 | while (skb_queue_len( &self->txq) > 0) { | ||
1022 | |||
1023 | IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__); | ||
1024 | if ((skb_queue_len( &self->txq) > 0) && | ||
1025 | (self->window > 0)) { | ||
1026 | skb = skb_dequeue( &self->txq); | ||
1027 | IRDA_ASSERT(skb != NULL, return;); | ||
1028 | |||
1029 | /* | ||
1030 | * If send window > 1 then send frame with pf | ||
1031 | * bit cleared | ||
1032 | */ | ||
1033 | if ((self->window > 1) && | ||
1034 | skb_queue_len(&self->txq) > 0) | ||
1035 | { | ||
1036 | irlap_send_data_primary(self, skb); | ||
1037 | } else { | ||
1038 | irlap_send_data_primary_poll(self, skb); | ||
1039 | } | ||
1040 | kfree_skb(skb); | ||
1041 | } | ||
1042 | } | ||
1043 | #endif | ||
1044 | } | ||
1045 | |||
1046 | void irlap_resend_rejected_frame(struct irlap_cb *self, int command) | ||
1047 | { | ||
1048 | struct sk_buff *tx_skb; | ||
1049 | struct sk_buff *skb; | ||
1050 | |||
1051 | IRDA_ASSERT(self != NULL, return;); | ||
1052 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
1053 | |||
1054 | /* Resend unacknowledged frame(s) */ | ||
1055 | skb = skb_peek(&self->wx_list); | ||
1056 | if (skb != NULL) { | ||
1057 | irlap_wait_min_turn_around(self, &self->qos_tx); | ||
1058 | |||
1059 | /* We copy the skb to be retransmitted since we will have to | ||
1060 | * modify it. Cloning will confuse packet sniffers | ||
1061 | */ | ||
1062 | /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ | ||
1063 | tx_skb = skb_copy(skb, GFP_ATOMIC); | ||
1064 | if (!tx_skb) { | ||
1065 | IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); | ||
1066 | return; | ||
1067 | } | ||
1068 | /* Unlink tx_skb from list */ | ||
1069 | tx_skb->next = tx_skb->prev = NULL; | ||
1070 | tx_skb->list = NULL; | ||
1071 | |||
1072 | /* Clear old Nr field + poll bit */ | ||
1073 | tx_skb->data[1] &= 0x0f; | ||
1074 | |||
1075 | /* Set poll/final bit */ | ||
1076 | tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ | ||
1077 | |||
1078 | irlap_send_i_frame(self, tx_skb, command); | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | /* | ||
1083 | * Function irlap_send_ui_frame (self, skb, command) | ||
1084 | * | ||
1085 | * Contruct and transmit an Unnumbered Information (UI) frame | ||
1086 | * | ||
1087 | */ | ||
1088 | void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
1089 | __u8 caddr, int command) | ||
1090 | { | ||
1091 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__); | ||
1092 | |||
1093 | IRDA_ASSERT(self != NULL, return;); | ||
1094 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
1095 | IRDA_ASSERT(skb != NULL, return;); | ||
1096 | |||
1097 | /* Insert connection address */ | ||
1098 | skb->data[0] = caddr | ((command) ? CMD_FRAME : 0); | ||
1099 | |||
1100 | irlap_queue_xmit(self, skb); | ||
1101 | } | ||
1102 | |||
1103 | /* | ||
1104 | * Function irlap_send_i_frame (skb) | ||
1105 | * | ||
1106 | * Contruct and transmit Information (I) frame | ||
1107 | */ | ||
1108 | static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
1109 | int command) | ||
1110 | { | ||
1111 | /* Insert connection address */ | ||
1112 | skb->data[0] = self->caddr; | ||
1113 | skb->data[0] |= (command) ? CMD_FRAME : 0; | ||
1114 | |||
1115 | /* Insert next to receive (Vr) */ | ||
1116 | skb->data[1] |= (self->vr << 5); /* insert nr */ | ||
1117 | |||
1118 | irlap_queue_xmit(self, skb); | ||
1119 | } | ||
1120 | |||
1121 | /* | ||
1122 | * Function irlap_recv_i_frame (skb, frame) | ||
1123 | * | ||
1124 | * Receive and parse an I (Information) frame, no harm in making it inline | ||
1125 | * since it's called only from one single place (irlap_driver_rcv). | ||
1126 | */ | ||
1127 | static inline void irlap_recv_i_frame(struct irlap_cb *self, | ||
1128 | struct sk_buff *skb, | ||
1129 | struct irlap_info *info, int command) | ||
1130 | { | ||
1131 | info->nr = skb->data[1] >> 5; /* Next to receive */ | ||
1132 | info->pf = skb->data[1] & PF_BIT; /* Final bit */ | ||
1133 | info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */ | ||
1134 | |||
1135 | /* Check if this is a command or a response frame */ | ||
1136 | if (command) | ||
1137 | irlap_do_event(self, RECV_I_CMD, skb, info); | ||
1138 | else | ||
1139 | irlap_do_event(self, RECV_I_RSP, skb, info); | ||
1140 | } | ||
1141 | |||
1142 | /* | ||
1143 | * Function irlap_recv_ui_frame (self, skb, info) | ||
1144 | * | ||
1145 | * Receive and parse an Unnumbered Information (UI) frame | ||
1146 | * | ||
1147 | */ | ||
1148 | static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
1149 | struct irlap_info *info) | ||
1150 | { | ||
1151 | IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); | ||
1152 | |||
1153 | info->pf = skb->data[1] & PF_BIT; /* Final bit */ | ||
1154 | |||
1155 | irlap_do_event(self, RECV_UI_FRAME, skb, info); | ||
1156 | } | ||
1157 | |||
1158 | /* | ||
1159 | * Function irlap_recv_frmr_frame (skb, frame) | ||
1160 | * | ||
1161 | * Received Frame Reject response. | ||
1162 | * | ||
1163 | */ | ||
1164 | static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
1165 | struct irlap_info *info) | ||
1166 | { | ||
1167 | __u8 *frame; | ||
1168 | int w, x, y, z; | ||
1169 | |||
1170 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__); | ||
1171 | |||
1172 | IRDA_ASSERT(self != NULL, return;); | ||
1173 | IRDA_ASSERT(self->magic == LAP_MAGIC, return;); | ||
1174 | IRDA_ASSERT(skb != NULL, return;); | ||
1175 | IRDA_ASSERT(info != NULL, return;); | ||
1176 | |||
1177 | if (!pskb_may_pull(skb, 4)) { | ||
1178 | IRDA_ERROR("%s: frame to short!\n", __FUNCTION__); | ||
1179 | return; | ||
1180 | } | ||
1181 | |||
1182 | frame = skb->data; | ||
1183 | |||
1184 | info->nr = frame[2] >> 5; /* Next to receive */ | ||
1185 | info->pf = frame[2] & PF_BIT; /* Final bit */ | ||
1186 | info->ns = (frame[2] >> 1) & 0x07; /* Next to send */ | ||
1187 | |||
1188 | w = frame[3] & 0x01; | ||
1189 | x = frame[3] & 0x02; | ||
1190 | y = frame[3] & 0x04; | ||
1191 | z = frame[3] & 0x08; | ||
1192 | |||
1193 | if (w) { | ||
1194 | IRDA_DEBUG(0, "Rejected control field is undefined or not " | ||
1195 | "implemented.\n"); | ||
1196 | } | ||
1197 | if (x) { | ||
1198 | IRDA_DEBUG(0, "Rejected control field was invalid because it " | ||
1199 | "contained a non permitted I field.\n"); | ||
1200 | } | ||
1201 | if (y) { | ||
1202 | IRDA_DEBUG(0, "Received I field exceeded the maximum negotiated " | ||
1203 | "for the existing connection or exceeded the maximum " | ||
1204 | "this station supports if no connection exists.\n"); | ||
1205 | } | ||
1206 | if (z) { | ||
1207 | IRDA_DEBUG(0, "Rejected control field control field contained an " | ||
1208 | "invalid Nr count.\n"); | ||
1209 | } | ||
1210 | irlap_do_event(self, RECV_FRMR_RSP, skb, info); | ||
1211 | } | ||
1212 | |||
1213 | /* | ||
1214 | * Function irlap_send_test_frame (self, daddr) | ||
1215 | * | ||
1216 | * Send a test frame response | ||
1217 | * | ||
1218 | */ | ||
1219 | void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, | ||
1220 | struct sk_buff *cmd) | ||
1221 | { | ||
1222 | struct sk_buff *tx_skb; | ||
1223 | struct test_frame *frame; | ||
1224 | __u8 *info; | ||
1225 | |||
1226 | tx_skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame)); | ||
1227 | if (!tx_skb) | ||
1228 | return; | ||
1229 | |||
1230 | /* Broadcast frames must include saddr and daddr fields */ | ||
1231 | if (caddr == CBROADCAST) { | ||
1232 | frame = (struct test_frame *) | ||
1233 | skb_put(tx_skb, sizeof(struct test_frame)); | ||
1234 | |||
1235 | /* Insert the swapped addresses */ | ||
1236 | frame->saddr = cpu_to_le32(self->saddr); | ||
1237 | frame->daddr = cpu_to_le32(daddr); | ||
1238 | } else | ||
1239 | frame = (struct test_frame *) skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); | ||
1240 | |||
1241 | frame->caddr = caddr; | ||
1242 | frame->control = TEST_RSP | PF_BIT; | ||
1243 | |||
1244 | /* Copy info */ | ||
1245 | info = skb_put(tx_skb, cmd->len); | ||
1246 | memcpy(info, cmd->data, cmd->len); | ||
1247 | |||
1248 | /* Return to sender */ | ||
1249 | irlap_wait_min_turn_around(self, &self->qos_tx); | ||
1250 | irlap_queue_xmit(self, tx_skb); | ||
1251 | } | ||
1252 | |||
1253 | /* | ||
1254 | * Function irlap_recv_test_frame (self, skb) | ||
1255 | * | ||
1256 | * Receive a test frame | ||
1257 | * | ||
1258 | */ | ||
1259 | static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, | ||
1260 | struct irlap_info *info, int command) | ||
1261 | { | ||
1262 | struct test_frame *frame; | ||
1263 | |||
1264 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__); | ||
1265 | |||
1266 | if (!pskb_may_pull(skb, sizeof(*frame))) { | ||
1267 | IRDA_ERROR("%s: frame to short!\n", __FUNCTION__); | ||
1268 | return; | ||
1269 | } | ||
1270 | frame = (struct test_frame *) skb->data; | ||
1271 | |||
1272 | /* Broadcast frames must carry saddr and daddr fields */ | ||
1273 | if (info->caddr == CBROADCAST) { | ||
1274 | if (skb->len < sizeof(struct test_frame)) { | ||
1275 | IRDA_DEBUG(0, "%s() test frame to short!\n", | ||
1276 | __FUNCTION__); | ||
1277 | return; | ||
1278 | } | ||
1279 | |||
1280 | /* Read and swap addresses */ | ||
1281 | info->daddr = le32_to_cpu(frame->saddr); | ||
1282 | info->saddr = le32_to_cpu(frame->daddr); | ||
1283 | |||
1284 | /* Make sure frame is addressed to us */ | ||
1285 | if ((info->saddr != self->saddr) && | ||
1286 | (info->saddr != BROADCAST)) { | ||
1287 | return; | ||
1288 | } | ||
1289 | } | ||
1290 | |||
1291 | if (command) | ||
1292 | irlap_do_event(self, RECV_TEST_CMD, skb, info); | ||
1293 | else | ||
1294 | irlap_do_event(self, RECV_TEST_RSP, skb, info); | ||
1295 | } | ||
1296 | |||
1297 | /* | ||
1298 | * Function irlap_driver_rcv (skb, netdev, ptype) | ||
1299 | * | ||
1300 | * Called when a frame is received. Dispatches the right receive function | ||
1301 | * for processing of the frame. | ||
1302 | * | ||
1303 | * Note on skb management : | ||
1304 | * After calling the higher layers of the IrDA stack, we always | ||
1305 | * kfree() the skb, which drop the reference count (and potentially | ||
1306 | * destroy it). | ||
1307 | * If a higher layer of the stack want to keep the skb around (to put | ||
1308 | * in a queue or pass it to the higher layer), it will need to use | ||
1309 | * skb_get() to keep a reference on it. This is usually done at the | ||
1310 | * LMP level in irlmp.c. | ||
1311 | * Jean II | ||
1312 | */ | ||
1313 | int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, | ||
1314 | struct packet_type *ptype) | ||
1315 | { | ||
1316 | struct irlap_info info; | ||
1317 | struct irlap_cb *self; | ||
1318 | int command; | ||
1319 | __u8 control; | ||
1320 | |||
1321 | /* FIXME: should we get our own field? */ | ||
1322 | self = (struct irlap_cb *) dev->atalk_ptr; | ||
1323 | |||
1324 | /* If the net device is down, then IrLAP is gone! */ | ||
1325 | if (!self || self->magic != LAP_MAGIC) { | ||
1326 | dev_kfree_skb(skb); | ||
1327 | return -1; | ||
1328 | } | ||
1329 | |||
1330 | /* We are no longer an "old" protocol, so we need to handle | ||
1331 | * share and non linear skbs. This should never happen, so | ||
1332 | * we don't need to be clever about it. Jean II */ | ||
1333 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { | ||
1334 | IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__); | ||
1335 | dev_kfree_skb(skb); | ||
1336 | return -1; | ||
1337 | } | ||
1338 | |||
1339 | /* Check if frame is large enough for parsing */ | ||
1340 | if (!pskb_may_pull(skb, 2)) { | ||
1341 | IRDA_ERROR("%s: frame to short!\n", __FUNCTION__); | ||
1342 | dev_kfree_skb(skb); | ||
1343 | return -1; | ||
1344 | } | ||
1345 | |||
1346 | command = skb->data[0] & CMD_FRAME; | ||
1347 | info.caddr = skb->data[0] & CBROADCAST; | ||
1348 | |||
1349 | info.pf = skb->data[1] & PF_BIT; | ||
1350 | info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */ | ||
1351 | |||
1352 | control = info.control; | ||
1353 | |||
1354 | /* First we check if this frame has a valid connection address */ | ||
1355 | if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) { | ||
1356 | IRDA_DEBUG(0, "%s(), wrong connection address!\n", | ||
1357 | __FUNCTION__); | ||
1358 | goto out; | ||
1359 | } | ||
1360 | /* | ||
1361 | * Optimize for the common case and check if the frame is an | ||
1362 | * I(nformation) frame. Only I-frames have bit 0 set to 0 | ||
1363 | */ | ||
1364 | if (~control & 0x01) { | ||
1365 | irlap_recv_i_frame(self, skb, &info, command); | ||
1366 | goto out; | ||
1367 | } | ||
1368 | /* | ||
1369 | * We now check is the frame is an S(upervisory) frame. Only | ||
1370 | * S-frames have bit 0 set to 1 and bit 1 set to 0 | ||
1371 | */ | ||
1372 | if (~control & 0x02) { | ||
1373 | /* | ||
1374 | * Received S(upervisory) frame, check which frame type it is | ||
1375 | * only the first nibble is of interest | ||
1376 | */ | ||
1377 | switch (control & 0x0f) { | ||
1378 | case RR: | ||
1379 | irlap_recv_rr_frame(self, skb, &info, command); | ||
1380 | break; | ||
1381 | case RNR: | ||
1382 | irlap_recv_rnr_frame(self, skb, &info, command); | ||
1383 | break; | ||
1384 | case REJ: | ||
1385 | irlap_recv_rej_frame(self, skb, &info, command); | ||
1386 | break; | ||
1387 | case SREJ: | ||
1388 | irlap_recv_srej_frame(self, skb, &info, command); | ||
1389 | break; | ||
1390 | default: | ||
1391 | IRDA_WARNING("%s: Unknown S-frame %02x received!\n", | ||
1392 | __FUNCTION__, info.control); | ||
1393 | break; | ||
1394 | } | ||
1395 | goto out; | ||
1396 | } | ||
1397 | /* | ||
1398 | * This must be a C(ontrol) frame | ||
1399 | */ | ||
1400 | switch (control) { | ||
1401 | case XID_RSP: | ||
1402 | irlap_recv_discovery_xid_rsp(self, skb, &info); | ||
1403 | break; | ||
1404 | case XID_CMD: | ||
1405 | irlap_recv_discovery_xid_cmd(self, skb, &info); | ||
1406 | break; | ||
1407 | case SNRM_CMD: | ||
1408 | irlap_recv_snrm_cmd(self, skb, &info); | ||
1409 | break; | ||
1410 | case DM_RSP: | ||
1411 | irlap_do_event(self, RECV_DM_RSP, skb, &info); | ||
1412 | break; | ||
1413 | case DISC_CMD: /* And RD_RSP since they have the same value */ | ||
1414 | irlap_recv_disc_frame(self, skb, &info, command); | ||
1415 | break; | ||
1416 | case TEST_CMD: | ||
1417 | irlap_recv_test_frame(self, skb, &info, command); | ||
1418 | break; | ||
1419 | case UA_RSP: | ||
1420 | irlap_recv_ua_frame(self, skb, &info); | ||
1421 | break; | ||
1422 | case FRMR_RSP: | ||
1423 | irlap_recv_frmr_frame(self, skb, &info); | ||
1424 | break; | ||
1425 | case UI_FRAME: | ||
1426 | irlap_recv_ui_frame(self, skb, &info); | ||
1427 | break; | ||
1428 | default: | ||
1429 | IRDA_WARNING("%s: Unknown frame %02x received!\n", | ||
1430 | __FUNCTION__, info.control); | ||
1431 | break; | ||
1432 | } | ||
1433 | out: | ||
1434 | /* Always drop our reference on the skb */ | ||
1435 | dev_kfree_skb(skb); | ||
1436 | return 0; | ||
1437 | } | ||