aboutsummaryrefslogtreecommitdiffstats
path: root/net/irda/irlan
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/irda/irlan
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/irlan')
-rw-r--r--net/irda/irlan/Kconfig14
-rw-r--r--net/irda/irlan/Makefile7
-rw-r--r--net/irda/irlan/irlan_client.c576
-rw-r--r--net/irda/irlan/irlan_client_event.c533
-rw-r--r--net/irda/irlan/irlan_common.c1200
-rw-r--r--net/irda/irlan/irlan_eth.c387
-rw-r--r--net/irda/irlan/irlan_event.c60
-rw-r--r--net/irda/irlan/irlan_filter.c246
-rw-r--r--net/irda/irlan/irlan_provider.c413
-rw-r--r--net/irda/irlan/irlan_provider_event.c241
10 files changed, 3677 insertions, 0 deletions
diff --git a/net/irda/irlan/Kconfig b/net/irda/irlan/Kconfig
new file mode 100644
index 000000000000..951abc2e3a7f
--- /dev/null
+++ b/net/irda/irlan/Kconfig
@@ -0,0 +1,14 @@
1config IRLAN
2 tristate "IrLAN protocol"
3 depends on IRDA
4 help
5 Say Y here if you want to build support for the IrLAN protocol.
6 To compile it as a module, choose M here: the module will be called
7 irlan. IrLAN emulates an Ethernet and makes it possible to put up
8 a wireless LAN using infrared beams.
9
10 The IrLAN protocol can be used to talk with infrared access points
11 like the HP NetbeamIR, or the ESI JetEye NET. You can also connect
12 to another Linux machine running the IrLAN protocol for ad-hoc
13 networking!
14
diff --git a/net/irda/irlan/Makefile b/net/irda/irlan/Makefile
new file mode 100644
index 000000000000..77549bc8641b
--- /dev/null
+++ b/net/irda/irlan/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the Linux IrDA IrLAN protocol layer.
3#
4
5obj-$(CONFIG_IRLAN) += irlan.o
6
7irlan-objs := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
new file mode 100644
index 000000000000..f8e6cb0db04b
--- /dev/null
+++ b/net/irda/irlan/irlan_client.c
@@ -0,0 +1,576 @@
1/*********************************************************************
2 *
3 * Filename: irlan_client.c
4 * Version: 0.9
5 * Description: IrDA LAN Access Protocol (IrLAN) Client
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 31 20:14:37 1997
9 * Modified at: Tue Dec 14 15:47:02 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
12 * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
13 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
14 *
15 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
16 * All Rights Reserved.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation; either version 2 of
21 * the License, or (at your option) any later version.
22 *
23 * Neither Dag Brattli nor University of Tromsų admit liability nor
24 * provide warranty for any of this software. This material is
25 * provided "AS-IS" and at no charge.
26 *
27 ********************************************************************/
28
29#include <linux/kernel.h>
30#include <linux/string.h>
31#include <linux/errno.h>
32#include <linux/init.h>
33#include <linux/netdevice.h>
34#include <linux/etherdevice.h>
35#include <linux/if_arp.h>
36#include <linux/bitops.h>
37#include <net/arp.h>
38
39#include <asm/system.h>
40#include <asm/byteorder.h>
41
42#include <net/irda/irda.h>
43#include <net/irda/irttp.h>
44#include <net/irda/irlmp.h>
45#include <net/irda/irias_object.h>
46#include <net/irda/iriap.h>
47#include <net/irda/timer.h>
48
49#include <net/irda/irlan_common.h>
50#include <net/irda/irlan_event.h>
51#include <net/irda/irlan_eth.h>
52#include <net/irda/irlan_provider.h>
53#include <net/irda/irlan_client.h>
54
55#undef CONFIG_IRLAN_GRATUITOUS_ARP
56
57static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
58 LM_REASON reason,
59 struct sk_buff *);
60static int irlan_client_ctrl_data_indication(void *instance, void *sap,
61 struct sk_buff *skb);
62static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
63 struct qos_info *qos,
64 __u32 max_sdu_size,
65 __u8 max_header_size,
66 struct sk_buff *);
67static void irlan_check_response_param(struct irlan_cb *self, char *param,
68 char *value, int val_len);
69static void irlan_client_open_ctrl_tsap(struct irlan_cb *self);
70
71static void irlan_client_kick_timer_expired(void *data)
72{
73 struct irlan_cb *self = (struct irlan_cb *) data;
74
75 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
76
77 IRDA_ASSERT(self != NULL, return;);
78 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
79
80 /*
81 * If we are in peer mode, the client may not have got the discovery
82 * indication it needs to make progress. If the client is still in
83 * IDLE state, we must kick it to, but only if the provider is not IDLE
84 */
85 if ((self->provider.access_type == ACCESS_PEER) &&
86 (self->client.state == IRLAN_IDLE) &&
87 (self->provider.state != IRLAN_IDLE)) {
88 irlan_client_wakeup(self, self->saddr, self->daddr);
89 }
90}
91
92static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
93{
94 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
95
96 irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
97 irlan_client_kick_timer_expired);
98}
99
100/*
101 * Function irlan_client_wakeup (self, saddr, daddr)
102 *
103 * Wake up client
104 *
105 */
106void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
107{
108 IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
109
110 IRDA_ASSERT(self != NULL, return;);
111 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
112
113 /*
114 * Check if we are already awake, or if we are a provider in direct
115 * mode (in that case we must leave the client idle
116 */
117 if ((self->client.state != IRLAN_IDLE) ||
118 (self->provider.access_type == ACCESS_DIRECT))
119 {
120 IRDA_DEBUG(0, "%s(), already awake!\n", __FUNCTION__ );
121 return;
122 }
123
124 /* Addresses may have changed! */
125 self->saddr = saddr;
126 self->daddr = daddr;
127
128 if (self->disconnect_reason == LM_USER_REQUEST) {
129 IRDA_DEBUG(0, "%s(), still stopped by user\n", __FUNCTION__ );
130 return;
131 }
132
133 /* Open TSAPs */
134 irlan_client_open_ctrl_tsap(self);
135 irlan_open_data_tsap(self);
136
137 irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
138
139 /* Start kick timer */
140 irlan_client_start_kick_timer(self, 2*HZ);
141}
142
143/*
144 * Function irlan_discovery_indication (daddr)
145 *
146 * Remote device with IrLAN server support discovered
147 *
148 */
149void irlan_client_discovery_indication(discinfo_t *discovery,
150 DISCOVERY_MODE mode,
151 void *priv)
152{
153 struct irlan_cb *self;
154 __u32 saddr, daddr;
155
156 IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
157
158 IRDA_ASSERT(discovery != NULL, return;);
159
160 /*
161 * I didn't check it, but I bet that IrLAN suffer from the same
162 * deficiency as IrComm and doesn't handle two instances
163 * simultaneously connecting to each other.
164 * Same workaround, drop passive discoveries.
165 * Jean II */
166 if(mode == DISCOVERY_PASSIVE)
167 return;
168
169 saddr = discovery->saddr;
170 daddr = discovery->daddr;
171
172 /* Find instance */
173 rcu_read_lock();
174 self = irlan_get_any();
175 if (self) {
176 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
177
178 IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ ,
179 daddr);
180
181 irlan_client_wakeup(self, saddr, daddr);
182 }
183 rcu_read_unlock();
184}
185
186/*
187 * Function irlan_client_data_indication (handle, skb)
188 *
189 * This function gets the data that is received on the control channel
190 *
191 */
192static int irlan_client_ctrl_data_indication(void *instance, void *sap,
193 struct sk_buff *skb)
194{
195 struct irlan_cb *self;
196
197 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
198
199 self = (struct irlan_cb *) instance;
200
201 IRDA_ASSERT(self != NULL, return -1;);
202 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
203 IRDA_ASSERT(skb != NULL, return -1;);
204
205 irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
206
207 /* Ready for a new command */
208 IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __FUNCTION__ );
209 self->client.tx_busy = FALSE;
210
211 /* Check if we have some queued commands waiting to be sent */
212 irlan_run_ctrl_tx_queue(self);
213
214 return 0;
215}
216
217static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
218 LM_REASON reason,
219 struct sk_buff *userdata)
220{
221 struct irlan_cb *self;
222 struct tsap_cb *tsap;
223 struct sk_buff *skb;
224
225 IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
226
227 self = (struct irlan_cb *) instance;
228 tsap = (struct tsap_cb *) sap;
229
230 IRDA_ASSERT(self != NULL, return;);
231 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
232 IRDA_ASSERT(tsap != NULL, return;);
233 IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
234
235 IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;);
236
237 /* Remove frames queued on the control channel */
238 while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
239 dev_kfree_skb(skb);
240 }
241 self->client.tx_busy = FALSE;
242
243 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
244}
245
246/*
247 * Function irlan_client_open_tsaps (self)
248 *
249 * Initialize callbacks and open IrTTP TSAPs
250 *
251 */
252static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
253{
254 struct tsap_cb *tsap;
255 notify_t notify;
256
257 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
258
259 IRDA_ASSERT(self != NULL, return;);
260 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
261
262 /* Check if already open */
263 if (self->client.tsap_ctrl)
264 return;
265
266 irda_notify_init(&notify);
267
268 /* Set up callbacks */
269 notify.data_indication = irlan_client_ctrl_data_indication;
270 notify.connect_confirm = irlan_client_ctrl_connect_confirm;
271 notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
272 notify.instance = self;
273 strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name));
274
275 tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
276 if (!tsap) {
277 IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
278 return;
279 }
280 self->client.tsap_ctrl = tsap;
281}
282
283/*
284 * Function irlan_client_connect_confirm (handle, skb)
285 *
286 * Connection to peer IrLAN laye confirmed
287 *
288 */
289static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
290 struct qos_info *qos,
291 __u32 max_sdu_size,
292 __u8 max_header_size,
293 struct sk_buff *skb)
294{
295 struct irlan_cb *self;
296
297 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
298
299 self = (struct irlan_cb *) instance;
300
301 IRDA_ASSERT(self != NULL, return;);
302 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
303
304 self->client.max_sdu_size = max_sdu_size;
305 self->client.max_header_size = max_header_size;
306
307 /* TODO: we could set the MTU depending on the max_sdu_size */
308
309 irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
310}
311
312/*
313 * Function print_ret_code (code)
314 *
315 * Print return code of request to peer IrLAN layer.
316 *
317 */
318static void print_ret_code(__u8 code)
319{
320 switch(code) {
321 case 0:
322 printk(KERN_INFO "Success\n");
323 break;
324 case 1:
325 IRDA_WARNING("IrLAN: Insufficient resources\n");
326 break;
327 case 2:
328 IRDA_WARNING("IrLAN: Invalid command format\n");
329 break;
330 case 3:
331 IRDA_WARNING("IrLAN: Command not supported\n");
332 break;
333 case 4:
334 IRDA_WARNING("IrLAN: Parameter not supported\n");
335 break;
336 case 5:
337 IRDA_WARNING("IrLAN: Value not supported\n");
338 break;
339 case 6:
340 IRDA_WARNING("IrLAN: Not open\n");
341 break;
342 case 7:
343 IRDA_WARNING("IrLAN: Authentication required\n");
344 break;
345 case 8:
346 IRDA_WARNING("IrLAN: Invalid password\n");
347 break;
348 case 9:
349 IRDA_WARNING("IrLAN: Protocol error\n");
350 break;
351 case 255:
352 IRDA_WARNING("IrLAN: Asynchronous status\n");
353 break;
354 }
355}
356
357/*
358 * Function irlan_client_parse_response (self, skb)
359 *
360 * Extract all parameters from received buffer, then feed them to
361 * check_params for parsing
362 */
363void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
364{
365 __u8 *frame;
366 __u8 *ptr;
367 int count;
368 int ret;
369 __u16 val_len;
370 int i;
371 char *name;
372 char *value;
373
374 IRDA_ASSERT(skb != NULL, return;);
375
376 IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len);
377
378 IRDA_ASSERT(self != NULL, return;);
379 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
380
381 if (!skb) {
382 IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__);
383 return;
384 }
385 frame = skb->data;
386
387 /*
388 * Check return code and print it if not success
389 */
390 if (frame[0]) {
391 print_ret_code(frame[0]);
392 return;
393 }
394
395 name = kmalloc(255, GFP_ATOMIC);
396 if (!name)
397 return;
398 value = kmalloc(1016, GFP_ATOMIC);
399 if (!value) {
400 kfree(name);
401 return;
402 }
403
404 /* How many parameters? */
405 count = frame[1];
406
407 IRDA_DEBUG(4, "%s(), got %d parameters\n", __FUNCTION__ , count);
408
409 ptr = frame+2;
410
411 /* For all parameters */
412 for (i=0; i<count;i++) {
413 ret = irlan_extract_param(ptr, name, value, &val_len);
414 if (ret < 0) {
415 IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
416 break;
417 }
418 ptr += ret;
419 irlan_check_response_param(self, name, value, val_len);
420 }
421 /* Cleanup */
422 kfree(name);
423 kfree(value);
424}
425
426/*
427 * Function irlan_check_response_param (self, param, value, val_len)
428 *
429 * Check which parameter is received and update local variables
430 *
431 */
432static void irlan_check_response_param(struct irlan_cb *self, char *param,
433 char *value, int val_len)
434{
435 __u16 tmp_cpu; /* Temporary value in host order */
436 __u8 *bytes;
437 int i;
438
439 IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param);
440
441 IRDA_ASSERT(self != NULL, return;);
442 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
443
444 /* Media type */
445 if (strcmp(param, "MEDIA") == 0) {
446 if (strcmp(value, "802.3") == 0)
447 self->media = MEDIA_802_3;
448 else
449 self->media = MEDIA_802_5;
450 return;
451 }
452 if (strcmp(param, "FILTER_TYPE") == 0) {
453 if (strcmp(value, "DIRECTED") == 0)
454 self->client.filter_type |= IRLAN_DIRECTED;
455 else if (strcmp(value, "FUNCTIONAL") == 0)
456 self->client.filter_type |= IRLAN_FUNCTIONAL;
457 else if (strcmp(value, "GROUP") == 0)
458 self->client.filter_type |= IRLAN_GROUP;
459 else if (strcmp(value, "MAC_FRAME") == 0)
460 self->client.filter_type |= IRLAN_MAC_FRAME;
461 else if (strcmp(value, "MULTICAST") == 0)
462 self->client.filter_type |= IRLAN_MULTICAST;
463 else if (strcmp(value, "BROADCAST") == 0)
464 self->client.filter_type |= IRLAN_BROADCAST;
465 else if (strcmp(value, "IPX_SOCKET") == 0)
466 self->client.filter_type |= IRLAN_IPX_SOCKET;
467
468 }
469 if (strcmp(param, "ACCESS_TYPE") == 0) {
470 if (strcmp(value, "DIRECT") == 0)
471 self->client.access_type = ACCESS_DIRECT;
472 else if (strcmp(value, "PEER") == 0)
473 self->client.access_type = ACCESS_PEER;
474 else if (strcmp(value, "HOSTED") == 0)
475 self->client.access_type = ACCESS_HOSTED;
476 else {
477 IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
478 }
479 }
480 /* IRLAN version */
481 if (strcmp(param, "IRLAN_VER") == 0) {
482 IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
483 (__u8) value[1]);
484
485 self->version[0] = value[0];
486 self->version[1] = value[1];
487 return;
488 }
489 /* Which remote TSAP to use for data channel */
490 if (strcmp(param, "DATA_CHAN") == 0) {
491 self->dtsap_sel_data = value[0];
492 IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
493 return;
494 }
495 if (strcmp(param, "CON_ARB") == 0) {
496 memcpy(&tmp_cpu, value, 2); /* Align value */
497 le16_to_cpus(&tmp_cpu); /* Convert to host order */
498 self->client.recv_arb_val = tmp_cpu;
499 IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __FUNCTION__ ,
500 self->client.recv_arb_val);
501 }
502 if (strcmp(param, "MAX_FRAME") == 0) {
503 memcpy(&tmp_cpu, value, 2); /* Align value */
504 le16_to_cpus(&tmp_cpu); /* Convert to host order */
505 self->client.max_frame = tmp_cpu;
506 IRDA_DEBUG(4, "%s(), max frame=%d\n", __FUNCTION__ ,
507 self->client.max_frame);
508 }
509
510 /* RECONNECT_KEY, in case the link goes down! */
511 if (strcmp(param, "RECONNECT_KEY") == 0) {
512 IRDA_DEBUG(4, "Got reconnect key: ");
513 /* for (i = 0; i < val_len; i++) */
514/* printk("%02x", value[i]); */
515 memcpy(self->client.reconnect_key, value, val_len);
516 self->client.key_len = val_len;
517 IRDA_DEBUG(4, "\n");
518 }
519 /* FILTER_ENTRY, have we got an ethernet address? */
520 if (strcmp(param, "FILTER_ENTRY") == 0) {
521 bytes = value;
522 IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
523 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
524 bytes[5]);
525 for (i = 0; i < 6; i++)
526 self->dev->dev_addr[i] = bytes[i];
527 }
528}
529
530/*
531 * Function irlan_client_get_value_confirm (obj_id, value)
532 *
533 * Got results from remote LM-IAS
534 *
535 */
536void irlan_client_get_value_confirm(int result, __u16 obj_id,
537 struct ias_value *value, void *priv)
538{
539 struct irlan_cb *self;
540
541 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
542
543 IRDA_ASSERT(priv != NULL, return;);
544
545 self = (struct irlan_cb *) priv;
546 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
547
548 /* We probably don't need to make any more queries */
549 iriap_close(self->client.iriap);
550 self->client.iriap = NULL;
551
552 /* Check if request succeeded */
553 if (result != IAS_SUCCESS) {
554 IRDA_DEBUG(2, "%s(), got NULL value!\n", __FUNCTION__ );
555 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
556 NULL);
557 return;
558 }
559
560 switch (value->type) {
561 case IAS_INTEGER:
562 self->dtsap_sel_ctrl = value->t.integer;
563
564 if (value->t.integer != -1) {
565 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
566 NULL);
567 return;
568 }
569 irias_delete_value(value);
570 break;
571 default:
572 IRDA_DEBUG(2, "%s(), unknown type!\n", __FUNCTION__ );
573 break;
574 }
575 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
576}
diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c
new file mode 100644
index 000000000000..ce943b69e996
--- /dev/null
+++ b/net/irda/irlan/irlan_client_event.c
@@ -0,0 +1,533 @@
1/*********************************************************************
2 *
3 * Filename: irlan_client_event.c
4 * Version: 0.9
5 * Description: IrLAN client state machine
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 31 20:14:37 1997
9 * Modified at: Sun Dec 26 21:52:24 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * Neither Dag Brattli nor University of Tromsų admit liability nor
21 * provide warranty for any of this software. This material is
22 * provided "AS-IS" and at no charge.
23 *
24 ********************************************************************/
25
26#include <linux/skbuff.h>
27
28#include <net/irda/irda.h>
29#include <net/irda/timer.h>
30#include <net/irda/irmod.h>
31#include <net/irda/iriap.h>
32#include <net/irda/irlmp.h>
33#include <net/irda/irttp.h>
34
35#include <net/irda/irlan_common.h>
36#include <net/irda/irlan_client.h>
37#include <net/irda/irlan_event.h>
38
39static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,
40 struct sk_buff *skb);
41static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
42 struct sk_buff *skb);
43static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,
44 struct sk_buff *skb);
45static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,
46 struct sk_buff *skb);
47static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
48 struct sk_buff *skb);
49static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,
50 struct sk_buff *skb);
51static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,
52 struct sk_buff *skb);
53static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event,
54 struct sk_buff *skb);
55static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,
56 struct sk_buff *skb);
57static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
58 struct sk_buff *skb);
59static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,
60 struct sk_buff *skb);
61
62static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =
63{
64 irlan_client_state_idle,
65 irlan_client_state_query,
66 irlan_client_state_conn,
67 irlan_client_state_info,
68 irlan_client_state_media,
69 irlan_client_state_open,
70 irlan_client_state_wait,
71 irlan_client_state_arb,
72 irlan_client_state_data,
73 irlan_client_state_close,
74 irlan_client_state_sync
75};
76
77void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
78 struct sk_buff *skb)
79{
80 IRDA_ASSERT(self != NULL, return;);
81 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
82
83 (*state[ self->client.state]) (self, event, skb);
84}
85
86/*
87 * Function irlan_client_state_idle (event, skb, info)
88 *
89 * IDLE, We are waiting for an indication that there is a provider
90 * available.
91 */
92static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
93 struct sk_buff *skb)
94{
95 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
96
97 IRDA_ASSERT(self != NULL, return -1;);
98 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
99
100 switch (event) {
101 case IRLAN_DISCOVERY_INDICATION:
102 if (self->client.iriap) {
103 IRDA_WARNING("%s(), busy with a previous query\n",
104 __FUNCTION__);
105 return -EBUSY;
106 }
107
108 self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
109 irlan_client_get_value_confirm);
110 /* Get some values from peer IAS */
111 irlan_next_client_state(self, IRLAN_QUERY);
112 iriap_getvaluebyclass_request(self->client.iriap,
113 self->saddr, self->daddr,
114 "IrLAN", "IrDA:TinyTP:LsapSel");
115 break;
116 case IRLAN_WATCHDOG_TIMEOUT:
117 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
118 break;
119 default:
120 IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
121 break;
122 }
123 if (skb)
124 dev_kfree_skb(skb);
125
126 return 0;
127}
128
129/*
130 * Function irlan_client_state_query (event, skb, info)
131 *
132 * QUERY, We have queryed the remote IAS and is ready to connect
133 * to provider, just waiting for the confirm.
134 *
135 */
136static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
137 struct sk_buff *skb)
138{
139 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
140
141 IRDA_ASSERT(self != NULL, return -1;);
142 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
143
144 switch(event) {
145 case IRLAN_IAS_PROVIDER_AVAIL:
146 IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
147
148 self->client.open_retries = 0;
149
150 irttp_connect_request(self->client.tsap_ctrl,
151 self->dtsap_sel_ctrl,
152 self->saddr, self->daddr, NULL,
153 IRLAN_MTU, NULL);
154 irlan_next_client_state(self, IRLAN_CONN);
155 break;
156 case IRLAN_IAS_PROVIDER_NOT_AVAIL:
157 IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ );
158 irlan_next_client_state(self, IRLAN_IDLE);
159
160 /* Give the client a kick! */
161 if ((self->provider.access_type == ACCESS_PEER) &&
162 (self->provider.state != IRLAN_IDLE))
163 irlan_client_wakeup(self, self->saddr, self->daddr);
164 break;
165 case IRLAN_LMP_DISCONNECT:
166 case IRLAN_LAP_DISCONNECT:
167 irlan_next_client_state(self, IRLAN_IDLE);
168 break;
169 case IRLAN_WATCHDOG_TIMEOUT:
170 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
171 break;
172 default:
173 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
174 break;
175 }
176 if (skb)
177 dev_kfree_skb(skb);
178
179 return 0;
180}
181
182/*
183 * Function irlan_client_state_conn (event, skb, info)
184 *
185 * CONN, We have connected to a provider but has not issued any
186 * commands yet.
187 *
188 */
189static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
190 struct sk_buff *skb)
191{
192 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
193
194 IRDA_ASSERT(self != NULL, return -1;);
195
196 switch (event) {
197 case IRLAN_CONNECT_COMPLETE:
198 /* Send getinfo cmd */
199 irlan_get_provider_info(self);
200 irlan_next_client_state(self, IRLAN_INFO);
201 break;
202 case IRLAN_LMP_DISCONNECT:
203 case IRLAN_LAP_DISCONNECT:
204 irlan_next_client_state(self, IRLAN_IDLE);
205 break;
206 case IRLAN_WATCHDOG_TIMEOUT:
207 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
208 break;
209 default:
210 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
211 break;
212 }
213 if (skb)
214 dev_kfree_skb(skb);
215
216 return 0;
217}
218
219/*
220 * Function irlan_client_state_info (self, event, skb, info)
221 *
222 * INFO, We have issued a GetInfo command and is awaiting a reply.
223 */
224static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
225 struct sk_buff *skb)
226{
227 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
228
229 IRDA_ASSERT(self != NULL, return -1;);
230
231 switch (event) {
232 case IRLAN_DATA_INDICATION:
233 IRDA_ASSERT(skb != NULL, return -1;);
234
235 irlan_client_parse_response(self, skb);
236
237 irlan_next_client_state(self, IRLAN_MEDIA);
238
239 irlan_get_media_char(self);
240 break;
241
242 case IRLAN_LMP_DISCONNECT:
243 case IRLAN_LAP_DISCONNECT:
244 irlan_next_client_state(self, IRLAN_IDLE);
245 break;
246 case IRLAN_WATCHDOG_TIMEOUT:
247 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
248 break;
249 default:
250 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
251 break;
252 }
253 if (skb)
254 dev_kfree_skb(skb);
255
256 return 0;
257}
258
259/*
260 * Function irlan_client_state_media (self, event, skb, info)
261 *
262 * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
263 * reply.
264 *
265 */
266static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
267 struct sk_buff *skb)
268{
269 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
270
271 IRDA_ASSERT(self != NULL, return -1;);
272
273 switch(event) {
274 case IRLAN_DATA_INDICATION:
275 irlan_client_parse_response(self, skb);
276 irlan_open_data_channel(self);
277 irlan_next_client_state(self, IRLAN_OPEN);
278 break;
279 case IRLAN_LMP_DISCONNECT:
280 case IRLAN_LAP_DISCONNECT:
281 irlan_next_client_state(self, IRLAN_IDLE);
282 break;
283 case IRLAN_WATCHDOG_TIMEOUT:
284 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
285 break;
286 default:
287 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
288 break;
289 }
290 if (skb)
291 dev_kfree_skb(skb);
292
293 return 0;
294}
295
296/*
297 * Function irlan_client_state_open (self, event, skb, info)
298 *
299 * OPEN, The irlan_client has issued a OpenData command and is awaiting a
300 * reply
301 *
302 */
303static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
304 struct sk_buff *skb)
305{
306 struct qos_info qos;
307
308 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
309
310 IRDA_ASSERT(self != NULL, return -1;);
311
312 switch(event) {
313 case IRLAN_DATA_INDICATION:
314 irlan_client_parse_response(self, skb);
315
316 /*
317 * Check if we have got the remote TSAP for data
318 * communications
319 */
320 IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
321
322 /* Check which access type we are dealing with */
323 switch (self->client.access_type) {
324 case ACCESS_PEER:
325 if (self->provider.state == IRLAN_OPEN) {
326
327 irlan_next_client_state(self, IRLAN_ARB);
328 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
329 NULL);
330 } else {
331
332 irlan_next_client_state(self, IRLAN_WAIT);
333 }
334 break;
335 case ACCESS_DIRECT:
336 case ACCESS_HOSTED:
337 qos.link_disc_time.bits = 0x01; /* 3 secs */
338
339 irttp_connect_request(self->tsap_data,
340 self->dtsap_sel_data,
341 self->saddr, self->daddr, &qos,
342 IRLAN_MTU, NULL);
343
344 irlan_next_client_state(self, IRLAN_DATA);
345 break;
346 default:
347 IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
348 break;
349 }
350 break;
351 case IRLAN_LMP_DISCONNECT:
352 case IRLAN_LAP_DISCONNECT:
353 irlan_next_client_state(self, IRLAN_IDLE);
354 break;
355 case IRLAN_WATCHDOG_TIMEOUT:
356 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
357 break;
358 default:
359 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
360 break;
361 }
362
363 if (skb)
364 dev_kfree_skb(skb);
365
366 return 0;
367}
368
369/*
370 * Function irlan_client_state_wait (self, event, skb, info)
371 *
372 * WAIT, The irlan_client is waiting for the local provider to enter the
373 * provider OPEN state.
374 *
375 */
376static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
377 struct sk_buff *skb)
378{
379 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
380
381 IRDA_ASSERT(self != NULL, return -1;);
382
383 switch(event) {
384 case IRLAN_PROVIDER_SIGNAL:
385 irlan_next_client_state(self, IRLAN_ARB);
386 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
387 break;
388 case IRLAN_LMP_DISCONNECT:
389 case IRLAN_LAP_DISCONNECT:
390 irlan_next_client_state(self, IRLAN_IDLE);
391 break;
392 case IRLAN_WATCHDOG_TIMEOUT:
393 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
394 break;
395 default:
396 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
397 break;
398 }
399 if (skb)
400 dev_kfree_skb(skb);
401
402 return 0;
403}
404
405static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
406 struct sk_buff *skb)
407{
408 struct qos_info qos;
409
410 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
411
412 IRDA_ASSERT(self != NULL, return -1;);
413
414 switch(event) {
415 case IRLAN_CHECK_CON_ARB:
416 if (self->client.recv_arb_val == self->provider.send_arb_val) {
417 irlan_next_client_state(self, IRLAN_CLOSE);
418 irlan_close_data_channel(self);
419 } else if (self->client.recv_arb_val <
420 self->provider.send_arb_val)
421 {
422 qos.link_disc_time.bits = 0x01; /* 3 secs */
423
424 irlan_next_client_state(self, IRLAN_DATA);
425 irttp_connect_request(self->tsap_data,
426 self->dtsap_sel_data,
427 self->saddr, self->daddr, &qos,
428 IRLAN_MTU, NULL);
429 } else if (self->client.recv_arb_val >
430 self->provider.send_arb_val)
431 {
432 IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ );
433 }
434 break;
435 case IRLAN_DATA_CONNECT_INDICATION:
436 irlan_next_client_state(self, IRLAN_DATA);
437 break;
438 case IRLAN_LMP_DISCONNECT:
439 case IRLAN_LAP_DISCONNECT:
440 irlan_next_client_state(self, IRLAN_IDLE);
441 break;
442 case IRLAN_WATCHDOG_TIMEOUT:
443 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
444 break;
445 default:
446 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
447 break;
448 }
449 if (skb)
450 dev_kfree_skb(skb);
451
452 return 0;
453}
454
455/*
456 * Function irlan_client_state_data (self, event, skb, info)
457 *
458 * DATA, The data channel is connected, allowing data transfers between
459 * the local and remote machines.
460 *
461 */
462static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
463 struct sk_buff *skb)
464{
465 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
466
467 IRDA_ASSERT(self != NULL, return -1;);
468 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
469
470 switch(event) {
471 case IRLAN_DATA_INDICATION:
472 irlan_client_parse_response(self, skb);
473 break;
474 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
475 case IRLAN_LAP_DISCONNECT:
476 irlan_next_client_state(self, IRLAN_IDLE);
477 break;
478 default:
479 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
480 break;
481 }
482 if (skb)
483 dev_kfree_skb(skb);
484
485 return 0;
486}
487
488/*
489 * Function irlan_client_state_close (self, event, skb, info)
490 *
491 *
492 *
493 */
494static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
495 struct sk_buff *skb)
496{
497 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
498
499 if (skb)
500 dev_kfree_skb(skb);
501
502 return 0;
503}
504
505/*
506 * Function irlan_client_state_sync (self, event, skb, info)
507 *
508 *
509 *
510 */
511static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
512 struct sk_buff *skb)
513{
514 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
515
516 if (skb)
517 dev_kfree_skb(skb);
518
519 return 0;
520}
521
522
523
524
525
526
527
528
529
530
531
532
533
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
new file mode 100644
index 000000000000..657d12210578
--- /dev/null
+++ b/net/irda/irlan/irlan_common.c
@@ -0,0 +1,1200 @@
1/*********************************************************************
2 *
3 * Filename: irlan_common.c
4 * Version: 0.9
5 * Description: IrDA LAN Access Protocol Implementation
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 31 20:14:37 1997
9 * Modified at: Sun Dec 26 21:53:10 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * Neither Dag Brattli nor University of Tromsų admit liability nor
21 * provide warranty for any of this software. This material is
22 * provided "AS-IS" and at no charge.
23 *
24 ********************************************************************/
25
26#include <linux/config.h>
27#include <linux/module.h>
28
29#include <linux/kernel.h>
30#include <linux/string.h>
31#include <linux/init.h>
32#include <linux/errno.h>
33#include <linux/proc_fs.h>
34#include <linux/seq_file.h>
35#include <linux/random.h>
36#include <linux/netdevice.h>
37#include <linux/etherdevice.h>
38#include <linux/rtnetlink.h>
39#include <linux/moduleparam.h>
40#include <linux/bitops.h>
41
42#include <asm/system.h>
43#include <asm/byteorder.h>
44
45#include <net/irda/irda.h>
46#include <net/irda/irttp.h>
47#include <net/irda/irlmp.h>
48#include <net/irda/iriap.h>
49#include <net/irda/timer.h>
50
51#include <net/irda/irlan_common.h>
52#include <net/irda/irlan_client.h>
53#include <net/irda/irlan_provider.h>
54#include <net/irda/irlan_eth.h>
55#include <net/irda/irlan_filter.h>
56
57
58/*
59 * Send gratuitous ARP when connected to a new AP or not. May be a clever
60 * thing to do, but for some reason the machine crashes if you use DHCP. So
61 * lets not use it by default.
62 */
63#undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
64
65/* extern char sysctl_devname[]; */
66
67/*
68 * Master structure
69 */
70static LIST_HEAD(irlans);
71
72static void *ckey;
73static void *skey;
74
75/* Module parameters */
76static int eth; /* Use "eth" or "irlan" name for devices */
77static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
78
79#ifdef CONFIG_PROC_FS
80static const char *irlan_access[] = {
81 "UNKNOWN",
82 "DIRECT",
83 "PEER",
84 "HOSTED"
85};
86
87static const char *irlan_media[] = {
88 "UNKNOWN",
89 "802.3",
90 "802.5"
91};
92
93extern struct proc_dir_entry *proc_irda;
94
95static int irlan_seq_open(struct inode *inode, struct file *file);
96
97static struct file_operations irlan_fops = {
98 .owner = THIS_MODULE,
99 .open = irlan_seq_open,
100 .read = seq_read,
101 .llseek = seq_lseek,
102 .release = seq_release,
103};
104
105extern struct proc_dir_entry *proc_irda;
106#endif /* CONFIG_PROC_FS */
107
108static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr);
109static void __irlan_close(struct irlan_cb *self);
110static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
111 __u8 value_byte, __u16 value_short,
112 __u8 *value_array, __u16 value_len);
113static void irlan_open_unicast_addr(struct irlan_cb *self);
114static void irlan_get_unicast_addr(struct irlan_cb *self);
115void irlan_close_tsaps(struct irlan_cb *self);
116
117/*
118 * Function irlan_init (void)
119 *
120 * Initialize IrLAN layer
121 *
122 */
123static int __init irlan_init(void)
124{
125 struct irlan_cb *new;
126 __u16 hints;
127
128 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
129
130#ifdef CONFIG_PROC_FS
131 { struct proc_dir_entry *proc;
132 proc = create_proc_entry("irlan", 0, proc_irda);
133 if (!proc) {
134 printk(KERN_ERR "irlan_init: can't create /proc entry!\n");
135 return -ENODEV;
136 }
137
138 proc->proc_fops = &irlan_fops;
139 }
140#endif /* CONFIG_PROC_FS */
141
142 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
143 hints = irlmp_service_to_hint(S_LAN);
144
145 /* Register with IrLMP as a client */
146 ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
147 NULL, NULL);
148
149 /* Register with IrLMP as a service */
150 skey = irlmp_register_service(hints);
151
152 /* Start the master IrLAN instance (the only one for now) */
153 new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
154
155 /* The master will only open its (listen) control TSAP */
156 irlan_provider_open_ctrl_tsap(new);
157
158 /* Do some fast discovery! */
159 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
160
161 return 0;
162}
163
164static void __exit irlan_cleanup(void)
165{
166 struct irlan_cb *self, *next;
167
168 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
169
170 irlmp_unregister_client(ckey);
171 irlmp_unregister_service(skey);
172
173#ifdef CONFIG_PROC_FS
174 remove_proc_entry("irlan", proc_irda);
175#endif /* CONFIG_PROC_FS */
176
177 /* Cleanup any leftover network devices */
178 rtnl_lock();
179 list_for_each_entry_safe(self, next, &irlans, dev_list) {
180 __irlan_close(self);
181 }
182 rtnl_unlock();
183}
184
185/*
186 * Function irlan_open (void)
187 *
188 * Open new instance of a client/provider, we should only register the
189 * network device if this instance is ment for a particular client/provider
190 */
191static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
192{
193 struct net_device *dev;
194 struct irlan_cb *self;
195
196 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
197
198 /* Create network device with irlan */
199 dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
200 if (!dev)
201 return NULL;
202
203 self = dev->priv;
204 self->dev = dev;
205
206 /*
207 * Initialize local device structure
208 */
209 self->magic = IRLAN_MAGIC;
210 self->saddr = saddr;
211 self->daddr = daddr;
212
213 /* Provider access can only be PEER, DIRECT, or HOSTED */
214 self->provider.access_type = access;
215 if (access == ACCESS_DIRECT) {
216 /*
217 * Since we are emulating an IrLAN sever we will have to
218 * give ourself an ethernet address!
219 */
220 dev->dev_addr[0] = 0x40;
221 dev->dev_addr[1] = 0x00;
222 dev->dev_addr[2] = 0x00;
223 dev->dev_addr[3] = 0x00;
224 get_random_bytes(dev->dev_addr+4, 1);
225 get_random_bytes(dev->dev_addr+5, 1);
226 }
227
228 self->media = MEDIA_802_3;
229 self->disconnect_reason = LM_USER_REQUEST;
230 init_timer(&self->watchdog_timer);
231 init_timer(&self->client.kick_timer);
232 init_waitqueue_head(&self->open_wait);
233
234 skb_queue_head_init(&self->client.txq);
235
236 irlan_next_client_state(self, IRLAN_IDLE);
237 irlan_next_provider_state(self, IRLAN_IDLE);
238
239 if (register_netdev(dev)) {
240 IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
241 __FUNCTION__ );
242 self = NULL;
243 free_netdev(dev);
244 } else {
245 rtnl_lock();
246 list_add_rcu(&self->dev_list, &irlans);
247 rtnl_unlock();
248 }
249
250 return self;
251}
252/*
253 * Function __irlan_close (self)
254 *
255 * This function closes and deallocates the IrLAN client instances. Be
256 * aware that other functions which calls client_close() must
257 * remove self from irlans list first.
258 */
259static void __irlan_close(struct irlan_cb *self)
260{
261 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
262
263 ASSERT_RTNL();
264 IRDA_ASSERT(self != NULL, return;);
265 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
266
267 del_timer_sync(&self->watchdog_timer);
268 del_timer_sync(&self->client.kick_timer);
269
270 /* Close all open connections and remove TSAPs */
271 irlan_close_tsaps(self);
272
273 if (self->client.iriap)
274 iriap_close(self->client.iriap);
275
276 /* Remove frames queued on the control channel */
277 skb_queue_purge(&self->client.txq);
278
279 /* Unregister and free self via destructor */
280 unregister_netdevice(self->dev);
281}
282
283/* Find any instance of irlan, used for client discovery wakeup */
284struct irlan_cb *irlan_get_any(void)
285{
286 struct irlan_cb *self;
287
288 list_for_each_entry_rcu(self, &irlans, dev_list) {
289 return self;
290 }
291 return NULL;
292}
293
294/*
295 * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
296 *
297 * Here we receive the connect indication for the data channel
298 *
299 */
300static void irlan_connect_indication(void *instance, void *sap,
301 struct qos_info *qos,
302 __u32 max_sdu_size,
303 __u8 max_header_size,
304 struct sk_buff *skb)
305{
306 struct irlan_cb *self;
307 struct tsap_cb *tsap;
308
309 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
310
311 self = (struct irlan_cb *) instance;
312 tsap = (struct tsap_cb *) sap;
313
314 IRDA_ASSERT(self != NULL, return;);
315 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
316 IRDA_ASSERT(tsap == self->tsap_data,return;);
317
318 self->max_sdu_size = max_sdu_size;
319 self->max_header_size = max_header_size;
320
321 IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
322
323 del_timer(&self->watchdog_timer);
324
325 /* If you want to pass the skb to *both* state machines, you will
326 * need to skb_clone() it, so that you don't free it twice.
327 * As the state machines don't need it, git rid of it here...
328 * Jean II */
329 if (skb)
330 dev_kfree_skb(skb);
331
332 irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
333 irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
334
335 if (self->provider.access_type == ACCESS_PEER) {
336 /*
337 * Data channel is open, so we are now allowed to
338 * configure the remote filter
339 */
340 irlan_get_unicast_addr(self);
341 irlan_open_unicast_addr(self);
342 }
343 /* Ready to transfer Ethernet frames (at last) */
344 netif_start_queue(self->dev); /* Clear reason */
345}
346
347static void irlan_connect_confirm(void *instance, void *sap,
348 struct qos_info *qos,
349 __u32 max_sdu_size,
350 __u8 max_header_size,
351 struct sk_buff *skb)
352{
353 struct irlan_cb *self;
354
355 self = (struct irlan_cb *) instance;
356
357 IRDA_ASSERT(self != NULL, return;);
358 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
359
360 self->max_sdu_size = max_sdu_size;
361 self->max_header_size = max_header_size;
362
363 /* TODO: we could set the MTU depending on the max_sdu_size */
364
365 IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
366 del_timer(&self->watchdog_timer);
367
368 /*
369 * Data channel is open, so we are now allowed to configure the remote
370 * filter
371 */
372 irlan_get_unicast_addr(self);
373 irlan_open_unicast_addr(self);
374
375 /* Open broadcast and multicast filter by default */
376 irlan_set_broadcast_filter(self, TRUE);
377 irlan_set_multicast_filter(self, TRUE);
378
379 /* Ready to transfer Ethernet frames */
380 netif_start_queue(self->dev);
381 self->disconnect_reason = 0; /* Clear reason */
382#ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
383 irlan_eth_send_gratuitous_arp(&self->dev);
384#endif
385 wake_up_interruptible(&self->open_wait);
386}
387
388/*
389 * Function irlan_client_disconnect_indication (handle)
390 *
391 * Callback function for the IrTTP layer. Indicates a disconnection of
392 * the specified connection (handle)
393 */
394static void irlan_disconnect_indication(void *instance,
395 void *sap, LM_REASON reason,
396 struct sk_buff *userdata)
397{
398 struct irlan_cb *self;
399 struct tsap_cb *tsap;
400
401 IRDA_DEBUG(0, "%s(), reason=%d\n", __FUNCTION__ , reason);
402
403 self = (struct irlan_cb *) instance;
404 tsap = (struct tsap_cb *) sap;
405
406 IRDA_ASSERT(self != NULL, return;);
407 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
408 IRDA_ASSERT(tsap != NULL, return;);
409 IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
410
411 IRDA_ASSERT(tsap == self->tsap_data, return;);
412
413 IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
414
415 /* Save reason so we know if we should try to reconnect or not */
416 self->disconnect_reason = reason;
417
418 switch (reason) {
419 case LM_USER_REQUEST: /* User request */
420 IRDA_DEBUG(2, "%s(), User requested\n", __FUNCTION__ );
421 break;
422 case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
423 IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __FUNCTION__ );
424 break;
425 case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
426 IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __FUNCTION__ );
427 break;
428 case LM_LAP_RESET: /* IrLAP reset */
429 IRDA_DEBUG(2, "%s(), IrLAP reset\n", __FUNCTION__ );
430 break;
431 case LM_INIT_DISCONNECT:
432 IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ );
433 break;
434 default:
435 IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__);
436 break;
437 }
438
439 /* If you want to pass the skb to *both* state machines, you will
440 * need to skb_clone() it, so that you don't free it twice.
441 * As the state machines don't need it, git rid of it here...
442 * Jean II */
443 if (userdata)
444 dev_kfree_skb(userdata);
445
446 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
447 irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
448
449 wake_up_interruptible(&self->open_wait);
450}
451
452void irlan_open_data_tsap(struct irlan_cb *self)
453{
454 struct tsap_cb *tsap;
455 notify_t notify;
456
457 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
458
459 IRDA_ASSERT(self != NULL, return;);
460 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
461
462 /* Check if already open */
463 if (self->tsap_data)
464 return;
465
466 irda_notify_init(&notify);
467
468 notify.data_indication = irlan_eth_receive;
469 notify.udata_indication = irlan_eth_receive;
470 notify.connect_indication = irlan_connect_indication;
471 notify.connect_confirm = irlan_connect_confirm;
472 notify.flow_indication = irlan_eth_flow_indication;
473 notify.disconnect_indication = irlan_disconnect_indication;
474 notify.instance = self;
475 strlcpy(notify.name, "IrLAN data", sizeof(notify.name));
476
477 tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
478 if (!tsap) {
479 IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
480 return;
481 }
482 self->tsap_data = tsap;
483
484 /*
485 * This is the data TSAP selector which we will pass to the client
486 * when the client ask for it.
487 */
488 self->stsap_sel_data = self->tsap_data->stsap_sel;
489}
490
491void irlan_close_tsaps(struct irlan_cb *self)
492{
493 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
494
495 IRDA_ASSERT(self != NULL, return;);
496 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
497
498 /* Disconnect and close all open TSAP connections */
499 if (self->tsap_data) {
500 irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
501 irttp_close_tsap(self->tsap_data);
502 self->tsap_data = NULL;
503 }
504 if (self->client.tsap_ctrl) {
505 irttp_disconnect_request(self->client.tsap_ctrl, NULL,
506 P_NORMAL);
507 irttp_close_tsap(self->client.tsap_ctrl);
508 self->client.tsap_ctrl = NULL;
509 }
510 if (self->provider.tsap_ctrl) {
511 irttp_disconnect_request(self->provider.tsap_ctrl, NULL,
512 P_NORMAL);
513 irttp_close_tsap(self->provider.tsap_ctrl);
514 self->provider.tsap_ctrl = NULL;
515 }
516 self->disconnect_reason = LM_USER_REQUEST;
517}
518
519/*
520 * Function irlan_ias_register (self, tsap_sel)
521 *
522 * Register with LM-IAS
523 *
524 */
525void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
526{
527 struct ias_object *obj;
528 struct ias_value *new_value;
529
530 IRDA_ASSERT(self != NULL, return;);
531 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
532
533 /*
534 * Check if object has already been registered by a previous provider.
535 * If that is the case, we just change the value of the attribute
536 */
537 if (!irias_find_object("IrLAN")) {
538 obj = irias_new_object("IrLAN", IAS_IRLAN_ID);
539 irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel,
540 IAS_KERNEL_ATTR);
541 irias_insert_object(obj);
542 } else {
543 new_value = irias_new_integer_value(tsap_sel);
544 irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel",
545 new_value);
546 }
547
548 /* Register PnP object only if not registered before */
549 if (!irias_find_object("PnP")) {
550 obj = irias_new_object("PnP", IAS_PNP_ID);
551#if 0
552 irias_add_string_attrib(obj, "Name", sysctl_devname,
553 IAS_KERNEL_ATTR);
554#else
555 irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR);
556#endif
557 irias_add_string_attrib(obj, "DeviceID", "HWP19F0",
558 IAS_KERNEL_ATTR);
559 irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR);
560 if (self->provider.access_type == ACCESS_PEER)
561 irias_add_string_attrib(obj, "Comp#01", "PNP8389",
562 IAS_KERNEL_ATTR);
563 else
564 irias_add_string_attrib(obj, "Comp#01", "PNP8294",
565 IAS_KERNEL_ATTR);
566
567 irias_add_string_attrib(obj, "Manufacturer",
568 "Linux-IrDA Project", IAS_KERNEL_ATTR);
569 irias_insert_object(obj);
570 }
571}
572
573/*
574 * Function irlan_run_ctrl_tx_queue (self)
575 *
576 * Try to send the next command in the control transmit queue
577 *
578 */
579int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
580{
581 struct sk_buff *skb;
582
583 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
584
585 if (irda_lock(&self->client.tx_busy) == FALSE)
586 return -EBUSY;
587
588 skb = skb_dequeue(&self->client.txq);
589 if (!skb) {
590 self->client.tx_busy = FALSE;
591 return 0;
592 }
593
594 /* Check that it's really possible to send commands */
595 if ((self->client.tsap_ctrl == NULL) ||
596 (self->client.state == IRLAN_IDLE))
597 {
598 self->client.tx_busy = FALSE;
599 dev_kfree_skb(skb);
600 return -1;
601 }
602 IRDA_DEBUG(2, "%s(), sending ...\n", __FUNCTION__ );
603
604 return irttp_data_request(self->client.tsap_ctrl, skb);
605}
606
607/*
608 * Function irlan_ctrl_data_request (self, skb)
609 *
610 * This function makes sure that commands on the control channel is being
611 * sent in a command/response fashion
612 */
613static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
614{
615 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
616
617 /* Queue command */
618 skb_queue_tail(&self->client.txq, skb);
619
620 /* Try to send command */
621 irlan_run_ctrl_tx_queue(self);
622}
623
624/*
625 * Function irlan_get_provider_info (self)
626 *
627 * Send Get Provider Information command to peer IrLAN layer
628 *
629 */
630void irlan_get_provider_info(struct irlan_cb *self)
631{
632 struct sk_buff *skb;
633 __u8 *frame;
634
635 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
636
637 IRDA_ASSERT(self != NULL, return;);
638 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
639
640 skb = dev_alloc_skb(64);
641 if (!skb)
642 return;
643
644 /* Reserve space for TTP, LMP, and LAP header */
645 skb_reserve(skb, self->client.max_header_size);
646 skb_put(skb, 2);
647
648 frame = skb->data;
649
650 frame[0] = CMD_GET_PROVIDER_INFO;
651 frame[1] = 0x00; /* Zero parameters */
652
653 irlan_ctrl_data_request(self, skb);
654}
655
656/*
657 * Function irlan_open_data_channel (self)
658 *
659 * Send an Open Data Command to provider
660 *
661 */
662void irlan_open_data_channel(struct irlan_cb *self)
663{
664 struct sk_buff *skb;
665 __u8 *frame;
666
667 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
668
669 IRDA_ASSERT(self != NULL, return;);
670 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
671
672 skb = dev_alloc_skb(64);
673 if (!skb)
674 return;
675
676 skb_reserve(skb, self->client.max_header_size);
677 skb_put(skb, 2);
678
679 frame = skb->data;
680
681 /* Build frame */
682 frame[0] = CMD_OPEN_DATA_CHANNEL;
683 frame[1] = 0x02; /* Two parameters */
684
685 irlan_insert_string_param(skb, "MEDIA", "802.3");
686 irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
687 /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */
688
689/* self->use_udata = TRUE; */
690
691 irlan_ctrl_data_request(self, skb);
692}
693
694void irlan_close_data_channel(struct irlan_cb *self)
695{
696 struct sk_buff *skb;
697 __u8 *frame;
698
699 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
700
701 IRDA_ASSERT(self != NULL, return;);
702 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
703
704 /* Check if the TSAP is still there */
705 if (self->client.tsap_ctrl == NULL)
706 return;
707
708 skb = dev_alloc_skb(64);
709 if (!skb)
710 return;
711
712 skb_reserve(skb, self->client.max_header_size);
713 skb_put(skb, 2);
714
715 frame = skb->data;
716
717 /* Build frame */
718 frame[0] = CMD_CLOSE_DATA_CHAN;
719 frame[1] = 0x01; /* Two parameters */
720
721 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
722
723 irlan_ctrl_data_request(self, skb);
724}
725
726/*
727 * Function irlan_open_unicast_addr (self)
728 *
729 * Make IrLAN provider accept ethernet frames addressed to the unicast
730 * address.
731 *
732 */
733static void irlan_open_unicast_addr(struct irlan_cb *self)
734{
735 struct sk_buff *skb;
736 __u8 *frame;
737
738 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
739
740 IRDA_ASSERT(self != NULL, return;);
741 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
742
743 skb = dev_alloc_skb(128);
744 if (!skb)
745 return;
746
747 /* Reserve space for TTP, LMP, and LAP header */
748 skb_reserve(skb, self->max_header_size);
749 skb_put(skb, 2);
750
751 frame = skb->data;
752
753 frame[0] = CMD_FILTER_OPERATION;
754 frame[1] = 0x03; /* Three parameters */
755 irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data);
756 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
757 irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
758
759 irlan_ctrl_data_request(self, skb);
760}
761
762/*
763 * Function irlan_set_broadcast_filter (self, status)
764 *
765 * Make IrLAN provider accept ethernet frames addressed to the broadcast
766 * address. Be careful with the use of this one, since there may be a lot
767 * of broadcast traffic out there. We can still function without this
768 * one but then _we_ have to initiate all communication with other
769 * hosts, since ARP request for this host will not be answered.
770 */
771void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
772{
773 struct sk_buff *skb;
774 __u8 *frame;
775
776 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
777
778 IRDA_ASSERT(self != NULL, return;);
779 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
780
781 skb = dev_alloc_skb(128);
782 if (!skb)
783 return;
784
785 /* Reserve space for TTP, LMP, and LAP header */
786 skb_reserve(skb, self->client.max_header_size);
787 skb_put(skb, 2);
788
789 frame = skb->data;
790
791 frame[0] = CMD_FILTER_OPERATION;
792 frame[1] = 0x03; /* Three parameters */
793 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
794 irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
795 if (status)
796 irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
797 else
798 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
799
800 irlan_ctrl_data_request(self, skb);
801}
802
803/*
804 * Function irlan_set_multicast_filter (self, status)
805 *
806 * Make IrLAN provider accept ethernet frames addressed to the multicast
807 * address.
808 *
809 */
810void irlan_set_multicast_filter(struct irlan_cb *self, int status)
811{
812 struct sk_buff *skb;
813 __u8 *frame;
814
815 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
816
817 IRDA_ASSERT(self != NULL, return;);
818 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
819
820 skb = dev_alloc_skb(128);
821 if (!skb)
822 return;
823
824 /* Reserve space for TTP, LMP, and LAP header */
825 skb_reserve(skb, self->client.max_header_size);
826 skb_put(skb, 2);
827
828 frame = skb->data;
829
830 frame[0] = CMD_FILTER_OPERATION;
831 frame[1] = 0x03; /* Three parameters */
832 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
833 irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
834 if (status)
835 irlan_insert_string_param(skb, "FILTER_MODE", "ALL");
836 else
837 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
838
839 irlan_ctrl_data_request(self, skb);
840}
841
842/*
843 * Function irlan_get_unicast_addr (self)
844 *
845 * Retrieves the unicast address from the IrLAN provider. This address
846 * will be inserted into the devices structure, so the ethernet layer
847 * can construct its packets.
848 *
849 */
850static void irlan_get_unicast_addr(struct irlan_cb *self)
851{
852 struct sk_buff *skb;
853 __u8 *frame;
854
855 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
856
857 IRDA_ASSERT(self != NULL, return;);
858 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
859
860 skb = dev_alloc_skb(128);
861 if (!skb)
862 return;
863
864 /* Reserve space for TTP, LMP, and LAP header */
865 skb_reserve(skb, self->client.max_header_size);
866 skb_put(skb, 2);
867
868 frame = skb->data;
869
870 frame[0] = CMD_FILTER_OPERATION;
871 frame[1] = 0x03; /* Three parameters */
872 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
873 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
874 irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC");
875
876 irlan_ctrl_data_request(self, skb);
877}
878
879/*
880 * Function irlan_get_media_char (self)
881 *
882 *
883 *
884 */
885void irlan_get_media_char(struct irlan_cb *self)
886{
887 struct sk_buff *skb;
888 __u8 *frame;
889
890 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
891
892 IRDA_ASSERT(self != NULL, return;);
893 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
894
895 skb = dev_alloc_skb(64);
896 if (!skb)
897 return;
898
899 /* Reserve space for TTP, LMP, and LAP header */
900 skb_reserve(skb, self->client.max_header_size);
901 skb_put(skb, 2);
902
903 frame = skb->data;
904
905 /* Build frame */
906 frame[0] = CMD_GET_MEDIA_CHAR;
907 frame[1] = 0x01; /* One parameter */
908
909 irlan_insert_string_param(skb, "MEDIA", "802.3");
910 irlan_ctrl_data_request(self, skb);
911}
912
913/*
914 * Function insert_byte_param (skb, param, value)
915 *
916 * Insert byte parameter into frame
917 *
918 */
919int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value)
920{
921 return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0);
922}
923
924int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value)
925{
926 return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0);
927}
928
929/*
930 * Function insert_string (skb, param, value)
931 *
932 * Insert string parameter into frame
933 *
934 */
935int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string)
936{
937 int string_len = strlen(string);
938
939 return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string,
940 string_len);
941}
942
943/*
944 * Function insert_array_param(skb, param, value, len_value)
945 *
946 * Insert array parameter into frame
947 *
948 */
949int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array,
950 __u16 array_len)
951{
952 return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array,
953 array_len);
954}
955
956/*
957 * Function insert_param (skb, param, value, byte)
958 *
959 * Insert parameter at end of buffer, structure of a parameter is:
960 *
961 * -----------------------------------------------------------------------
962 * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]|
963 * -----------------------------------------------------------------------
964 */
965static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
966 __u8 value_byte, __u16 value_short,
967 __u8 *value_array, __u16 value_len)
968{
969 __u8 *frame;
970 __u8 param_len;
971 __u16 tmp_le; /* Temporary value in little endian format */
972 int n=0;
973
974 if (skb == NULL) {
975 IRDA_DEBUG(2, "%s(), Got NULL skb\n", __FUNCTION__ );
976 return 0;
977 }
978
979 param_len = strlen(param);
980 switch (type) {
981 case IRLAN_BYTE:
982 value_len = 1;
983 break;
984 case IRLAN_SHORT:
985 value_len = 2;
986 break;
987 case IRLAN_ARRAY:
988 IRDA_ASSERT(value_array != NULL, return 0;);
989 IRDA_ASSERT(value_len > 0, return 0;);
990 break;
991 default:
992 IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ );
993 return 0;
994 break;
995 }
996
997 /* Insert at end of sk-buffer */
998 frame = skb->tail;
999
1000 /* Make space for data */
1001 if (skb_tailroom(skb) < (param_len+value_len+3)) {
1002 IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __FUNCTION__ );
1003 return 0;
1004 }
1005 skb_put(skb, param_len+value_len+3);
1006
1007 /* Insert parameter length */
1008 frame[n++] = param_len;
1009
1010 /* Insert parameter */
1011 memcpy(frame+n, param, param_len); n += param_len;
1012
1013 /* Insert value length (2 byte little endian format, LSB first) */
1014 tmp_le = cpu_to_le16(value_len);
1015 memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */
1016
1017 /* Insert value */
1018 switch (type) {
1019 case IRLAN_BYTE:
1020 frame[n++] = value_byte;
1021 break;
1022 case IRLAN_SHORT:
1023 tmp_le = cpu_to_le16(value_short);
1024 memcpy(frame+n, &tmp_le, 2); n += 2;
1025 break;
1026 case IRLAN_ARRAY:
1027 memcpy(frame+n, value_array, value_len); n+=value_len;
1028 break;
1029 default:
1030 break;
1031 }
1032 IRDA_ASSERT(n == (param_len+value_len+3), return 0;);
1033
1034 return param_len+value_len+3;
1035}
1036
1037/*
1038 * Function irlan_extract_param (buf, name, value, len)
1039 *
1040 * Extracts a single parameter name/value pair from buffer and updates
1041 * the buffer pointer to point to the next name/value pair.
1042 */
1043int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
1044{
1045 __u8 name_len;
1046 __u16 val_len;
1047 int n=0;
1048
1049 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
1050
1051 /* get length of parameter name (1 byte) */
1052 name_len = buf[n++];
1053
1054 if (name_len > 254) {
1055 IRDA_DEBUG(2, "%s(), name_len > 254\n", __FUNCTION__ );
1056 return -RSP_INVALID_COMMAND_FORMAT;
1057 }
1058
1059 /* get parameter name */
1060 memcpy(name, buf+n, name_len);
1061 name[name_len] = '\0';
1062 n+=name_len;
1063
1064 /*
1065 * Get length of parameter value (2 bytes in little endian
1066 * format)
1067 */
1068 memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */
1069 le16_to_cpus(&val_len); n+=2;
1070
1071 if (val_len > 1016) {
1072 IRDA_DEBUG(2, "%s(), parameter length to long\n", __FUNCTION__ );
1073 return -RSP_INVALID_COMMAND_FORMAT;
1074 }
1075 *len = val_len;
1076
1077 /* get parameter value */
1078 memcpy(value, buf+n, val_len);
1079 value[val_len] = '\0';
1080 n+=val_len;
1081
1082 IRDA_DEBUG(4, "Parameter: %s ", name);
1083 IRDA_DEBUG(4, "Value: %s\n", value);
1084
1085 return n;
1086}
1087
1088#ifdef CONFIG_PROC_FS
1089
1090/*
1091 * Start of reading /proc entries.
1092 * Return entry at pos,
1093 * or start_token to indicate print header line
1094 * or NULL if end of file
1095 */
1096static void *irlan_seq_start(struct seq_file *seq, loff_t *pos)
1097{
1098 int i = 1;
1099 struct irlan_cb *self;
1100
1101 rcu_read_lock();
1102 if (*pos == 0)
1103 return SEQ_START_TOKEN;
1104
1105 list_for_each_entry(self, &irlans, dev_list) {
1106 if (*pos == i)
1107 return self;
1108 ++i;
1109 }
1110 return NULL;
1111}
1112
1113/* Return entry after v, and increment pos */
1114static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1115{
1116 struct list_head *nxt;
1117
1118 ++*pos;
1119 if (v == SEQ_START_TOKEN)
1120 nxt = irlans.next;
1121 else
1122 nxt = ((struct irlan_cb *)v)->dev_list.next;
1123
1124 return (nxt == &irlans) ? NULL
1125 : list_entry(nxt, struct irlan_cb, dev_list);
1126}
1127
1128/* End of reading /proc file */
1129static void irlan_seq_stop(struct seq_file *seq, void *v)
1130{
1131 rcu_read_unlock();
1132}
1133
1134
1135/*
1136 * Show one entry in /proc file.
1137 */
1138static int irlan_seq_show(struct seq_file *seq, void *v)
1139{
1140 if (v == SEQ_START_TOKEN)
1141 seq_puts(seq, "IrLAN instances:\n");
1142 else {
1143 struct irlan_cb *self = v;
1144
1145 IRDA_ASSERT(self != NULL, return -1;);
1146 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
1147
1148 seq_printf(seq,"ifname: %s,\n",
1149 self->dev->name);
1150 seq_printf(seq,"client state: %s, ",
1151 irlan_state[ self->client.state]);
1152 seq_printf(seq,"provider state: %s,\n",
1153 irlan_state[ self->provider.state]);
1154 seq_printf(seq,"saddr: %#08x, ",
1155 self->saddr);
1156 seq_printf(seq,"daddr: %#08x\n",
1157 self->daddr);
1158 seq_printf(seq,"version: %d.%d,\n",
1159 self->version[1], self->version[0]);
1160 seq_printf(seq,"access type: %s\n",
1161 irlan_access[self->client.access_type]);
1162 seq_printf(seq,"media: %s\n",
1163 irlan_media[self->media]);
1164
1165 seq_printf(seq,"local filter:\n");
1166 seq_printf(seq,"remote filter: ");
1167 irlan_print_filter(seq, self->client.filter_type);
1168 seq_printf(seq,"tx busy: %s\n",
1169 netif_queue_stopped(self->dev) ? "TRUE" : "FALSE");
1170
1171 seq_putc(seq,'\n');
1172 }
1173 return 0;
1174}
1175
1176static struct seq_operations irlan_seq_ops = {
1177 .start = irlan_seq_start,
1178 .next = irlan_seq_next,
1179 .stop = irlan_seq_stop,
1180 .show = irlan_seq_show,
1181};
1182
1183static int irlan_seq_open(struct inode *inode, struct file *file)
1184{
1185 return seq_open(file, &irlan_seq_ops);
1186}
1187#endif
1188
1189MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
1190MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
1191MODULE_LICENSE("GPL");
1192
1193module_param(eth, bool, 0);
1194MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)");
1195module_param(access, int, 0);
1196MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3");
1197
1198module_init(irlan_init);
1199module_exit(irlan_cleanup);
1200
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
new file mode 100644
index 000000000000..071cd2cefd8a
--- /dev/null
+++ b/net/irda/irlan/irlan_eth.c
@@ -0,0 +1,387 @@
1/*********************************************************************
2 *
3 * Filename: irlan_eth.c
4 * Version:
5 * Description:
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Thu Oct 15 08:37:58 1998
9 * Modified at: Tue Mar 21 09:06:41 2000
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
12 * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
13 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
14 *
15 * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 * Neither Dag Brattli nor University of Tromsų admit liability nor
23 * provide warranty for any of this software. This material is
24 * provided "AS-IS" and at no charge.
25 *
26 ********************************************************************/
27
28#include <linux/config.h>
29#include <linux/netdevice.h>
30#include <linux/etherdevice.h>
31#include <linux/inetdevice.h>
32#include <linux/if_arp.h>
33#include <linux/module.h>
34#include <net/arp.h>
35
36#include <net/irda/irda.h>
37#include <net/irda/irmod.h>
38#include <net/irda/irlan_common.h>
39#include <net/irda/irlan_client.h>
40#include <net/irda/irlan_event.h>
41#include <net/irda/irlan_eth.h>
42
43static int irlan_eth_open(struct net_device *dev);
44static int irlan_eth_close(struct net_device *dev);
45static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev);
46static void irlan_eth_set_multicast_list( struct net_device *dev);
47static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev);
48
49/*
50 * Function irlan_eth_setup (dev)
51 *
52 * The network device initialization function.
53 *
54 */
55static void irlan_eth_setup(struct net_device *dev)
56{
57 dev->open = irlan_eth_open;
58 dev->stop = irlan_eth_close;
59 dev->hard_start_xmit = irlan_eth_xmit;
60 dev->get_stats = irlan_eth_get_stats;
61 dev->set_multicast_list = irlan_eth_set_multicast_list;
62 dev->destructor = free_netdev;
63
64 SET_MODULE_OWNER(dev);
65
66 ether_setup(dev);
67
68 /*
69 * Lets do all queueing in IrTTP instead of this device driver.
70 * Queueing here as well can introduce some strange latency
71 * problems, which we will avoid by setting the queue size to 0.
72 */
73 /*
74 * The bugs in IrTTP and IrLAN that created this latency issue
75 * have now been fixed, and we can propagate flow control properly
76 * to the network layer. However, this requires a minimal queue of
77 * packets for the device.
78 * Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14
79 * With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11
80 * See irlan_eth_flow_indication()...
81 * Note : this number was randomly selected and would need to
82 * be adjusted.
83 * Jean II */
84 dev->tx_queue_len = 4;
85}
86
87/*
88 * Function alloc_irlandev
89 *
90 * Allocate network device and control block
91 *
92 */
93struct net_device *alloc_irlandev(const char *name)
94{
95 return alloc_netdev(sizeof(struct irlan_cb), name,
96 irlan_eth_setup);
97}
98
99/*
100 * Function irlan_eth_open (dev)
101 *
102 * Network device has been opened by user
103 *
104 */
105static int irlan_eth_open(struct net_device *dev)
106{
107 struct irlan_cb *self = netdev_priv(dev);
108
109 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
110
111 /* Ready to play! */
112 netif_stop_queue(dev); /* Wait until data link is ready */
113
114 /* We are now open, so time to do some work */
115 self->disconnect_reason = 0;
116 irlan_client_wakeup(self, self->saddr, self->daddr);
117
118 /* Make sure we have a hardware address before we return,
119 so DHCP clients gets happy */
120 return wait_event_interruptible(self->open_wait,
121 !self->tsap_data->connected);
122}
123
124/*
125 * Function irlan_eth_close (dev)
126 *
127 * Stop the ether network device, his function will usually be called by
128 * ifconfig down. We should now disconnect the link, We start the
129 * close timer, so that the instance will be removed if we are unable
130 * to discover the remote device after the disconnect.
131 */
132static int irlan_eth_close(struct net_device *dev)
133{
134 struct irlan_cb *self = netdev_priv(dev);
135
136 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
137
138 /* Stop device */
139 netif_stop_queue(dev);
140
141 irlan_close_data_channel(self);
142 irlan_close_tsaps(self);
143
144 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
145 irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
146
147 /* Remove frames queued on the control channel */
148 skb_queue_purge(&self->client.txq);
149
150 self->client.tx_busy = 0;
151
152 return 0;
153}
154
155/*
156 * Function irlan_eth_tx (skb)
157 *
158 * Transmits ethernet frames over IrDA link.
159 *
160 */
161static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
162{
163 struct irlan_cb *self = netdev_priv(dev);
164 int ret;
165
166 /* skb headroom large enough to contain all IrDA-headers? */
167 if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
168 struct sk_buff *new_skb =
169 skb_realloc_headroom(skb, self->max_header_size);
170
171 /* We have to free the original skb anyway */
172 dev_kfree_skb(skb);
173
174 /* Did the realloc succeed? */
175 if (new_skb == NULL)
176 return 0;
177
178 /* Use the new skb instead */
179 skb = new_skb;
180 }
181
182 dev->trans_start = jiffies;
183
184 /* Now queue the packet in the transport layer */
185 if (self->use_udata)
186 ret = irttp_udata_request(self->tsap_data, skb);
187 else
188 ret = irttp_data_request(self->tsap_data, skb);
189
190 if (ret < 0) {
191 /*
192 * IrTTPs tx queue is full, so we just have to
193 * drop the frame! You might think that we should
194 * just return -1 and don't deallocate the frame,
195 * but that is dangerous since it's possible that
196 * we have replaced the original skb with a new
197 * one with larger headroom, and that would really
198 * confuse do_dev_queue_xmit() in dev.c! I have
199 * tried :-) DB
200 */
201 /* irttp_data_request already free the packet */
202 self->stats.tx_dropped++;
203 } else {
204 self->stats.tx_packets++;
205 self->stats.tx_bytes += skb->len;
206 }
207
208 return 0;
209}
210
211/*
212 * Function irlan_eth_receive (handle, skb)
213 *
214 * This function gets the data that is received on the data channel
215 *
216 */
217int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
218{
219 struct irlan_cb *self = instance;
220
221 if (skb == NULL) {
222 ++self->stats.rx_dropped;
223 return 0;
224 }
225 if (skb->len < ETH_HLEN) {
226 IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
227 __FUNCTION__, skb->len);
228 ++self->stats.rx_dropped;
229 dev_kfree_skb(skb);
230 return 0;
231 }
232
233 /*
234 * Adopt this frame! Important to set all these fields since they
235 * might have been previously set by the low level IrDA network
236 * device driver
237 */
238 skb->dev = self->dev;
239 skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
240
241 self->stats.rx_packets++;
242 self->stats.rx_bytes += skb->len;
243
244 netif_rx(skb); /* Eat it! */
245
246 return 0;
247}
248
249/*
250 * Function irlan_eth_flow (status)
251 *
252 * Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by
253 * controlling the queue stop/start.
254 *
255 * The IrDA link layer has the advantage to have flow control, and
256 * IrTTP now properly handles that. Flow controlling the higher layers
257 * prevent us to drop Tx packets in here (up to 15% for a TCP socket,
258 * more for UDP socket).
259 * Also, this allow us to reduce the overall transmit queue, which means
260 * less latency in case of mixed traffic.
261 * Jean II
262 */
263void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
264{
265 struct irlan_cb *self;
266 struct net_device *dev;
267
268 self = (struct irlan_cb *) instance;
269
270 IRDA_ASSERT(self != NULL, return;);
271 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
272
273 dev = self->dev;
274
275 IRDA_ASSERT(dev != NULL, return;);
276
277 IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__,
278 flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
279 netif_running(dev));
280
281 switch (flow) {
282 case FLOW_STOP:
283 /* IrTTP is full, stop higher layers */
284 netif_stop_queue(dev);
285 break;
286 case FLOW_START:
287 default:
288 /* Tell upper layers that its time to transmit frames again */
289 /* Schedule network layer */
290 netif_wake_queue(dev);
291 break;
292 }
293}
294
295/*
296 * Function irlan_etc_send_gratuitous_arp (dev)
297 *
298 * Send gratuitous ARP to announce that we have changed
299 * hardware address, so that all peers updates their ARP tables
300 */
301void irlan_eth_send_gratuitous_arp(struct net_device *dev)
302{
303 struct in_device *in_dev;
304
305 /*
306 * When we get a new MAC address do a gratuitous ARP. This
307 * is useful if we have changed access points on the same
308 * subnet.
309 */
310#ifdef CONFIG_INET
311 IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
312 rcu_read_lock();
313 in_dev = __in_dev_get(dev);
314 if (in_dev == NULL)
315 goto out;
316 if (in_dev->ifa_list)
317
318 arp_send(ARPOP_REQUEST, ETH_P_ARP,
319 in_dev->ifa_list->ifa_address,
320 dev,
321 in_dev->ifa_list->ifa_address,
322 NULL, dev->dev_addr, NULL);
323out:
324 rcu_read_unlock();
325#endif /* CONFIG_INET */
326}
327
328/*
329 * Function set_multicast_list (dev)
330 *
331 * Configure the filtering of the device
332 *
333 */
334#define HW_MAX_ADDRS 4 /* Must query to get it! */
335static void irlan_eth_set_multicast_list(struct net_device *dev)
336{
337 struct irlan_cb *self = netdev_priv(dev);
338
339 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
340
341 /* Check if data channel has been connected yet */
342 if (self->client.state != IRLAN_DATA) {
343 IRDA_DEBUG(1, "%s(), delaying!\n", __FUNCTION__ );
344 return;
345 }
346
347 if (dev->flags & IFF_PROMISC) {
348 /* Enable promiscuous mode */
349 IRDA_WARNING("Promiscous mode not implemented by IrLAN!\n");
350 }
351 else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
352 /* Disable promiscuous mode, use normal mode. */
353 IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
354 /* hardware_set_filter(NULL); */
355
356 irlan_set_multicast_filter(self, TRUE);
357 }
358 else if (dev->mc_count) {
359 IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
360 /* Walk the address list, and load the filter */
361 /* hardware_set_filter(dev->mc_list); */
362
363 irlan_set_multicast_filter(self, TRUE);
364 }
365 else {
366 IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __FUNCTION__ );
367 irlan_set_multicast_filter(self, FALSE);
368 }
369
370 if (dev->flags & IFF_BROADCAST)
371 irlan_set_broadcast_filter(self, TRUE);
372 else
373 irlan_set_broadcast_filter(self, FALSE);
374}
375
376/*
377 * Function irlan_get_stats (dev)
378 *
379 * Get the current statistics for this device
380 *
381 */
382static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev)
383{
384 struct irlan_cb *self = netdev_priv(dev);
385
386 return &self->stats;
387}
diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c
new file mode 100644
index 000000000000..2778d8c6aa31
--- /dev/null
+++ b/net/irda/irlan/irlan_event.c
@@ -0,0 +1,60 @@
1/*********************************************************************
2 *
3 * Filename: irlan_event.c
4 * Version:
5 * Description:
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Tue Oct 20 09:10:16 1998
9 * Modified at: Sat Oct 30 12:59:01 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
18 *
19 * Neither Dag Brattli nor University of Tromsų admit liability nor
20 * provide warranty for any of this software. This material is
21 * provided "AS-IS" and at no charge.
22 *
23 ********************************************************************/
24
25#include <net/irda/irlan_event.h>
26
27char *irlan_state[] = {
28 "IRLAN_IDLE",
29 "IRLAN_QUERY",
30 "IRLAN_CONN",
31 "IRLAN_INFO",
32 "IRLAN_MEDIA",
33 "IRLAN_OPEN",
34 "IRLAN_WAIT",
35 "IRLAN_ARB",
36 "IRLAN_DATA",
37 "IRLAN_CLOSE",
38 "IRLAN_SYNC",
39};
40
41void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
42{
43 IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
44
45 IRDA_ASSERT(self != NULL, return;);
46 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
47
48 self->client.state = state;
49}
50
51void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state)
52{
53 IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
54
55 IRDA_ASSERT(self != NULL, return;);
56 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
57
58 self->provider.state = state;
59}
60
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
new file mode 100644
index 000000000000..343c5d4a1a1d
--- /dev/null
+++ b/net/irda/irlan/irlan_filter.c
@@ -0,0 +1,246 @@
1/*********************************************************************
2 *
3 * Filename: irlan_filter.c
4 * Version:
5 * Description:
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Fri Jan 29 11:16:38 1999
9 * Modified at: Sat Oct 30 12:58:45 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
18 *
19 * Neither Dag Brattli nor University of Tromsų admit liability nor
20 * provide warranty for any of this software. This material is
21 * provided "AS-IS" and at no charge.
22 *
23 ********************************************************************/
24
25#include <linux/skbuff.h>
26#include <linux/random.h>
27#include <linux/seq_file.h>
28
29#include <net/irda/irlan_common.h>
30
31/*
32 * Function irlan_filter_request (self, skb)
33 *
34 * Handle filter request from client peer device
35 *
36 */
37void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb)
38{
39 IRDA_ASSERT(self != NULL, return;);
40 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
41
42 if ((self->provider.filter_type == IRLAN_DIRECTED) &&
43 (self->provider.filter_operation == DYNAMIC))
44 {
45 IRDA_DEBUG(0, "Giving peer a dynamic Ethernet address\n");
46 self->provider.mac_address[0] = 0x40;
47 self->provider.mac_address[1] = 0x00;
48 self->provider.mac_address[2] = 0x00;
49 self->provider.mac_address[3] = 0x00;
50
51 /* Use arbitration value to generate MAC address */
52 if (self->provider.access_type == ACCESS_PEER) {
53 self->provider.mac_address[4] =
54 self->provider.send_arb_val & 0xff;
55 self->provider.mac_address[5] =
56 (self->provider.send_arb_val >> 8) & 0xff;
57 } else {
58 /* Just generate something for now */
59 get_random_bytes(self->provider.mac_address+4, 1);
60 get_random_bytes(self->provider.mac_address+5, 1);
61 }
62
63 skb->data[0] = 0x00; /* Success */
64 skb->data[1] = 0x03;
65 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
66 irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001);
67 irlan_insert_array_param(skb, "FILTER_ENTRY",
68 self->provider.mac_address, 6);
69 return;
70 }
71
72 if ((self->provider.filter_type == IRLAN_DIRECTED) &&
73 (self->provider.filter_mode == FILTER))
74 {
75 IRDA_DEBUG(0, "Directed filter on\n");
76 skb->data[0] = 0x00; /* Success */
77 skb->data[1] = 0x00;
78 return;
79 }
80 if ((self->provider.filter_type == IRLAN_DIRECTED) &&
81 (self->provider.filter_mode == NONE))
82 {
83 IRDA_DEBUG(0, "Directed filter off\n");
84 skb->data[0] = 0x00; /* Success */
85 skb->data[1] = 0x00;
86 return;
87 }
88
89 if ((self->provider.filter_type == IRLAN_BROADCAST) &&
90 (self->provider.filter_mode == FILTER))
91 {
92 IRDA_DEBUG(0, "Broadcast filter on\n");
93 skb->data[0] = 0x00; /* Success */
94 skb->data[1] = 0x00;
95 return;
96 }
97 if ((self->provider.filter_type == IRLAN_BROADCAST) &&
98 (self->provider.filter_mode == NONE))
99 {
100 IRDA_DEBUG(0, "Broadcast filter off\n");
101 skb->data[0] = 0x00; /* Success */
102 skb->data[1] = 0x00;
103 return;
104 }
105 if ((self->provider.filter_type == IRLAN_MULTICAST) &&
106 (self->provider.filter_mode == FILTER))
107 {
108 IRDA_DEBUG(0, "Multicast filter on\n");
109 skb->data[0] = 0x00; /* Success */
110 skb->data[1] = 0x00;
111 return;
112 }
113 if ((self->provider.filter_type == IRLAN_MULTICAST) &&
114 (self->provider.filter_mode == NONE))
115 {
116 IRDA_DEBUG(0, "Multicast filter off\n");
117 skb->data[0] = 0x00; /* Success */
118 skb->data[1] = 0x00;
119 return;
120 }
121 if ((self->provider.filter_type == IRLAN_MULTICAST) &&
122 (self->provider.filter_operation == GET))
123 {
124 IRDA_DEBUG(0, "Multicast filter get\n");
125 skb->data[0] = 0x00; /* Success? */
126 skb->data[1] = 0x02;
127 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
128 irlan_insert_short_param(skb, "MAX_ENTRY", 16);
129 return;
130 }
131 skb->data[0] = 0x00; /* Command not supported */
132 skb->data[1] = 0x00;
133
134 IRDA_DEBUG(0, "Not implemented!\n");
135}
136
137/*
138 * Function check_request_param (self, param, value)
139 *
140 * Check parameters in request from peer device
141 *
142 */
143void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
144{
145 __u8 *bytes;
146
147 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
148
149 bytes = value;
150
151 IRDA_ASSERT(self != NULL, return;);
152 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
153
154 IRDA_DEBUG(4, "%s, %s\n", param, value);
155
156 /*
157 * This is experimental!! DB.
158 */
159 if (strcmp(param, "MODE") == 0) {
160 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
161 self->use_udata = TRUE;
162 return;
163 }
164
165 /*
166 * FILTER_TYPE
167 */
168 if (strcmp(param, "FILTER_TYPE") == 0) {
169 if (strcmp(value, "DIRECTED") == 0) {
170 self->provider.filter_type = IRLAN_DIRECTED;
171 return;
172 }
173 if (strcmp(value, "MULTICAST") == 0) {
174 self->provider.filter_type = IRLAN_MULTICAST;
175 return;
176 }
177 if (strcmp(value, "BROADCAST") == 0) {
178 self->provider.filter_type = IRLAN_BROADCAST;
179 return;
180 }
181 }
182 /*
183 * FILTER_MODE
184 */
185 if (strcmp(param, "FILTER_MODE") == 0) {
186 if (strcmp(value, "ALL") == 0) {
187 self->provider.filter_mode = ALL;
188 return;
189 }
190 if (strcmp(value, "FILTER") == 0) {
191 self->provider.filter_mode = FILTER;
192 return;
193 }
194 if (strcmp(value, "NONE") == 0) {
195 self->provider.filter_mode = FILTER;
196 return;
197 }
198 }
199 /*
200 * FILTER_OPERATION
201 */
202 if (strcmp(param, "FILTER_OPERATION") == 0) {
203 if (strcmp(value, "DYNAMIC") == 0) {
204 self->provider.filter_operation = DYNAMIC;
205 return;
206 }
207 if (strcmp(value, "GET") == 0) {
208 self->provider.filter_operation = GET;
209 return;
210 }
211 }
212}
213
214/*
215 * Function irlan_print_filter (filter_type, buf)
216 *
217 * Print status of filter. Used by /proc file system
218 *
219 */
220#ifdef CONFIG_PROC_FS
221#define MASK2STR(m,s) { .mask = m, .str = s }
222
223void irlan_print_filter(struct seq_file *seq, int filter_type)
224{
225 static struct {
226 int mask;
227 const char *str;
228 } filter_mask2str[] = {
229 MASK2STR(IRLAN_DIRECTED, "DIRECTED"),
230 MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"),
231 MASK2STR(IRLAN_GROUP, "GROUP"),
232 MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"),
233 MASK2STR(IRLAN_MULTICAST, "MULTICAST"),
234 MASK2STR(IRLAN_BROADCAST, "BROADCAST"),
235 MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"),
236 MASK2STR(0, NULL)
237 }, *p;
238
239 for (p = filter_mask2str; p->str; p++) {
240 if (filter_type & p->mask)
241 seq_printf(seq, "%s ", p->str);
242 }
243 seq_putc(seq, '\n');
244}
245#undef MASK2STR
246#endif
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
new file mode 100644
index 000000000000..39c202d1c374
--- /dev/null
+++ b/net/irda/irlan/irlan_provider.c
@@ -0,0 +1,413 @@
1/*********************************************************************
2 *
3 * Filename: irlan_provider.c
4 * Version: 0.9
5 * Description: IrDA LAN Access Protocol Implementation
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 31 20:14:37 1997
9 * Modified at: Sat Oct 30 12:52:10 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
12 * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
13 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
14 *
15 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
16 * All Rights Reserved.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation; either version 2 of
21 * the License, or (at your option) any later version.
22 *
23 * Neither Dag Brattli nor University of Tromsų admit liability nor
24 * provide warranty for any of this software. This material is
25 * provided "AS-IS" and at no charge.
26 *
27 ********************************************************************/
28
29#include <linux/kernel.h>
30#include <linux/string.h>
31#include <linux/errno.h>
32#include <linux/netdevice.h>
33#include <linux/etherdevice.h>
34#include <linux/init.h>
35#include <linux/random.h>
36#include <linux/bitops.h>
37
38#include <asm/system.h>
39#include <asm/byteorder.h>
40
41#include <net/irda/irda.h>
42#include <net/irda/irttp.h>
43#include <net/irda/irlmp.h>
44#include <net/irda/irias_object.h>
45#include <net/irda/iriap.h>
46#include <net/irda/timer.h>
47
48#include <net/irda/irlan_common.h>
49#include <net/irda/irlan_eth.h>
50#include <net/irda/irlan_event.h>
51#include <net/irda/irlan_provider.h>
52#include <net/irda/irlan_filter.h>
53#include <net/irda/irlan_client.h>
54
55static void irlan_provider_connect_indication(void *instance, void *sap,
56 struct qos_info *qos,
57 __u32 max_sdu_size,
58 __u8 max_header_size,
59 struct sk_buff *skb);
60
61/*
62 * Function irlan_provider_control_data_indication (handle, skb)
63 *
64 * This function gets the data that is received on the control channel
65 *
66 */
67static int irlan_provider_data_indication(void *instance, void *sap,
68 struct sk_buff *skb)
69{
70 struct irlan_cb *self;
71 __u8 code;
72
73 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
74
75 self = (struct irlan_cb *) instance;
76
77 IRDA_ASSERT(self != NULL, return -1;);
78 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
79
80 IRDA_ASSERT(skb != NULL, return -1;);
81
82 code = skb->data[0];
83 switch(code) {
84 case CMD_GET_PROVIDER_INFO:
85 IRDA_DEBUG(4, "Got GET_PROVIDER_INFO command!\n");
86 irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb);
87 break;
88
89 case CMD_GET_MEDIA_CHAR:
90 IRDA_DEBUG(4, "Got GET_MEDIA_CHAR command!\n");
91 irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb);
92 break;
93 case CMD_OPEN_DATA_CHANNEL:
94 IRDA_DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n");
95 irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb);
96 break;
97 case CMD_FILTER_OPERATION:
98 IRDA_DEBUG(4, "Got FILTER_OPERATION command!\n");
99 irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
100 break;
101 case CMD_RECONNECT_DATA_CHAN:
102 IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __FUNCTION__ );
103 IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
104 break;
105 case CMD_CLOSE_DATA_CHAN:
106 IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
107 IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
108 break;
109 default:
110 IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
111 break;
112 }
113 return 0;
114}
115
116/*
117 * Function irlan_provider_connect_indication (handle, skb, priv)
118 *
119 * Got connection from peer IrLAN client
120 *
121 */
122static void irlan_provider_connect_indication(void *instance, void *sap,
123 struct qos_info *qos,
124 __u32 max_sdu_size,
125 __u8 max_header_size,
126 struct sk_buff *skb)
127{
128 struct irlan_cb *self;
129 struct tsap_cb *tsap;
130 __u32 saddr, daddr;
131
132 IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
133
134 self = (struct irlan_cb *) instance;
135 tsap = (struct tsap_cb *) sap;
136
137 IRDA_ASSERT(self != NULL, return;);
138 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
139
140 IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;);
141 IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;);
142
143 daddr = irttp_get_daddr(tsap);
144 saddr = irttp_get_saddr(tsap);
145 self->provider.max_sdu_size = max_sdu_size;
146 self->provider.max_header_size = max_header_size;
147
148 irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL);
149
150 /*
151 * If we are in peer mode, the client may not have got the discovery
152 * indication it needs to make progress. If the client is still in
153 * IDLE state, we must kick it.
154 */
155 if ((self->provider.access_type == ACCESS_PEER) &&
156 (self->client.state == IRLAN_IDLE))
157 {
158 irlan_client_wakeup(self, self->saddr, self->daddr);
159 }
160}
161
162/*
163 * Function irlan_provider_connect_response (handle)
164 *
165 * Accept incoming connection
166 *
167 */
168void irlan_provider_connect_response(struct irlan_cb *self,
169 struct tsap_cb *tsap)
170{
171 IRDA_ASSERT(self != NULL, return;);
172 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
173
174 /* Just accept */
175 irttp_connect_response(tsap, IRLAN_MTU, NULL);
176}
177
178static void irlan_provider_disconnect_indication(void *instance, void *sap,
179 LM_REASON reason,
180 struct sk_buff *userdata)
181{
182 struct irlan_cb *self;
183 struct tsap_cb *tsap;
184
185 IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
186
187 self = (struct irlan_cb *) instance;
188 tsap = (struct tsap_cb *) sap;
189
190 IRDA_ASSERT(self != NULL, return;);
191 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
192 IRDA_ASSERT(tsap != NULL, return;);
193 IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
194
195 IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;);
196
197 irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
198}
199
200/*
201 * Function irlan_parse_open_data_cmd (self, skb)
202 *
203 *
204 *
205 */
206int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb)
207{
208 int ret;
209
210 ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
211
212 /* Open data channel */
213 irlan_open_data_tsap(self);
214
215 return ret;
216}
217
218/*
219 * Function parse_command (skb)
220 *
221 * Extract all parameters from received buffer, then feed them to
222 * check_params for parsing
223 *
224 */
225int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
226 struct sk_buff *skb)
227{
228 __u8 *frame;
229 __u8 *ptr;
230 int count;
231 __u16 val_len;
232 int i;
233 char *name;
234 char *value;
235 int ret = RSP_SUCCESS;
236
237 IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
238
239 IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len);
240
241 IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
242 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
243
244 if (!skb)
245 return -RSP_PROTOCOL_ERROR;
246
247 frame = skb->data;
248
249 name = kmalloc(255, GFP_ATOMIC);
250 if (!name)
251 return -RSP_INSUFFICIENT_RESOURCES;
252 value = kmalloc(1016, GFP_ATOMIC);
253 if (!value) {
254 kfree(name);
255 return -RSP_INSUFFICIENT_RESOURCES;
256 }
257
258 /* How many parameters? */
259 count = frame[1];
260
261 IRDA_DEBUG(4, "Got %d parameters\n", count);
262
263 ptr = frame+2;
264
265 /* For all parameters */
266 for (i=0; i<count;i++) {
267 ret = irlan_extract_param(ptr, name, value, &val_len);
268 if (ret < 0) {
269 IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
270 break;
271 }
272 ptr+=ret;
273 ret = RSP_SUCCESS;
274 irlan_check_command_param(self, name, value);
275 }
276 /* Cleanup */
277 kfree(name);
278 kfree(value);
279
280 return ret;
281}
282
283/*
284 * Function irlan_provider_send_reply (self, info)
285 *
286 * Send reply to query to peer IrLAN layer
287 *
288 */
289void irlan_provider_send_reply(struct irlan_cb *self, int command,
290 int ret_code)
291{
292 struct sk_buff *skb;
293
294 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
295
296 IRDA_ASSERT(self != NULL, return;);
297 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
298
299 skb = dev_alloc_skb(128);
300 if (!skb)
301 return;
302
303 /* Reserve space for TTP, LMP, and LAP header */
304 skb_reserve(skb, self->provider.max_header_size);
305 skb_put(skb, 2);
306
307 switch (command) {
308 case CMD_GET_PROVIDER_INFO:
309 skb->data[0] = 0x00; /* Success */
310 skb->data[1] = 0x02; /* 2 parameters */
311 switch (self->media) {
312 case MEDIA_802_3:
313 irlan_insert_string_param(skb, "MEDIA", "802.3");
314 break;
315 case MEDIA_802_5:
316 irlan_insert_string_param(skb, "MEDIA", "802.5");
317 break;
318 default:
319 IRDA_DEBUG(2, "%s(), unknown media type!\n", __FUNCTION__ );
320 break;
321 }
322 irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
323 break;
324
325 case CMD_GET_MEDIA_CHAR:
326 skb->data[0] = 0x00; /* Success */
327 skb->data[1] = 0x05; /* 5 parameters */
328 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
329 irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
330 irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
331
332 switch (self->provider.access_type) {
333 case ACCESS_DIRECT:
334 irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
335 break;
336 case ACCESS_PEER:
337 irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER");
338 break;
339 case ACCESS_HOSTED:
340 irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
341 break;
342 default:
343 IRDA_DEBUG(2, "%s(), Unknown access type\n", __FUNCTION__ );
344 break;
345 }
346 irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
347 break;
348 case CMD_OPEN_DATA_CHANNEL:
349 skb->data[0] = 0x00; /* Success */
350 if (self->provider.send_arb_val) {
351 skb->data[1] = 0x03; /* 3 parameters */
352 irlan_insert_short_param(skb, "CON_ARB",
353 self->provider.send_arb_val);
354 } else
355 skb->data[1] = 0x02; /* 2 parameters */
356 irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data);
357 irlan_insert_array_param(skb, "RECONNECT_KEY", "LINUX RULES!",
358 12);
359 break;
360 case CMD_FILTER_OPERATION:
361 irlan_filter_request(self, skb);
362 break;
363 default:
364 IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
365 break;
366 }
367
368 irttp_data_request(self->provider.tsap_ctrl, skb);
369}
370
371/*
372 * Function irlan_provider_register(void)
373 *
374 * Register provider support so we can accept incoming connections.
375 *
376 */
377int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
378{
379 struct tsap_cb *tsap;
380 notify_t notify;
381
382 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
383
384 IRDA_ASSERT(self != NULL, return -1;);
385 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
386
387 /* Check if already open */
388 if (self->provider.tsap_ctrl)
389 return -1;
390
391 /*
392 * First register well known control TSAP
393 */
394 irda_notify_init(&notify);
395 notify.data_indication = irlan_provider_data_indication;
396 notify.connect_indication = irlan_provider_connect_indication;
397 notify.disconnect_indication = irlan_provider_disconnect_indication;
398 notify.instance = self;
399 strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name));
400
401 tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
402 if (!tsap) {
403 IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
404 return -1;
405 }
406 self->provider.tsap_ctrl = tsap;
407
408 /* Register with LM-IAS */
409 irlan_ias_register(self, tsap->stsap_sel);
410
411 return 0;
412}
413
diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c
new file mode 100644
index 000000000000..5a086f9827ed
--- /dev/null
+++ b/net/irda/irlan/irlan_provider_event.c
@@ -0,0 +1,241 @@
1/*********************************************************************
2 *
3 * Filename: irlan_provider_event.c
4 * Version: 0.9
5 * Description: IrLAN provider state machine)
6 * Status: Experimental.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 31 20:14:37 1997
9 * Modified at: Sat Oct 30 12:52:41 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
18 *
19 * Neither Dag Brattli nor University of Tromsų admit liability nor
20 * provide warranty for any of this software. This material is
21 * provided "AS-IS" and at no charge.
22 *
23 ********************************************************************/
24
25#include <net/irda/irda.h>
26#include <net/irda/iriap.h>
27#include <net/irda/irlmp.h>
28#include <net/irda/irttp.h>
29
30#include <net/irda/irlan_provider.h>
31#include <net/irda/irlan_event.h>
32
33static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
34 struct sk_buff *skb);
35static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
36 struct sk_buff *skb);
37static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
38 struct sk_buff *skb);
39static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
40 struct sk_buff *skb);
41
42static int (*state[])(struct irlan_cb *self, IRLAN_EVENT event,
43 struct sk_buff *skb) =
44{
45 irlan_provider_state_idle,
46 NULL, /* Query */
47 NULL, /* Info */
48 irlan_provider_state_info,
49 NULL, /* Media */
50 irlan_provider_state_open,
51 NULL, /* Wait */
52 NULL, /* Arb */
53 irlan_provider_state_data,
54 NULL, /* Close */
55 NULL, /* Sync */
56};
57
58void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event,
59 struct sk_buff *skb)
60{
61 IRDA_ASSERT(*state[ self->provider.state] != NULL, return;);
62
63 (*state[self->provider.state]) (self, event, skb);
64}
65
66/*
67 * Function irlan_provider_state_idle (event, skb, info)
68 *
69 * IDLE, We are waiting for an indication that there is a provider
70 * available.
71 */
72static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
73 struct sk_buff *skb)
74{
75 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
76
77 IRDA_ASSERT(self != NULL, return -1;);
78
79 switch(event) {
80 case IRLAN_CONNECT_INDICATION:
81 irlan_provider_connect_response( self, self->provider.tsap_ctrl);
82 irlan_next_provider_state( self, IRLAN_INFO);
83 break;
84 default:
85 IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
86 break;
87 }
88 if (skb)
89 dev_kfree_skb(skb);
90
91 return 0;
92}
93
94/*
95 * Function irlan_provider_state_info (self, event, skb, info)
96 *
97 * INFO, We have issued a GetInfo command and is awaiting a reply.
98 */
99static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
100 struct sk_buff *skb)
101{
102 int ret;
103
104 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
105
106 IRDA_ASSERT(self != NULL, return -1;);
107
108 switch(event) {
109 case IRLAN_GET_INFO_CMD:
110 /* Be sure to use 802.3 in case of peer mode */
111 if (self->provider.access_type == ACCESS_PEER) {
112 self->media = MEDIA_802_3;
113
114 /* Check if client has started yet */
115 if (self->client.state == IRLAN_IDLE) {
116 /* This should get the client going */
117 irlmp_discovery_request(8);
118 }
119 }
120
121 irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO,
122 RSP_SUCCESS);
123 /* Keep state */
124 break;
125 case IRLAN_GET_MEDIA_CMD:
126 irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR,
127 RSP_SUCCESS);
128 /* Keep state */
129 break;
130 case IRLAN_OPEN_DATA_CMD:
131 ret = irlan_parse_open_data_cmd(self, skb);
132 if (self->provider.access_type == ACCESS_PEER) {
133 /* FIXME: make use of random functions! */
134 self->provider.send_arb_val = (jiffies & 0xffff);
135 }
136 irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret);
137
138 if (ret == RSP_SUCCESS) {
139 irlan_next_provider_state(self, IRLAN_OPEN);
140
141 /* Signal client that we are now open */
142 irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL);
143 }
144 break;
145 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
146 case IRLAN_LAP_DISCONNECT:
147 irlan_next_provider_state(self, IRLAN_IDLE);
148 break;
149 default:
150 IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
151 break;
152 }
153 if (skb)
154 dev_kfree_skb(skb);
155
156 return 0;
157}
158
159/*
160 * Function irlan_provider_state_open (self, event, skb, info)
161 *
162 * OPEN, The client has issued a OpenData command and is awaiting a
163 * reply
164 *
165 */
166static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
167 struct sk_buff *skb)
168{
169 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
170
171 IRDA_ASSERT(self != NULL, return -1;);
172
173 switch(event) {
174 case IRLAN_FILTER_CONFIG_CMD:
175 irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
176 irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
177 RSP_SUCCESS);
178 /* Keep state */
179 break;
180 case IRLAN_DATA_CONNECT_INDICATION:
181 irlan_next_provider_state(self, IRLAN_DATA);
182 irlan_provider_connect_response(self, self->tsap_data);
183 break;
184 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
185 case IRLAN_LAP_DISCONNECT:
186 irlan_next_provider_state(self, IRLAN_IDLE);
187 break;
188 default:
189 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
190 break;
191 }
192 if (skb)
193 dev_kfree_skb(skb);
194
195 return 0;
196}
197
198/*
199 * Function irlan_provider_state_data (self, event, skb, info)
200 *
201 * DATA, The data channel is connected, allowing data transfers between
202 * the local and remote machines.
203 *
204 */
205static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
206 struct sk_buff *skb)
207{
208 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
209
210 IRDA_ASSERT(self != NULL, return -1;);
211 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
212
213 switch(event) {
214 case IRLAN_FILTER_CONFIG_CMD:
215 irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
216 irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
217 RSP_SUCCESS);
218 break;
219 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
220 case IRLAN_LAP_DISCONNECT:
221 irlan_next_provider_state(self, IRLAN_IDLE);
222 break;
223 default:
224 IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
225 break;
226 }
227 if (skb)
228 dev_kfree_skb(skb);
229
230 return 0;
231}
232
233
234
235
236
237
238
239
240
241