1 /*********************************************************************
2 *
3 * Filename: irlmp.c
4 * Version: 1.0
5 * Description: IrDA Link Management Protocol (LMP) layer
6 * Status: Stable.
7 * Author: Dag Brattli <dagb@cs.uit.no>
8 * Created at: Sun Aug 17 20:54:32 1997
9 * Modified at: Wed Jan 5 11:26:03 2000
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
11 *
12 * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
14 *
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/malloc.h>
28 #include <linux/string.h>
29 #include <linux/skbuff.h>
30 #include <linux/types.h>
31 #include <linux/proc_fs.h>
32 #include <linux/init.h>
33 #include <linux/kmod.h>
34 #include <linux/random.h>
35
36 #include <net/irda/irda.h>
37 #include <net/irda/irmod.h>
38 #include <net/irda/timer.h>
39 #include <net/irda/qos.h>
40 #include <net/irda/irlap.h>
41 #include <net/irda/iriap.h>
42 #include <net/irda/irlmp.h>
43 #include <net/irda/irlmp_frame.h>
44
45 /* Master structure */
46 struct irlmp_cb *irlmp = NULL;
47
48 /* These can be altered by the sysctl interface */
49 int sysctl_discovery = 0;
50 int sysctl_discovery_timeout = 3; /* 3 seconds by default */
51 int sysctl_discovery_slots = 6; /* 6 slots by default */
52 char sysctl_devname[65];
53
54 char *lmp_reasons[] = {
55 "ERROR, NOT USED",
56 "LM_USER_REQUEST",
57 "LM_LAP_DISCONNECT",
58 "LM_CONNECT_FAILURE",
59 "LM_LAP_RESET",
60 "LM_INIT_DISCONNECT",
61 "ERROR, NOT USED",
62 };
63
64 __u8 *irlmp_hint_to_service(__u8 *hint);
65 #ifdef CONFIG_PROC_FS
66 int irlmp_proc_read(char *buf, char **start, off_t offst, int len);
67 #endif
68
69 /*
70 * Function irlmp_init (void)
71 *
72 * Create (allocate) the main IrLMP structure
73 *
74 */
75 int __init irlmp_init(void)
76 {
77 IRDA_DEBUG(0, __FUNCTION__ "()\n");
78 /* Initialize the irlmp structure. */
79 irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
80 if (irlmp == NULL)
81 return -ENOMEM;
82 memset(irlmp, 0, sizeof(struct irlmp_cb));
83
84 irlmp->magic = LMP_MAGIC;
85 spin_lock_init(&irlmp->log_lock);
86
87 irlmp->clients = hashbin_new(HB_GLOBAL);
88 irlmp->services = hashbin_new(HB_GLOBAL);
89 irlmp->links = hashbin_new(HB_GLOBAL);
90 irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL);
91 irlmp->cachelog = hashbin_new(HB_GLOBAL);
92
93 irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */
94 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
95 irlmp->cache.valid = FALSE;
96 #endif
97 strcpy(sysctl_devname, "Linux");
98
99 /* Do discovery every 3 seconds */
100 init_timer(&irlmp->discovery_timer);
101 irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ);
102
103 return 0;
104 }
105
106 /*
107 * Function irlmp_cleanup (void)
108 *
109 * Remove IrLMP layer
110 *
111 */
112 void irlmp_cleanup(void)
113 {
114 /* Check for main structure */
115 ASSERT(irlmp != NULL, return;);
116 ASSERT(irlmp->magic == LMP_MAGIC, return;);
117
118 del_timer(&irlmp->discovery_timer);
119
120 hashbin_delete(irlmp->links, (FREE_FUNC) kfree);
121 hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree);
122 hashbin_delete(irlmp->clients, (FREE_FUNC) kfree);
123 hashbin_delete(irlmp->services, (FREE_FUNC) kfree);
124 hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree);
125
126 /* De-allocate main structure */
127 kfree(irlmp);
128 irlmp = NULL;
129 }
130
131 /*
132 * Function irlmp_open_lsap (slsap, notify)
133 *
134 * Register with IrLMP and create a local LSAP,
135 * returns handle to LSAP.
136 */
137 struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
138 {
139 struct lsap_cb *self;
140
141 ASSERT(notify != NULL, return NULL;);
142 ASSERT(irlmp != NULL, return NULL;);
143 ASSERT(irlmp->magic == LMP_MAGIC, return NULL;);
144
145 /* Does the client care which Source LSAP selector it gets? */
146 if (slsap_sel == LSAP_ANY) {
147 slsap_sel = irlmp_find_free_slsap();
148 if (!slsap_sel)
149 return NULL;
150 } else if (irlmp_slsap_inuse(slsap_sel))
151 return NULL;
152
153 /* Allocate new instance of a LSAP connection */
154 self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
155 if (self == NULL) {
156 ERROR(__FUNCTION__ "(), can't allocate memory");
157 return NULL;
158 }
159 memset(self, 0, sizeof(struct lsap_cb));
160
161 self->magic = LMP_LSAP_MAGIC;
162 self->slsap_sel = slsap_sel;
163
164 /* Fix connectionless LSAP's */
165 if (slsap_sel == LSAP_CONNLESS) {
166 #ifdef CONFIG_IRDA_ULTRA
167 self->dlsap_sel = LSAP_CONNLESS;
168 self->pid = pid;
169 #endif /* CONFIG_IRDA_ULTRA */
170 } else
171 self->dlsap_sel = LSAP_ANY;
172 self->connected = FALSE;
173
174 init_timer(&self->watchdog_timer);
175
176 ASSERT(notify->instance != NULL, return NULL;);
177 self->notify = *notify;
178
179 irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
180
181 /* Insert into queue of unconnected LSAPs */
182 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self,
183 NULL);
184
185 return self;
186 }
187
188 /*
189 * Function __irlmp_close_lsap (self)
190 *
191 * Remove an instance of LSAP
192 */
193 static void __irlmp_close_lsap(struct lsap_cb *self)
194 {
195 IRDA_DEBUG(4, __FUNCTION__ "()\n");
196
197 ASSERT(self != NULL, return;);
198 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
199
200 /*
201 * Set some of the variables to preset values
202 */
203 self->magic = 0;
204 del_timer(&self->watchdog_timer); /* Important! */
205
206 if (self->conn_skb)
207 dev_kfree_skb(self->conn_skb);
208
209 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
210 ASSERT(irlmp != NULL, return;);
211 irlmp->cache.valid = FALSE;
212 #endif
213 kfree(self);
214 }
215
216 /*
217 * Function irlmp_close_lsap (self)
218 *
219 * Close and remove LSAP
220 *
221 */
222 void irlmp_close_lsap(struct lsap_cb *self)
223 {
224 struct lap_cb *lap;
225 struct lsap_cb *lsap = NULL;
226
227 ASSERT(self != NULL, return;);
228 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
229
230 /*
231 * Find out if we should remove this LSAP from a link or from the
232 * list of unconnected lsaps (not associated with a link)
233 */
234 lap = self->lap;
235 if (lap) {
236 ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
237 lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
238 }
239 /* Check if we found the LSAP! If not then try the unconnected lsaps */
240 if (!lsap) {
241 lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self,
242 NULL);
243 }
244 if (!lsap) {
245 IRDA_DEBUG(0, __FUNCTION__
246 "(), Looks like somebody has removed me already!\n");
247 return;
248 }
249 __irlmp_close_lsap(self);
250 }
251
252 /*
253 * Function irlmp_register_irlap (saddr, notify)
254 *
255 * Register IrLAP layer with IrLMP. There is possible to have multiple
256 * instances of the IrLAP layer, each connected to different IrDA ports
257 *
258 */
259 void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
260 {
261 struct lap_cb *lap;
262
263 ASSERT(irlmp != NULL, return;);
264 ASSERT(irlmp->magic == LMP_MAGIC, return;);
265 ASSERT(notify != NULL, return;);
266
267 /*
268 * Allocate new instance of a LSAP connection
269 */
270 lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL);
271 if (lap == NULL) {
272 ERROR(__FUNCTION__ "(), unable to kmalloc\n");
273 return;
274 }
275 memset(lap, 0, sizeof(struct lap_cb));
276
277 lap->irlap = irlap;
278 lap->magic = LMP_LAP_MAGIC;
279 lap->saddr = saddr;
280 lap->daddr = DEV_ADDR_ANY;
281 lap->lsaps = hashbin_new(HB_GLOBAL);
282
283 irlmp_next_lap_state(lap, LAP_STANDBY);
284
285 init_timer(&lap->idle_timer);
286
287 /*
288 * Insert into queue of LMP links
289 */
290 hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL);
291
292 /*
293 * We set only this variable so IrLAP can tell us on which link the
294 * different events happened on
295 */
296 irda_notify_init(notify);
297 notify->instance = lap;
298 }
299
300 /*
301 * Function irlmp_unregister_irlap (saddr)
302 *
303 * IrLAP layer has been removed!
304 *
305 */
306 void irlmp_unregister_link(__u32 saddr)
307 {
308 struct lap_cb *link;
309
310 IRDA_DEBUG(4, __FUNCTION__ "()\n");
311
312 link = hashbin_remove(irlmp->links, saddr, NULL);
313 if (link) {
314 ASSERT(link->magic == LMP_LAP_MAGIC, return;);
315
316 /* Remove all discoveries discovered at this link */
317 irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE);
318
319 del_timer(&link->idle_timer);
320
321 link->magic = 0;
322 kfree(link);
323 }
324 }
325
326 /*
327 * Function irlmp_connect_request (handle, dlsap, userdata)
328 *
329 * Connect with a peer LSAP
330 *
331 */
332 int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
333 __u32 saddr, __u32 daddr,
334 struct qos_info *qos, struct sk_buff *userdata)
335 {
336 struct sk_buff *skb = NULL;
337 struct lap_cb *lap;
338 struct lsap_cb *lsap;
339 discovery_t *discovery;
340
341 ASSERT(self != NULL, return -EBADR;);
342 ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
343
344 IRDA_DEBUG(2, __FUNCTION__
345 "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
346 self->slsap_sel, dlsap_sel, saddr, daddr);
347
348 if (self->connected)
349 return -EISCONN;
350
351 /* Client must supply destination device address */
352 if (!daddr)
353 return -EINVAL;
354
355 /* Any userdata? */
356 if (userdata == NULL) {
357 skb = dev_alloc_skb(64);
358 if (!skb)
359 return -ENOMEM;
360
361 skb_reserve(skb, LMP_MAX_HEADER);
362 } else
363 skb = userdata;
364
365 /* Make room for MUX control header (3 bytes) */
366 ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
367 skb_push(skb, LMP_CONTROL_HEADER);
368
369 self->dlsap_sel = dlsap_sel;
370
371 /*
372 * Find the link to where we should try to connect since there may
373 * be more than one IrDA port on this machine. If the client has
374 * passed us the saddr (and already knows which link to use), then
375 * we use that to find the link, if not then we have to look in the
376 * discovery log and check if any of the links has discovered a
377 * device with the given daddr
378 */
379 if (!saddr) {
380 if (daddr != DEV_ADDR_ANY)
381 discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
382 else {
383 IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n");
384 discovery = (discovery_t *)
385 hashbin_get_first(irlmp->cachelog);
386 }
387
388 if (discovery) {
389 saddr = discovery->saddr;
390 daddr = discovery->daddr;
391 }
392 }
393 lap = hashbin_find(irlmp->links, saddr, NULL);
394 if (lap == NULL) {
395 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
396 return -EHOSTUNREACH;
397 }
398
399 /* Check if LAP is disconnected or already connected */
400 if (lap->daddr == DEV_ADDR_ANY)
401 lap->daddr = daddr;
402 else if (lap->daddr != daddr) {
403 struct lsap_cb *any_lsap;
404
405 /* Check if some LSAPs are active on this LAP */
406 any_lsap = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
407 if (any_lsap == NULL) {
408 /* No active connection, but LAP hasn't been
409 * disconnected yet (waiting for timeout in LAP).
410 * Maybe we could give LAP a bit of help in this case.
411 */
412 IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but I'm waiting for LAP to timeout!\n");
413 return -EAGAIN;
414 }
415
416 /* LAP is already connected to a different node, and LAP
417 * can only talk to one node at a time */
418 IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
419 return -EBUSY;
420 }
421
422 self->lap = lap;
423
424 /*
425 * Remove LSAP from list of unconnected LSAPs and insert it into the
426 * list of connected LSAPs for the particular link
427 */
428 lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, NULL);
429
430 ASSERT(lsap != NULL, return -1;);
431 ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
432 ASSERT(lsap->lap != NULL, return -1;);
433 ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
434
435 hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL);
436
437 self->connected = TRUE;
438
439 /*
440 * User supplied qos specifications?
441 */
442 if (qos)
443 self->qos = *qos;
444
445 irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, skb);
446
447 return 0;
448 }
449
450 /*
451 * Function irlmp_connect_indication (self)
452 *
453 * Incomming connection
454 *
455 */
456 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
457 {
458 int max_seg_size;
459 int lap_header_size;
460 int max_header_size;
461
462 ASSERT(self != NULL, return;);
463 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
464 ASSERT(skb != NULL, return;);
465 ASSERT(self->lap != NULL, return;);
466
467 IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
468 self->slsap_sel, self->dlsap_sel);
469
470 self->qos = *self->lap->qos;
471
472 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
473 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
474 max_header_size = LMP_HEADER + lap_header_size;
475
476 /* Hide LMP_CONTROL_HEADER header from layer above */
477 skb_pull(skb, LMP_CONTROL_HEADER);
478
479 if (self->notify.connect_indication)
480 self->notify.connect_indication(self->notify.instance, self,
481 &self->qos, max_seg_size,
482 max_header_size, skb);
483 }
484
485 /*
486 * Function irlmp_connect_response (handle, userdata)
487 *
488 * Service user is accepting connection
489 *
490 */
491 int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
492 {
493 ASSERT(self != NULL, return -1;);
494 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
495 ASSERT(userdata != NULL, return -1;);
496
497 self->connected = TRUE;
498
499 IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
500 self->slsap_sel, self->dlsap_sel);
501
502 /* Make room for MUX control header (3 bytes) */
503 ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
504 skb_push(userdata, LMP_CONTROL_HEADER);
505
506 irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
507
508 return 0;
509 }
510
511 /*
512 * Function irlmp_connect_confirm (handle, skb)
513 *
514 * LSAP connection confirmed peer device!
515 */
516 void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
517 {
518 int max_header_size;
519 int lap_header_size;
520 int max_seg_size;
521
522 IRDA_DEBUG(3, __FUNCTION__ "()\n");
523
524 ASSERT(skb != NULL, return;);
525 ASSERT(self != NULL, return;);
526 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
527 ASSERT(self->lap != NULL, return;);
528
529 self->qos = *self->lap->qos;
530
531 max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
532 lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap);
533 max_header_size = LMP_HEADER + lap_header_size;
534
535 IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n",
536 max_header_size);
537
538 /* Hide LMP_CONTROL_HEADER header from layer above */
539 skb_pull(skb, LMP_CONTROL_HEADER);
540
541 if (self->notify.connect_confirm) {
542 self->notify.connect_confirm(self->notify.instance, self,
543 &self->qos, max_seg_size,
544 max_header_size, skb);
545 }
546 }
547
548 /*
549 * Function irlmp_dup (orig, instance)
550 *
551 * Duplicate LSAP, can be used by servers to confirm a connection on a
552 * new LSAP so it can keep listening on the old one.
553 *
554 */
555 struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
556 {
557 struct lsap_cb *new;
558
559 IRDA_DEBUG(1, __FUNCTION__ "()\n");
560
561 /* Only allowed to duplicate unconnected LSAP's */
562 if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) {
563 IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
564 return NULL;
565 }
566 new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
567 if (!new) {
568 IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
569 return NULL;
570 }
571 /* Dup */
572 memcpy(new, orig, sizeof(struct lsap_cb));
573 new->notify.instance = instance;
574
575 init_timer(&new->watchdog_timer);
576
577 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new,
578 NULL);
579
580 /* Make sure that we invalidate the cache */
581 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
582 irlmp->cache.valid = FALSE;
583 #endif /* CONFIG_IRDA_CACHE_LAST_LSAP */
584
585 return new;
586 }
587
588 /*
589 * Function irlmp_disconnect_request (handle, userdata)
590 *
591 * The service user is requesting disconnection, this will not remove the
592 * LSAP, but only mark it as disconnected
593 */
594 int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
595 {
596 struct lsap_cb *lsap;
597
598 ASSERT(self != NULL, return -1;);
599 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
600
601 /* Already disconnected? */
602 if (!self->connected) {
603 WARNING(__FUNCTION__ "(), already disconnected!\n");
604 return -1;
605 }
606
607 ASSERT(userdata != NULL, return -1;);
608 ASSERT(self->connected == TRUE, return -1;);
609
610 skb_push(userdata, LMP_CONTROL_HEADER);
611
612 /*
613 * Do the event before the other stuff since we must know
614 * which lap layer that the frame should be transmitted on
615 */
616 irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
617
618 /*
619 * Remove LSAP from list of connected LSAPs for the particular link
620 * and insert it into the list of unconnected LSAPs
621 */
622 ASSERT(self->lap != NULL, return -1;);
623 ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
624 ASSERT(self->lap->lsaps != NULL, return -1;);
625
626 lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
627
628 ASSERT(lsap != NULL, return -1;);
629 ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
630 ASSERT(lsap == self, return -1;);
631
632 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self,
633 NULL);
634
635 /* Reset some values */
636 self->connected = FALSE;
637 self->dlsap_sel = LSAP_ANY;
638 self->lap = NULL;
639
640 return 0;
641 }
642
643 /*
644 * Function irlmp_disconnect_indication (reason, userdata)
645 *
646 * LSAP is being closed!
647 */
648 void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
649 struct sk_buff *userdata)
650 {
651 struct lsap_cb *lsap;
652
653 IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]);
654 ASSERT(self != NULL, return;);
655 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
656 ASSERT(self->connected == TRUE, return;);
657
658 IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
659 self->slsap_sel, self->dlsap_sel);
660
661 self->connected = FALSE;
662 self->dlsap_sel = LSAP_ANY;
663
664 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
665 irlmp->cache.valid = FALSE;
666 #endif
667
668 /*
669 * Remove association between this LSAP and the link it used
670 */
671 ASSERT(self->lap != NULL, return;);
672 ASSERT(self->lap->lsaps != NULL, return;);
673
674 lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
675
676 ASSERT(lsap != NULL, return;);
677 ASSERT(lsap == self, return;);
678 hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap,
679 NULL);
680
681 self->lap = NULL;
682
683 /*
684 * Inform service user
685 */
686 if (self->notify.disconnect_indication)
687 self->notify.disconnect_indication(self->notify.instance,
688 self, reason, userdata);
689 else {
690 IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n");
691 dev_kfree_skb(userdata);
692 }
693 }
694
695 /*
696 * Function irlmp_do_discovery (nslots)
697 *
698 * Do some discovery on all links
699 *
700 */
701 void irlmp_do_discovery(int nslots)
702 {
703 struct lap_cb *lap;
704
705 /* Make sure the value is sane */
706 if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
707 WARNING(__FUNCTION__
708 "(), invalid value for number of slots!\n");
709 nslots = sysctl_discovery_slots = 8;
710 }
711
712 /* Construct new discovery info to be used by IrLAP, */
713 irlmp->discovery_cmd.hints.word = irlmp->hints.word;
714
715 /*
716 * Set character set for device name (we use ASCII), and
717 * copy device name. Remember to make room for a \0 at the
718 * end
719 */
720 irlmp->discovery_cmd.charset = CS_ASCII;
721 strncpy(irlmp->discovery_cmd.nickname, sysctl_devname,
722 NICKNAME_MAX_LEN);
723 irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.nickname);
724 irlmp->discovery_cmd.nslots = nslots;
725
726 /*
727 * Try to send discovery packets on all links
728 */
729 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
730 while (lap != NULL) {
731 ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
732
733 if (lap->lap_state == LAP_STANDBY) {
734 /* Expire discoveries discovered on this link */
735 irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
736 FALSE);
737
738 /* Try to discover */
739 irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST,
740 NULL);
741 }
742 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
743 }
744 }
745
746 /*
747 * Function irlmp_discovery_request (nslots)
748 *
749 * Do a discovery of devices in front of the computer
750 *
751 */
752 void irlmp_discovery_request(int nslots)
753 {
754 /* Check if user wants to override the default */
755 if (nslots == DISCOVERY_DEFAULT_SLOTS)
756 nslots = sysctl_discovery_slots;
757
758 /* Return current cached discovery log */
759 irlmp_discovery_confirm(irlmp->cachelog);
760
761 /*
762 * Start a single discovery operation if discovery is not already
763 * running
764 */
765 if (!sysctl_discovery)
766 irlmp_do_discovery(nslots);
767 }
768
769 /*
770 * Function irlmp_get_discoveries (pn, mask)
771 *
772 * Return the current discovery log
773 *
774 */
775 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask)
776 {
777 /* Return current cached discovery log */
778 return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask));
779 }
780
781 #if 0
782 /*
783 * Function irlmp_check_services (discovery)
784 *
785 *
786 *
787 */
788 void irlmp_check_services(discovery_t *discovery)
789 {
790 struct irlmp_client *client;
791 __u8 *service_log;
792 __u8 service;
793 int i = 0;
794
795 IRDA_DEBUG(1, "IrDA Discovered: %s\n", discovery->info);
796 IRDA_DEBUG(1, " Services: ");
797
798 service_log = irlmp_hint_to_service(discovery->hints.byte);
799 if (!service_log)
800 return;
801
802 /*
803 * Check all services on the device
804 */
805 while ((service = service_log[i++]) != S_END) {
806 IRDA_DEBUG( 4, "service=%02x\n", service);
807 client = hashbin_find(irlmp->registry, service, NULL);
808 if (entry && entry->discovery_callback) {
809 IRDA_DEBUG( 4, "discovery_callback!\n");
810
811 entry->discovery_callback(discovery);
812 } else {
813 /* Don't notify about the ANY service */
814 if (service == S_ANY)
815 continue;
816 /*
817 * Found no clients for dealing with this service,
818 */
819 }
820 }
821 kfree(service_log);
822 }
823 #endif
824 /*
825 * Function irlmp_notify_client (log)
826 *
827 * Notify all about discovered devices
828 *
829 * Clients registered with IrLMP are :
830 * o IrComm
831 * o IrLAN
832 * o Any socket (in any state - ouch, that may be a lot !)
833 * The client may have defined a callback to be notified in case of
834 * partial/selective discovery based on the hints that it passed to IrLMP.
835 */
836 static inline void
837 irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
838 {
839 discovery_t *discovery;
840
841 IRDA_DEBUG(3, __FUNCTION__ "()\n");
842
843 /* Check if client wants or not partial/selective log (optimisation) */
844 if (!client->disco_callback)
845 return;
846
847 /*
848 * Now, check all discovered devices (if any), and notify client
849 * only about the services that the client is interested in
850 */
851 discovery = (discovery_t *) hashbin_get_first(log);
852 while (discovery != NULL) {
853 IRDA_DEBUG(3, "discovery->daddr = 0x%08x\n", discovery->daddr);
854
855 /*
856 * Any common hint bits? Remember to mask away the extension
857 * bits ;-)
858 */
859 if (client->hint_mask & discovery->hints.word & 0x7f7f)
860 client->disco_callback(discovery, client->priv);
861
862 discovery = (discovery_t *) hashbin_get_next(log);
863 }
864 }
865
866 /*
867 * Function irlmp_discovery_confirm ( self, log)
868 *
869 * Some device(s) answered to our discovery request! Check to see which
870 * device it is, and give indication to the client(s)
871 *
872 */
873 void irlmp_discovery_confirm(hashbin_t *log)
874 {
875 irlmp_client_t *client;
876
877 IRDA_DEBUG(3, __FUNCTION__ "()\n");
878
879 ASSERT(log != NULL, return;);
880
881 if (!(HASHBIN_GET_SIZE(log)))
882 return;
883
884 client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
885 while (client != NULL) {
886 /* Check if we should notify client */
887 irlmp_notify_client(client, log);
888
889 client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
890 }
891 }
892
893 /*
894 * Function irlmp_discovery_expiry (expiry)
895 *
896 * This device is no longer been discovered, and therefore it is beeing
897 * purged from the discovery log. Inform all clients who have
898 * registered for this event...
899 *
900 * Note : called exclusively from discovery.c
901 * Note : as we are currently processing the log, the clients callback
902 * should *NOT* attempt to touch the log now.
903 */
904 void irlmp_discovery_expiry(discovery_t *expiry)
905 {
906 irlmp_client_t *client;
907
908 IRDA_DEBUG(3, __FUNCTION__ "()\n");
909
910 ASSERT(expiry != NULL, return;);
911
912 client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
913 while (client != NULL) {
914 /* Check if we should notify client */
915 if ((client->expir_callback) &&
916 (client->hint_mask & expiry->hints.word & 0x7f7f))
917 client->expir_callback(expiry, client->priv);
918
919 /* Next client */
920 client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
921 }
922 }
923
924 /*
925 * Function irlmp_get_discovery_response ()
926 *
927 * Used by IrLAP to get the discovery info it needs when answering
928 * discovery requests by other devices.
929 */
930 discovery_t *irlmp_get_discovery_response()
931 {
932 IRDA_DEBUG(4, __FUNCTION__ "()\n");
933
934 ASSERT(irlmp != NULL, return NULL;);
935
936 irlmp->discovery_rsp.hints.word = irlmp->hints.word;
937
938 /*
939 * Set character set for device name (we use ASCII), and
940 * copy device name. Remember to make room for a \0 at the
941 * end
942 */
943 irlmp->discovery_rsp.charset = CS_ASCII;
944
945 strncpy(irlmp->discovery_rsp.nickname, sysctl_devname,
946 NICKNAME_MAX_LEN);
947 irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.nickname);
948
949 return &irlmp->discovery_rsp;
950 }
951
952 /*
953 * Function irlmp_data_request (self, skb)
954 *
955 * Send some data to peer device
956 *
957 */
958 int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb)
959 {
960 ASSERT(self != NULL, return -1;);
961 ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
962
963 /* Make room for MUX header */
964 ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
965 skb_push(skb, LMP_HEADER);
966
967 return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb);
968 }
969
970 /*
971 * Function irlmp_data_indication (handle, skb)
972 *
973 * Got data from LAP layer so pass it up to upper layer
974 *
975 */
976 void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
977 {
978 /* Hide LMP header from layer above */
979 skb_pull(skb, LMP_HEADER);
980
981 if (self->notify.data_indication)
982 self->notify.data_indication(self->notify.instance, self, skb);
983 else
984 dev_kfree_skb(skb);
985 }
986
987 /*
988 * Function irlmp_udata_request (self, skb)
989 *
990 *
991 *
992 */
993 int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb)
994 {
995 IRDA_DEBUG(4, __FUNCTION__ "()\n");
996
997 ASSERT(skb != NULL, return -1;);
998
999 /* Make room for MUX header */
1000 ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
1001 skb_push(skb, LMP_HEADER);
1002
1003 return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
1004 }
1005
1006 /*
1007 * Function irlmp_udata_indication (self, skb)
1008 *
1009 * Send unreliable data (but still within the connection)
1010 *
1011 */
1012 void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
1013 {
1014 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1015
1016 ASSERT(self != NULL, return;);
1017 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
1018 ASSERT(skb != NULL, return;);
1019
1020 /* Hide LMP header from layer above */
1021 skb_pull(skb, LMP_HEADER);
1022
1023 if (self->notify.udata_indication)
1024 self->notify.udata_indication(self->notify.instance, self,
1025 skb);
1026 else
1027 dev_kfree_skb(skb);
1028 }
1029
1030 /*
1031 * Function irlmp_connless_data_request (self, skb)
1032 *
1033 *
1034 *
1035 */
1036 #ifdef CONFIG_IRDA_ULTRA
1037 int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb)
1038 {
1039 struct sk_buff *clone_skb;
1040 struct lap_cb *lap;
1041
1042 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1043
1044 ASSERT(skb != NULL, return -1;);
1045
1046 /* Make room for MUX and PID header */
1047 ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;);
1048
1049 /* Insert protocol identifier */
1050 skb_push(skb, LMP_PID_HEADER);
1051 skb->data[0] = self->pid;
1052
1053 /* Connectionless sockets must use 0x70 */
1054 skb_push(skb, LMP_HEADER);
1055 skb->data[0] = skb->data[1] = LSAP_CONNLESS;
1056
1057 /* Try to send Connectionless packets out on all links */
1058 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
1059 while (lap != NULL) {
1060 ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
1061
1062 clone_skb = skb_clone(skb, GFP_ATOMIC);
1063 if (!clone_skb)
1064 return -ENOMEM;
1065
1066 irlap_unitdata_request(lap->irlap, clone_skb);
1067
1068 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
1069 }
1070 dev_kfree_skb(skb);
1071
1072 return 0;
1073 }
1074 #endif /* CONFIG_IRDA_ULTRA */
1075
1076 /*
1077 * Function irlmp_connless_data_indication (self, skb)
1078 *
1079 * Receive unreliable data outside any connection. Mostly used by Ultra
1080 *
1081 */
1082 #ifdef CONFIG_IRDA_ULTRA
1083 void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
1084 {
1085 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1086
1087 ASSERT(self != NULL, return;);
1088 ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
1089 ASSERT(skb != NULL, return;);
1090
1091 /* Hide LMP and PID header from layer above */
1092 skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
1093
1094 if (self->notify.udata_indication)
1095 self->notify.udata_indication(self->notify.instance, self,
1096 skb);
1097 else
1098 dev_kfree_skb(skb);
1099 }
1100 #endif /* CONFIG_IRDA_ULTRA */
1101
1102 void irlmp_status_request(void)
1103 {
1104 IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
1105 }
1106
1107 /*
1108 * Propagate status indication from LAP to LSAPs (via LMP)
1109 * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb,
1110 * and the event is stateless, therefore we can bypass both state machines
1111 * and send the event direct to the LSAP user.
1112 * Jean II
1113 */
1114 void irlmp_status_indication(struct lap_cb *self,
1115 LINK_STATUS link, LOCK_STATUS lock)
1116 {
1117 struct lsap_cb *next;
1118 struct lsap_cb *curr;
1119
1120 /* Send status_indication to all LSAPs using this link */
1121 next = (struct lsap_cb *) hashbin_get_first( self->lsaps);
1122 while (next != NULL ) {
1123 curr = next;
1124 next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
1125
1126 ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
1127 /*
1128 * Inform service user if he has requested it
1129 */
1130 if (curr->notify.status_indication != NULL)
1131 curr->notify.status_indication(curr->notify.instance,
1132 link, lock);
1133 else
1134 IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
1135 }
1136 }
1137
1138 /*
1139 * Function irlmp_hint_to_service (hint)
1140 *
1141 * Returns a list of all servics contained in the given hint bits. This
1142 * funtion assumes that the hint bits have the size of two bytes only
1143 */
1144 __u8 *irlmp_hint_to_service(__u8 *hint)
1145 {
1146 __u8 *service;
1147 int i = 0;
1148
1149 /*
1150 * Allocate array to store services in. 16 entries should be safe
1151 * since we currently only support 2 hint bytes
1152 */
1153 service = kmalloc(16, GFP_ATOMIC);
1154 if (!service) {
1155 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
1156 return NULL;
1157 }
1158
1159 if (!hint[0]) {
1160 IRDA_DEBUG(1, "<None>\n");
1161 kfree(service);
1162 return NULL;
1163 }
1164 if (hint[0] & HINT_PNP)
1165 IRDA_DEBUG(1, "PnP Compatible ");
1166 if (hint[0] & HINT_PDA)
1167 IRDA_DEBUG(1, "PDA/Palmtop ");
1168 if (hint[0] & HINT_COMPUTER)
1169 IRDA_DEBUG(1, "Computer ");
1170 if (hint[0] & HINT_PRINTER) {
1171 IRDA_DEBUG(1, "Printer ");
1172 service[i++] = S_PRINTER;
1173 }
1174 if (hint[0] & HINT_MODEM)
1175 IRDA_DEBUG(1, "Modem ");
1176 if (hint[0] & HINT_FAX)
1177 IRDA_DEBUG(1, "Fax ");
1178 if (hint[0] & HINT_LAN) {
1179 IRDA_DEBUG(1, "LAN Access ");
1180 service[i++] = S_LAN;
1181 }
1182 /*
1183 * Test if extension byte exists. This byte will usually be
1184 * there, but this is not really required by the standard.
1185 * (IrLMP p. 29)
1186 */
1187 if (hint[0] & HINT_EXTENSION) {
1188 if (hint[1] & HINT_TELEPHONY) {
1189 IRDA_DEBUG(1, "Telephony ");
1190 service[i++] = S_TELEPHONY;
1191 } if (hint[1] & HINT_FILE_SERVER)
1192 IRDA_DEBUG(1, "File Server ");
1193
1194 if (hint[1] & HINT_COMM) {
1195 IRDA_DEBUG(1, "IrCOMM ");
1196 service[i++] = S_COMM;
1197 }
1198 if (hint[1] & HINT_OBEX) {
1199 IRDA_DEBUG(1, "IrOBEX ");
1200 service[i++] = S_OBEX;
1201 }
1202 }
1203 IRDA_DEBUG(1, "\n");
1204
1205 /* So that client can be notified about any discovery */
1206 service[i++] = S_ANY;
1207
1208 service[i] = S_END;
1209
1210 return service;
1211 }
1212
1213 /*
1214 * Function irlmp_service_to_hint (service)
1215 *
1216 * Converts a service type, to a hint bit
1217 *
1218 * Returns: a 16 bit hint value, with the service bit set
1219 */
1220 __u16 irlmp_service_to_hint(int service)
1221 {
1222 __u16_host_order hint;
1223
1224 hint.word = 0;
1225
1226 switch (service) {
1227 case S_PNP:
1228 hint.byte[0] |= HINT_PNP;
1229 break;
1230 case S_PDA:
1231 hint.byte[0] |= HINT_PDA;
1232 break;
1233 case S_COMPUTER:
1234 hint.byte[0] |= HINT_COMPUTER;
1235 break;
1236 case S_PRINTER:
1237 hint.byte[0] |= HINT_PRINTER;
1238 break;
1239 case S_MODEM:
1240 hint.byte[0] |= HINT_PRINTER;
1241 break;
1242 case S_LAN:
1243 hint.byte[0] |= HINT_LAN;
1244 break;
1245 case S_COMM:
1246 hint.byte[0] |= HINT_EXTENSION;
1247 hint.byte[1] |= HINT_COMM;
1248 break;
1249 case S_OBEX:
1250 hint.byte[0] |= HINT_EXTENSION;
1251 hint.byte[1] |= HINT_OBEX;
1252 break;
1253 case S_TELEPHONY:
1254 hint.byte[0] |= HINT_EXTENSION;
1255 hint.byte[1] |= HINT_TELEPHONY;
1256 break;
1257 case S_ANY:
1258 hint.word = 0xffff;
1259 break;
1260 default:
1261 IRDA_DEBUG( 1, __FUNCTION__ "(), Unknown service!\n");
1262 break;
1263 }
1264 return hint.word;
1265 }
1266
1267 /*
1268 * Function irlmp_register_service (service)
1269 *
1270 * Register local service with IrLMP
1271 *
1272 */
1273 __u32 irlmp_register_service(__u16 hints)
1274 {
1275 irlmp_service_t *service;
1276 __u32 handle;
1277
1278 IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
1279
1280 /* Get a unique handle for this service */
1281 get_random_bytes(&handle, sizeof(handle));
1282 while (hashbin_find(irlmp->services, handle, NULL) || !handle)
1283 get_random_bytes(&handle, sizeof(handle));
1284
1285 irlmp->hints.word |= hints;
1286
1287 /* Make a new registration */
1288 service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
1289 if (!service) {
1290 IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n");
1291 return 0;
1292 }
1293 service->hints = hints;
1294 hashbin_insert(irlmp->services, (irda_queue_t *) service, handle, NULL);
1295
1296 return handle;
1297 }
1298
1299 /*
1300 * Function irlmp_unregister_service (handle)
1301 *
1302 * Unregister service with IrLMP.
1303 *
1304 * Returns: 0 on success, -1 on error
1305 */
1306 int irlmp_unregister_service(__u32 handle)
1307 {
1308 irlmp_service_t *service;
1309
1310 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1311
1312 if (!handle)
1313 return -1;
1314
1315 service = hashbin_find(irlmp->services, handle, NULL);
1316 if (!service) {
1317 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
1318 return -1;
1319 }
1320
1321 service = hashbin_remove(irlmp->services, handle, NULL);
1322 if (service)
1323 kfree(service);
1324
1325 /* Remove old hint bits */
1326 irlmp->hints.word = 0;
1327
1328 /* Refresh current hint bits */
1329 service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
1330 while (service) {
1331 irlmp->hints.word |= service->hints;
1332
1333 service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
1334 }
1335 return 0;
1336 }
1337
1338 /*
1339 * Function irlmp_register_client (hint_mask, callback1, callback2)
1340 *
1341 * Register a local client with IrLMP
1342 * First callback is selective discovery (based on hints)
1343 * Second callback is for selective discovery expiries
1344 *
1345 * Returns: handle > 0 on success, 0 on error
1346 */
1347 __u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
1348 DISCOVERY_CALLBACK1 expir_clb, void *priv)
1349 {
1350 irlmp_client_t *client;
1351 __u32 handle;
1352
1353 IRDA_DEBUG(0, __FUNCTION__ "()\n");
1354 ASSERT(irlmp != NULL, return 0;);
1355
1356 /* Get a unique handle for this client */
1357 get_random_bytes(&handle, sizeof(handle));
1358 while (hashbin_find(irlmp->clients, handle, NULL) || !handle)
1359 get_random_bytes(&handle, sizeof(handle));
1360
1361 /* Make a new registration */
1362 client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
1363 if (!client) {
1364 IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
1365 return 0;
1366 }
1367
1368 /* Register the details */
1369 client->hint_mask = hint_mask;
1370 client->disco_callback = disco_clb;
1371 client->expir_callback = expir_clb;
1372 client->priv = priv;
1373
1374 hashbin_insert(irlmp->clients, (irda_queue_t *) client, handle, NULL);
1375
1376 return handle;
1377 }
1378
1379 /*
1380 * Function irlmp_update_client (handle, hint_mask, callback1, callback2)
1381 *
1382 * Updates specified client (handle) with possibly new hint_mask and
1383 * callback
1384 *
1385 * Returns: 0 on success, -1 on error
1386 */
1387 int irlmp_update_client(__u32 handle, __u16 hint_mask,
1388 DISCOVERY_CALLBACK1 disco_clb,
1389 DISCOVERY_CALLBACK1 expir_clb, void *priv)
1390 {
1391 irlmp_client_t *client;
1392
1393 if (!handle)
1394 return -1;
1395
1396 client = hashbin_find(irlmp->clients, handle, NULL);
1397 if (!client) {
1398 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
1399 return -1;
1400 }
1401
1402 client->hint_mask = hint_mask;
1403 client->disco_callback = disco_clb;
1404 client->expir_callback = expir_clb;
1405 client->priv = priv;
1406
1407 return 0;
1408 }
1409
1410 /*
1411 * Function irlmp_unregister_client (handle)
1412 *
1413 * Returns: 0 on success, -1 on error
1414 *
1415 */
1416 int irlmp_unregister_client(__u32 handle)
1417 {
1418 struct irlmp_client *client;
1419
1420 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1421
1422 if (!handle)
1423 return -1;
1424
1425 client = hashbin_find(irlmp->clients, handle, NULL);
1426 if (!client) {
1427 IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
1428 return -1;
1429 }
1430
1431 IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n");
1432 client = hashbin_remove( irlmp->clients, handle, NULL);
1433 if (client)
1434 kfree(client);
1435
1436 return 0;
1437 }
1438
1439 /*
1440 * Function irlmp_slsap_inuse (slsap)
1441 *
1442 * Check if the given source LSAP selector is in use
1443 */
1444 int irlmp_slsap_inuse(__u8 slsap_sel)
1445 {
1446 struct lsap_cb *self;
1447 struct lap_cb *lap;
1448
1449 ASSERT(irlmp != NULL, return TRUE;);
1450 ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
1451 ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
1452
1453 IRDA_DEBUG(4, __FUNCTION__ "()\n");
1454
1455 #ifdef CONFIG_IRDA_ULTRA
1456 /* Accept all bindings to the connectionless LSAP */
1457 if (slsap_sel == LSAP_CONNLESS)
1458 return FALSE;
1459 #endif /* CONFIG_IRDA_ULTRA */
1460
1461 /* Valid values are between 0 and 127 */
1462 if (slsap_sel > LSAP_MAX)
1463 return TRUE;
1464
1465 /*
1466 * Check if slsap is already in use. To do this we have to loop over
1467 * every IrLAP connection and check every LSAP assosiated with each
1468 * the connection.
1469 */
1470 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
1471 while (lap != NULL) {
1472 ASSERT(lap->magic == LMP_LAP_MAGIC, return TRUE;);
1473
1474 self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
1475 while (self != NULL) {
1476 ASSERT(self->magic == LMP_LSAP_MAGIC, return TRUE;);
1477
1478 if ((self->slsap_sel == slsap_sel)) {
1479 IRDA_DEBUG(4, "Source LSAP selector=%02x in use\n",
1480 self->slsap_sel);
1481 return TRUE;
1482 }
1483 self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
1484 }
1485 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
1486 }
1487 return FALSE;
1488 }
1489
1490 /*
1491 * Function irlmp_find_free_slsap ()
1492 *
1493 * Find a free source LSAP to use. This function is called if the service
1494 * user has requested a source LSAP equal to LM_ANY
1495 */
1496 __u8 irlmp_find_free_slsap(void)
1497 {
1498 __u8 lsap_sel;
1499 int wrapped = 0;
1500
1501 ASSERT(irlmp != NULL, return -1;);
1502 ASSERT(irlmp->magic == LMP_MAGIC, return -1;);
1503
1504 lsap_sel = irlmp->free_lsap_sel++;
1505
1506 /* Check if the new free lsap is really free */
1507 while (irlmp_slsap_inuse(irlmp->free_lsap_sel)) {
1508 irlmp->free_lsap_sel++;
1509
1510 /* Check if we need to wraparound (0x70-0x7f are reserved) */
1511 if (irlmp->free_lsap_sel > LSAP_MAX) {
1512 irlmp->free_lsap_sel = 10;
1513
1514 /* Make sure we terminate the loop */
1515 if (wrapped++)
1516 return 0;
1517 }
1518 }
1519 IRDA_DEBUG(4, __FUNCTION__ "(), next free lsap_sel=%02x\n", lsap_sel);
1520
1521 return lsap_sel;
1522 }
1523
1524 /*
1525 * Function irlmp_convert_lap_reason (lap_reason)
1526 *
1527 * Converts IrLAP disconnect reason codes to IrLMP disconnect reason
1528 * codes
1529 *
1530 */
1531 LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason)
1532 {
1533 int reason = LM_LAP_DISCONNECT;
1534
1535 switch (lap_reason) {
1536 case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
1537 IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_DISC_INDICATION\n");
1538 reason = LM_USER_REQUEST;
1539 break;
1540 case LAP_NO_RESPONSE: /* To many retransmits without response */
1541 IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_NO_RESPONSE\n");
1542 reason = LM_LAP_DISCONNECT;
1543 break;
1544 case LAP_RESET_INDICATION:
1545 IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_RESET_INDICATION\n");
1546 reason = LM_LAP_RESET;
1547 break;
1548 case LAP_FOUND_NONE:
1549 case LAP_MEDIA_BUSY:
1550 case LAP_PRIMARY_CONFLICT:
1551 IRDA_DEBUG(1, __FUNCTION__ "(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n");
1552 reason = LM_CONNECT_FAILURE;
1553 break;
1554 default:
1555 IRDA_DEBUG(1, __FUNCTION__
1556 "(), Unknow IrLAP disconnect reason %d!\n", lap_reason);
1557 reason = LM_LAP_DISCONNECT;
1558 break;
1559 }
1560
1561 return reason;
1562 }
1563
1564 __u32 irlmp_get_saddr(struct lsap_cb *self)
1565 {
1566 ASSERT(self != NULL, return 0;);
1567 ASSERT(self->lap != NULL, return 0;);
1568
1569 return self->lap->saddr;
1570 }
1571
1572 __u32 irlmp_get_daddr(struct lsap_cb *self)
1573 {
1574 ASSERT(self != NULL, return 0;);
1575 ASSERT(self->lap != NULL, return 0;);
1576
1577 return self->lap->daddr;
1578 }
1579
1580 #ifdef CONFIG_PROC_FS
1581 /*
1582 * Function irlmp_proc_read (buf, start, offset, len, unused)
1583 *
1584 * Give some info to the /proc file system
1585 *
1586 */
1587 int irlmp_proc_read(char *buf, char **start, off_t offset, int len)
1588 {
1589 struct lsap_cb *self;
1590 struct lap_cb *lap;
1591 unsigned long flags;
1592
1593 ASSERT(irlmp != NULL, return 0;);
1594
1595 save_flags( flags);
1596 cli();
1597
1598 len = 0;
1599
1600 len += sprintf( buf+len, "Unconnected LSAPs:\n");
1601 self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps);
1602 while (self != NULL) {
1603 ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
1604 len += sprintf(buf+len, "lsap state: %s, ",
1605 irlsap_state[ self->lsap_state]);
1606 len += sprintf(buf+len,
1607 "slsap_sel: %#02x, dlsap_sel: %#02x, ",
1608 self->slsap_sel, self->dlsap_sel);
1609 len += sprintf(buf+len, "(%s)", self->notify.name);
1610 len += sprintf(buf+len, "\n");
1611
1612 self = (struct lsap_cb *) hashbin_get_next(
1613 irlmp->unconnected_lsaps);
1614 }
1615
1616 len += sprintf(buf+len, "\nRegistred Link Layers:\n");
1617
1618 lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
1619 while (lap != NULL) {
1620 len += sprintf(buf+len, "lap state: %s, ",
1621 irlmp_state[lap->lap_state]);
1622
1623 len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
1624 lap->saddr, lap->daddr);
1625 len += sprintf(buf+len, "refcount: %d", lap->refcount);
1626 len += sprintf(buf+len, "\n");
1627
1628 len += sprintf(buf+len, "\nConnected LSAPs:\n");
1629 self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
1630 while (self != NULL) {
1631 ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
1632 len += sprintf(buf+len, "lsap state: %s, ",
1633 irlsap_state[ self->lsap_state]);
1634 len += sprintf(buf+len,
1635 "slsap_sel: %#02x, dlsap_sel: %#02x, ",
1636 self->slsap_sel, self->dlsap_sel);
1637 len += sprintf(buf+len, "(%s)", self->notify.name);
1638 len += sprintf(buf+len, "\n");
1639
1640 self = (struct lsap_cb *) hashbin_get_next(
1641 lap->lsaps);
1642 }
1643 len += sprintf(buf+len, "\n");
1644
1645 lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
1646 }
1647 restore_flags(flags);
1648
1649 return len;
1650 }
1651
1652 #endif /* PROC_FS */
1653
1654
1655
1656
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.