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