1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/skbuff.h>
28#include <linux/kernel.h>
29
30#include <net/irda/irda.h>
31#include <net/irda/irlap.h>
32#include <net/irda/timer.h>
33#include <net/irda/irlmp.h>
34#include <net/irda/irlmp_frame.h>
35#include <net/irda/discovery.h>
36
37static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap,
38 __u8 slsap, int status, hashbin_t *);
39
40inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
41 int expedited, struct sk_buff *skb)
42{
43 skb->data[0] = dlsap;
44 skb->data[1] = slsap;
45
46 if (expedited) {
47 IRDA_DEBUG(4, "%s(), sending expedited data\n", __func__);
48 irlap_data_request(self->irlap, skb, TRUE);
49 } else
50 irlap_data_request(self->irlap, skb, FALSE);
51}
52
53
54
55
56
57
58void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
59 __u8 opcode, struct sk_buff *skb)
60{
61 __u8 *frame;
62
63 IRDA_DEBUG(2, "%s()\n", __func__);
64
65 IRDA_ASSERT(self != NULL, return;);
66 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
67 IRDA_ASSERT(skb != NULL, return;);
68
69 frame = skb->data;
70
71 frame[0] = dlsap | CONTROL_BIT;
72 frame[1] = slsap;
73
74 frame[2] = opcode;
75
76 if (opcode == DISCONNECT)
77 frame[3] = 0x01;
78 else
79 frame[3] = 0x00;
80
81 irlap_data_request(self->irlap, skb, FALSE);
82}
83
84
85
86
87
88
89
90void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
91 int unreliable)
92{
93 struct lsap_cb *lsap;
94 __u8 slsap_sel;
95 __u8 dlsap_sel;
96 __u8 *fp;
97
98 IRDA_DEBUG(4, "%s()\n", __func__);
99
100 IRDA_ASSERT(self != NULL, return;);
101 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
102 IRDA_ASSERT(skb->len > 2, return;);
103
104 fp = skb->data;
105
106
107
108
109
110 slsap_sel = fp[0] & LSAP_MASK;
111 dlsap_sel = fp[1];
112
113
114
115
116
117 if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
118 IRDA_DEBUG(3, "%s(), incoming connection, "
119 "source LSAP=%d, dest LSAP=%d\n",
120 __func__, slsap_sel, dlsap_sel);
121
122
123 lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
124 irlmp->unconnected_lsaps);
125
126
127 if (!lsap) {
128 IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __func__);
129 lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
130 self->lsaps);
131 }
132 } else
133 lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
134 self->lsaps);
135
136 if (lsap == NULL) {
137 IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
138 IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
139 __func__, slsap_sel, dlsap_sel);
140 if (fp[0] & CONTROL_BIT) {
141 IRDA_DEBUG(2, "%s(), received control frame %02x\n",
142 __func__, fp[2]);
143 } else {
144 IRDA_DEBUG(2, "%s(), received data frame\n", __func__);
145 }
146 return;
147 }
148
149
150
151
152 if (fp[0] & CONTROL_BIT) {
153 switch (fp[2]) {
154 case CONNECT_CMD:
155 lsap->lap = self;
156 irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb);
157 break;
158 case CONNECT_CNF:
159 irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb);
160 break;
161 case DISCONNECT:
162 IRDA_DEBUG(4, "%s(), Disconnect indication!\n",
163 __func__);
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 break;
170 case ACCESSMODE_CNF:
171 IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
172 break;
173 default:
174 IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
175 __func__, fp[2]);
176 break;
177 }
178 } else if (unreliable) {
179
180 if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
181 irlmp_udata_indication(lsap, skb);
182 else
183 irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
184 } else {
185
186 if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
187 irlmp_data_indication(lsap, skb);
188 else
189 irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
190 }
191}
192
193
194
195
196
197
198
199#ifdef CONFIG_IRDA_ULTRA
200void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
201{
202 struct lsap_cb *lsap;
203 __u8 slsap_sel;
204 __u8 dlsap_sel;
205 __u8 pid;
206 __u8 *fp;
207 unsigned long flags;
208
209 IRDA_DEBUG(4, "%s()\n", __func__);
210
211 IRDA_ASSERT(self != NULL, return;);
212 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
213 IRDA_ASSERT(skb->len > 2, return;);
214
215 fp = skb->data;
216
217
218
219
220
221 slsap_sel = fp[0] & LSAP_MASK;
222 dlsap_sel = fp[1];
223 pid = fp[2];
224
225 if (pid & 0x80) {
226 IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
227 __func__);
228 return;
229 }
230
231
232 if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
233 IRDA_DEBUG(0, "%s(), dropping frame!\n", __func__);
234 return;
235 }
236
237
238 spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
239 lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
240 while (lsap != NULL) {
241
242
243
244 if ((lsap->slsap_sel == slsap_sel) &&
245 (lsap->dlsap_sel == dlsap_sel) &&
246 (lsap->pid == pid))
247 {
248 break;
249 }
250 lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
251 }
252 spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
253
254 if (lsap)
255 irlmp_connless_data_indication(lsap, skb);
256 else {
257 IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __func__);
258 }
259}
260#endif
261
262
263
264
265
266
267
268void irlmp_link_disconnect_indication(struct lap_cb *lap,
269 struct irlap_cb *irlap,
270 LAP_REASON reason,
271 struct sk_buff *skb)
272{
273 IRDA_DEBUG(2, "%s()\n", __func__);
274
275 IRDA_ASSERT(lap != NULL, return;);
276 IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
277
278 lap->reason = reason;
279 lap->daddr = DEV_ADDR_ANY;
280
281
282
283
284
285
286 irlmp_do_lap_event(lap, LM_LAP_DISCONNECT_INDICATION, NULL);
287}
288
289
290
291
292
293
294
295void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
296 __u32 daddr, struct qos_info *qos,
297 struct sk_buff *skb)
298{
299 IRDA_DEBUG(4, "%s()\n", __func__);
300
301
302 self->qos = qos;
303
304
305 self->daddr = daddr;
306 IRDA_ASSERT(self->saddr == saddr, return;);
307
308 irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
309}
310
311
312
313
314
315
316
317void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
318 struct sk_buff *skb)
319{
320 IRDA_DEBUG(4, "%s()\n", __func__);
321
322 IRDA_ASSERT(self != NULL, return;);
323 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
324 IRDA_ASSERT(qos != NULL, return;);
325
326
327
328
329 self->qos = qos;
330
331 irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL);
332}
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362void irlmp_link_discovery_indication(struct lap_cb *self,
363 discovery_t *discovery)
364{
365 IRDA_ASSERT(self != NULL, return;);
366 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
367
368
369 irlmp_add_discovery(irlmp->cachelog, discovery);
370
371
372
373 irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE);
374}
375
376
377
378
379
380
381
382
383
384void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
385{
386 IRDA_DEBUG(4, "%s()\n", __func__);
387
388 IRDA_ASSERT(self != NULL, return;);
389 IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
390
391
392 irlmp_add_discovery_log(irlmp->cachelog, log);
393
394
395
396
397
398
399
400 irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE);
401}
402
403#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
404static inline void irlmp_update_cache(struct lap_cb *lap,
405 struct lsap_cb *lsap)
406{
407
408 lap->cache.valid = FALSE;
409
410 lap->cache.dlsap_sel = lsap->dlsap_sel;
411 lap->cache.slsap_sel = lsap->slsap_sel;
412 lap->cache.lsap = lsap;
413 lap->cache.valid = TRUE;
414}
415#endif
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
435 __u8 slsap_sel, int status,
436 hashbin_t *queue)
437{
438 struct lsap_cb *lsap;
439 unsigned long flags;
440
441
442
443
444
445
446#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
447 if ((self->cache.valid) &&
448 (self->cache.slsap_sel == slsap_sel) &&
449 (self->cache.dlsap_sel == dlsap_sel))
450 {
451 return self->cache.lsap;
452 }
453#endif
454
455 spin_lock_irqsave(&queue->hb_spinlock, flags);
456
457 lsap = (struct lsap_cb *) hashbin_get_first(queue);
458 while (lsap != NULL) {
459
460
461
462
463
464
465 if ((status == CONNECT_CMD) &&
466 (lsap->slsap_sel == slsap_sel) &&
467 (lsap->dlsap_sel == LSAP_ANY)) {
468
469
470 lsap->dlsap_sel = dlsap_sel;
471 break;
472 }
473
474
475
476 if ((lsap->slsap_sel == slsap_sel) &&
477 (lsap->dlsap_sel == dlsap_sel))
478 break;
479
480 lsap = (struct lsap_cb *) hashbin_get_next(queue);
481 }
482#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
483 if(lsap)
484 irlmp_update_cache(self, lsap);
485#endif
486 spin_unlock_irqrestore(&queue->hb_spinlock, flags);
487
488
489 return lsap;
490}
491