1/* $NetBSD: rfcomm_upper.c,v 1.22 2014/11/16 21:34:27 plunky Exp $ */
2
3/*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Written by Iain Hibbert for Itronix Inc.
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__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.22 2014/11/16 21:34:27 plunky Exp $");
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/mbuf.h>
40#include <sys/kmem.h>
41#include <sys/socketvar.h>
42#include <sys/systm.h>
43
44#include <netbt/bluetooth.h>
45#include <netbt/hci.h>
46#include <netbt/l2cap.h>
47#include <netbt/rfcomm.h>
48
49/****************************************************************************
50 *
51 * RFCOMM DLC - Upper Protocol API
52 *
53 * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
54 * but it is should be possible to provide a pseudo-device for a direct
55 * tty interface.
56 */
57
58/*
59 * rfcomm_attach_pcb(handle, proto, upper)
60 *
61 * attach a new RFCOMM DLC to handle, populate with reasonable defaults
62 */
63int
64rfcomm_attach_pcb(struct rfcomm_dlc **handle,
65 const struct btproto *proto, void *upper)
66{
67 struct rfcomm_dlc *dlc;
68
69 KASSERT(handle != NULL);
70 KASSERT(proto != NULL);
71 KASSERT(upper != NULL);
72
73 dlc = kmem_intr_zalloc(sizeof(struct rfcomm_dlc), KM_NOSLEEP);
74 if (dlc == NULL)
75 return ENOMEM;
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 callout_init(&dlc->rd_timeout, 0);
94 callout_setfunc(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
95
96 *handle = dlc;
97 return 0;
98}
99
100/*
101 * rfcomm_bind_pcb(dlc, sockaddr)
102 *
103 * bind DLC to local address
104 */
105int
106rfcomm_bind_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
107{
108
109 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
110 return EINVAL;
111
112 memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
113 return 0;
114}
115
116/*
117 * rfcomm_sockaddr_pcb(dlc, sockaddr)
118 *
119 * return local address
120 */
121int
122rfcomm_sockaddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
123{
124
125 memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
126 return 0;
127}
128
129/*
130 * rfcomm_connect_pcb(dlc, sockaddr)
131 *
132 * Initiate connection of RFCOMM DLC to remote address.
133 */
134int
135rfcomm_connect_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
136{
137 struct rfcomm_session *rs;
138 int err = 0;
139
140 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
141 return EISCONN;
142
143 memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
144
145 if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
146 || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
147 || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
148 return EDESTADDRREQ;
149
150 if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
151 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
152 else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
153 && (dlc->rd_raddr.bt_psm < 0x1001
154 || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
155 return EINVAL;
156
157 /*
158 * We are allowed only one RFCOMM session between any 2 Bluetooth
159 * devices, so see if there is a session already otherwise create
160 * one and set it connecting.
161 */
162 rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
163 if (rs == NULL) {
164 rs = rfcomm_session_alloc(&rfcomm_session_active,
165 &dlc->rd_laddr);
166 if (rs == NULL)
167 return ENOMEM;
168
169 rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
170 rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
171
172 err = l2cap_connect_pcb(rs->rs_l2cap, &dlc->rd_raddr);
173 if (err) {
174 rfcomm_session_free(rs);
175 return err;
176 }
177
178 /*
179 * This session will start up automatically when its
180 * L2CAP channel is connected.
181 */
182 }
183
184 /* construct DLC */
185 dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
186 if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
187 return EBUSY;
188
189 l2cap_sockaddr_pcb(rs->rs_l2cap, &dlc->rd_laddr);
190
191 /*
192 * attach the DLC to the session and start it off
193 */
194 dlc->rd_session = rs;
195 dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
196 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
197
198 if (rs->rs_state == RFCOMM_SESSION_OPEN)
199 err = rfcomm_dlc_connect(dlc);
200
201 return err;
202}
203
204/*
205 * rfcomm_peeraddr_pcb(dlc, sockaddr)
206 *
207 * return remote address
208 */
209int
210rfcomm_peeraddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
211{
212
213 memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
214 return 0;
215}
216
217/*
218 * rfcomm_disconnect_pcb(dlc, linger)
219 *
220 * disconnect RFCOMM DLC
221 */
222int
223rfcomm_disconnect_pcb(struct rfcomm_dlc *dlc, int linger)
224{
225 struct rfcomm_session *rs = dlc->rd_session;
226 int err = 0;
227
228 KASSERT(dlc != NULL);
229
230 switch (dlc->rd_state) {
231 case RFCOMM_DLC_CLOSED:
232 case RFCOMM_DLC_LISTEN:
233 return EINVAL;
234
235 case RFCOMM_DLC_WAIT_SEND_UA:
236 err = rfcomm_session_send_frame(rs,
237 RFCOMM_FRAME_DM, dlc->rd_dlci);
238
239 /* fall through */
240 case RFCOMM_DLC_WAIT_SESSION:
241 case RFCOMM_DLC_WAIT_CONNECT:
242 case RFCOMM_DLC_WAIT_SEND_SABM:
243 rfcomm_dlc_close(dlc, 0);
244 break;
245
246 case RFCOMM_DLC_OPEN:
247 if (dlc->rd_txbuf != NULL && linger != 0) {
248 dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
249 break;
250 }
251
252 /* else fall through */
253 case RFCOMM_DLC_WAIT_RECV_UA:
254 dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
255 err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
256 dlc->rd_dlci);
257 callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
258 break;
259
260 case RFCOMM_DLC_WAIT_DISCONNECT:
261 err = EALREADY;
262 break;
263
264 default:
265 UNKNOWN(dlc->rd_state);
266 break;
267 }
268
269 return err;
270}
271
272/*
273 * rfcomm_detach_pcb(handle)
274 *
275 * detach RFCOMM DLC from handle
276 */
277void
278rfcomm_detach_pcb(struct rfcomm_dlc **handle)
279{
280 struct rfcomm_dlc *dlc = *handle;
281
282 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
283 rfcomm_dlc_close(dlc, 0);
284
285 if (dlc->rd_txbuf != NULL) {
286 m_freem(dlc->rd_txbuf);
287 dlc->rd_txbuf = NULL;
288 }
289
290 dlc->rd_upper = NULL;
291 *handle = NULL;
292
293 /*
294 * If callout is invoking we can't free the DLC so
295 * mark it and let the callout release it.
296 */
297 if (callout_invoking(&dlc->rd_timeout))
298 dlc->rd_flags |= RFCOMM_DLC_DETACH;
299 else {
300 callout_destroy(&dlc->rd_timeout);
301 kmem_intr_free(dlc, sizeof(*dlc));
302 }
303}
304
305/*
306 * rfcomm_listen_pcb(dlc)
307 *
308 * This DLC is a listener. We look for an existing listening session
309 * with a matching address to attach to or else create a new one on
310 * the listeners list. If the ANY channel is given, allocate the first
311 * available for the session.
312 */
313int
314rfcomm_listen_pcb(struct rfcomm_dlc *dlc)
315{
316 struct rfcomm_session *rs;
317 struct rfcomm_dlc *used;
318 struct sockaddr_bt addr;
319 int err, channel;
320
321 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
322 return EISCONN;
323
324 if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
325 && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
326 || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
327 return EADDRNOTAVAIL;
328
329 if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
330 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
331 else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
332 && (dlc->rd_laddr.bt_psm < 0x1001
333 || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
334 return EADDRNOTAVAIL;
335
336 LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
337 l2cap_sockaddr_pcb(rs->rs_l2cap, &addr);
338
339 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
340 continue;
341
342 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
343 break;
344 }
345
346 if (rs == NULL) {
347 rs = rfcomm_session_alloc(&rfcomm_session_listen,
348 &dlc->rd_laddr);
349 if (rs == NULL)
350 return ENOMEM;
351
352 rs->rs_state = RFCOMM_SESSION_LISTEN;
353
354 err = l2cap_listen_pcb(rs->rs_l2cap);
355 if (err) {
356 rfcomm_session_free(rs);
357 return err;
358 }
359 }
360
361 if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
362 channel = RFCOMM_CHANNEL_MIN;
363 used = LIST_FIRST(&rs->rs_dlcs);
364
365 while (used != NULL) {
366 if (used->rd_laddr.bt_channel == channel) {
367 if (channel++ == RFCOMM_CHANNEL_MAX)
368 return EADDRNOTAVAIL;
369
370 used = LIST_FIRST(&rs->rs_dlcs);
371 } else {
372 used = LIST_NEXT(used, rd_next);
373 }
374 }
375
376 dlc->rd_laddr.bt_channel = channel;
377 }
378
379 dlc->rd_session = rs;
380 dlc->rd_state = RFCOMM_DLC_LISTEN;
381 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
382
383 return 0;
384}
385
386/*
387 * rfcomm_send_pcb(dlc, mbuf)
388 *
389 * Output data on DLC. This is streamed data, so we add it
390 * to our buffer and start the DLC, which will assemble
391 * packets and send them if it can.
392 */
393int
394rfcomm_send_pcb(struct rfcomm_dlc *dlc, struct mbuf *m)
395{
396
397 if (dlc->rd_txbuf != NULL) {
398 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
399 m_cat(dlc->rd_txbuf, m);
400 } else {
401 dlc->rd_txbuf = m;
402 }
403
404 if (dlc->rd_state == RFCOMM_DLC_OPEN)
405 rfcomm_dlc_start(dlc);
406
407 return 0;
408}
409
410/*
411 * rfcomm_rcvd_pcb(dlc, space)
412 *
413 * Indicate space now available in receive buffer
414 *
415 * This should be used to give an initial value of the receive buffer
416 * size when the DLC is attached and anytime data is cleared from the
417 * buffer after that.
418 */
419int
420rfcomm_rcvd_pcb(struct rfcomm_dlc *dlc, size_t space)
421{
422
423 KASSERT(dlc != NULL);
424
425 dlc->rd_rxsize = space;
426
427 /*
428 * if we are using credit based flow control, we may
429 * want to send some credits..
430 */
431 if (dlc->rd_state == RFCOMM_DLC_OPEN
432 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
433 rfcomm_dlc_start(dlc);
434
435 return 0;
436}
437
438/*
439 * rfcomm_setopt(dlc, sopt)
440 *
441 * set DLC options
442 */
443int
444rfcomm_setopt(struct rfcomm_dlc *dlc, const struct sockopt *sopt)
445{
446 int mode, err = 0;
447 uint16_t mtu;
448
449 switch (sopt->sopt_name) {
450 case SO_RFCOMM_MTU:
451 err = sockopt_get(sopt, &mtu, sizeof(mtu));
452 if (err)
453 break;
454
455 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
456 err = EINVAL;
457 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
458 dlc->rd_mtu = mtu;
459 else
460 err = EBUSY;
461
462 break;
463
464 case SO_RFCOMM_LM:
465 err = sockopt_getint(sopt, &mode);
466 if (err)
467 break;
468
469 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
470
471 if (mode & RFCOMM_LM_SECURE)
472 mode |= RFCOMM_LM_ENCRYPT;
473
474 if (mode & RFCOMM_LM_ENCRYPT)
475 mode |= RFCOMM_LM_AUTH;
476
477 dlc->rd_mode = mode;
478
479 if (dlc->rd_state == RFCOMM_DLC_OPEN)
480 err = rfcomm_dlc_setmode(dlc);
481
482 break;
483
484 default:
485 err = ENOPROTOOPT;
486 break;
487 }
488 return err;
489}
490
491/*
492 * rfcomm_getopt(dlc, sopt)
493 *
494 * get DLC options
495 */
496int
497rfcomm_getopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
498{
499 struct rfcomm_fc_info fc;
500
501 switch (sopt->sopt_name) {
502 case SO_RFCOMM_MTU:
503 return sockopt_set(sopt, &dlc->rd_mtu, sizeof(uint16_t));
504
505 case SO_RFCOMM_FC_INFO:
506 memset(&fc, 0, sizeof(fc));
507 fc.lmodem = dlc->rd_lmodem;
508 fc.rmodem = dlc->rd_rmodem;
509 fc.tx_cred = max(dlc->rd_txcred, 0xff);
510 fc.rx_cred = max(dlc->rd_rxcred, 0xff);
511 if (dlc->rd_session
512 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
513 fc.cfc = 1;
514
515 return sockopt_set(sopt, &fc, sizeof(fc));
516
517 case SO_RFCOMM_LM:
518 return sockopt_setint(sopt, dlc->rd_mode);
519
520 default:
521 break;
522 }
523
524 return ENOPROTOOPT;
525}
526