xref: /netbsd-src/sys/netbt/rfcomm_upper.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
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