rfcomm_upper.c revision 1.11 1 /* $NetBSD: rfcomm_upper.c,v 1.11 2008/08/06 15:01: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.11 2008/08/06 15:01: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/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(handle, proto, upper)
60 *
61 * attach a new RFCOMM DLC to handle, populate with reasonable defaults
62 */
63 int
64 rfcomm_attach(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 = malloc(sizeof(struct rfcomm_dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
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(dlc, sockaddr)
102 *
103 * bind DLC to local address
104 */
105 int
106 rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
107 {
108
109 memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
110 return 0;
111 }
112
113 /*
114 * rfcomm_sockaddr(dlc, sockaddr)
115 *
116 * return local address
117 */
118 int
119 rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
120 {
121
122 memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
123 return 0;
124 }
125
126 /*
127 * rfcomm_connect(dlc, sockaddr)
128 *
129 * Initiate connection of RFCOMM DLC to remote address.
130 */
131 int
132 rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
133 {
134 struct rfcomm_session *rs;
135 int err = 0;
136
137 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
138 return EISCONN;
139
140 memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
141
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;
146
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;
153
154 /*
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.
158 */
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;
165
166 rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
167 rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
168
169 err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
170 if (err) {
171 rfcomm_session_free(rs);
172 return err;
173 }
174
175 /*
176 * This session will start up automatically when its
177 * L2CAP channel is connected.
178 */
179 }
180
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;
185
186 l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
187
188 /*
189 * attach the DLC to the session and start it off
190 */
191 dlc->rd_session = rs;
192 dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
193 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
194
195 if (rs->rs_state == RFCOMM_SESSION_OPEN)
196 err = rfcomm_dlc_connect(dlc);
197
198 return err;
199 }
200
201 /*
202 * rfcomm_peeraddr(dlc, sockaddr)
203 *
204 * return remote address
205 */
206 int
207 rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
208 {
209
210 memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
211 return 0;
212 }
213
214 /*
215 * rfcomm_disconnect(dlc, linger)
216 *
217 * disconnect RFCOMM DLC
218 */
219 int
220 rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
221 {
222 struct rfcomm_session *rs = dlc->rd_session;
223 int err = 0;
224
225 KASSERT(dlc != NULL);
226
227 switch (dlc->rd_state) {
228 case RFCOMM_DLC_CLOSED:
229 case RFCOMM_DLC_LISTEN:
230 return EINVAL;
231
232 case RFCOMM_DLC_WAIT_SEND_UA:
233 err = rfcomm_session_send_frame(rs,
234 RFCOMM_FRAME_DM, dlc->rd_dlci);
235
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;
242
243 case RFCOMM_DLC_OPEN:
244 if (dlc->rd_txbuf != NULL && linger != 0) {
245 dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
246 break;
247 }
248
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_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
255 break;
256
257 case RFCOMM_DLC_WAIT_DISCONNECT:
258 err = EALREADY;
259 break;
260
261 default:
262 UNKNOWN(dlc->rd_state);
263 break;
264 }
265
266 return err;
267 }
268
269 /*
270 * rfcomm_detach(handle)
271 *
272 * detach RFCOMM DLC from handle
273 */
274 int
275 rfcomm_detach(struct rfcomm_dlc **handle)
276 {
277 struct rfcomm_dlc *dlc = *handle;
278
279 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
280 rfcomm_dlc_close(dlc, 0);
281
282 if (dlc->rd_txbuf != NULL) {
283 m_freem(dlc->rd_txbuf);
284 dlc->rd_txbuf = NULL;
285 }
286
287 dlc->rd_upper = NULL;
288 *handle = NULL;
289
290 /*
291 * If callout is invoking we can't free the DLC so
292 * mark it and let the callout release it.
293 */
294 if (callout_invoking(&dlc->rd_timeout))
295 dlc->rd_flags |= RFCOMM_DLC_DETACH;
296 else {
297 callout_destroy(&dlc->rd_timeout);
298 free(dlc, M_BLUETOOTH);
299 }
300
301 return 0;
302 }
303
304 /*
305 * rfcomm_listen(dlc)
306 *
307 * This DLC is a listener. We look for an existing listening session
308 * with a matching address to attach to or else create a new one on
309 * the listeners list. If the ANY channel is given, allocate the first
310 * available for the session.
311 */
312 int
313 rfcomm_listen(struct rfcomm_dlc *dlc)
314 {
315 struct rfcomm_session *rs;
316 struct rfcomm_dlc *used;
317 struct sockaddr_bt addr;
318 int err, channel;
319
320 if (dlc->rd_state != RFCOMM_DLC_CLOSED)
321 return EISCONN;
322
323 if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
324 && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
325 || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
326 return EADDRNOTAVAIL;
327
328 if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
329 dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
330 else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
331 && (dlc->rd_laddr.bt_psm < 0x1001
332 || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
333 return EADDRNOTAVAIL;
334
335 LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
336 l2cap_sockaddr(rs->rs_l2cap, &addr);
337
338 if (addr.bt_psm != dlc->rd_laddr.bt_psm)
339 continue;
340
341 if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
342 break;
343 }
344
345 if (rs == NULL) {
346 rs = rfcomm_session_alloc(&rfcomm_session_listen,
347 &dlc->rd_laddr);
348 if (rs == NULL)
349 return ENOMEM;
350
351 rs->rs_state = RFCOMM_SESSION_LISTEN;
352
353 err = l2cap_listen(rs->rs_l2cap);
354 if (err) {
355 rfcomm_session_free(rs);
356 return err;
357 }
358 }
359
360 if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
361 channel = RFCOMM_CHANNEL_MIN;
362 used = LIST_FIRST(&rs->rs_dlcs);
363
364 while (used != NULL) {
365 if (used->rd_laddr.bt_channel == channel) {
366 if (channel++ == RFCOMM_CHANNEL_MAX)
367 return EADDRNOTAVAIL;
368
369 used = LIST_FIRST(&rs->rs_dlcs);
370 } else {
371 used = LIST_NEXT(used, rd_next);
372 }
373 }
374
375 dlc->rd_laddr.bt_channel = channel;
376 }
377
378 dlc->rd_session = rs;
379 dlc->rd_state = RFCOMM_DLC_LISTEN;
380 LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
381
382 return 0;
383 }
384
385 /*
386 * rfcomm_send(dlc, mbuf)
387 *
388 * Output data on DLC. This is streamed data, so we add it
389 * to our buffer and start the the DLC, which will assemble
390 * packets and send them if it can.
391 */
392 int
393 rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
394 {
395
396 if (dlc->rd_txbuf != NULL) {
397 dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
398 m_cat(dlc->rd_txbuf, m);
399 } else {
400 dlc->rd_txbuf = m;
401 }
402
403 if (dlc->rd_state == RFCOMM_DLC_OPEN)
404 rfcomm_dlc_start(dlc);
405
406 return 0;
407 }
408
409 /*
410 * rfcomm_rcvd(dlc, space)
411 *
412 * Indicate space now available in receive buffer
413 *
414 * This should be used to give an initial value of the receive buffer
415 * size when the DLC is attached and anytime data is cleared from the
416 * buffer after that.
417 */
418 int
419 rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
420 {
421
422 KASSERT(dlc != NULL);
423
424 dlc->rd_rxsize = space;
425
426 /*
427 * if we are using credit based flow control, we may
428 * want to send some credits..
429 */
430 if (dlc->rd_state == RFCOMM_DLC_OPEN
431 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
432 rfcomm_dlc_start(dlc);
433
434 return 0;
435 }
436
437 /*
438 * rfcomm_setopt(dlc, sopt)
439 *
440 * set DLC options
441 */
442 int
443 rfcomm_setopt(struct rfcomm_dlc *dlc, const struct sockopt *sopt)
444 {
445 int mode, err = 0;
446 uint16_t mtu;
447
448 switch (sopt->sopt_name) {
449 case SO_RFCOMM_MTU:
450 err = sockopt_get(sopt, &mtu, sizeof(mtu));
451 if (err)
452 break;
453
454 if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
455 err = EINVAL;
456 else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
457 dlc->rd_mtu = mtu;
458 else
459 err = EBUSY;
460
461 break;
462
463 case SO_RFCOMM_LM:
464 err = sockopt_getint(sopt, &mode);
465 if (err)
466 break;
467
468 mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
469
470 if (mode & RFCOMM_LM_SECURE)
471 mode |= RFCOMM_LM_ENCRYPT;
472
473 if (mode & RFCOMM_LM_ENCRYPT)
474 mode |= RFCOMM_LM_AUTH;
475
476 dlc->rd_mode = mode;
477
478 if (dlc->rd_state == RFCOMM_DLC_OPEN)
479 err = rfcomm_dlc_setmode(dlc);
480
481 break;
482
483 default:
484 err = ENOPROTOOPT;
485 break;
486 }
487 return err;
488 }
489
490 /*
491 * rfcomm_getopt(dlc, sopt)
492 *
493 * get DLC options
494 */
495 int
496 rfcomm_getopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
497 {
498 struct rfcomm_fc_info fc;
499
500 switch (sopt->sopt_name) {
501 case SO_RFCOMM_MTU:
502 return sockopt_set(sopt, &dlc->rd_mtu, sizeof(uint16_t));
503
504 case SO_RFCOMM_FC_INFO:
505 memset(&fc, 0, sizeof(fc));
506 fc.lmodem = dlc->rd_lmodem;
507 fc.rmodem = dlc->rd_rmodem;
508 fc.tx_cred = max(dlc->rd_txcred, 0xff);
509 fc.rx_cred = max(dlc->rd_rxcred, 0xff);
510 if (dlc->rd_session
511 && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
512 fc.cfc = 1;
513
514 return sockopt_set(sopt, &fc, sizeof(fc));
515
516 case SO_RFCOMM_LM:
517 return sockopt_setint(sopt, dlc->rd_mode);
518
519 default:
520 break;
521 }
522
523 return ENOPROTOOPT;
524 }
525