Remove tm.h and xm.h handling, as it wasn't used. Use nm.h only when needed.
[dragonfly.git] / sys / netbt / rfcomm_upper.c
blobdceeac6c7e0f133035b6ea57a04a6315ef17c594
1 /* $OpenBSD: rfcomm_upper.c,v 1.3 2007/10/01 16:39:30 krw Exp $ */
2 /* $NetBSD: rfcomm_upper.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
3 /* $DragonFly: src/sys/netbt/rfcomm_upper.c,v 1.1 2007/12/30 20:02:56 hasso Exp $ */
5 /*-
6 * Copyright (c) 2006 Itronix Inc.
7 * All rights reserved.
9 * Written by Iain Hibbert for Itronix Inc.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of Itronix Inc. may not be used to endorse
20 * or promote products derived from this software without specific
21 * prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
36 #include <sys/cdefs.h>
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/proc.h>
42 #include <sys/systm.h>
43 #include <sys/socketvar.h>
45 #include <netbt/bluetooth.h>
46 #include <netbt/hci.h>
47 #include <netbt/l2cap.h>
48 #include <netbt/rfcomm.h>
50 /****************************************************************************
52 * RFCOMM DLC - Upper Protocol API
54 * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
55 * but it is should be possible to provide a pseudo-device for a direct
56 * tty interface.
60 * rfcomm_attach(handle, proto, upper)
62 * attach a new RFCOMM DLC to handle, populate with reasonable defaults
64 int
65 rfcomm_attach(struct rfcomm_dlc **handle,
66 const struct btproto *proto, void *upper)
68 struct rfcomm_dlc *dlc;
70 KKASSERT(handle != NULL);
71 KKASSERT(proto != NULL);
72 KKASSERT(upper != NULL);
74 dlc = kmalloc(sizeof(*dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
75 if (dlc == NULL)
76 return ENOMEM;
78 dlc->rd_state = RFCOMM_DLC_CLOSED;
79 dlc->rd_mtu = rfcomm_mtu_default;
81 dlc->rd_proto = proto;
82 dlc->rd_upper = upper;
84 dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
85 dlc->rd_laddr.bt_family = AF_BLUETOOTH;
86 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
88 dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
89 dlc->rd_raddr.bt_family = AF_BLUETOOTH;
90 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
92 dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
94 callout_init(&dlc->rd_timeout);
96 *handle = dlc;
97 return 0;
101 * rfcomm_bind(dlc, sockaddr)
103 * bind DLC to local address
106 rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
109 memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
110 return 0;
114 * rfcomm_sockaddr(dlc, sockaddr)
116 * return local address
119 rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
122 memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
123 return 0;
127 * rfcomm_connect(dlc, sockaddr)
129 * Initiate connection of RFCOMM DLC to remote address.
132 rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
134 struct rfcomm_session *rs;
135 int err = 0;
137 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
138 return EISCONN;
140 memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
142 if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
143 || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
144 || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
145 return EDESTADDRREQ;
147 if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
148 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
149 else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
150 && (dlc->rd_raddr.bt_psm < 0x1001
151 || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
152 return EINVAL;
155 * We are allowed only one RFCOMM session between any 2 Bluetooth
156 * devices, so see if there is a session already otherwise create
157 * one and set it connecting.
159 rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
160 if (rs == NULL) {
161 rs = rfcomm_session_alloc(&rfcomm_session_active,
162 &dlc->rd_laddr);
163 if (rs == NULL)
164 return ENOMEM;
166 rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
167 rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
169 err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
170 if (err) {
171 rfcomm_session_free(rs);
172 return err;
176 * This session will start up automatically when its
177 * L2CAP channel is connected.
181 /* construct DLC */
182 dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
183 if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
184 return EBUSY;
186 l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
189 * attach the DLC to the session and start it off
191 dlc->rd_session = rs;
192 dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
193 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
195 if (rs->rs_state == RFCOMM_SESSION_OPEN)
196 err = rfcomm_dlc_connect(dlc);
198 return err;
202 * rfcomm_peeraddr(dlc, sockaddr)
204 * return remote address
207 rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
210 memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
211 return 0;
215 * rfcomm_disconnect(dlc, linger)
217 * disconnect RFCOMM DLC
220 rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
222 struct rfcomm_session *rs = dlc->rd_session;
223 int err = 0;
225 KKASSERT(dlc != NULL);
227 switch (dlc->rd_state) {
228 case RFCOMM_DLC_CLOSED:
229 case RFCOMM_DLC_LISTEN:
230 return EINVAL;
232 case RFCOMM_DLC_WAIT_SEND_UA:
233 err = rfcomm_session_send_frame(rs,
234 RFCOMM_FRAME_DM, dlc->rd_dlci);
236 /* fall through */
237 case RFCOMM_DLC_WAIT_SESSION:
238 case RFCOMM_DLC_WAIT_CONNECT:
239 case RFCOMM_DLC_WAIT_SEND_SABM:
240 rfcomm_dlc_close(dlc, 0);
241 break;
243 case RFCOMM_DLC_OPEN:
244 if (dlc->rd_txbuf != NULL && linger != 0) {
245 dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
246 break;
249 /* else fall through */
250 case RFCOMM_DLC_WAIT_RECV_UA:
251 dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
252 err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
253 dlc->rd_dlci);
254 callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
255 rfcomm_dlc_timeout, dlc);
256 break;
258 case RFCOMM_DLC_WAIT_DISCONNECT:
259 err = EALREADY;
260 break;
262 default:
263 UNKNOWN(dlc->rd_state);
264 break;
267 return err;
271 * rfcomm_detach(handle)
273 * detach RFCOMM DLC from handle
276 rfcomm_detach(struct rfcomm_dlc **handle)
278 struct rfcomm_dlc *dlc = *handle;
280 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
281 rfcomm_dlc_close(dlc, 0);
283 if (dlc->rd_txbuf != NULL) {
284 m_freem(dlc->rd_txbuf);
285 dlc->rd_txbuf = NULL;
288 dlc->rd_upper = NULL;
289 *handle = NULL;
292 * If callout is invoking we can't free the DLC so
293 * mark it and let the callout release it.
295 if (callout_active(&dlc->rd_timeout))
296 dlc->rd_flags |= RFCOMM_DLC_DETACH;
297 else
298 kfree(dlc, M_BLUETOOTH);
300 return 0;
304 * rfcomm_listen(dlc)
306 * This DLC is a listener. We look for an existing listening session
307 * with a matching address to attach to or else create a new one on
308 * the listeners list.
311 rfcomm_listen(struct rfcomm_dlc *dlc)
313 struct rfcomm_session *rs, *any, *best;
314 struct sockaddr_bt addr;
315 int err;
317 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
318 return EISCONN;
320 if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
321 || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)
322 return EADDRNOTAVAIL;
324 if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
325 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
326 else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
327 && (dlc->rd_laddr.bt_psm < 0x1001
328 || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
329 return EADDRNOTAVAIL;
331 any = best = NULL;
332 LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
333 l2cap_sockaddr(rs->rs_l2cap, &addr);
335 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
336 continue;
338 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
339 best = rs;
341 if (bdaddr_any(&addr.bt_bdaddr))
342 any = rs;
345 rs = best ? best : any;
346 if (rs == NULL) {
347 rs = rfcomm_session_alloc(&rfcomm_session_listen,
348 &dlc->rd_laddr);
349 if (rs == NULL)
350 return ENOMEM;
352 rs->rs_state = RFCOMM_SESSION_LISTEN;
354 err = l2cap_listen(rs->rs_l2cap);
355 if (err) {
356 rfcomm_session_free(rs);
357 return err;
361 dlc->rd_session = rs;
362 dlc->rd_state = RFCOMM_DLC_LISTEN;
363 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
365 return 0;
369 * rfcomm_send(dlc, mbuf)
371 * Output data on DLC. This is streamed data, so we add it
372 * to our buffer and start the DLC, which will assemble
373 * packets and send them if it can.
376 rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
379 if (dlc->rd_txbuf != NULL) {
380 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
381 m_cat(dlc->rd_txbuf, m);
382 } else {
383 dlc->rd_txbuf = m;
386 if (dlc->rd_state == RFCOMM_DLC_OPEN)
387 rfcomm_dlc_start(dlc);
389 return 0;
393 * rfcomm_rcvd(dlc, space)
395 * Indicate space now available in receive buffer
397 * This should be used to give an initial value of the receive buffer
398 * size when the DLC is attached and anytime data is cleared from the
399 * buffer after that.
402 rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
405 KKASSERT(dlc != NULL);
407 dlc->rd_rxsize = space;
410 * if we are using credit based flow control, we may
411 * want to send some credits..
413 if (dlc->rd_state == RFCOMM_DLC_OPEN
414 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
415 rfcomm_dlc_start(dlc);
417 return 0;
421 * rfcomm_setopt(dlc, option, addr)
423 * set DLC options
426 rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
428 int mode, err = 0;
429 uint16_t mtu;
431 switch (opt) {
432 case SO_RFCOMM_MTU:
433 mtu = *(uint16_t *)addr;
434 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
435 err = EINVAL;
436 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
437 dlc->rd_mtu = mtu;
438 else
439 err = EBUSY;
441 break;
443 case SO_RFCOMM_LM:
444 mode = *(int *)addr;
445 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
447 if (mode & RFCOMM_LM_SECURE)
448 mode |= RFCOMM_LM_ENCRYPT;
450 if (mode & RFCOMM_LM_ENCRYPT)
451 mode |= RFCOMM_LM_AUTH;
453 dlc->rd_mode = mode;
455 if (dlc->rd_state == RFCOMM_DLC_OPEN)
456 err = rfcomm_dlc_setmode(dlc);
458 break;
460 default:
461 err = ENOPROTOOPT;
462 break;
464 return err;
469 rfcomm_setopt2(struct rfcomm_dlc *dlc, int opt, struct socket *so,
470 struct sockopt *sopt)
472 int mode, err = 0;
473 uint16_t mtu;
475 switch (opt) {
476 case SO_RFCOMM_MTU:
477 err = sooptcopyin(sopt, &mtu, sizeof(uint16_t),
478 sizeof(uint16_t));
479 if (err) break;
481 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
482 err = EINVAL;
483 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
484 dlc->rd_mtu = mtu;
485 else
486 err = EBUSY;
488 break;
490 case SO_RFCOMM_LM:
491 err = sooptcopyin(sopt, &mode, sizeof(int), sizeof(int));
492 if (err) break;
494 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
496 if (mode & RFCOMM_LM_SECURE)
497 mode |= RFCOMM_LM_ENCRYPT;
499 if (mode & RFCOMM_LM_ENCRYPT)
500 mode |= RFCOMM_LM_AUTH;
502 dlc->rd_mode = mode;
504 if (dlc->rd_state == RFCOMM_DLC_OPEN)
505 err = rfcomm_dlc_setmode(dlc);
507 break;
509 default:
510 err = ENOPROTOOPT;
511 break;
513 return err;
517 * rfcomm_getopt(dlc, option, addr)
519 * get DLC options
522 rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
524 struct rfcomm_fc_info *fc;
526 switch (opt) {
527 case SO_RFCOMM_MTU:
528 *(uint16_t *)addr = dlc->rd_mtu;
529 return sizeof(uint16_t);
531 case SO_RFCOMM_FC_INFO:
532 fc = addr;
533 memset(fc, 0, sizeof(*fc));
534 fc->lmodem = dlc->rd_lmodem;
535 fc->rmodem = dlc->rd_rmodem;
536 fc->tx_cred = max(dlc->rd_txcred, 0xff);
537 fc->rx_cred = max(dlc->rd_rxcred, 0xff);
538 if (dlc->rd_session
539 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
540 fc->cfc = 1;
542 return sizeof(*fc);
544 case SO_RFCOMM_LM:
545 *(int *)addr = dlc->rd_mode;
546 return sizeof(int);
548 default:
549 break;
552 return 0;