xref: /netbsd-src/sys/netbt/rfcomm_upper.c (revision 503611ba29d4c920cb1878a9ece7ebd1e0ac2e16)
1 /*	$NetBSD: rfcomm_upper.c,v 1.1 2006/06/19 15:44:45 gdamore 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.1 2006/06/19 15:44:45 gdamore 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);
69 	KASSERT(proto);
70 	KASSERT(upper);
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);
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_SESSION:
232 		rfcomm_dlc_close(dlc, 0);
233 		break;
234 
235 	case RFCOMM_DLC_OPEN:
236 		if (dlc->rd_txbuf != NULL && linger != 0) {
237 			dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
238 			break;
239 		}
240 
241 		/* else fall through */
242 	case RFCOMM_DLC_WAIT_CONNECT:
243 		dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
244 		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
245 							dlc->rd_dlci);
246 		callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
247 		break;
248 
249 	case RFCOMM_DLC_WAIT_DISCONNECT:
250 		err = EALREADY;
251 		break;
252 
253 	default:
254 		UNKNOWN(dlc->rd_state);
255 		break;
256 	}
257 
258 	return err;
259 }
260 
261 /*
262  * rfcomm_detach(handle)
263  *
264  * detach RFCOMM DLC from handle
265  */
266 int
267 rfcomm_detach(struct rfcomm_dlc **handle)
268 {
269 	struct rfcomm_dlc *dlc = *handle;
270 
271 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
272 		rfcomm_dlc_close(dlc, 0);
273 
274 	if (dlc->rd_txbuf != NULL) {
275 		m_freem(dlc->rd_txbuf);
276 		dlc->rd_txbuf = NULL;
277 	}
278 
279 	dlc->rd_upper = NULL;
280 	*handle = NULL;
281 
282 	/*
283 	 * If callout is invoking we can't free the DLC so
284 	 * mark it and let the callout release it.
285 	 */
286 	if (callout_invoking(&dlc->rd_timeout))
287 		dlc->rd_flags |= RFCOMM_DLC_DETACH;
288 	else
289 		free(dlc, M_BLUETOOTH);
290 
291 	return 0;
292 }
293 
294 /*
295  * rfcomm_listen(dlc)
296  *
297  * This DLC is a listener. We look for an existing listening session
298  * with a matching address to attach to or else create a new one on
299  * the listeners list.
300  */
301 int
302 rfcomm_listen(struct rfcomm_dlc *dlc)
303 {
304 	struct rfcomm_session *rs, *any, *best;
305 	struct sockaddr_bt addr;
306 	int err;
307 
308 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
309 		return EISCONN;
310 
311 	if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
312 	    || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)
313 		return EADDRNOTAVAIL;
314 
315 	if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
316 		dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
317 	else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
318 	    && (dlc->rd_laddr.bt_psm < 0x1001
319 	    || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
320 		return EADDRNOTAVAIL;
321 
322 	any = best = NULL;
323 	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
324 		l2cap_sockaddr(rs->rs_l2cap, &addr);
325 
326 		if (addr.bt_psm != dlc->rd_laddr.bt_psm)
327 			continue;
328 
329 		if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
330 			best = rs;
331 
332 		if (bdaddr_any(&addr.bt_bdaddr))
333 			any = rs;
334 	}
335 
336 	rs = best ? best : any;
337 	if (rs == NULL) {
338 		rs = rfcomm_session_alloc(&rfcomm_session_listen,
339 						&dlc->rd_laddr);
340 		if (rs == NULL)
341 			return ENOMEM;
342 
343 		rs->rs_state = RFCOMM_SESSION_LISTEN;
344 
345 		err = l2cap_listen(rs->rs_l2cap);
346 		if (err) {
347 			rfcomm_session_free(rs);
348 			return err;
349 		}
350 	}
351 
352 	dlc->rd_session = rs;
353 	dlc->rd_state = RFCOMM_DLC_LISTEN;
354 	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
355 
356 	return 0;
357 }
358 
359 /*
360  * rfcomm_send(dlc, mbuf)
361  *
362  * Output data on DLC. This is streamed data, so we add it
363  * to our buffer and start the the DLC, which will assemble
364  * packets and send them if it can.
365  */
366 int
367 rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
368 {
369 
370 	if (dlc->rd_txbuf != NULL) {
371 		dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
372 		m_cat(dlc->rd_txbuf, m);
373 	} else {
374 		dlc->rd_txbuf = m;
375 	}
376 
377 	if (dlc->rd_state == RFCOMM_DLC_OPEN)
378 		rfcomm_dlc_start(dlc);
379 
380 	return 0;
381 }
382 
383 /*
384  * rfcomm_rcvd(dlc, space)
385  *
386  * Indicate space now available in receive buffer
387  *
388  * This should be used to give an initial value of the receive buffer
389  * size when the DLC is attached and anytime data is cleared from the
390  * buffer after that.
391  */
392 int
393 rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
394 {
395 
396 	KASSERT(dlc != NULL);
397 
398 	dlc->rd_rxsize = space;
399 
400 	/*
401 	 * if we are using credit based flow control, we may
402 	 * want to send some credits..
403 	 */
404 	if (dlc->rd_state == RFCOMM_DLC_OPEN
405 	    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
406 		rfcomm_dlc_start(dlc);
407 
408 	return 0;
409 }
410 
411 /*
412  * rfcomm_setopt(dlc, option, addr)
413  *
414  * set DLC options
415  */
416 int
417 rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
418 {
419 	int err = 0;
420 
421 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
422 		return EBUSY;
423 
424 	switch (opt) {
425 	case SO_RFCOMM_MTU:
426 		dlc->rd_mtu = *(uint16_t *)addr;
427 		if (dlc->rd_mtu < RFCOMM_MTU_MIN
428 		    || dlc->rd_mtu > RFCOMM_MTU_MAX) {
429 			dlc->rd_mtu = rfcomm_mtu_default;
430 			err = EINVAL;
431 		}
432 		break;
433 
434 	default:
435 		err = EINVAL;
436 		break;
437 	}
438 	return err;
439 }
440 
441 /*
442  * rfcomm_getopt(dlc, option, addr)
443  *
444  * get DLC options
445  */
446 int
447 rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
448 {
449 	struct rfcomm_fc_info *fc;
450 
451 	switch (opt) {
452 	case SO_RFCOMM_MTU:
453 		*(uint16_t *)addr = dlc->rd_mtu;
454 		return sizeof(uint16_t);
455 
456 	case SO_RFCOMM_FC_INFO:
457 		fc = addr;
458 		memset(fc, 0, sizeof(*fc));
459 		fc->lmodem = dlc->rd_lmodem;
460 		fc->rmodem = dlc->rd_rmodem;
461 		fc->tx_cred = max(dlc->rd_txcred, 0xff);
462 		fc->rx_cred = max(dlc->rd_rxcred, 0xff);
463 		if (dlc->rd_session
464 		    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
465 			fc->cfc = 1;
466 
467 		return sizeof(*fc);
468 
469 	default:
470 		break;
471 	}
472 
473 	return 0;
474 }
475