rfcomm_upper.c revision 1.9 1 /* $NetBSD: rfcomm_upper.c,v 1.9 2007/11/20 20:19:24 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.9 2007/11/20 20:19:24 plunky Exp $");
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 | M_ZERO);
73 if (dlc == NULL)
74 return ENOMEM;
75
76 dlc->rd_state = RFCOMM_DLC_CLOSED;
77 dlc->rd_mtu = rfcomm_mtu_default;
78
79 dlc->rd_proto = proto;
80 dlc->rd_upper = upper;
81
82 dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
83 dlc->rd_laddr.bt_family = AF_BLUETOOTH;
84 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
85
86 dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
87 dlc->rd_raddr.bt_family = AF_BLUETOOTH;
88 dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
89
90 dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
91
92 callout_init(&dlc->rd_timeout, 0);
93 callout_setfunc(&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 callout_schedule(&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 (callout_invoking(&dlc->rd_timeout))
294 dlc->rd_flags |= RFCOMM_DLC_DETACH;
295 else {
296 callout_destroy(&dlc->rd_timeout);
297 free(dlc, M_BLUETOOTH);
298 }
299
300 return 0;
301 }
302
303 /*
304 * rfcomm_listen(dlc)
305 *
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.
309 */
310 int
311 rfcomm_listen(struct rfcomm_dlc *dlc)
312 {
313 struct rfcomm_session *rs;
314 struct sockaddr_bt addr;
315 int err;
316
317 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
318 return EISCONN;
319
320 if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
321 || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)
322 return EADDRNOTAVAIL;
323
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;
330
331 LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
332 l2cap_sockaddr(rs->rs_l2cap, &addr);
333
334 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
335 continue;
336
337 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
338 break;
339 }
340
341 if (rs == NULL) {
342 rs = rfcomm_session_alloc(&rfcomm_session_listen,
343 &dlc->rd_laddr);
344 if (rs == NULL)
345 return ENOMEM;
346
347 rs->rs_state = RFCOMM_SESSION_LISTEN;
348
349 err = l2cap_listen(rs->rs_l2cap);
350 if (err) {
351 rfcomm_session_free(rs);
352 return err;
353 }
354 }
355
356 dlc->rd_session = rs;
357 dlc->rd_state = RFCOMM_DLC_LISTEN;
358 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
359
360 return 0;
361 }
362
363 /*
364 * rfcomm_send(dlc, mbuf)
365 *
366 * Output data on DLC. This is streamed data, so we add it
367 * to our buffer and start the the DLC, which will assemble
368 * packets and send them if it can.
369 */
370 int
371 rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
372 {
373
374 if (dlc->rd_txbuf != NULL) {
375 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
376 m_cat(dlc->rd_txbuf, m);
377 } else {
378 dlc->rd_txbuf = m;
379 }
380
381 if (dlc->rd_state == RFCOMM_DLC_OPEN)
382 rfcomm_dlc_start(dlc);
383
384 return 0;
385 }
386
387 /*
388 * rfcomm_rcvd(dlc, space)
389 *
390 * Indicate space now available in receive buffer
391 *
392 * This should be used to give an initial value of the receive buffer
393 * size when the DLC is attached and anytime data is cleared from the
394 * buffer after that.
395 */
396 int
397 rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
398 {
399
400 KASSERT(dlc != NULL);
401
402 dlc->rd_rxsize = space;
403
404 /*
405 * if we are using credit based flow control, we may
406 * want to send some credits..
407 */
408 if (dlc->rd_state == RFCOMM_DLC_OPEN
409 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
410 rfcomm_dlc_start(dlc);
411
412 return 0;
413 }
414
415 /*
416 * rfcomm_setopt(dlc, option, addr)
417 *
418 * set DLC options
419 */
420 int
421 rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
422 {
423 int mode, err = 0;
424 uint16_t mtu;
425
426 switch (opt) {
427 case SO_RFCOMM_MTU:
428 mtu = *(uint16_t *)addr;
429 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
430 err = EINVAL;
431 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
432 dlc->rd_mtu = mtu;
433 else
434 err = EBUSY;
435
436 break;
437
438 case SO_RFCOMM_LM:
439 mode = *(int *)addr;
440 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
441
442 if (mode & RFCOMM_LM_SECURE)
443 mode |= RFCOMM_LM_ENCRYPT;
444
445 if (mode & RFCOMM_LM_ENCRYPT)
446 mode |= RFCOMM_LM_AUTH;
447
448 dlc->rd_mode = mode;
449
450 if (dlc->rd_state == RFCOMM_DLC_OPEN)
451 err = rfcomm_dlc_setmode(dlc);
452
453 break;
454
455 default:
456 err = ENOPROTOOPT;
457 break;
458 }
459 return err;
460 }
461
462 /*
463 * rfcomm_getopt(dlc, option, addr)
464 *
465 * get DLC options
466 */
467 int
468 rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
469 {
470 struct rfcomm_fc_info *fc;
471
472 switch (opt) {
473 case SO_RFCOMM_MTU:
474 *(uint16_t *)addr = dlc->rd_mtu;
475 return sizeof(uint16_t);
476
477 case SO_RFCOMM_FC_INFO:
478 fc = addr;
479 memset(fc, 0, sizeof(*fc));
480 fc->lmodem = dlc->rd_lmodem;
481 fc->rmodem = dlc->rd_rmodem;
482 fc->tx_cred = max(dlc->rd_txcred, 0xff);
483 fc->rx_cred = max(dlc->rd_rxcred, 0xff);
484 if (dlc->rd_session
485 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
486 fc->cfc = 1;
487
488 return sizeof(*fc);
489
490 case SO_RFCOMM_LM:
491 *(int *)addr = dlc->rd_mode;
492 return sizeof(int);
493
494 default:
495 break;
496 }
497
498 return 0;
499 }
500