Annotation of sys/netbt/l2cap_upper.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: l2cap_upper.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
2: /* $NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $ */
3:
4: /*-
5: * Copyright (c) 2005 Iain Hibbert.
6: * Copyright (c) 2006 Itronix Inc.
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. The name of Itronix Inc. may not be used to endorse
18: * or promote products derived from this software without specific
19: * prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28: * ON ANY THEORY OF LIABILITY, WHETHER IN
29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31: * POSSIBILITY OF SUCH DAMAGE.
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: * L2CAP Channel - Upper Protocol API
52: */
53:
54: /*
55: * l2cap_attach(handle, btproto, upper)
56: *
57: * attach new l2cap_channel to handle, populate
58: * with reasonable defaults
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: * l2cap_bind(l2cap_channel, sockaddr)
105: *
106: * set local address of channel
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: * l2cap_sockaddr(l2cap_channel, sockaddr)
118: *
119: * get local address of channel
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: * l2cap_connect(l2cap_channel, sockaddr)
131: *
132: * Initiate a connection to destination. This corresponds to
133: * "Open Channel Request" in the L2CAP specification and will
134: * result in one of the following:
135: *
136: * proto->connected(upper)
137: * proto->disconnected(upper, error)
138: *
139: * and, optionally
140: * proto->connecting(upper)
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: /* set local address if it needs setting */
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: /* attach to active list */
169: err = l2cap_cid_alloc(chan);
170: if (err)
171: return err;
172:
173: /* open link to remote device */
174: chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr);
175: if (chan->lc_link == NULL)
176: return EHOSTUNREACH;
177:
178: /* set the link mode */
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: * We can queue a connect request now even though the link may
190: * not yet be open; Our mode setting is assured, and the queue
191: * will be started automatically at the right time.
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: * l2cap_peeraddr(l2cap_channel, sockaddr)
209: *
210: * get remote address of channel
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: * l2cap_disconnect(l2cap_channel, linger)
222: *
223: * Initiate L2CAP disconnection. This corresponds to
224: * "Close Channel Request" in the L2CAP specification
225: * and will result in a call to
226: *
227: * proto->disconnected(upper, error)
228: *
229: * when the disconnection is complete. If linger is set,
230: * the call will not be made until data has flushed from
231: * the queue.
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: * no need to do anything unless the queue is empty or
246: * we are not lingering..
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: * l2cap_detach(handle)
260: *
261: * Detach l2cap channel from handle & close it down
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: * Could implement some kind of delayed expunge to make sure that the
283: * CID is really dead before it becomes available for reuse?
284: */
285:
286: free(chan, M_BLUETOOTH);
287: return 0;
288: }
289:
290: /*
291: * l2cap_listen(l2cap_channel)
292: *
293: * Use this channel as a listening post (until detached). This will
294: * result in calls to:
295: *
296: * proto->newconn(upper, laddr, raddr)
297: *
298: * for incoming connections matching the psm and local address of the
299: * channel (NULL psm/address are permitted and match any protocol/device).
300: *
301: * The upper layer should create and return a new channel.
302: *
303: * You cannot use this channel for anything else subsequent to this call
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: * This CID is irrelevant, as the channel is not stored on the active
319: * list and the socket code does not allow operations on listening
320: * sockets, but we set it so the detach code knows to LIST_REMOVE the
321: * channel.
322: */
323: chan->lc_lcid = L2CAP_SIGNAL_CID;
324:
325: /*
326: * The list of listening channels is stored in an order such that new
327: * listeners dont usurp current listeners, but that specific listening
328: * takes precedence over promiscuous, and the connect request code can
329: * easily use the first matching entry.
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: * l2cap_send(l2cap_channel, mbuf)
353: *
354: * Output SDU on channel described by channel. This corresponds
355: * to "Send Data Request" in the L2CAP specification. The upper
356: * layer will be notified when SDU's have completed sending by a
357: * call to:
358: *
359: * proto->complete(upper, n)
360: *
361: * (currently n == 1)
362: *
363: * Note: I'm not sure how this will work out, but I think that
364: * if outgoing Retransmission Mode or Flow Control Mode is
365: * negotiated then this call will not be made until the SDU has
366: * been acknowleged by the peer L2CAP entity. For 'Best Effort'
367: * it will be made when the packet has cleared the controller
368: * buffers.
369: *
370: * We only support Basic mode so far, so encapsulate with a
371: * B-Frame header and start sending if we are not already
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: /* Encapsulate with B-Frame */
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: /* Queue it on our list */
399: IF_ENQUEUE(&chan->lc_txq, m);
400:
401: /* If we are not sending, then start doing so */
402: if (chan->lc_pending == 0)
403: return l2cap_start(chan);
404:
405: return 0;
406: }
407:
408: /*
409: * l2cap_setopt(l2cap_channel, opt, addr)
410: *
411: * Apply configuration options to channel. This corresponds to
412: * "Configure Channel Request" in the L2CAP specification.
413: *
414: * for SO_L2CAP_LM, the settings will take effect when the
415: * channel is established. If the channel is already open,
416: * a call to
417: * proto->linkmode(upper, new)
418: *
419: * will be made when the change is complete.
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: /* set Incoming MTU */
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: /* set link mode */
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: /* set Outgoing QoS flow spec */
457: case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */
458: default:
459: err = ENOPROTOOPT;
460: break;
461: }
462:
463: return err;
464: }
465:
466: /*
467: * l2cap_getopt(l2cap_channel, opt, addr)
468: *
469: * Return configuration parameters.
470: */
471: int
472: l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
473: {
474:
475: switch (opt) {
476: case SO_L2CAP_IMTU: /* get Incoming MTU */
477: *(uint16_t *)addr = chan->lc_imtu;
478: return sizeof(uint16_t);
479:
480: case SO_L2CAP_OMTU: /* get Outgoing MTU */
481: *(uint16_t *)addr = chan->lc_omtu;
482: return sizeof(uint16_t);
483:
484: case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */
485: memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t));
486: return sizeof(l2cap_qos_t);
487:
488: case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */
489: memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t));
490: return sizeof(l2cap_qos_t);
491:
492: case SO_L2CAP_FLUSH: /* get Flush Timeout */
493: *(uint16_t *)addr = chan->lc_flush;
494: return sizeof(uint16_t);
495:
496: case SO_L2CAP_LM: /* get link mode */
497: *(int *)addr = chan->lc_mode;
498: return sizeof(int);
499:
500: default:
501: break;
502: }
503:
504: return 0;
505: }
CVSweb