OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [irda/] [irlmp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.