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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*********************************************************************
2
 *
3
 * Filename:      irlmp_frame.c
4
 * Version:       0.9
5
 * Description:   IrLMP frame implementation
6
 * Status:        Experimental.
7
 * Author:        Dag Brattli <dagb@cs.uit.no>
8
 * Created at:    Tue Aug 19 02:09:59 1997
9
 * Modified at:   Mon Dec 13 13:41:12 1999
10
 * Modified by:   Dag Brattli <dagb@cs.uit.no>
11
 *
12
 *     Copyright (c) 1998-1999 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/skbuff.h>
29
#include <linux/kernel.h>
30
 
31
#include <net/irda/irda.h>
32
#include <net/irda/irlap.h>
33
#include <net/irda/timer.h>
34
#include <net/irda/irlmp.h>
35
#include <net/irda/irlmp_frame.h>
36
#include <net/irda/discovery.h>
37
 
38
static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap,
39
                                       __u8 slsap, int status, hashbin_t *);
40
 
41
inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
42
                                int expedited, struct sk_buff *skb)
43
{
44
        skb->data[0] = dlsap;
45
        skb->data[1] = slsap;
46
 
47
        if (expedited) {
48
                IRDA_DEBUG(4, "%s(), sending expedited data\n", __FUNCTION__);
49
                irlap_data_request(self->irlap, skb, TRUE);
50
        } else
51
                irlap_data_request(self->irlap, skb, FALSE);
52
}
53
 
54
/*
55
 * Function irlmp_send_lcf_pdu (dlsap, slsap, opcode,skb)
56
 *
57
 *    Send Link Control Frame to IrLAP
58
 */
59
void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
60
                        __u8 opcode, struct sk_buff *skb)
61
{
62
        __u8 *frame;
63
 
64
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
65
 
66
        ASSERT(self != NULL, return;);
67
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
68
        ASSERT(skb != NULL, return;);
69
 
70
        frame = skb->data;
71
 
72
        frame[0] = dlsap | CONTROL_BIT;
73
        frame[1] = slsap;
74
 
75
        frame[2] = opcode;
76
 
77
        if (opcode == DISCONNECT)
78
                frame[3] = 0x01; /* Service user request */
79
        else
80
                frame[3] = 0x00; /* rsvd */
81
 
82
        irlap_data_request(self->irlap, skb, FALSE);
83
}
84
 
85
/*
86
 * Function irlmp_input (skb)
87
 *
88
 *    Used by IrLAP to pass received data frames to IrLMP layer
89
 *
90
 */
91
void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
92
                                int unreliable)
93
{
94
        struct lsap_cb *lsap;
95
        __u8   slsap_sel;   /* Source (this) LSAP address */
96
        __u8   dlsap_sel;   /* Destination LSAP address */
97
        __u8   *fp;
98
 
99
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
100
 
101
        ASSERT(self != NULL, return;);
102
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
103
        ASSERT(skb->len > 2, return;);
104
 
105
        fp = skb->data;
106
 
107
        /*
108
         *  The next statements may be confusing, but we do this so that
109
         *  destination LSAP of received frame is source LSAP in our view
110
         */
111
        slsap_sel = fp[0] & LSAP_MASK;
112
        dlsap_sel = fp[1];
113
 
114
        /*
115
         *  Check if this is an incoming connection, since we must deal with
116
         *  it in a different way than other established connections.
117
         */
118
        if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
119
                IRDA_DEBUG(3, "%s(), incoming connection, "
120
                           "source LSAP=%d, dest LSAP=%d\n",
121
                           __FUNCTION__, slsap_sel, dlsap_sel);
122
 
123
                /* Try to find LSAP among the unconnected LSAPs */
124
                lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
125
                                       irlmp->unconnected_lsaps);
126
 
127
                /* Maybe LSAP was already connected, so try one more time */
128
                if (!lsap) {
129
                        IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __FUNCTION__);
130
                        lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
131
                                               self->lsaps);
132
                }
133
        } else
134
                lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
135
                                       self->lsaps);
136
 
137
        if (lsap == NULL) {
138
                IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
139
                IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n", __FUNCTION__, slsap_sel,
140
                      dlsap_sel);
141
                if (fp[0] & CONTROL_BIT) {
142
                        IRDA_DEBUG(2, "%s(), received control frame %02x\n", __FUNCTION__, fp[2]);
143
                } else {
144
                        IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__);
145
                }
146
                dev_kfree_skb(skb);
147
                return;
148
        }
149
 
150
        /*
151
         *  Check if we received a control frame?
152
         */
153
        if (fp[0] & CONTROL_BIT) {
154
                switch (fp[2]) {
155
                case CONNECT_CMD:
156
                        lsap->lap = self;
157
                        irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb);
158
                        break;
159
                case CONNECT_CNF:
160
                        irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
161
                        break;
162
                case DISCONNECT:
163
                        IRDA_DEBUG(4, "%s(), Disconnect indication!\n", __FUNCTION__);
164
                        irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
165
                                            skb);
166
                        break;
