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