Annotation of sys/netbt/rfcomm_upper.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: rfcomm_upper.c,v 1.2 2007/06/26 10:30:05 tom Exp $ */
2: /* $NetBSD: rfcomm_upper.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
3:
4: /*-
5: * Copyright (c) 2006 Itronix Inc.
6: * All rights reserved.
7: *
8: * Written by Iain Hibbert for Itronix Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. The name of Itronix Inc. may not be used to endorse
19: * or promote products derived from this software without specific
20: * prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
26: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29: * ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32: * POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include <sys/cdefs.h>
36:
37: #include <sys/param.h>
38: #include <sys/kernel.h>
39: #include <sys/mbuf.h>
40: #include <sys/proc.h>
41: #include <sys/systm.h>
42:
43: #include <netbt/bluetooth.h>
44: #include <netbt/hci.h>
45: #include <netbt/l2cap.h>
46: #include <netbt/rfcomm.h>
47:
48: /****************************************************************************
49: *
50: * RFCOMM DLC - Upper Protocol API
51: *
52: * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
53: * but it is should be possible to provide a pseudo-device for a direct
54: * tty interface.
55: */
56:
57: /*
58: * rfcomm_attach(handle, proto, upper)
59: *
60: * attach a new RFCOMM DLC to handle, populate with reasonable defaults
61: */
62: int
63: rfcomm_attach(struct rfcomm_dlc **handle,
64: const struct btproto *proto, void *upper)
65: {
66: struct rfcomm_dlc *dlc;
67:
68: KASSERT(handle != NULL);
69: KASSERT(proto != NULL);
70: KASSERT(upper != NULL);
71:
72: dlc = malloc(sizeof(struct rfcomm_dlc), M_BLUETOOTH, M_NOWAIT);
73: if (dlc == NULL)
74: return ENOMEM;
75: bzero(dlc, sizeof *dlc);
76:
77: dlc->rd_state = RFCOMM_DLC_CLOSED;
78: dlc->rd_mtu = rfcomm_mtu_default;
79:
80: dlc->rd_proto = proto;
81: dlc->rd_upper = upper;
82:
83: dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
84: dlc->rd_laddr.bt_family = AF_BLUETOOTH;
85: dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
86:
87: dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
88: dlc->rd_raddr.bt_family = AF_BLUETOOTH;
89: dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
90:
91: dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
92:
93: timeout_set(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
94:
95: *handle = dlc;
96: return 0;
97: }
98:
99: /*
100: * rfcomm_bind(dlc, sockaddr)
101: *
102: * bind DLC to local address
103: */
104: int
105: rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
106: {
107:
108: memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
109: return 0;
110: }
111:
112: /*
113: * rfcomm_sockaddr(dlc, sockaddr)
114: *
115: * return local address
116: */
117: int
118: rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
119: {
120:
121: memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
122: return 0;
123: }
124:
125: /*
126: * rfcomm_connect(dlc, sockaddr)
127: *
128: * Initiate connection of RFCOMM DLC to remote address.
129: */
130: int
131: rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
132: {
133: struct rfcomm_session *rs;
134: int err = 0;
135:
136: if (dlc->rd_state != RFCOMM_DLC_CLOSED)
137: return EISCONN;
138:
139: memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
140:
141: if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
142: || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
143: || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
144: return EDESTADDRREQ;
145:
146: if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
147: dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
148: else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
149: && (dlc->rd_raddr.bt_psm < 0x1001
150: || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
151: return EINVAL;
152:
153: /*
154: * We are allowed only one RFCOMM session between any 2 Bluetooth
155: * devices, so see if there is a session already otherwise create
156: * one and set it connecting.
157: */
158: rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
159: if (rs == NULL) {
160: rs = rfcomm_session_alloc(&rfcomm_session_active,
161: &dlc->rd_laddr);
162: if (rs == NULL)
163: return ENOMEM;
164:
165: rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
166: rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
167:
168: err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
169: if (err) {
170: rfcomm_session_free(rs);
171: return err;
172: }
173:
174: /*
175: * This session will start up automatically when its
176: * L2CAP channel is connected.
177: */
178: }
179:
180: /* construct DLC */
181: dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
182: if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
183: return EBUSY;
184:
185: l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
186:
187: /*
188: * attach the DLC to the session and start it off
189: */
190: dlc->rd_session = rs;
191: dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
192: LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
193:
194: if (rs->rs_state == RFCOMM_SESSION_OPEN)
195: err = rfcomm_dlc_connect(dlc);
196:
197: return err;
198: }
199:
200: /*
201: * rfcomm_peeraddr(dlc, sockaddr)
202: *
203: * return remote address
204: */
205: int
206: rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
207: {
208:
209: memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
210: return 0;
211: }
212:
213: /*
214: * rfcomm_disconnect(dlc, linger)
215: *
216: * disconnect RFCOMM DLC
217: */
218: int
219: rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
220: {
221: struct rfcomm_session *rs = dlc->rd_session;
222: int err = 0;
223:
224: KASSERT(dlc != NULL);
225:
226: switch (dlc->rd_state) {
227: case RFCOMM_DLC_CLOSED:
228: case RFCOMM_DLC_LISTEN:
229: return EINVAL;
230:
231: case RFCOMM_DLC_WAIT_SEND_UA:
232: err = rfcomm_session_send_frame(rs,
233: RFCOMM_FRAME_DM, dlc->rd_dlci);
234:
235: /* fall through */
236: case RFCOMM_DLC_WAIT_SESSION:
237: case RFCOMM_DLC_WAIT_CONNECT:
238: case RFCOMM_DLC_WAIT_SEND_SABM:
239: rfcomm_dlc_close(dlc, 0);
240: break;
241:
242: case RFCOMM_DLC_OPEN:
243: if (dlc->rd_txbuf != NULL && linger != 0) {
244: dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
245: break;
246: }
247:
248: /* else fall through */
249: case RFCOMM_DLC_WAIT_RECV_UA:
250: dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
251: err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
252: dlc->rd_dlci);
253: timeout_add(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
254: break;
255:
256: case RFCOMM_DLC_WAIT_DISCONNECT:
257: err = EALREADY;
258: break;
259:
260: default:
261: UNKNOWN(dlc->rd_state);
262: break;
263: }
264:
265: return err;
266: }
267:
268: /*
269: * rfcomm_detach(handle)
270: *
271: * detach RFCOMM DLC from handle
272: */
273: int
274: rfcomm_detach(struct rfcomm_dlc **handle)
275: {
276: struct rfcomm_dlc *dlc = *handle;
277:
278: if (dlc->rd_state != RFCOMM_DLC_CLOSED)
279: rfcomm_dlc_close(dlc, 0);
280:
281: if (dlc->rd_txbuf != NULL) {
282: m_freem(dlc->rd_txbuf);
283: dlc->rd_txbuf = NULL;
284: }
285:
286: dlc->rd_upper = NULL;
287: *handle = NULL;
288:
289: /*
290: * If callout is invoking we can't free the DLC so
291: * mark it and let the callout release it.
292: */
293: if (timeout_triggered(&dlc->rd_timeout))
294: dlc->rd_flags |= RFCOMM_DLC_DETACH;
295: else
296: free(dlc, M_BLUETOOTH);
297:
298: return 0;
299: }
300:
301: /*
302: * rfcomm_listen(dlc)
303: *
304: * This DLC is a listener. We look for an existing listening session
305: * with a matching address to attach to or else create a new one on
306: * the listeners list.
307: */
308: int
309: rfcomm_listen(struct rfcomm_dlc *dlc)
310: {
311: struct rfcomm_session *rs, *any, *best;
312: struct sockaddr_bt addr;
313: int err;
314:
315: if (dlc->rd_state != RFCOMM_DLC_CLOSED)
316: return EISCONN;
317:
318: if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
319: || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)
320: return EADDRNOTAVAIL;
321:
322: if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
323: dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
324: else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
325: && (dlc->rd_laddr.bt_psm < 0x1001
326: || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
327: return EADDRNOTAVAIL;
328:
329: any = best = NULL;
330: LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
331: l2cap_sockaddr(rs->rs_l2cap, &addr);
332:
333: if (addr.bt_psm != dlc->rd_laddr.bt_psm)
334: continue;
335:
336: if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
337: best = rs;
338:
339: if (bdaddr_any(&addr.bt_bdaddr))
340: any = rs;
341: }
342:
343: rs = best ? best : any;
344: if (rs == NULL) {
345: rs = rfcomm_session_alloc(&rfcomm_session_listen,
346: &dlc->rd_laddr);
347: if (rs == NULL)
348: return ENOMEM;
349:
350: rs->rs_state = RFCOMM_SESSION_LISTEN;
351:
352: err = l2cap_listen(rs->rs_l2cap);
353: if (err) {
354: rfcomm_session_free(rs);
355: return err;
356: }
357: }
358:
359: dlc->rd_session = rs;
360: dlc->rd_state = RFCOMM_DLC_LISTEN;
361: LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
362:
363: return 0;
364: }
365:
366: /*
367: * rfcomm_send(dlc, mbuf)
368: *
369: * Output data on DLC. This is streamed data, so we add it
370: * to our buffer and start the DLC, which will assemble
371: * packets and send them if it can.
372: */
373: int
374: rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
375: {
376:
377: if (dlc->rd_txbuf != NULL) {
378: dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
379: m_cat(dlc->rd_txbuf, m);
380: } else {
381: dlc->rd_txbuf = m;
382: }
383:
384: if (dlc->rd_state == RFCOMM_DLC_OPEN)
385: rfcomm_dlc_start(dlc);
386:
387: return 0;
388: }
389:
390: /*
391: * rfcomm_rcvd(dlc, space)
392: *
393: * Indicate space now available in receive buffer
394: *
395: * This should be used to give an initial value of the receive buffer
396: * size when the DLC is attached and anytime data is cleared from the
397: * buffer after that.
398: */
399: int
400: rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
401: {
402:
403: KASSERT(dlc != NULL);
404:
405: dlc->rd_rxsize = space;
406:
407: /*
408: * if we are using credit based flow control, we may
409: * want to send some credits..
410: */
411: if (dlc->rd_state == RFCOMM_DLC_OPEN
412: && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
413: rfcomm_dlc_start(dlc);
414:
415: return 0;
416: }
417:
418: /*
419: * rfcomm_setopt(dlc, option, addr)
420: *
421: * set DLC options
422: */
423: int
424: rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
425: {
426: int mode, err = 0;
427: uint16_t mtu;
428:
429: switch (opt) {
430: case SO_RFCOMM_MTU:
431: mtu = *(uint16_t *)addr;
432: if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
433: err = EINVAL;
434: else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
435: dlc->rd_mtu = mtu;
436: else
437: err = EBUSY;
438:
439: break;
440:
441: case SO_RFCOMM_LM:
442: mode = *(int *)addr;
443: mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
444:
445: if (mode & RFCOMM_LM_SECURE)
446: mode |= RFCOMM_LM_ENCRYPT;
447:
448: if (mode & RFCOMM_LM_ENCRYPT)
449: mode |= RFCOMM_LM_AUTH;
450:
451: dlc->rd_mode = mode;
452:
453: if (dlc->rd_state == RFCOMM_DLC_OPEN)
454: err = rfcomm_dlc_setmode(dlc);
455:
456: break;
457:
458: default:
459: err = ENOPROTOOPT;
460: break;
461: }
462: return err;
463: }
464:
465: /*
466: * rfcomm_getopt(dlc, option, addr)
467: *
468: * get DLC options
469: */
470: int
471: rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
472: {
473: struct rfcomm_fc_info *fc;
474:
475: switch (opt) {
476: case SO_RFCOMM_MTU:
477: *(uint16_t *)addr = dlc->rd_mtu;
478: return sizeof(uint16_t);
479:
480: case SO_RFCOMM_FC_INFO:
481: fc = addr;
482: memset(fc, 0, sizeof(*fc));
483: fc->lmodem = dlc->rd_lmodem;
484: fc->rmodem = dlc->rd_rmodem;
485: fc->tx_cred = max(dlc->rd_txcred, 0xff);
486: fc->rx_cred = max(dlc->rd_rxcred, 0xff);
487: if (dlc->rd_session
488: && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
489: fc->cfc = 1;
490:
491: return sizeof(*fc);
492:
493: case SO_RFCOMM_LM:
494: *(int *)addr = dlc->rd_mode;
495: return sizeof(int);
496:
497: default:
498: break;
499: }
500:
501: return 0;
502: }
CVSweb