167
                case ACCESSMODE_CMD:
168
                        IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
169
                        dev_kfree_skb(skb);
170
                        break;
171
                case ACCESSMODE_CNF:
172
                        IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
173
                        dev_kfree_skb(skb);
174
                        break;
175
                default:
176
                        IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n", __FUNCTION__, fp[2]);
177
                        dev_kfree_skb(skb);
178
                        break;
179
                }
180
        } else if (unreliable) {
181
                /* Optimize and bypass the state machine if possible */
182
                if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
183
                        irlmp_udata_indication(lsap, skb);
184
                else
185
                        irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
186
        } else {
187
                /* Optimize and bypass the state machine if possible */
188
                if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
189
                        irlmp_data_indication(lsap, skb);
190
                else
191
                        irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
192
        }
193
}
194
 
195
/*
196
 * Function irlmp_link_unitdata_indication (self, skb)
197
 *
198
 *
199
 *
200
 */
201
#ifdef CONFIG_IRDA_ULTRA
202
void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
203
{
204
        struct lsap_cb *lsap;
205
        __u8   slsap_sel;   /* Source (this) LSAP address */
206
        __u8   dlsap_sel;   /* Destination LSAP address */
207
        __u8   pid;         /* Protocol identifier */
208
        __u8   *fp;
209
 
210
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
211
 
212
        ASSERT(self != NULL, return;);
213
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
214
        ASSERT(skb->len > 2, return;);
215
 
216
        fp = skb->data;
217
 
218
        /*
219
         *  The next statements may be confusing, but we do this so that
220
         *  destination LSAP of received frame is source LSAP in our view
221
         */
222
        slsap_sel = fp[0] & LSAP_MASK;
223
        dlsap_sel = fp[1];
224
        pid       = fp[2];
225
 
226
        if (pid & 0x80) {
227
                IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);
228
                dev_kfree_skb(skb);
229
 
230
                return;
231
        }
232
 
233
        /* Check if frame is addressed to the connectionless LSAP */
234
        if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
235
                IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__);
236
                dev_kfree_skb(skb);
237
 
238
                return;
239
        }
240
 
241
        lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
242
        while (lsap != NULL) {
243
                /*
244
                 *  Check if source LSAP and dest LSAP selectors and PID match.
245
                 */
246
                if ((lsap->slsap_sel == slsap_sel) &&
247
                    (lsap->dlsap_sel == dlsap_sel) &&
248
                    (lsap->pid == pid))
249
                {
250
                        break;
251
                }
252
                lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
253
        }
254
        if (lsap)
255
                irlmp_connless_data_indication(lsap, skb);
256
        else {
257
                IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__);
258
                dev_kfree_skb(skb);
259
        }
260
}
261
#endif /* CONFIG_IRDA_ULTRA */
262
 
263
/*
264
 * Function irlmp_link_disconnect_indication (reason, userdata)
265
 *
266
 *    IrLAP has disconnected
267
 *
268
 */
269
void irlmp_link_disconnect_indication(struct lap_cb *lap,
270
                                      struct irlap_cb *irlap,
271
                                      LAP_REASON reason,
272
                                      struct sk_buff *userdata)
273
{
274
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
275
 
276
        ASSERT(lap != NULL, return;);
277
        ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
278
 
279
        lap->reason = reason;
280
        lap->daddr = DEV_ADDR_ANY;
281
 
282
        /* FIXME: must do something with the userdata if any */
283
        if (userdata)
284
                dev_kfree_skb(userdata);
285
 
286
        /*
287
         *  Inform station state machine
288
         */
289
        irlmp_do_lap_event(lap, LM_LAP_DISCONNECT_INDICATION, NULL);
290
}
291
 
292
/*
293
 * Function irlmp_link_connect_indication (qos)
294
 *
295
 *    Incoming LAP connection!
296
 *
297
 */
298
void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
299
                                   __u32 daddr, struct qos_info *qos,
300
                                   struct sk_buff *skb)
301
{
302
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
303
 
304
        /* Copy QoS settings for this session */
305
        self->qos = qos;
306
 
307
        /* Update destination device address */
308
        self->daddr = daddr;
309
        ASSERT(self->saddr == saddr, return;);
310
 
311
        irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
312
}
313
 
314
/*
315
 * Function irlmp_link_connect_confirm (qos)
316
 *
317
 *    LAP connection confirmed!
318
 *
319
 */
320
void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
321
                                struct sk_buff *userdata)
322
{
323
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
324
 
325
        ASSERT(self != NULL, return;);
326
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
327
        ASSERT(qos != NULL, return;);
328
 
329
        /* Don't need use the userdata for now */
330
        if (userdata)
331
                dev_kfree_skb(userdata);
332
 
333
        /* Copy QoS settings for this session */
334
        self->qos = qos;
335
 
336
        irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL);
337
}
338
 
