~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/irda/irlmp.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.