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
27#include <linux/module.h>
28#include <linux/slab.h>
29#include <linux/string.h>
30#include <linux/skbuff.h>
31#include <linux/types.h>
32#include <linux/proc_fs.h>
33#include <linux/init.h>
34#include <linux/kmod.h>
35#include <linux/random.h>
36#include <linux/seq_file.h>
37
38#include <net/irda/irda.h>
39#include <net/irda/timer.h>
40#include <net/irda/qos.h>
41#include <net/irda/irlap.h>
42#include <net/irda/iriap.h>
43#include <net/irda/irlmp.h>
44#include <net/irda/irlmp_frame.h>
45
46#include <asm/unaligned.h>
47
48static __u8 irlmp_find_free_slsap(void);
49static int irlmp_slsap_inuse(__u8 slsap_sel);
50
51
52struct irlmp_cb *irlmp = NULL;
53
54
55int sysctl_discovery = 0;
56int sysctl_discovery_timeout = 3;
57int sysctl_discovery_slots = 6;
58int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;
59char sysctl_devname[65];
60
61const char *irlmp_reasons[] = {
62 "ERROR, NOT USED",
63 "LM_USER_REQUEST",
64 "LM_LAP_DISCONNECT",
65 "LM_CONNECT_FAILURE",
66 "LM_LAP_RESET",
67 "LM_INIT_DISCONNECT",
68 "ERROR, NOT USED",
69};
70
71
72
73
74
75
76
77int __init irlmp_init(void)
78{
79 IRDA_DEBUG(1, "%s()\n", __func__);
80
81 irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
82 if (irlmp == NULL)
83 return -ENOMEM;
84
85 irlmp->magic = LMP_MAGIC;
86
87 irlmp->clients = hashbin_new(HB_LOCK);
88 irlmp->services = hashbin_new(HB_LOCK);
89 irlmp->links = hashbin_new(HB_LOCK);
90 irlmp->unconnected_lsaps = hashbin_new(HB_LOCK);
91 irlmp->cachelog = hashbin_new(HB_NOLOCK);
92
93 if ((irlmp->clients == NULL) ||
94 (irlmp->services == NULL) ||
95 (irlmp->links == NULL) ||
96 (irlmp->unconnected_lsaps == NULL) ||
97 (irlmp->cachelog == NULL)) {
98 return -ENOMEM;
99 }
100
101 spin_lock_init(&irlmp->cachelog->hb_spinlock);
102
103 irlmp->last_lsap_sel = 0x0f;
104 strcpy(sysctl_devname, "Linux");
105
106 init_timer(&irlmp->discovery_timer);
107
108
109 if (sysctl_discovery)
110 irlmp_start_discovery_timer(irlmp,
111 sysctl_discovery_timeout*HZ);
112
113 return 0;
114}
115
116
117
118
119
120
121
122void irlmp_cleanup(void)
123{
124
125 IRDA_ASSERT(irlmp != NULL, return;);
126 IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
127
128 del_timer(&irlmp->discovery_timer);
129
130 hashbin_delete(irlmp->links, (FREE_FUNC) kfree);
131 hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree);
132 hashbin_delete(irlmp->clients, (FREE_FUNC) kfree);
133 hashbin_delete(irlmp->services, (FREE_FUNC) kfree);
134 hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree);
135
136
137 kfree(irlmp);
138 irlmp = NULL;
139}
140
141
142
143
144
145
146
147struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
148{
149 struct lsap_cb *self;
150
151 IRDA_ASSERT(notify != NULL, return NULL;);
152 IRDA_ASSERT(irlmp != NULL, return NULL;);
153 IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
154 IRDA_ASSERT(notify->instance != NULL, return NULL;);
155
156
157 if (slsap_sel == LSAP_ANY) {
158 slsap_sel = irlmp_find_free_slsap();
159 if (!slsap_sel)
160 return NULL;
161 } else if (irlmp_slsap_inuse(slsap_sel))
162 return NULL;
163
164
165 self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
166 if (self == NULL) {
167 IRDA_ERROR("%s: can't allocate memory\n", __func__);
168 return NULL;
169 }
170
171 self->magic = LMP_LSAP_MAGIC;
172 self->slsap_sel = slsap_sel;
173
174
175 if (slsap_sel == LSAP_CONNLESS) {
176#ifdef CONFIG_IRDA_ULTRA
177 self->dlsap_sel = LSAP_CONNLESS;
178 self->pid = pid;
179#endif
180 } else
181 self->dlsap_sel = LSAP_ANY;
182
183
184 init_timer(&self->watchdog_timer);
185
186 self->notify = *notify;
187
188 self->lsap_state = LSAP_DISCONNECTED;
189
190
191 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
192 (long) self, NULL);
193
194 return self;
195}
196EXPORT_SYMBOL(irlmp_open_lsap);
197
198
199
200
201
202
203static void __irlmp_close_lsap(struct lsap_cb *self)
204{
205 IRDA_DEBUG(4, "%s()\n", __func__);
206
207 IRDA_ASSERT(self != NULL, return;);
208 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
209
210
211
212
213 self->magic = 0;
214 del_timer(&self->watchdog_timer);
215
216 if (self->conn_skb)
217 dev_kfree_skb(self->conn_skb);
218
219 kfree(self);
220}
221
222
223
224
225
226
227
228void irlmp_close_lsap(struct lsap_cb *self)
229{
230 struct lap_cb *lap;
231 struct lsap_cb *lsap = NULL;
232
233 IRDA_ASSERT(self != NULL, return;);
234 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
235
236
237
238
239
240 lap = self->lap;
241 if (lap) {
242 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
243
244
245
246
247 if(self->lsap_state != LSAP_DISCONNECTED) {
248 self->lsap_state = LSAP_DISCONNECTED;
249 irlmp_do_lap_event(self->lap,
250 LM_LAP_DISCONNECT_REQUEST, NULL);
251 }
252
253 lsap = hashbin_remove(lap->lsaps, (long) self, NULL);
254#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
255 lap->cache.valid = FALSE;
256#endif
257 }
258 self->lap = NULL;
259
260 if (!lsap) {
261 lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
262 NULL);
263 }
264 if (!lsap) {
265 IRDA_DEBUG(0,
266 "%s(), Looks like somebody has removed me already!\n",
267 __func__);
268 return;
269 }
270 __irlmp_close_lsap(self);
271}
272EXPORT_SYMBOL(irlmp_close_lsap);
273
274
275
276
277
278
279
280
281void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
282{
283 struct lap_cb *lap;
284
285 IRDA_ASSERT(irlmp != NULL, return;);
286 IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;);
287 IRDA_ASSERT(notify != NULL, return;);
288
289
290
291
292 lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL);
293 if (lap == NULL) {
294 IRDA_ERROR("%s: unable to kmalloc\n", __func__);
295 return;
296 }
297
298 lap->irlap = irlap;
299 lap->magic = LMP_LAP_MAGIC;
300 lap->saddr = saddr;
301 lap->daddr = DEV_ADDR_ANY;
302#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
303 lap->cache.valid = FALSE;
304#endif
305 lap->lsaps = hashbin_new(HB_LOCK);
306 if (lap->lsaps == NULL) {
307 IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __func__);
308 kfree(lap);
309 return;
310 }
311
312 lap->lap_state = LAP_STANDBY;
313
314 init_timer(&lap->idle_timer);
315
316
317
318
319 hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL);
320
321
322
323
324
325 irda_notify_init(notify);
326 notify->instance = lap;
327}
328
329
330
331
332
333
334
335void irlmp_unregister_link(__u32 saddr)
336{
337 struct lap_cb *link;
338
339 IRDA_DEBUG(4, "%s()\n", __func__);
340
341
342
343
344 link = hashbin_remove(irlmp->links, saddr, NULL);
345 if (link) {
346 IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;);
347
348
349 link->reason = LAP_DISC_INDICATION;
350 link->daddr = DEV_ADDR_ANY;
351 irlmp_do_lap_event(link, LM_LAP_DISCONNECT_INDICATION, NULL);
352
353
354 irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE);
355
356
357 del_timer(&link->idle_timer);
358 link->magic = 0;
359 hashbin_delete(link->lsaps, (FREE_FUNC) __irlmp_close_lsap);
360 kfree(link);
361 }
362}
363
364
365
366
367
368
369
370int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
371 __u32 saddr, __u32 daddr,
372 struct qos_info *qos, struct sk_buff *userdata)
373{
374 struct sk_buff *tx_skb = userdata;
375 struct lap_cb *lap;
376 struct lsap_cb *lsap;
377 int ret;
378
379 IRDA_ASSERT(self != NULL, return -EBADR;);
380 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
381
382 IRDA_DEBUG(2,
383 "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
384 __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
385
386 if (test_bit(0, &self->connected)) {
387 ret = -EISCONN;
388 goto err;
389 }
390
391
392 if (!daddr) {
393 ret = -EINVAL;
394 goto err;
395 }
396
397
398 if (tx_skb == NULL) {
399 tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
400 if (!tx_skb)
401 return -ENOMEM;
402
403 skb_reserve(tx_skb, LMP_MAX_HEADER);
404 }
405
406
407 IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
408 skb_push(tx_skb, LMP_CONTROL_HEADER);
409
410 self->dlsap_sel = dlsap_sel;
411
412
413
414
415
416
417
418
419
420 if ((!saddr) || (saddr == DEV_ADDR_ANY)) {
421 discovery_t *discovery;
422 unsigned long flags;
423
424 spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags);
425 if (daddr != DEV_ADDR_ANY)
426 discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
427 else {
428 IRDA_DEBUG(2, "%s(), no daddr\n", __func__);
429 discovery = (discovery_t *)
430 hashbin_get_first(irlmp->cachelog);
431 }
432
433 if (discovery) {
434 saddr = discovery->data.saddr;
435 daddr = discovery->data.daddr;
436 }
437 spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags);
438 }
439 lap = hashbin_lock_find(irlmp->links, saddr, NULL);
440 if (lap == NULL) {
441 IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __func__);
442 ret = -EHOSTUNREACH;
443 goto err;
444 }
445
446
447 if (lap->daddr == DEV_ADDR_ANY)
448 lap->daddr = daddr;
449 else if (lap->daddr != daddr) {
450
451 if (HASHBIN_GET_SIZE(lap->lsaps) == 0) {
452
453
454
455
456 IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__);
457 ret = -EAGAIN;
458 goto err;
459 }
460
461
462
463 IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __func__);
464 ret = -EBUSY;
465 goto err;
466 }
467
468 self->lap = lap;
469
470
471
472
473
474 lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL);
475
476 IRDA_ASSERT(lsap != NULL, return -1;);
477 IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
478 IRDA_ASSERT(lsap->lap != NULL, return -1;);
479 IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
480
481 hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self,
482 NULL);
483
484 set_bit(0, &self->connected);
485
486
487
488
489 if (qos)
490 self->qos = *qos;
491
492 irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb);
493
494
495 dev_kfree_skb(tx_skb);
496
497 return 0;
498
499err:
500
501 if(tx_skb)
502 dev_kfree_skb(tx_skb);
503 return ret;
504}
505EXPORT_SYMBOL(irlmp_connect_request);
506
507
508
509
510
511
512
513void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
514{
515 int max_seg_size;
516 int lap_header_size;
517 int max_header_size;
518
519 IRDA_ASSERT(self != NULL, return;);
520 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
521 IRDA_ASSERT(skb != NULL, return;);
522 IRDA_ASSERT(self->lap != NULL, return;);
523
524 IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
525 __func__, self->slsap_sel, self->dlsap_sel);
526
527
528
529
530
531
532 self->qos = *self->lap->qos;
533
534 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
535 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
536 max_header_size = LMP_HEADER + lap_header_size;
537
538
539 skb_pull(skb, LMP_CONTROL_HEADER);
540
541 if (self->notify.connect_indication) {
542
543 skb_get(skb);
544 self->notify.connect_indication(self->notify.instance, self,
545 &self->qos, max_seg_size,
546 max_header_size, skb);
547 }
548}
549
550
551
552
553
554
555
556int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
557{
558 IRDA_ASSERT(self != NULL, return -1;);
559 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
560 IRDA_ASSERT(userdata != NULL, return -1;);
561
562
563
564
565 IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
566 __func__, self->slsap_sel, self->dlsap_sel);
567
568
569 IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
570 skb_push(userdata, LMP_CONTROL_HEADER);
571
572 irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
573
574
575 dev_kfree_skb(userdata);
576
577 return 0;
578}
579EXPORT_SYMBOL(irlmp_connect_response);
580
581
582
583
584
585
586void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
587{
588 int max_header_size;
589 int lap_header_size;
590 int max_seg_size;
591
592 IRDA_DEBUG(3, "%s()\n", __func__);
593
594 IRDA_ASSERT(skb != NULL, return;);
595 IRDA_ASSERT(self != NULL, return;);
596 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
597 IRDA_ASSERT(self->lap != NULL, return;);
598
599 self->qos = *self->lap->qos;
600
601 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
602 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
603 max_header_size = LMP_HEADER + lap_header_size;
604
605 IRDA_DEBUG(2, "%s(), max_header_size=%d\n",
606 __func__, max_header_size);
607
608
609 skb_pull(skb, LMP_CONTROL_HEADER);
610
611 if (self->notify.connect_confirm) {
612
613 skb_get(skb);
614 self->notify.connect_confirm(self->notify.instance, self,
615 &self->qos, max_seg_size,
616 max_header_size, skb);
617 }
618}
619
620
621
622
623
624
625
626
627struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
628{
629 struct lsap_cb *new;
630 unsigned long flags;
631
632 IRDA_DEBUG(1, "%s()\n", __func__);
633
634 spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
635
636
637
638 if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||
639 (orig->lap == NULL)) {
640 IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n",
641 __func__);
642 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
643 flags);
644 return NULL;
645 }
646
647
648 new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);
649 if (!new) {
650 IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
651 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
652 flags);
653 return NULL;
654 }
655
656
657 new->conn_skb = NULL;
658
659 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
660
661
662 new->notify.instance = instance;
663
664 init_timer(&new->watchdog_timer);
665
666 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new,
667 (long) new, NULL);
668
669#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
670
671 new->lap->cache.valid = FALSE;
672#endif
673
674 return new;
675}
676
677
678
679
680
681
682
683int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
684{
685 struct lsap_cb *lsap;
686
687 IRDA_ASSERT(self != NULL, return -1;);
688 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
689 IRDA_ASSERT(userdata != NULL, return -1;);
690
691
692
693
694
695 if (! test_and_clear_bit(0, &self->connected)) {
696 IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
697 dev_kfree_skb(userdata);
698 return -1;
699 }
700
701 skb_push(userdata, LMP_CONTROL_HEADER);
702
703
704
705
706
707 irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
708
709
710 dev_kfree_skb(userdata);
711
712
713
714
715
716 IRDA_ASSERT(self->lap != NULL, return -1;);
717 IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
718 IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
719
720 lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
721#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
722 self->lap->cache.valid = FALSE;
723#endif
724
725 IRDA_ASSERT(lsap != NULL, return -1;);
726 IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
727 IRDA_ASSERT(lsap == self, return -1;);
728
729 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
730 (long) self, NULL);
731
732
733 self->dlsap_sel = LSAP_ANY;
734 self->lap = NULL;
735
736 return 0;
737}
738EXPORT_SYMBOL(irlmp_disconnect_request);
739
740
741
742
743
744
745void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
746 struct sk_buff *skb)
747{
748 struct lsap_cb *lsap;
749
750 IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
751 IRDA_ASSERT(self != NULL, return;);
752 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
753
754 IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
755 __func__, self->slsap_sel, self->dlsap_sel);
756
757
758
759
760
761 if (! test_and_clear_bit(0, &self->connected)) {
762 IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
763 return;
764 }
765
766
767
768
769 IRDA_ASSERT(self->lap != NULL, return;);
770 IRDA_ASSERT(self->lap->lsaps != NULL, return;);
771
772 lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
773#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
774 self->lap->cache.valid = FALSE;
775#endif
776
777 IRDA_ASSERT(lsap != NULL, return;);
778 IRDA_ASSERT(lsap == self, return;);
779 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap,
780 (long) lsap, NULL);
781
782 self->dlsap_sel = LSAP_ANY;
783 self->lap = NULL;
784
785
786
787
788 if (self->notify.disconnect_indication) {
789
790 if(skb)
791 skb_get(skb);
792 self->notify.disconnect_indication(self->notify.instance,
793 self, reason, skb);
794 } else {
795 IRDA_DEBUG(0, "%s(), no handler\n", __func__);
796 }
797}
798
799
800
801
802
803
804
805
806
807void irlmp_do_expiry(void)
808{
809 struct lap_cb *lap;
810
811
812
813
814
815
816
817
818
819
820 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
821 while (lap != NULL) {
822 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
823
824 if (lap->lap_state == LAP_STANDBY) {
825
826 irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
827 FALSE);
828 }
829 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
830 }
831}
832
833
834
835
836
837
838
839
840void irlmp_do_discovery(int nslots)
841{
842 struct lap_cb *lap;
843 __u16 *data_hintsp;
844
845
846 if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
847 IRDA_WARNING("%s: invalid value for number of slots!\n",
848 __func__);
849 nslots = sysctl_discovery_slots = 8;
850 }
851
852
853 data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints;
854 put_unaligned(irlmp->hints.word, data_hintsp);
855
856
857
858
859
860
861 irlmp->discovery_cmd.data.charset = CS_ASCII;
862 strncpy(irlmp->discovery_cmd.data.info, sysctl_devname,
863 NICKNAME_MAX_LEN);
864 irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info);
865 irlmp->discovery_cmd.nslots = nslots;
866
867
868
869
870 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
871 while (lap != NULL) {
872 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
873
874 if (lap->lap_state == LAP_STANDBY) {
875
876 irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST,
877 NULL);
878 }
879 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
880 }
881}
882
883
884
885
886
887
888
889
890
891
892void irlmp_discovery_request(int nslots)
893{
894
895 irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG);
896
897
898
899
900
901 if (!sysctl_discovery) {
902
903 if (nslots == DISCOVERY_DEFAULT_SLOTS)
904 nslots = sysctl_discovery_slots;
905
906 irlmp_do_discovery(nslots);
907
908
909
910 }
911}
912EXPORT_SYMBOL(irlmp_discovery_request);
913
914
915
916
917
918
919
920
921
922struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots)
923{
924
925
926
927
928
929 if (!sysctl_discovery) {
930
931 if (nslots == DISCOVERY_DEFAULT_SLOTS)
932 nslots = sysctl_discovery_slots;
933
934
935 irlmp_do_discovery(nslots);
936
937
938
939 }
940
941
942 return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE));
943}
944EXPORT_SYMBOL(irlmp_get_discoveries);
945
946
947
948
949
950
951
952
953
954
955
956
957
958static inline void
959irlmp_notify_client(irlmp_client_t *client,
960 hashbin_t *log, DISCOVERY_MODE mode)
961{
962 discinfo_t *discoveries;
963 int number;
964 int i;
965
966 IRDA_DEBUG(3, "%s()\n", __func__);
967
968
969 if (!client->disco_callback)
970 return;
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990 discoveries = irlmp_copy_discoveries(log, &number,
991 client->hint_mask.word,
992 (mode == DISCOVERY_LOG));
993
994 if (discoveries == NULL)
995 return;
996
997
998 for(i = 0; i < number; i++)
999 client->disco_callback(&(discoveries[i]), mode, client->priv);
1000
1001
1002 kfree(discoveries);
1003}
1004
1005
1006
1007
1008
1009
1010
1011
1012void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode)
1013{
1014 irlmp_client_t *client;
1015 irlmp_client_t *client_next;
1016
1017 IRDA_DEBUG(3, "%s()\n", __func__);
1018
1019 IRDA_ASSERT(log != NULL, return;);
1020
1021 if (!(HASHBIN_GET_SIZE(log)))
1022 return;
1023
1024
1025 client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
1026 while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
1027 (void *) &client_next) ) {
1028
1029 irlmp_notify_client(client, log, mode);
1030
1031 client = client_next;
1032 }
1033}
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046void irlmp_discovery_expiry(discinfo_t *expiries, int number)
1047{
1048 irlmp_client_t *client;
1049 irlmp_client_t *client_next;
1050 int i;
1051
1052 IRDA_DEBUG(3, "%s()\n", __func__);
1053
1054 IRDA_ASSERT(expiries != NULL, return;);
1055
1056
1057 client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
1058 while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
1059 (void *) &client_next) ) {
1060
1061
1062 for(i = 0; i < number; i++) {
1063
1064 if ((client->expir_callback) &&
1065 (client->hint_mask.word &
1066 get_unaligned((__u16 *)expiries[i].hints)
1067 & 0x7f7f) )
1068 client->expir_callback(&(expiries[i]),
1069 EXPIRY_TIMEOUT,
1070 client->priv);
1071 }
1072
1073
1074 client = client_next;
1075 }
1076}
1077
1078
1079
1080
1081
1082
1083
1084discovery_t *irlmp_get_discovery_response(void)
1085{
1086 IRDA_DEBUG(4, "%s()\n", __func__);
1087
1088 IRDA_ASSERT(irlmp != NULL, return NULL;);
1089
1090 put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints);
1091
1092
1093
1094
1095
1096
1097 irlmp->discovery_rsp.data.charset = CS_ASCII;
1098
1099 strncpy(irlmp->discovery_rsp.data.info, sysctl_devname,
1100 NICKNAME_MAX_LEN);
1101 irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info);
1102
1103 return &irlmp->discovery_rsp;
1104}
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata)
1120{
1121 int ret;
1122
1123 IRDA_ASSERT(self != NULL, return -1;);
1124 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
1125
1126
1127 IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
1128 skb_push(userdata, LMP_HEADER);
1129
1130 ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata);
1131
1132
1133 dev_kfree_skb(userdata);
1134
1135 return ret;
1136}
1137EXPORT_SYMBOL(irlmp_data_request);
1138
1139
1140
1141
1142
1143
1144
1145void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
1146{
1147
1148 skb_pull(skb, LMP_HEADER);
1149
1150 if (self->notify.data_indication) {
1151
1152 skb_get(skb);
1153 self->notify.data_indication(self->notify.instance, self, skb);
1154 }
1155}
1156
1157
1158
1159
1160int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
1161{
1162 int ret;
1163
1164 IRDA_DEBUG(4, "%s()\n", __func__);
1165
1166 IRDA_ASSERT(userdata != NULL, return -1;);
1167
1168
1169 IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
1170 skb_push(userdata, LMP_HEADER);
1171
1172 ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata);
1173
1174
1175 dev_kfree_skb(userdata);
1176
1177 return ret;
1178}
1179
1180
1181
1182
1183
1184
1185
1186void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
1187{
1188 IRDA_DEBUG(4, "%s()\n", __func__);
1189
1190 IRDA_ASSERT(self != NULL, return;);
1191 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
1192 IRDA_ASSERT(skb != NULL, return;);
1193
1194
1195 skb_pull(skb, LMP_HEADER);
1196
1197 if (self->notify.udata_indication) {
1198
1199 skb_get(skb);
1200 self->notify.udata_indication(self->notify.instance, self,
1201 skb);
1202 }
1203}
1204
1205
1206
1207
1208#ifdef CONFIG_IRDA_ULTRA
1209int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata,
1210 __u8 pid)
1211{
1212 struct sk_buff *clone_skb;
1213 struct lap_cb *lap;
1214
1215 IRDA_DEBUG(4, "%s()\n", __func__);
1216
1217 IRDA_ASSERT(userdata != NULL, return -1;);
1218
1219
1220 IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
1221 return -1;);
1222
1223
1224 skb_push(userdata, LMP_PID_HEADER);
1225 if(self != NULL)
1226 userdata->data[0] = self->pid;
1227 else
1228 userdata->data[0] = pid;
1229
1230
1231 skb_push(userdata, LMP_HEADER);
1232 userdata->data[0] = userdata->data[1] = LSAP_CONNLESS;
1233
1234
1235 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
1236 while (lap != NULL) {
1237 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
1238
1239 clone_skb = skb_clone(userdata, GFP_ATOMIC);
1240 if (!clone_skb) {
1241 dev_kfree_skb(userdata);
1242 return -ENOMEM;
1243 }
1244
1245 irlap_unitdata_request(lap->irlap, clone_skb);
1246
1247
1248
1249 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
1250 }
1251 dev_kfree_skb(userdata);
1252
1253 return 0;
1254}
1255#endif
1256
1257
1258
1259
1260
1261
1262
1263#ifdef CONFIG_IRDA_ULTRA
1264void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
1265{
1266 IRDA_DEBUG(4, "%s()\n", __func__);
1267
1268 IRDA_ASSERT(self != NULL, return;);
1269 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
1270 IRDA_ASSERT(skb != NULL, return;);
1271
1272
1273 skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
1274
1275 if (self->notify.udata_indication) {
1276
1277 skb_get(skb);
1278 self->notify.udata_indication(self->notify.instance, self,
1279 skb);
1280 }
1281}
1282#endif
1283
1284
1285
1286
1287
1288
1289
1290
1291void irlmp_status_indication(struct lap_cb *self,
1292 LINK_STATUS link, LOCK_STATUS lock)
1293{
1294 struct lsap_cb *next;
1295 struct lsap_cb *curr;
1296
1297
1298 curr = (struct lsap_cb *) hashbin_get_first( self->lsaps);
1299 while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL,
1300 (void *) &next) ) {
1301 IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
1302
1303
1304
1305 if (curr->notify.status_indication != NULL)
1306 curr->notify.status_indication(curr->notify.instance,
1307 link, lock);
1308 else
1309 IRDA_DEBUG(2, "%s(), no handler\n", __func__);
1310
1311 curr = next;
1312 }
1313}
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
1326{
1327 struct lsap_cb *next;
1328 struct lsap_cb *curr;
1329 int lsap_todo;
1330
1331 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
1332 IRDA_ASSERT(flow == FLOW_START, return;);
1333
1334
1335
1336 lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
1337 IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __func__, lsap_todo);
1338
1339
1340
1341
1342
1343 while((lsap_todo--) &&
1344 (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) {
1345
1346 next = self->flow_next;
1347
1348 if(next == NULL)
1349 next = (struct lsap_cb *) hashbin_get_first(self->lsaps);
1350
1351 curr = hashbin_find_next(self->lsaps, (long) next, NULL,
1352 (void *) &self->flow_next);
1353
1354 if(curr == NULL)
1355 break;
1356 IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
1357
1358
1359 if (curr->notify.flow_indication != NULL)
1360 curr->notify.flow_indication(curr->notify.instance,
1361 curr, flow);
1362 else
1363 IRDA_DEBUG(1, "%s(), no handler\n", __func__);
1364 }
1365}
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444static const __u16 service_hint_mapping[S_END][2] = {
1445 { HINT_PNP, 0 },
1446 { HINT_PDA, 0 },
1447 { HINT_COMPUTER, 0 },
1448 { HINT_PRINTER, 0 },
1449 { HINT_MODEM, 0 },
1450 { HINT_FAX, 0 },
1451 { HINT_LAN, 0 },
1452 { HINT_EXTENSION, HINT_TELEPHONY },
1453 { HINT_EXTENSION, HINT_COMM },
1454 { HINT_EXTENSION, HINT_OBEX },
1455 { 0xFF, 0xFF },
1456};
1457
1458
1459
1460
1461
1462
1463
1464
1465__u16 irlmp_service_to_hint(int service)
1466{
1467 __u16_host_order hint;
1468
1469 hint.byte[0] = service_hint_mapping[service][0];
1470 hint.byte[1] = service_hint_mapping[service][1];
1471
1472 return hint.word;
1473}
1474EXPORT_SYMBOL(irlmp_service_to_hint);
1475
1476
1477
1478
1479
1480
1481
1482void *irlmp_register_service(__u16 hints)
1483{
1484 irlmp_service_t *service;
1485
1486 IRDA_DEBUG(4, "%s(), hints = %04x\n", __func__, hints);
1487
1488
1489 service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
1490 if (!service) {
1491 IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
1492 return NULL;
1493 }
1494 service->hints.word = hints;
1495 hashbin_insert(irlmp->services, (irda_queue_t *) service,
1496 (long) service, NULL);
1497
1498 irlmp->hints.word |= hints;
1499
1500 return (void *)service;
1501}
1502EXPORT_SYMBOL(irlmp_register_service);
1503
1504
1505
1506
1507
1508
1509
1510
1511int irlmp_unregister_service(void *handle)
1512{
1513 irlmp_service_t *service;
1514 unsigned long flags;
1515
1516 IRDA_DEBUG(4, "%s()\n", __func__);
1517
1518 if (!handle)
1519 return -1;
1520
1521
1522 service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
1523 if (!service) {
1524 IRDA_DEBUG(1, "%s(), Unknown service!\n", __func__);
1525 return -1;
1526 }
1527
1528 hashbin_remove_this(irlmp->services, (irda_queue_t *) service);
1529 kfree(service);
1530
1531
1532 irlmp->hints.word = 0;
1533
1534
1535 spin_lock_irqsave(&irlmp->services->hb_spinlock, flags);
1536 service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
1537 while (service) {
1538 irlmp->hints.word |= service->hints.word;
1539
1540 service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
1541 }
1542 spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags);
1543 return 0;
1544}
1545EXPORT_SYMBOL(irlmp_unregister_service);
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
1557 DISCOVERY_CALLBACK2 expir_clb, void *priv)
1558{
1559 irlmp_client_t *client;
1560
1561 IRDA_DEBUG(1, "%s()\n", __func__);
1562 IRDA_ASSERT(irlmp != NULL, return NULL;);
1563
1564
1565 client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
1566 if (!client) {
1567 IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __func__);
1568 return NULL;
1569 }
1570
1571
1572 client->hint_mask.word = hint_mask;
1573 client->disco_callback = disco_clb;
1574 client->expir_callback = expir_clb;
1575 client->priv = priv;
1576
1577 hashbin_insert(irlmp->clients, (irda_queue_t *) client,
1578 (long) client, NULL);
1579
1580 return (void *) client;
1581}
1582EXPORT_SYMBOL(irlmp_register_client);
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592int irlmp_update_client(void *handle, __u16 hint_mask,
1593 DISCOVERY_CALLBACK1 disco_clb,
1594 DISCOVERY_CALLBACK2 expir_clb, void *priv)
1595{
1596 irlmp_client_t *client;
1597
1598 if (!handle)
1599 return -1;
1600
1601 client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
1602 if (!client) {
1603 IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
1604 return -1;
1605 }
1606
1607 client->hint_mask.word = hint_mask;
1608 client->disco_callback = disco_clb;
1609 client->expir_callback = expir_clb;
1610 client->priv = priv;
1611
1612 return 0;
1613}
1614EXPORT_SYMBOL(irlmp_update_client);
1615
1616
1617
1618
1619
1620
1621
1622int irlmp_unregister_client(void *handle)
1623{
1624 struct irlmp_client *client;
1625
1626 IRDA_DEBUG(4, "%s()\n", __func__);
1627
1628 if (!handle)
1629 return -1;
1630
1631
1632 client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
1633 if (!client) {
1634 IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
1635 return -1;
1636 }
1637
1638 IRDA_DEBUG(4, "%s(), removing client!\n", __func__);
1639 hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
1640 kfree(client);
1641
1642 return 0;
1643}
1644EXPORT_SYMBOL(irlmp_unregister_client);
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657static int irlmp_slsap_inuse(__u8 slsap_sel)
1658{
1659 struct lsap_cb *self;
1660 struct lap_cb *lap;
1661 unsigned long flags;
1662
1663 IRDA_ASSERT(irlmp != NULL, return TRUE;);
1664 IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
1665 IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
1666
1667 IRDA_DEBUG(4, "%s()\n", __func__);
1668
1669#ifdef CONFIG_IRDA_ULTRA
1670
1671 if (slsap_sel == LSAP_CONNLESS)
1672 return FALSE;
1673#endif
1674
1675
1676 if (slsap_sel > LSAP_MAX)
1677 return TRUE;
1678
1679
1680
1681
1682
1683
1684 spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags,
1685 SINGLE_DEPTH_NESTING);
1686 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
1687 while (lap != NULL) {
1688 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;);
1689
1690
1691
1692
1693 spin_lock(&lap->lsaps->hb_spinlock);
1694
1695
1696 self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
1697 while (self != NULL) {
1698 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
1699 goto errlsap;);
1700
1701 if ((self->slsap_sel == slsap_sel)) {
1702 IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n",
1703 self->slsap_sel);
1704 goto errlsap;
1705 }
1706 self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
1707 }
1708 spin_unlock(&lap->lsaps->hb_spinlock);
1709
1710
1711 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
1712 }
1713 spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
1714
1715
1716
1717
1718
1719
1720
1721 spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
1722
1723 self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
1724 while (self != NULL) {
1725 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;);
1726 if ((self->slsap_sel == slsap_sel)) {
1727 IRDA_DEBUG(4, "Source LSAP selector=%02x in use (unconnected)\n",
1728 self->slsap_sel);
1729 goto erruncon;
1730 }
1731 self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
1732 }
1733 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
1734
1735 return FALSE;
1736
1737
1738
1739
1740errlsap:
1741 spin_unlock(&lap->lsaps->hb_spinlock);
1742IRDA_ASSERT_LABEL(errlap:)
1743 spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
1744 return TRUE;
1745
1746
1747
1748erruncon:
1749 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
1750 return TRUE;
1751}
1752
1753
1754
1755
1756
1757
1758
1759static __u8 irlmp_find_free_slsap(void)
1760{
1761 __u8 lsap_sel;
1762 int wrapped = 0;
1763
1764 IRDA_ASSERT(irlmp != NULL, return -1;);
1765 IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;);
1766
1767
1768
1769
1770
1771
1772 do {
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784 irlmp->last_lsap_sel++;
1785
1786
1787 if (irlmp->last_lsap_sel > LSAP_MAX) {
1788
1789 irlmp->last_lsap_sel = 0x10;
1790
1791
1792 if (wrapped++) {
1793 IRDA_ERROR("%s: no more free LSAPs !\n",
1794 __func__);
1795 return 0;
1796 }
1797 }
1798
1799
1800
1801
1802
1803
1804 } while (irlmp_slsap_inuse(irlmp->last_lsap_sel));
1805
1806
1807 lsap_sel = irlmp->last_lsap_sel;
1808 IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n",
1809 __func__, lsap_sel);
1810
1811 return lsap_sel;
1812}
1813
1814
1815
1816
1817
1818
1819
1820
1821LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason)
1822{
1823 int reason = LM_LAP_DISCONNECT;
1824
1825 switch (lap_reason) {
1826 case LAP_DISC_INDICATION:
1827 IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __func__);
1828 reason = LM_USER_REQUEST;
1829 break;
1830 case LAP_NO_RESPONSE:
1831 IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __func__);
1832 reason = LM_LAP_DISCONNECT;
1833 break;
1834 case LAP_RESET_INDICATION:
1835 IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __func__);
1836 reason = LM_LAP_RESET;
1837 break;
1838 case LAP_FOUND_NONE:
1839 case LAP_MEDIA_BUSY:
1840 case LAP_PRIMARY_CONFLICT:
1841 IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__);
1842 reason = LM_CONNECT_FAILURE;
1843 break;
1844 default:
1845 IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n",
1846 __func__, lap_reason);
1847 reason = LM_LAP_DISCONNECT;
1848 break;
1849 }
1850
1851 return reason;
1852}
1853
1854#ifdef CONFIG_PROC_FS
1855
1856struct irlmp_iter_state {
1857 hashbin_t *hashbin;
1858};
1859
1860#define LSAP_START_TOKEN ((void *)1)
1861#define LINK_START_TOKEN ((void *)2)
1862
1863static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off)
1864{
1865 void *element;
1866
1867 spin_lock_irq(&iter->hashbin->hb_spinlock);
1868 for (element = hashbin_get_first(iter->hashbin);
1869 element != NULL;
1870 element = hashbin_get_next(iter->hashbin)) {
1871 if (!off || *off-- == 0) {
1872
1873 return element;
1874 }
1875 }
1876 spin_unlock_irq(&iter->hashbin->hb_spinlock);
1877 iter->hashbin = NULL;
1878 return NULL;
1879}
1880
1881
1882static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos)
1883{
1884 struct irlmp_iter_state *iter = seq->private;
1885 void *v;
1886 loff_t off = *pos;
1887
1888 iter->hashbin = NULL;
1889 if (off-- == 0)
1890 return LSAP_START_TOKEN;
1891
1892 iter->hashbin = irlmp->unconnected_lsaps;
1893 v = irlmp_seq_hb_idx(iter, &off);
1894 if (v)
1895 return v;
1896
1897 if (off-- == 0)
1898 return LINK_START_TOKEN;
1899
1900 iter->hashbin = irlmp->links;
1901 return irlmp_seq_hb_idx(iter, &off);
1902}
1903
1904static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1905{
1906 struct irlmp_iter_state *iter = seq->private;
1907
1908 ++*pos;
1909
1910 if (v == LSAP_START_TOKEN) {
1911 iter->hashbin = irlmp->unconnected_lsaps;
1912 v = irlmp_seq_hb_idx(iter, NULL);
1913 return v ? v : LINK_START_TOKEN;
1914 }
1915
1916 if (v == LINK_START_TOKEN) {
1917 iter->hashbin = irlmp->links;
1918 return irlmp_seq_hb_idx(iter, NULL);
1919 }
1920
1921 v = hashbin_get_next(iter->hashbin);
1922
1923 if (v == NULL) {
1924 spin_unlock_irq(&iter->hashbin->hb_spinlock);
1925
1926 if (iter->hashbin == irlmp->unconnected_lsaps)
1927 v = LINK_START_TOKEN;
1928
1929 iter->hashbin = NULL;
1930 }
1931 return v;
1932}
1933
1934static void irlmp_seq_stop(struct seq_file *seq, void *v)
1935{
1936 struct irlmp_iter_state *iter = seq->private;
1937
1938 if (iter->hashbin)
1939 spin_unlock_irq(&iter->hashbin->hb_spinlock);
1940}
1941
1942static int irlmp_seq_show(struct seq_file *seq, void *v)
1943{
1944 const struct irlmp_iter_state *iter = seq->private;
1945 struct lsap_cb *self = v;
1946
1947 if (v == LSAP_START_TOKEN)
1948 seq_puts(seq, "Unconnected LSAPs:\n");
1949 else if (v == LINK_START_TOKEN)
1950 seq_puts(seq, "\nRegistered Link Layers:\n");
1951 else if (iter->hashbin == irlmp->unconnected_lsaps) {
1952 self = v;
1953 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; );
1954 seq_printf(seq, "lsap state: %s, ",
1955 irlsap_state[ self->lsap_state]);
1956 seq_printf(seq,
1957 "slsap_sel: %#02x, dlsap_sel: %#02x, ",
1958 self->slsap_sel, self->dlsap_sel);
1959 seq_printf(seq, "(%s)", self->notify.name);
1960 seq_printf(seq, "\n");
1961 } else if (iter->hashbin == irlmp->links) {
1962 struct lap_cb *lap = v;
1963
1964 seq_printf(seq, "lap state: %s, ",
1965 irlmp_state[lap->lap_state]);
1966
1967 seq_printf(seq, "saddr: %#08x, daddr: %#08x, ",
1968 lap->saddr, lap->daddr);
1969 seq_printf(seq, "num lsaps: %d",
1970 HASHBIN_GET_SIZE(lap->lsaps));
1971 seq_printf(seq, "\n");
1972
1973
1974
1975
1976 spin_lock(&lap->lsaps->hb_spinlock);
1977
1978 seq_printf(seq, "\n Connected LSAPs:\n");
1979 for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
1980 self != NULL;
1981 self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) {
1982 IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC,
1983 goto outloop;);
1984 seq_printf(seq, " lsap state: %s, ",
1985 irlsap_state[ self->lsap_state]);
1986 seq_printf(seq,
1987 "slsap_sel: %#02x, dlsap_sel: %#02x, ",
1988 self->slsap_sel, self->dlsap_sel);
1989 seq_printf(seq, "(%s)", self->notify.name);
1990 seq_putc(seq, '\n');
1991
1992 }
1993 IRDA_ASSERT_LABEL(outloop:)
1994 spin_unlock(&lap->lsaps->hb_spinlock);
1995 seq_putc(seq, '\n');
1996 } else
1997 return -EINVAL;
1998
1999 return 0;
2000}
2001
2002static const struct seq_operations irlmp_seq_ops = {
2003 .start = irlmp_seq_start,
2004 .next = irlmp_seq_next,
2005 .stop = irlmp_seq_stop,
2006 .show = irlmp_seq_show,
2007};
2008
2009static int irlmp_seq_open(struct inode *inode, struct file *file)
2010{
2011 IRDA_ASSERT(irlmp != NULL, return -EINVAL;);
2012
2013 return seq_open_private(file, &irlmp_seq_ops,
2014 sizeof(struct irlmp_iter_state));
2015}
2016
2017const struct file_operations irlmp_seq_fops = {
2018 .owner = THIS_MODULE,
2019 .open = irlmp_seq_open,
2020 .read = seq_read,
2021 .llseek = seq_lseek,
2022 .release = seq_release_private,
2023};
2024
2025#endif