339
/*
340
 * Function irlmp_link_discovery_indication (self, log)
341
 *
342
 *    Device is discovering us
343
 *
344
 * It's not an answer to our own discoveries, just another device trying
345
 * to perform discovery, but we don't want to miss the opportunity
346
 * to exploit this information, because :
347
 *      o We may not actively perform discovery (just passive discovery)
348
 *      o This type of discovery is much more reliable. In some cases, it
349
 *        seem that less than 50% of our discoveries get an answer, while
350
 *        we always get ~100% of these.
351
 *      o Make faster discovery, statistically divide time of discovery
352
 *        events by 2 (important for the latency aspect and user feel)
353
 *      o Even is we do active discovery, the other node might not
354
 *        answer our discoveries (ex: Palm). The Palm will just perform
355
 *        one active discovery and connect directly to us.
356
 *
357
 * However, when both devices discover each other, they might attempt to
358
 * connect to each other following the discovery event, and it would create
359
 * collisions on the medium (SNRM battle).
360
 * The "fix" for that is to disable all connection requests in IrLAP
361
 * for 100ms after a discovery indication by setting the media_busy flag.
362
 * Previously, we used to postpone the event which was quite ugly. Now
363
 * that IrLAP takes care of this problem, just pass the event up...
364
 *
365
 * Jean II
366
 */
367
void irlmp_link_discovery_indication(struct lap_cb *self,
368
                                     discovery_t *discovery)
369
{
370
        ASSERT(self != NULL, return;);
371
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
372
 
373
        irlmp_add_discovery(irlmp->cachelog, discovery);
374
 
375
        /* Just handle it the same way as a discovery confirm,
376
         * bypass the LM_LAP state machine (see below) */
377
        irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
378
}
379
 
380
/*
381
 * Function irlmp_link_discovery_confirm (self, log)
382
 *
383
 *    Called by IrLAP with a list of discoveries after the discovery
384
 *    request has been carried out. A NULL log is received if IrLAP
385
 *    was unable to carry out the discovery request
386
 *
387
 */
388
void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
389
{
390
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
391
 
392
        ASSERT(self != NULL, return;);
393
        ASSERT(self->magic == LMP_LAP_MAGIC, return;);
394
 
395
        irlmp_add_discovery_log(irlmp->cachelog, log);
396
 
397
        /* Propagate event to various LSAPs registered for it.
398
         * We bypass the LM_LAP state machine because
399
         *      1) We do it regardless of the LM_LAP state
400
         *      2) It doesn't affect the LM_LAP state
401
         *      3) Faster, slimer, simpler, ...
402
         * Jean II */
403
        irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
404
}
405
 
406
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
407
inline void irlmp_update_cache(struct lsap_cb *self)
408
{
409
        /* Update cache entry */
410
        irlmp->cache.dlsap_sel = self->dlsap_sel;
411
        irlmp->cache.slsap_sel = self->slsap_sel;
412
        irlmp->cache.lsap = self;
413
        irlmp->cache.valid = TRUE;
414
}
415
#endif
416
 
417
/*
418
 * Function irlmp_find_handle (self, dlsap_sel, slsap_sel, status, queue)
419
 *
420
 *    Find handle assosiated with destination and source LSAP
421
 *
422
 */
423
static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
424
                                       __u8 slsap_sel, int status,
425
                                       hashbin_t *queue)
426
{
427
        struct lsap_cb *lsap;
428
 
429
        /*
430
         *  Optimize for the common case. We assume that the last frame
431
         *  received is in the same connection as the last one, so check in
432
         *  cache first to avoid the linear search
433
         */
434
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
435
        if ((irlmp->cache.valid) &&
436
            (irlmp->cache.slsap_sel == slsap_sel) &&
437
            (irlmp->cache.dlsap_sel == dlsap_sel))
438
        {
439
                return (irlmp->cache.lsap);
440
        }
441
#endif
442
        lsap = (struct lsap_cb *) hashbin_get_first(queue);
443
        while (lsap != NULL) {
444
                /*
445
                 *  If this is an incoming connection, then the destination
446
                 *  LSAP selector may have been specified as LM_ANY so that
447
                 *  any client can connect. In that case we only need to check
448
                 *  if the source LSAP (in our view!) match!
449
                 */
450
                if ((status == CONNECT_CMD) &&
451
                    (lsap->slsap_sel == slsap_sel) &&
452
                    (lsap->dlsap_sel == LSAP_ANY))
453
                {
454
                        lsap->dlsap_sel = dlsap_sel;
455
 
456
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
457
                        irlmp_update_cache(lsap);
458
#endif
459
                        return lsap;
460
                }
461
                /*
462
                 *  Check if source LSAP and dest LSAP selectors match.
463
                 */
464
                if ((lsap->slsap_sel == slsap_sel) &&
465
                    (lsap->dlsap_sel == dlsap_sel))
466
                {
467
#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
468
                        irlmp_update_cache(lsap);
469
#endif
470
                        return lsap;
471
                }
472
                lsap = (struct lsap_cb *) hashbin_get_next(queue);
473
        }
474
 
475
        /* Sorry not found! */
476
        return NULL;
477
}

powered by: WebSVN 2.1.0

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