1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/module.h>
27
28#include <linux/kernel.h>
29#include <linux/string.h>
30#include <linux/gfp.h>
31#include <linux/init.h>
32#include <linux/errno.h>
33#include <linux/proc_fs.h>
34#include <linux/sched.h>
35#include <linux/seq_file.h>
36#include <linux/random.h>
37#include <linux/netdevice.h>
38#include <linux/etherdevice.h>
39#include <linux/rtnetlink.h>
40#include <linux/moduleparam.h>
41#include <linux/bitops.h>
42
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
60
61
62
63static LIST_HEAD(irlans);
64
65static void *ckey;
66static void *skey;
67
68
69static bool eth;
70static int access = ACCESS_PEER;
71
72#ifdef CONFIG_PROC_FS
73static const char *const irlan_access[] = {
74 "UNKNOWN",
75 "DIRECT",
76 "PEER",
77 "HOSTED"
78};
79
80static const char *const irlan_media[] = {
81 "UNKNOWN",
82 "802.3",
83 "802.5"
84};
85
86extern struct proc_dir_entry *proc_irda;
87
88static int irlan_seq_open(struct inode *inode, struct file *file);
89
90static const struct file_operations irlan_fops = {
91 .owner = THIS_MODULE,
92 .open = irlan_seq_open,
93 .read = seq_read,
94 .llseek = seq_lseek,
95 .release = seq_release,
96};
97
98extern struct proc_dir_entry *proc_irda;
99#endif
100
101static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr);
102static void __irlan_close(struct irlan_cb *self);
103static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
104 __u8 value_byte, __u16 value_short,
105 __u8 *value_array, __u16 value_len);
106static void irlan_open_unicast_addr(struct irlan_cb *self);
107static void irlan_get_unicast_addr(struct irlan_cb *self);
108void irlan_close_tsaps(struct irlan_cb *self);
109
110
111
112
113
114
115
116static int __init irlan_init(void)
117{
118 struct irlan_cb *new;
119 __u16 hints;
120
121 IRDA_DEBUG(2, "%s()\n", __func__ );
122
123#ifdef CONFIG_PROC_FS
124 { struct proc_dir_entry *proc;
125 proc = proc_create("irlan", 0, proc_irda, &irlan_fops);
126 if (!proc) {
127 printk(KERN_ERR "irlan_init: can't create /proc entry!\n");
128 return -ENODEV;
129 }
130 }
131#endif
132
133 IRDA_DEBUG(4, "%s()\n", __func__ );
134 hints = irlmp_service_to_hint(S_LAN);
135
136
137 ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
138 NULL, NULL);
139 if (!ckey)
140 goto err_ckey;
141
142
143 skey = irlmp_register_service(hints);
144 if (!skey)
145 goto err_skey;
146
147
148 new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
149 if (!new)
150 goto err_open;
151
152
153 irlan_provider_open_ctrl_tsap(new);
154
155
156 irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
157
158 return 0;
159
160err_open:
161 irlmp_unregister_service(skey);
162err_skey:
163 irlmp_unregister_client(ckey);
164err_ckey:
165#ifdef CONFIG_PROC_FS
166 remove_proc_entry("irlan", proc_irda);
167#endif
168
169 return -ENOMEM;
170}
171
172static void __exit irlan_cleanup(void)
173{
174 struct irlan_cb *self, *next;
175
176 IRDA_DEBUG(4, "%s()\n", __func__ );
177
178 irlmp_unregister_client(ckey);
179 irlmp_unregister_service(skey);
180
181#ifdef CONFIG_PROC_FS
182 remove_proc_entry("irlan", proc_irda);
183#endif
184
185
186 rtnl_lock();
187 list_for_each_entry_safe(self, next, &irlans, dev_list) {
188 __irlan_close(self);
189 }
190 rtnl_unlock();
191}
192
193
194
195
196
197
198
199static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
200{
201 struct net_device *dev;
202 struct irlan_cb *self;
203
204 IRDA_DEBUG(2, "%s()\n", __func__ );
205
206
207 dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
208 if (!dev)
209 return NULL;
210
211 self = netdev_priv(dev);
212 self->dev = dev;
213
214
215
216
217 self->magic = IRLAN_MAGIC;
218 self->saddr = saddr;
219 self->daddr = daddr;
220
221
222 self->provider.access_type = access;
223 if (access == ACCESS_DIRECT) {
224
225
226
227
228 dev->dev_addr[0] = 0x40;
229 dev->dev_addr[1] = 0x00;
230 dev->dev_addr[2] = 0x00;
231 dev->dev_addr[3] = 0x00;
232 get_random_bytes(dev->dev_addr+4, 1);
233 get_random_bytes(dev->dev_addr+5, 1);
234 }
235
236 self->media = MEDIA_802_3;
237 self->disconnect_reason = LM_USER_REQUEST;
238 init_timer(&self->watchdog_timer);
239 init_timer(&self->client.kick_timer);
240 init_waitqueue_head(&self->open_wait);
241
242 skb_queue_head_init(&self->client.txq);
243
244 irlan_next_client_state(self, IRLAN_IDLE);
245 irlan_next_provider_state(self, IRLAN_IDLE);
246
247 if (register_netdev(dev)) {
248 IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
249 __func__ );
250 self = NULL;
251 free_netdev(dev);
252 } else {
253 rtnl_lock();
254 list_add_rcu(&self->dev_list, &irlans);
255 rtnl_unlock();
256 }
257
258 return self;
259}
260
261
262
263
264
265
266
267static void __irlan_close(struct irlan_cb *self)
268{
269 IRDA_DEBUG(2, "%s()\n", __func__ );
270
271 ASSERT_RTNL();
272 IRDA_ASSERT(self != NULL, return;);
273 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
274
275 del_timer_sync(&self->watchdog_timer);
276 del_timer_sync(&self->client.kick_timer);
277
278
279 irlan_close_tsaps(self);
280
281 if (self->client.iriap)
282 iriap_close(self->client.iriap);
283
284
285 skb_queue_purge(&self->client.txq);
286
287
288 unregister_netdevice(self->dev);
289}
290
291
292struct irlan_cb *irlan_get_any(void)
293{
294 struct irlan_cb *self;
295
296 list_for_each_entry_rcu(self, &irlans, dev_list) {
297 return self;
298 }
299 return NULL;
300}
301
302
303
304
305
306
307
308static void irlan_connect_indication(void *instance, void *sap,
309 struct qos_info *qos,
310 __u32 max_sdu_size,
311 __u8 max_header_size,
312 struct sk_buff *skb)
313{
314 struct irlan_cb *self;
315 struct tsap_cb *tsap;
316
317 IRDA_DEBUG(2, "%s()\n", __func__ );
318
319 self = instance;
320 tsap = sap;
321
322 IRDA_ASSERT(self != NULL, return;);
323 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
324 IRDA_ASSERT(tsap == self->tsap_data,return;);
325
326 self->max_sdu_size = max_sdu_size;
327 self->max_header_size = max_header_size;
328
329 IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
330
331 del_timer(&self->watchdog_timer);
332
333
334
335
336
337 if (skb)
338 dev_kfree_skb(skb);
339
340 irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
341 irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL);
342
343 if (self->provider.access_type == ACCESS_PEER) {
344
345
346
347
348 irlan_get_unicast_addr(self);
349 irlan_open_unicast_addr(self);
350 }
351
352 netif_start_queue(self->dev);
353}
354
355static void irlan_connect_confirm(void *instance, void *sap,
356 struct qos_info *qos,
357 __u32 max_sdu_size,
358 __u8 max_header_size,
359 struct sk_buff *skb)
360{
361 struct irlan_cb *self;
362
363 self = instance;
364
365 IRDA_ASSERT(self != NULL, return;);
366 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
367
368 self->max_sdu_size = max_sdu_size;
369 self->max_header_size = max_header_size;
370
371
372
373 IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
374 del_timer(&self->watchdog_timer);
375
376
377
378
379
380 irlan_get_unicast_addr(self);
381 irlan_open_unicast_addr(self);
382
383
384 irlan_set_broadcast_filter(self, TRUE);
385 irlan_set_multicast_filter(self, TRUE);
386
387
388 netif_start_queue(self->dev);
389 self->disconnect_reason = 0;
390 wake_up_interruptible(&self->open_wait);
391}
392
393
394
395
396
397
398
399static void irlan_disconnect_indication(void *instance,
400 void *sap, LM_REASON reason,
401 struct sk_buff *userdata)
402{
403 struct irlan_cb *self;
404 struct tsap_cb *tsap;
405
406 IRDA_DEBUG(0, "%s(), reason=%d\n", __func__ , reason);
407
408 self = instance;
409 tsap = sap;
410
411 IRDA_ASSERT(self != NULL, return;);
412 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
413 IRDA_ASSERT(tsap != NULL, return;);
414 IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
415
416 IRDA_ASSERT(tsap == self->tsap_data, return;);
417
418 IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
419
420
421 self->disconnect_reason = reason;
422
423 switch (reason) {
424 case LM_USER_REQUEST:
425 IRDA_DEBUG(2, "%s(), User requested\n", __func__ );
426 break;
427 case LM_LAP_DISCONNECT:
428 IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __func__ );
429 break;
430 case LM_CONNECT_FAILURE:
431 IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __func__ );
432 break;
433 case LM_LAP_RESET:
434 IRDA_DEBUG(2, "%s(), IrLAP reset\n", __func__ );
435 break;
436 case LM_INIT_DISCONNECT:
437 IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __func__ );
438 break;
439 default:
440 IRDA_ERROR("%s(), Unknown disconnect reason\n", __func__);
441 break;
442 }
443
444
445
446
447
448 if (userdata)
449 dev_kfree_skb(userdata);
450
451 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
452 irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
453
454 wake_up_interruptible(&self->open_wait);
455}
456
457void irlan_open_data_tsap(struct irlan_cb *self)
458{
459 struct tsap_cb *tsap;
460 notify_t notify;
461
462 IRDA_DEBUG(2, "%s()\n", __func__ );
463
464 IRDA_ASSERT(self != NULL, return;);
465 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
466
467
468 if (self->tsap_data)
469 return;
470
471 irda_notify_init(¬ify);
472
473 notify.data_indication = irlan_eth_receive;
474 notify.udata_indication = irlan_eth_receive;
475 notify.connect_indication = irlan_connect_indication;
476 notify.connect_confirm = irlan_connect_confirm;
477 notify.flow_indication = irlan_eth_flow_indication;
478 notify.disconnect_indication = irlan_disconnect_indication;
479 notify.instance = self;
480 strlcpy(notify.name, "IrLAN data", sizeof(notify.name));
481
482 tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
483 if (!tsap) {
484 IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
485 return;
486 }
487 self->tsap_data = tsap;
488
489
490
491
492
493 self->stsap_sel_data = self->tsap_data->stsap_sel;
494}
495
496void irlan_close_tsaps(struct irlan_cb *self)
497{
498 IRDA_DEBUG(4, "%s()\n", __func__ );
499
500 IRDA_ASSERT(self != NULL, return;);
501 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
502
503
504 if (self->tsap_data) {
505 irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
506 irttp_close_tsap(self->tsap_data);
507 self->tsap_data = NULL;
508 }
509 if (self->client.tsap_ctrl) {
510 irttp_disconnect_request(self->client.tsap_ctrl, NULL,
511 P_NORMAL);
512 irttp_close_tsap(self->client.tsap_ctrl);
513 self->client.tsap_ctrl = NULL;
514 }
515 if (self->provider.tsap_ctrl) {
516 irttp_disconnect_request(self->provider.tsap_ctrl, NULL,
517 P_NORMAL);
518 irttp_close_tsap(self->provider.tsap_ctrl);
519 self->provider.tsap_ctrl = NULL;
520 }
521 self->disconnect_reason = LM_USER_REQUEST;
522}
523
524
525
526
527
528
529
530void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
531{
532 struct ias_object *obj;
533 struct ias_value *new_value;
534
535 IRDA_ASSERT(self != NULL, return;);
536 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
537
538
539
540
541
542 if (!irias_find_object("IrLAN")) {
543 obj = irias_new_object("IrLAN", IAS_IRLAN_ID);
544 irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel,
545 IAS_KERNEL_ATTR);
546 irias_insert_object(obj);
547 } else {
548 new_value = irias_new_integer_value(tsap_sel);
549 irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel",
550 new_value);
551 }
552
553
554 if (!irias_find_object("PnP")) {
555 obj = irias_new_object("PnP", IAS_PNP_ID);
556#if 0
557 irias_add_string_attrib(obj, "Name", sysctl_devname,
558 IAS_KERNEL_ATTR);
559#else
560 irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR);
561#endif
562 irias_add_string_attrib(obj, "DeviceID", "HWP19F0",
563 IAS_KERNEL_ATTR);
564 irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR);
565 if (self->provider.access_type == ACCESS_PEER)
566 irias_add_string_attrib(obj, "Comp#01", "PNP8389",
567 IAS_KERNEL_ATTR);
568 else
569 irias_add_string_attrib(obj, "Comp#01", "PNP8294",
570 IAS_KERNEL_ATTR);
571
572 irias_add_string_attrib(obj, "Manufacturer",
573 "Linux-IrDA Project", IAS_KERNEL_ATTR);
574 irias_insert_object(obj);
575 }
576}
577
578
579
580
581
582
583
584int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
585{
586 struct sk_buff *skb;
587
588 IRDA_DEBUG(2, "%s()\n", __func__ );
589
590 if (irda_lock(&self->client.tx_busy) == FALSE)
591 return -EBUSY;
592
593 skb = skb_dequeue(&self->client.txq);
594 if (!skb) {
595 self->client.tx_busy = FALSE;
596 return 0;
597 }
598
599
600 if ((self->client.tsap_ctrl == NULL) ||
601 (self->client.state == IRLAN_IDLE))
602 {
603 self->client.tx_busy = FALSE;
604 dev_kfree_skb(skb);
605 return -1;
606 }
607 IRDA_DEBUG(2, "%s(), sending ...\n", __func__ );
608
609 return irttp_data_request(self->client.tsap_ctrl, skb);
610}
611
612
613
614
615
616
617
618static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
619{
620 IRDA_DEBUG(2, "%s()\n", __func__ );
621
622
623 skb_queue_tail(&self->client.txq, skb);
624
625
626 irlan_run_ctrl_tx_queue(self);
627}
628
629
630
631
632
633
634
635void irlan_get_provider_info(struct irlan_cb *self)
636{
637 struct sk_buff *skb;
638 __u8 *frame;
639
640 IRDA_DEBUG(4, "%s()\n", __func__ );
641
642 IRDA_ASSERT(self != NULL, return;);
643 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
644
645 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER,
646 GFP_ATOMIC);
647 if (!skb)
648 return;
649
650
651 skb_reserve(skb, self->client.max_header_size);
652 skb_put(skb, 2);
653
654 frame = skb->data;
655
656 frame[0] = CMD_GET_PROVIDER_INFO;
657 frame[1] = 0x00;
658
659 irlan_ctrl_data_request(self, skb);
660}
661
662
663
664
665
666
667
668void irlan_open_data_channel(struct irlan_cb *self)
669{
670 struct sk_buff *skb;
671 __u8 *frame;
672
673 IRDA_DEBUG(4, "%s()\n", __func__ );
674
675 IRDA_ASSERT(self != NULL, return;);
676 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
677
678 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
679 IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") +
680 IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"),
681 GFP_ATOMIC);
682 if (!skb)
683 return;
684
685 skb_reserve(skb, self->client.max_header_size);
686 skb_put(skb, 2);
687
688 frame = skb->data;
689
690
691 frame[0] = CMD_OPEN_DATA_CHANNEL;
692 frame[1] = 0x02;
693
694 irlan_insert_string_param(skb, "MEDIA", "802.3");
695 irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
696
697
698
699
700 irlan_ctrl_data_request(self, skb);
701}
702
703void irlan_close_data_channel(struct irlan_cb *self)
704{
705 struct sk_buff *skb;
706 __u8 *frame;
707
708 IRDA_DEBUG(4, "%s()\n", __func__ );
709
710 IRDA_ASSERT(self != NULL, return;);
711 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
712
713
714 if (self->client.tsap_ctrl == NULL)
715 return;
716
717 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
718 IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"),
719 GFP_ATOMIC);
720 if (!skb)
721 return;
722
723 skb_reserve(skb, self->client.max_header_size);
724 skb_put(skb, 2);
725
726 frame = skb->data;
727
728
729 frame[0] = CMD_CLOSE_DATA_CHAN;
730 frame[1] = 0x01;
731
732 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
733
734 irlan_ctrl_data_request(self, skb);
735}
736
737
738
739
740
741
742
743
744static void irlan_open_unicast_addr(struct irlan_cb *self)
745{
746 struct sk_buff *skb;
747 __u8 *frame;
748
749 IRDA_DEBUG(4, "%s()\n", __func__ );
750
751 IRDA_ASSERT(self != NULL, return;);
752 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
753
754 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
755 IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
756 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
757 IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
758 GFP_ATOMIC);
759 if (!skb)
760 return;
761
762
763 skb_reserve(skb, self->max_header_size);
764 skb_put(skb, 2);
765
766 frame = skb->data;
767
768 frame[0] = CMD_FILTER_OPERATION;
769 frame[1] = 0x03;
770 irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data);
771 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
772 irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
773
774 irlan_ctrl_data_request(self, skb);
775}
776
777
778
779
780
781
782
783
784
785
786void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
787{
788 struct sk_buff *skb;
789 __u8 *frame;
790
791 IRDA_DEBUG(2, "%s()\n", __func__ );
792
793 IRDA_ASSERT(self != NULL, return;);
794 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
795
796 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
797 IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
798 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
799
800 IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
801 GFP_ATOMIC);
802 if (!skb)
803 return;
804
805
806 skb_reserve(skb, self->client.max_header_size);
807 skb_put(skb, 2);
808
809 frame = skb->data;
810
811 frame[0] = CMD_FILTER_OPERATION;
812 frame[1] = 0x03;
813 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
814 irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
815 if (status)
816 irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
817 else
818 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
819
820 irlan_ctrl_data_request(self, skb);
821}
822
823
824
825
826
827
828
829
830void irlan_set_multicast_filter(struct irlan_cb *self, int status)
831{
832 struct sk_buff *skb;
833 __u8 *frame;
834
835 IRDA_DEBUG(2, "%s()\n", __func__ );
836
837 IRDA_ASSERT(self != NULL, return;);
838 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
839
840 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
841 IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
842 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
843
844 IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"),
845 GFP_ATOMIC);
846 if (!skb)
847 return;
848
849
850 skb_reserve(skb, self->client.max_header_size);
851 skb_put(skb, 2);
852
853 frame = skb->data;
854
855 frame[0] = CMD_FILTER_OPERATION;
856 frame[1] = 0x03;
857 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
858 irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
859 if (status)
860 irlan_insert_string_param(skb, "FILTER_MODE", "ALL");
861 else
862 irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
863
864 irlan_ctrl_data_request(self, skb);
865}
866
867
868
869
870
871
872
873
874
875static void irlan_get_unicast_addr(struct irlan_cb *self)
876{
877 struct sk_buff *skb;
878 __u8 *frame;
879
880 IRDA_DEBUG(2, "%s()\n", __func__ );
881
882 IRDA_ASSERT(self != NULL, return;);
883 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
884
885 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
886 IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
887 IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
888 IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION",
889 "DYNAMIC"),
890 GFP_ATOMIC);
891 if (!skb)
892 return;
893
894
895 skb_reserve(skb, self->client.max_header_size);
896 skb_put(skb, 2);
897
898 frame = skb->data;
899
900 frame[0] = CMD_FILTER_OPERATION;
901 frame[1] = 0x03;
902 irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
903 irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
904 irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC");
905
906 irlan_ctrl_data_request(self, skb);
907}
908
909
910
911
912
913
914
915void irlan_get_media_char(struct irlan_cb *self)
916{
917 struct sk_buff *skb;
918 __u8 *frame;
919
920 IRDA_DEBUG(4, "%s()\n", __func__ );
921
922 IRDA_ASSERT(self != NULL, return;);
923 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
924
925 skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
926 IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"),
927 GFP_ATOMIC);
928
929 if (!skb)
930 return;
931
932
933 skb_reserve(skb, self->client.max_header_size);
934 skb_put(skb, 2);
935
936 frame = skb->data;
937
938
939 frame[0] = CMD_GET_MEDIA_CHAR;
940 frame[1] = 0x01;
941
942 irlan_insert_string_param(skb, "MEDIA", "802.3");
943 irlan_ctrl_data_request(self, skb);
944}
945
946
947
948
949
950
951
952int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value)
953{
954 return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0);
955}
956
957int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value)
958{
959 return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0);
960}
961
962
963
964
965
966
967
968int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string)
969{
970 int string_len = strlen(string);
971
972 return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string,
973 string_len);
974}
975
976
977
978
979
980
981
982int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array,
983 __u16 array_len)
984{
985 return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array,
986 array_len);
987}
988
989
990
991
992
993
994
995
996
997
998static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
999 __u8 value_byte, __u16 value_short,
1000 __u8 *value_array, __u16 value_len)
1001{
1002 __u8 *frame;
1003 __u8 param_len;
1004 __le16 tmp_le;
1005 int n=0;
1006
1007 if (skb == NULL) {
1008 IRDA_DEBUG(2, "%s(), Got NULL skb\n", __func__ );
1009 return 0;
1010 }
1011
1012 param_len = strlen(param);
1013 switch (type) {
1014 case IRLAN_BYTE:
1015 value_len = 1;
1016 break;
1017 case IRLAN_SHORT:
1018 value_len = 2;
1019 break;
1020 case IRLAN_ARRAY:
1021 IRDA_ASSERT(value_array != NULL, return 0;);
1022 IRDA_ASSERT(value_len > 0, return 0;);
1023 break;
1024 default:
1025 IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ );
1026 return 0;
1027 break;
1028 }
1029
1030
1031 frame = skb_tail_pointer(skb);
1032
1033
1034 if (skb_tailroom(skb) < (param_len+value_len+3)) {
1035 IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __func__ );
1036 return 0;
1037 }
1038 skb_put(skb, param_len+value_len+3);
1039
1040
1041 frame[n++] = param_len;
1042
1043
1044 memcpy(frame+n, param, param_len); n += param_len;
1045
1046
1047 tmp_le = cpu_to_le16(value_len);
1048 memcpy(frame+n, &tmp_le, 2); n += 2;
1049
1050
1051 switch (type) {
1052 case IRLAN_BYTE:
1053 frame[n++] = value_byte;
1054 break;
1055 case IRLAN_SHORT:
1056 tmp_le = cpu_to_le16(value_short);
1057 memcpy(frame+n, &tmp_le, 2); n += 2;
1058 break;
1059 case IRLAN_ARRAY:
1060 memcpy(frame+n, value_array, value_len); n+=value_len;
1061 break;
1062 default:
1063 break;
1064 }
1065 IRDA_ASSERT(n == (param_len+value_len+3), return 0;);
1066
1067 return param_len+value_len+3;
1068}
1069
1070
1071
1072
1073
1074
1075
1076int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
1077{
1078 __u8 name_len;
1079 __u16 val_len;
1080 int n=0;
1081
1082 IRDA_DEBUG(4, "%s()\n", __func__ );
1083
1084
1085 name_len = buf[n++];
1086
1087 if (name_len > 254) {
1088 IRDA_DEBUG(2, "%s(), name_len > 254\n", __func__ );
1089 return -RSP_INVALID_COMMAND_FORMAT;
1090 }
1091
1092
1093 memcpy(name, buf+n, name_len);
1094 name[name_len] = '\0';
1095 n+=name_len;
1096
1097
1098
1099
1100
1101 memcpy(&val_len, buf+n, 2);
1102 le16_to_cpus(&val_len); n+=2;
1103
1104 if (val_len >= 1016) {
1105 IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ );
1106 return -RSP_INVALID_COMMAND_FORMAT;
1107 }
1108 *len = val_len;
1109
1110
1111 memcpy(value, buf+n, val_len);
1112 value[val_len] = '\0';
1113 n+=val_len;
1114
1115 IRDA_DEBUG(4, "Parameter: %s ", name);
1116 IRDA_DEBUG(4, "Value: %s\n", value);
1117
1118 return n;
1119}
1120
1121#ifdef CONFIG_PROC_FS
1122
1123
1124
1125
1126
1127
1128
1129static void *irlan_seq_start(struct seq_file *seq, loff_t *pos)
1130{
1131 rcu_read_lock();
1132 return seq_list_start_head(&irlans, *pos);
1133}
1134
1135
1136static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1137{
1138 return seq_list_next(v, &irlans, pos);
1139}
1140
1141
1142static void irlan_seq_stop(struct seq_file *seq, void *v)
1143{
1144 rcu_read_unlock();
1145}
1146
1147
1148
1149
1150
1151static int irlan_seq_show(struct seq_file *seq, void *v)
1152{
1153 if (v == &irlans)
1154 seq_puts(seq, "IrLAN instances:\n");
1155 else {
1156 struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list);
1157
1158 IRDA_ASSERT(self != NULL, return -1;);
1159 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
1160
1161 seq_printf(seq,"ifname: %s,\n",
1162 self->dev->name);
1163 seq_printf(seq,"client state: %s, ",
1164 irlan_state[ self->client.state]);
1165 seq_printf(seq,"provider state: %s,\n",
1166 irlan_state[ self->provider.state]);
1167 seq_printf(seq,"saddr: %#08x, ",
1168 self->saddr);
1169 seq_printf(seq,"daddr: %#08x\n",
1170 self->daddr);
1171 seq_printf(seq,"version: %d.%d,\n",
1172 self->version[1], self->version[0]);
1173 seq_printf(seq,"access type: %s\n",
1174 irlan_access[self->client.access_type]);
1175 seq_printf(seq,"media: %s\n",
1176 irlan_media[self->media]);
1177
1178 seq_printf(seq,"local filter:\n");
1179 seq_printf(seq,"remote filter: ");
1180 irlan_print_filter(seq, self->client.filter_type);
1181 seq_printf(seq,"tx busy: %s\n",
1182 netif_queue_stopped(self->dev) ? "TRUE" : "FALSE");
1183
1184 seq_putc(seq,'\n');
1185 }
1186 return 0;
1187}
1188
1189static const struct seq_operations irlan_seq_ops = {
1190 .start = irlan_seq_start,
1191 .next = irlan_seq_next,
1192 .stop = irlan_seq_stop,
1193 .show = irlan_seq_show,
1194};
1195
1196static int irlan_seq_open(struct inode *inode, struct file *file)
1197{
1198 return seq_open(file, &irlan_seq_ops);
1199}
1200#endif
1201
1202MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
1203MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
1204MODULE_LICENSE("GPL");
1205
1206module_param(eth, bool, 0);
1207MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)");
1208module_param(access, int, 0);
1209MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3");
1210
1211module_init(irlan_init);
1212module_exit(irlan_cleanup);
1213
1214