This source file includes following definitions.
- l2cap_attach
- l2cap_bind
- l2cap_sockaddr
- l2cap_connect
- l2cap_peeraddr
- l2cap_disconnect
- l2cap_detach
- l2cap_listen
- l2cap_send
- l2cap_setopt
- l2cap_getopt
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
28
29
30
31
32
33
34 #include <sys/cdefs.h>
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/mbuf.h>
39 #include <sys/proc.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/systm.h>
44
45 #include <netbt/bluetooth.h>
46 #include <netbt/hci.h>
47 #include <netbt/l2cap.h>
48
49
50
51
52
53
54
55
56
57
58
59
60 int
61 l2cap_attach(struct l2cap_channel **handle,
62 const struct btproto *proto, void *upper)
63 {
64 struct l2cap_channel *chan;
65
66 KASSERT(handle != NULL);
67 KASSERT(proto != NULL);
68 KASSERT(upper != NULL);
69
70 chan = malloc(sizeof(struct l2cap_channel), M_BLUETOOTH,
71 M_NOWAIT);
72 if (chan == NULL)
73 return ENOMEM;
74 bzero(chan, sizeof *chan);
75
76 chan->lc_proto = proto;
77 chan->lc_upper = upper;
78
79 chan->lc_state = L2CAP_CLOSED;
80
81 chan->lc_lcid = L2CAP_NULL_CID;
82 chan->lc_rcid = L2CAP_NULL_CID;
83
84 chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt);
85 chan->lc_laddr.bt_family = AF_BLUETOOTH;
86 chan->lc_laddr.bt_psm = L2CAP_PSM_ANY;
87
88 chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt);
89 chan->lc_raddr.bt_family = AF_BLUETOOTH;
90 chan->lc_raddr.bt_psm = L2CAP_PSM_ANY;
91
92 chan->lc_imtu = L2CAP_MTU_DEFAULT;
93 chan->lc_omtu = L2CAP_MTU_DEFAULT;
94 chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT;
95
96 memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t));
97 memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t));
98
99 *handle = chan;
100 return 0;
101 }
102
103
104
105
106
107
108 int
109 l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr)
110 {
111
112 memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt));
113 return 0;
114 }
115
116
117
118
119
120
121 int
122 l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
123 {
124
125 memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt));
126 return 0;
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 int
143 l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest)
144 {
145 struct hci_unit *unit;
146 int err;
147
148 memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt));
149
150 if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm))
151 return EINVAL;
152
153 if (bdaddr_any(&chan->lc_raddr.bt_bdaddr))
154 return EDESTADDRREQ;
155
156
157 if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) {
158 err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr,
159 &chan->lc_raddr.bt_bdaddr);
160 if (err)
161 return err;
162 }
163
164 unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr);
165 if (unit == NULL)
166 return EHOSTUNREACH;
167
168
169 err = l2cap_cid_alloc(chan);
170 if (err)
171 return err;
172
173
174 chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr);
175 if (chan->lc_link == NULL)
176 return EHOSTUNREACH;
177
178
179 err = l2cap_setmode(chan);
180 if (err == EINPROGRESS) {
181 chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ;
182 (*chan->lc_proto->connecting)(chan->lc_upper);
183 return 0;
184 }
185 if (err)
186 goto fail;
187
188
189
190
191
192
193 chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP;
194 err = l2cap_send_connect_req(chan);
195 if (err)
196 goto fail;
197
198 return 0;
199
200 fail:
201 chan->lc_state = L2CAP_CLOSED;
202 hci_acl_close(chan->lc_link, err);
203 chan->lc_link = NULL;
204 return err;
205 }
206
207
208
209
210
211
212 int
213 l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
214 {
215
216 memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt));
217 return 0;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233 int
234 l2cap_disconnect(struct l2cap_channel *chan, int linger)
235 {
236 int err = 0;
237
238 if (chan->lc_state == L2CAP_CLOSED
239 || chan->lc_state == L2CAP_WAIT_DISCONNECT)
240 return EINVAL;
241
242 chan->lc_flags |= L2CAP_SHUTDOWN;
243
244
245
246
247
248 if ((IF_IS_EMPTY(&chan->lc_txq) && chan->lc_pending == 0)
249 || linger == 0) {
250 chan->lc_state = L2CAP_WAIT_DISCONNECT;
251 err = l2cap_send_disconnect_req(chan);
252 if (err)
253 l2cap_close(chan, err);
254 }
255 return err;
256 }
257
258
259
260
261
262
263 int
264 l2cap_detach(struct l2cap_channel **handle)
265 {
266 struct l2cap_channel *chan;
267
268 chan = *handle;
269 *handle = NULL;
270
271 if (chan->lc_state != L2CAP_CLOSED)
272 l2cap_close(chan, 0);
273
274 if (chan->lc_lcid != L2CAP_NULL_CID) {
275 LIST_REMOVE(chan, lc_ncid);
276 chan->lc_lcid = L2CAP_NULL_CID;
277 }
278
279 IF_PURGE(&chan->lc_txq);
280
281
282
283
284
285
286 free(chan, M_BLUETOOTH);
287 return 0;
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 int
306 l2cap_listen(struct l2cap_channel *chan)
307 {
308 struct l2cap_channel *used, *prev = NULL;
309
310 if (chan->lc_lcid != L2CAP_NULL_CID)
311 return EINVAL;
312
313 if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY
314 && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm))
315 return EADDRNOTAVAIL;
316
317
318
319
320
321
322
323 chan->lc_lcid = L2CAP_SIGNAL_CID;
324
325
326
327
328
329
330
331 LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) {
332 if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm)
333 break;
334
335 if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm
336 && bdaddr_any(&used->lc_laddr.bt_bdaddr)
337 && !bdaddr_any(&chan->lc_laddr.bt_bdaddr))
338 break;
339
340 prev = used;
341 }
342
343 if (prev == NULL)
344 LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid);
345 else
346 LIST_INSERT_AFTER(prev, chan, lc_ncid);
347
348 return 0;
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373 int
374 l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
375 {
376 l2cap_hdr_t *hdr;
377 int plen;
378
379 if (chan->lc_state == L2CAP_CLOSED) {
380 m_freem(m);
381 return ENOTCONN;
382 }
383
384 plen = m->m_pkthdr.len;
385
386 DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n",
387 plen, chan->lc_lcid, chan->lc_pending);
388
389
390 M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT);
391 if (m == NULL)
392 return ENOMEM;
393
394 hdr = mtod(m, l2cap_hdr_t *);
395 hdr->length = htole16(plen);
396 hdr->dcid = htole16(chan->lc_rcid);
397
398
399 IF_ENQUEUE(&chan->lc_txq, m);
400
401
402 if (chan->lc_pending == 0)
403 return l2cap_start(chan);
404
405 return 0;
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 int
422 l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
423 {
424 int mode, err = 0;
425 uint16_t mtu;
426
427 switch (opt) {
428 case SO_L2CAP_IMTU:
429 mtu = *(uint16_t *)addr;
430 if (mtu < L2CAP_MTU_MINIMUM)
431 err = EINVAL;
432 else if (chan->lc_state == L2CAP_CLOSED)
433 chan->lc_imtu = mtu;
434 else
435 err = EBUSY;
436
437 break;
438
439 case SO_L2CAP_LM:
440 mode = *(int *)addr;
441 mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
442
443 if (mode & L2CAP_LM_SECURE)
444 mode |= L2CAP_LM_ENCRYPT;
445
446 if (mode & L2CAP_LM_ENCRYPT)
447 mode |= L2CAP_LM_AUTH;
448
449 chan->lc_mode = mode;
450
451 if (chan->lc_state == L2CAP_OPEN)
452 err = l2cap_setmode(chan);
453
454 break;
455
456 case SO_L2CAP_OQOS:
457 case SO_L2CAP_FLUSH:
458 default:
459 err = ENOPROTOOPT;
460 break;
461 }
462
463 return err;
464 }
465
466
467
468
469
470
471 int
472 l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
473 {
474
475 switch (opt) {
476 case SO_L2CAP_IMTU:
477 *(uint16_t *)addr = chan->lc_imtu;
478 return sizeof(uint16_t);
479
480 case SO_L2CAP_OMTU:
481 *(uint16_t *)addr = chan->lc_omtu;
482 return sizeof(uint16_t);
483
484 case SO_L2CAP_IQOS:
485 memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t));
486 return sizeof(l2cap_qos_t);
487
488 case SO_L2CAP_OQOS:
489 memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t));
490 return sizeof(l2cap_qos_t);
491
492 case SO_L2CAP_FLUSH:
493 *(uint16_t *)addr = chan->lc_flush;
494 return sizeof(uint16_t);
495
496 case SO_L2CAP_LM:
497 *(int *)addr = chan->lc_mode;
498 return sizeof(int);
499
500 default:
501 break;
502 }
503
504 return 0;
505 }