xref: /dflybsd-src/sys/netbt/rfcomm_upper.c (revision 805c8e8e4093ceca2e27510ad3a66d4de8060a55)
183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/rfcomm_upper.c,v 1.4 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
60a9108ebSHasso Tepper  * All rights reserved.
70a9108ebSHasso Tepper  *
80a9108ebSHasso Tepper  * Written by Iain Hibbert for Itronix Inc.
90a9108ebSHasso Tepper  *
100a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
110a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
120a9108ebSHasso Tepper  * are met:
130a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
140a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
150a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
160a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
170a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
180a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
190a9108ebSHasso Tepper  *    or promote products derived from this software without specific
200a9108ebSHasso Tepper  *    prior written permission.
210a9108ebSHasso Tepper  *
220a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
230a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
240a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
250a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
260a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
270a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
280a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
290a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
300a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
310a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
320a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
330a9108ebSHasso Tepper  */
340a9108ebSHasso Tepper 
350a9108ebSHasso Tepper #include <sys/param.h>
360a9108ebSHasso Tepper #include <sys/kernel.h>
37*805c8e8eSzrj #include <sys/malloc.h>
380a9108ebSHasso Tepper #include <sys/mbuf.h>
390a9108ebSHasso Tepper #include <sys/proc.h>
400a9108ebSHasso Tepper #include <sys/systm.h>
410a9108ebSHasso Tepper #include <sys/socketvar.h>
420a9108ebSHasso Tepper 
430a9108ebSHasso Tepper #include <netbt/bluetooth.h>
440a9108ebSHasso Tepper #include <netbt/hci.h>
450a9108ebSHasso Tepper #include <netbt/l2cap.h>
460a9108ebSHasso Tepper #include <netbt/rfcomm.h>
470a9108ebSHasso Tepper 
480a9108ebSHasso Tepper /****************************************************************************
490a9108ebSHasso Tepper  *
500a9108ebSHasso Tepper  *	RFCOMM DLC - Upper Protocol API
510a9108ebSHasso Tepper  *
520a9108ebSHasso Tepper  * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
530a9108ebSHasso Tepper  * but it is should be possible to provide a pseudo-device for a direct
540a9108ebSHasso Tepper  * tty interface.
550a9108ebSHasso Tepper  */
560a9108ebSHasso Tepper 
570a9108ebSHasso Tepper /*
580a9108ebSHasso Tepper  * rfcomm_attach(handle, proto, upper)
590a9108ebSHasso Tepper  *
600a9108ebSHasso Tepper  * attach a new RFCOMM DLC to handle, populate with reasonable defaults
610a9108ebSHasso Tepper  */
620a9108ebSHasso Tepper int
rfcomm_attach(struct rfcomm_dlc ** handle,const struct btproto * proto,void * upper)630a9108ebSHasso Tepper rfcomm_attach(struct rfcomm_dlc **handle,
640a9108ebSHasso Tepper 		const struct btproto *proto, void *upper)
650a9108ebSHasso Tepper {
660a9108ebSHasso Tepper 	struct rfcomm_dlc *dlc;
670a9108ebSHasso Tepper 
680a9108ebSHasso Tepper 	KKASSERT(handle != NULL);
690a9108ebSHasso Tepper 	KKASSERT(proto != NULL);
700a9108ebSHasso Tepper 	KKASSERT(upper != NULL);
710a9108ebSHasso Tepper 
720a9108ebSHasso Tepper 	dlc = kmalloc(sizeof(*dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
730a9108ebSHasso Tepper 	if (dlc == NULL)
740a9108ebSHasso Tepper 		return ENOMEM;
750a9108ebSHasso Tepper 
760a9108ebSHasso Tepper 	dlc->rd_state = RFCOMM_DLC_CLOSED;
770a9108ebSHasso Tepper 	dlc->rd_mtu = rfcomm_mtu_default;
780a9108ebSHasso Tepper 
790a9108ebSHasso Tepper 	dlc->rd_proto = proto;
800a9108ebSHasso Tepper 	dlc->rd_upper = upper;
810a9108ebSHasso Tepper 
820a9108ebSHasso Tepper 	dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
830a9108ebSHasso Tepper 	dlc->rd_laddr.bt_family = AF_BLUETOOTH;
840a9108ebSHasso Tepper 	dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
850a9108ebSHasso Tepper 
860a9108ebSHasso Tepper 	dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
870a9108ebSHasso Tepper 	dlc->rd_raddr.bt_family = AF_BLUETOOTH;
880a9108ebSHasso Tepper 	dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
890a9108ebSHasso Tepper 
900a9108ebSHasso Tepper 	dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
910a9108ebSHasso Tepper 
920a9108ebSHasso Tepper 	callout_init(&dlc->rd_timeout);
930a9108ebSHasso Tepper 
940a9108ebSHasso Tepper 	*handle = dlc;
950a9108ebSHasso Tepper 	return 0;
960a9108ebSHasso Tepper }
970a9108ebSHasso Tepper 
980a9108ebSHasso Tepper /*
990a9108ebSHasso Tepper  * rfcomm_bind(dlc, sockaddr)
1000a9108ebSHasso Tepper  *
1010a9108ebSHasso Tepper  * bind DLC to local address
1020a9108ebSHasso Tepper  */
1030a9108ebSHasso Tepper int
rfcomm_bind(struct rfcomm_dlc * dlc,struct sockaddr_bt * addr)1040a9108ebSHasso Tepper rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
1050a9108ebSHasso Tepper {
1060a9108ebSHasso Tepper 
1070a9108ebSHasso Tepper 	memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
1080a9108ebSHasso Tepper 	return 0;
1090a9108ebSHasso Tepper }
1100a9108ebSHasso Tepper 
1110a9108ebSHasso Tepper /*
1120a9108ebSHasso Tepper  * rfcomm_sockaddr(dlc, sockaddr)
1130a9108ebSHasso Tepper  *
1140a9108ebSHasso Tepper  * return local address
1150a9108ebSHasso Tepper  */
1160a9108ebSHasso Tepper int
rfcomm_sockaddr(struct rfcomm_dlc * dlc,struct sockaddr_bt * addr)1170a9108ebSHasso Tepper rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
1180a9108ebSHasso Tepper {
1190a9108ebSHasso Tepper 
1200a9108ebSHasso Tepper 	memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
1210a9108ebSHasso Tepper 	return 0;
1220a9108ebSHasso Tepper }
1230a9108ebSHasso Tepper 
1240a9108ebSHasso Tepper /*
1250a9108ebSHasso Tepper  * rfcomm_connect(dlc, sockaddr)
1260a9108ebSHasso Tepper  *
1270a9108ebSHasso Tepper  * Initiate connection of RFCOMM DLC to remote address.
1280a9108ebSHasso Tepper  */
1290a9108ebSHasso Tepper int
rfcomm_connect(struct rfcomm_dlc * dlc,struct sockaddr_bt * dest)1300a9108ebSHasso Tepper rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
1310a9108ebSHasso Tepper {
1320a9108ebSHasso Tepper 	struct rfcomm_session *rs;
1330a9108ebSHasso Tepper 	int err = 0;
1340a9108ebSHasso Tepper 
1350a9108ebSHasso Tepper 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
1360a9108ebSHasso Tepper 		return EISCONN;
1370a9108ebSHasso Tepper 
1380a9108ebSHasso Tepper 	memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
1390a9108ebSHasso Tepper 
1400a9108ebSHasso Tepper 	if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
1410a9108ebSHasso Tepper 	    || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
1420a9108ebSHasso Tepper 	    || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
1430a9108ebSHasso Tepper 		return EDESTADDRREQ;
1440a9108ebSHasso Tepper 
1450a9108ebSHasso Tepper 	if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
1460a9108ebSHasso Tepper 		dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
1470a9108ebSHasso Tepper 	else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
1480a9108ebSHasso Tepper 	    && (dlc->rd_raddr.bt_psm < 0x1001
1490a9108ebSHasso Tepper 	    || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
1500a9108ebSHasso Tepper 		return EINVAL;
1510a9108ebSHasso Tepper 
1520a9108ebSHasso Tepper 	/*
1530a9108ebSHasso Tepper 	 * We are allowed only one RFCOMM session between any 2 Bluetooth
1540a9108ebSHasso Tepper 	 * devices, so see if there is a session already otherwise create
1550a9108ebSHasso Tepper 	 * one and set it connecting.
1560a9108ebSHasso Tepper 	 */
1570a9108ebSHasso Tepper 	rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
1580a9108ebSHasso Tepper 	if (rs == NULL) {
1590a9108ebSHasso Tepper 		rs = rfcomm_session_alloc(&rfcomm_session_active,
1600a9108ebSHasso Tepper 						&dlc->rd_laddr);
1610a9108ebSHasso Tepper 		if (rs == NULL)
1620a9108ebSHasso Tepper 			return ENOMEM;
1630a9108ebSHasso Tepper 
1640a9108ebSHasso Tepper 		rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
1650a9108ebSHasso Tepper 		rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
1660a9108ebSHasso Tepper 
1670a9108ebSHasso Tepper 		err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
1680a9108ebSHasso Tepper 		if (err) {
1690a9108ebSHasso Tepper 			rfcomm_session_free(rs);
1700a9108ebSHasso Tepper 			return err;
1710a9108ebSHasso Tepper 		}
1720a9108ebSHasso Tepper 
1730a9108ebSHasso Tepper 		/*
1740a9108ebSHasso Tepper 		 * This session will start up automatically when its
1750a9108ebSHasso Tepper 		 * L2CAP channel is connected.
1760a9108ebSHasso Tepper 		 */
1770a9108ebSHasso Tepper 	}
1780a9108ebSHasso Tepper 
1790a9108ebSHasso Tepper 	/* construct DLC */
1800a9108ebSHasso Tepper 	dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
1810a9108ebSHasso Tepper 	if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
1820a9108ebSHasso Tepper 		return EBUSY;
1830a9108ebSHasso Tepper 
1840a9108ebSHasso Tepper 	l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
1850a9108ebSHasso Tepper 
1860a9108ebSHasso Tepper 	/*
1870a9108ebSHasso Tepper 	 * attach the DLC to the session and start it off
1880a9108ebSHasso Tepper 	 */
1890a9108ebSHasso Tepper 	dlc->rd_session = rs;
1900a9108ebSHasso Tepper 	dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
1910a9108ebSHasso Tepper 	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
1920a9108ebSHasso Tepper 
1930a9108ebSHasso Tepper 	if (rs->rs_state == RFCOMM_SESSION_OPEN)
1940a9108ebSHasso Tepper 		err = rfcomm_dlc_connect(dlc);
1950a9108ebSHasso Tepper 
1960a9108ebSHasso Tepper 	return err;
1970a9108ebSHasso Tepper }
1980a9108ebSHasso Tepper 
1990a9108ebSHasso Tepper /*
2000a9108ebSHasso Tepper  * rfcomm_peeraddr(dlc, sockaddr)
2010a9108ebSHasso Tepper  *
2020a9108ebSHasso Tepper  * return remote address
2030a9108ebSHasso Tepper  */
2040a9108ebSHasso Tepper int
rfcomm_peeraddr(struct rfcomm_dlc * dlc,struct sockaddr_bt * addr)2050a9108ebSHasso Tepper rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
2060a9108ebSHasso Tepper {
2070a9108ebSHasso Tepper 
2080a9108ebSHasso Tepper 	memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
2090a9108ebSHasso Tepper 	return 0;
2100a9108ebSHasso Tepper }
2110a9108ebSHasso Tepper 
2120a9108ebSHasso Tepper /*
2130a9108ebSHasso Tepper  * rfcomm_disconnect(dlc, linger)
2140a9108ebSHasso Tepper  *
2150a9108ebSHasso Tepper  * disconnect RFCOMM DLC
2160a9108ebSHasso Tepper  */
2170a9108ebSHasso Tepper int
rfcomm_disconnect(struct rfcomm_dlc * dlc,int linger)2180a9108ebSHasso Tepper rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
2190a9108ebSHasso Tepper {
2200a9108ebSHasso Tepper 	struct rfcomm_session *rs = dlc->rd_session;
2210a9108ebSHasso Tepper 	int err = 0;
2220a9108ebSHasso Tepper 
2230a9108ebSHasso Tepper 	KKASSERT(dlc != NULL);
2240a9108ebSHasso Tepper 
2250a9108ebSHasso Tepper 	switch (dlc->rd_state) {
2260a9108ebSHasso Tepper 	case RFCOMM_DLC_CLOSED:
2270a9108ebSHasso Tepper 	case RFCOMM_DLC_LISTEN:
2280a9108ebSHasso Tepper 		return EINVAL;
2290a9108ebSHasso Tepper 
2300a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_SEND_UA:
2310a9108ebSHasso Tepper 		err = rfcomm_session_send_frame(rs,
2320a9108ebSHasso Tepper 				RFCOMM_FRAME_DM, dlc->rd_dlci);
2330a9108ebSHasso Tepper 
2340a9108ebSHasso Tepper 		/* fall through */
2350a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_SESSION:
2360a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_CONNECT:
2370a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_SEND_SABM:
2380a9108ebSHasso Tepper 		rfcomm_dlc_close(dlc, 0);
2390a9108ebSHasso Tepper 		break;
2400a9108ebSHasso Tepper 
2410a9108ebSHasso Tepper 	case RFCOMM_DLC_OPEN:
2420a9108ebSHasso Tepper 		if (dlc->rd_txbuf != NULL && linger != 0) {
2430a9108ebSHasso Tepper 			dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
2440a9108ebSHasso Tepper 			break;
2450a9108ebSHasso Tepper 		}
2460a9108ebSHasso Tepper 
2470a9108ebSHasso Tepper 		/* else fall through */
2480a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_RECV_UA:
2490a9108ebSHasso Tepper 		dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
2500a9108ebSHasso Tepper 		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
2510a9108ebSHasso Tepper 							dlc->rd_dlci);
2520a9108ebSHasso Tepper 		callout_reset(&dlc->rd_timeout, rfcomm_ack_timeout * hz,
2530a9108ebSHasso Tepper 		    rfcomm_dlc_timeout, dlc);
2540a9108ebSHasso Tepper 		break;
2550a9108ebSHasso Tepper 
2560a9108ebSHasso Tepper 	case RFCOMM_DLC_WAIT_DISCONNECT:
2570a9108ebSHasso Tepper 		err = EALREADY;
2580a9108ebSHasso Tepper 		break;
2590a9108ebSHasso Tepper 
2600a9108ebSHasso Tepper 	default:
2610a9108ebSHasso Tepper 		UNKNOWN(dlc->rd_state);
2620a9108ebSHasso Tepper 		break;
2630a9108ebSHasso Tepper 	}
2640a9108ebSHasso Tepper 
2650a9108ebSHasso Tepper 	return err;
2660a9108ebSHasso Tepper }
2670a9108ebSHasso Tepper 
2680a9108ebSHasso Tepper /*
2690a9108ebSHasso Tepper  * rfcomm_detach(handle)
2700a9108ebSHasso Tepper  *
2710a9108ebSHasso Tepper  * detach RFCOMM DLC from handle
2720a9108ebSHasso Tepper  */
2730a9108ebSHasso Tepper int
rfcomm_detach(struct rfcomm_dlc ** handle)2740a9108ebSHasso Tepper rfcomm_detach(struct rfcomm_dlc **handle)
2750a9108ebSHasso Tepper {
2760a9108ebSHasso Tepper 	struct rfcomm_dlc *dlc = *handle;
2770a9108ebSHasso Tepper 
2780a9108ebSHasso Tepper 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
2790a9108ebSHasso Tepper 		rfcomm_dlc_close(dlc, 0);
2800a9108ebSHasso Tepper 
2810a9108ebSHasso Tepper 	if (dlc->rd_txbuf != NULL) {
2820a9108ebSHasso Tepper 		m_freem(dlc->rd_txbuf);
2830a9108ebSHasso Tepper 		dlc->rd_txbuf = NULL;
2840a9108ebSHasso Tepper 	}
2850a9108ebSHasso Tepper 
2860a9108ebSHasso Tepper 	dlc->rd_upper = NULL;
2870a9108ebSHasso Tepper 	*handle = NULL;
2880a9108ebSHasso Tepper 
2890a9108ebSHasso Tepper 	/*
2900a9108ebSHasso Tepper 	 * If callout is invoking we can't free the DLC so
2910a9108ebSHasso Tepper 	 * mark it and let the callout release it.
2920a9108ebSHasso Tepper 	 */
2930a9108ebSHasso Tepper 	if (callout_active(&dlc->rd_timeout))
2940a9108ebSHasso Tepper 		dlc->rd_flags |= RFCOMM_DLC_DETACH;
2950a9108ebSHasso Tepper 	else
2960a9108ebSHasso Tepper 		kfree(dlc, M_BLUETOOTH);
2970a9108ebSHasso Tepper 
2980a9108ebSHasso Tepper 	return 0;
2990a9108ebSHasso Tepper }
3000a9108ebSHasso Tepper 
3010a9108ebSHasso Tepper /*
3020a9108ebSHasso Tepper  * rfcomm_listen(dlc)
3030a9108ebSHasso Tepper  *
3040a9108ebSHasso Tepper  * This DLC is a listener. We look for an existing listening session
3050a9108ebSHasso Tepper  * with a matching address to attach to or else create a new one on
30683aacedeSHasso Tepper  * the listeners list. If the ANY channel is given, allocate the first
30783aacedeSHasso Tepper  * available for the session.
3080a9108ebSHasso Tepper  */
3090a9108ebSHasso Tepper int
rfcomm_listen(struct rfcomm_dlc * dlc)3100a9108ebSHasso Tepper rfcomm_listen(struct rfcomm_dlc *dlc)
3110a9108ebSHasso Tepper {
31283aacedeSHasso Tepper 	struct rfcomm_session *rs;
31383aacedeSHasso Tepper 	struct rfcomm_dlc *used;
3140a9108ebSHasso Tepper 	struct sockaddr_bt addr;
31583aacedeSHasso Tepper 	int err, channel;
3160a9108ebSHasso Tepper 
3170a9108ebSHasso Tepper 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
3180a9108ebSHasso Tepper 		return EISCONN;
3190a9108ebSHasso Tepper 
32083aacedeSHasso Tepper 	if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY
32183aacedeSHasso Tepper 	    && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
32283aacedeSHasso Tepper 	    || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX))
3230a9108ebSHasso Tepper 		return EADDRNOTAVAIL;
3240a9108ebSHasso Tepper 
3250a9108ebSHasso Tepper 	if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
3260a9108ebSHasso Tepper 		dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
3270a9108ebSHasso Tepper 	else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
3280a9108ebSHasso Tepper 	    && (dlc->rd_laddr.bt_psm < 0x1001
3290a9108ebSHasso Tepper 	    || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
3300a9108ebSHasso Tepper 		return EADDRNOTAVAIL;
3310a9108ebSHasso Tepper 
3320a9108ebSHasso Tepper 	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
3330a9108ebSHasso Tepper 		l2cap_sockaddr(rs->rs_l2cap, &addr);
3340a9108ebSHasso Tepper 
3350a9108ebSHasso Tepper 		if (addr.bt_psm != dlc->rd_laddr.bt_psm)
3360a9108ebSHasso Tepper 			continue;
3370a9108ebSHasso Tepper 
3380a9108ebSHasso Tepper 		if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
33983aacedeSHasso Tepper 			break;
3400a9108ebSHasso Tepper 	}
3410a9108ebSHasso Tepper 
3420a9108ebSHasso Tepper 	if (rs == NULL) {
3430a9108ebSHasso Tepper 		rs = rfcomm_session_alloc(&rfcomm_session_listen,
3440a9108ebSHasso Tepper 						&dlc->rd_laddr);
3450a9108ebSHasso Tepper 		if (rs == NULL)
3460a9108ebSHasso Tepper 			return ENOMEM;
3470a9108ebSHasso Tepper 
3480a9108ebSHasso Tepper 		rs->rs_state = RFCOMM_SESSION_LISTEN;
3490a9108ebSHasso Tepper 
3500a9108ebSHasso Tepper 		err = l2cap_listen(rs->rs_l2cap);
3510a9108ebSHasso Tepper 		if (err) {
3520a9108ebSHasso Tepper 			rfcomm_session_free(rs);
3530a9108ebSHasso Tepper 			return err;
3540a9108ebSHasso Tepper 		}
3550a9108ebSHasso Tepper 	}
3560a9108ebSHasso Tepper 
35783aacedeSHasso Tepper 	if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) {
35883aacedeSHasso Tepper 		channel = RFCOMM_CHANNEL_MIN;
35983aacedeSHasso Tepper 		used = LIST_FIRST(&rs->rs_dlcs);
36083aacedeSHasso Tepper 
36183aacedeSHasso Tepper 		while (used != NULL) {
36283aacedeSHasso Tepper 			if (used->rd_laddr.bt_channel == channel) {
36383aacedeSHasso Tepper 				if (channel++ == RFCOMM_CHANNEL_MAX)
36483aacedeSHasso Tepper 					return EADDRNOTAVAIL;
36583aacedeSHasso Tepper 
36683aacedeSHasso Tepper 				used = LIST_FIRST(&rs->rs_dlcs);
36783aacedeSHasso Tepper 			} else {
36883aacedeSHasso Tepper 				used = LIST_NEXT(used, rd_next);
36983aacedeSHasso Tepper 			}
37083aacedeSHasso Tepper 		}
37183aacedeSHasso Tepper 
37283aacedeSHasso Tepper 		dlc->rd_laddr.bt_channel = channel;
37383aacedeSHasso Tepper 	}
37483aacedeSHasso Tepper 
3750a9108ebSHasso Tepper 	dlc->rd_session = rs;
3760a9108ebSHasso Tepper 	dlc->rd_state = RFCOMM_DLC_LISTEN;
3770a9108ebSHasso Tepper 	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
3780a9108ebSHasso Tepper 
3790a9108ebSHasso Tepper 	return 0;
3800a9108ebSHasso Tepper }
3810a9108ebSHasso Tepper 
3820a9108ebSHasso Tepper /*
3830a9108ebSHasso Tepper  * rfcomm_send(dlc, mbuf)
3840a9108ebSHasso Tepper  *
3850a9108ebSHasso Tepper  * Output data on DLC. This is streamed data, so we add it
3860a9108ebSHasso Tepper  * to our buffer and start the DLC, which will assemble
3870a9108ebSHasso Tepper  * packets and send them if it can.
3880a9108ebSHasso Tepper  */
3890a9108ebSHasso Tepper int
rfcomm_send(struct rfcomm_dlc * dlc,struct mbuf * m)3900a9108ebSHasso Tepper rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
3910a9108ebSHasso Tepper {
3920a9108ebSHasso Tepper 
3930a9108ebSHasso Tepper 	if (dlc->rd_txbuf != NULL) {
3940a9108ebSHasso Tepper 		dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
3950a9108ebSHasso Tepper 		m_cat(dlc->rd_txbuf, m);
3960a9108ebSHasso Tepper 	} else {
3970a9108ebSHasso Tepper 		dlc->rd_txbuf = m;
3980a9108ebSHasso Tepper 	}
3990a9108ebSHasso Tepper 
4000a9108ebSHasso Tepper 	if (dlc->rd_state == RFCOMM_DLC_OPEN)
4010a9108ebSHasso Tepper 		rfcomm_dlc_start(dlc);
4020a9108ebSHasso Tepper 
4030a9108ebSHasso Tepper 	return 0;
4040a9108ebSHasso Tepper }
4050a9108ebSHasso Tepper 
4060a9108ebSHasso Tepper /*
4070a9108ebSHasso Tepper  * rfcomm_rcvd(dlc, space)
4080a9108ebSHasso Tepper  *
4090a9108ebSHasso Tepper  * Indicate space now available in receive buffer
4100a9108ebSHasso Tepper  *
4110a9108ebSHasso Tepper  * This should be used to give an initial value of the receive buffer
4120a9108ebSHasso Tepper  * size when the DLC is attached and anytime data is cleared from the
4130a9108ebSHasso Tepper  * buffer after that.
4140a9108ebSHasso Tepper  */
4150a9108ebSHasso Tepper int
rfcomm_rcvd(struct rfcomm_dlc * dlc,size_t space)4160a9108ebSHasso Tepper rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
4170a9108ebSHasso Tepper {
4180a9108ebSHasso Tepper 
4190a9108ebSHasso Tepper 	KKASSERT(dlc != NULL);
4200a9108ebSHasso Tepper 
4210a9108ebSHasso Tepper 	dlc->rd_rxsize = space;
4220a9108ebSHasso Tepper 
4230a9108ebSHasso Tepper 	/*
4240a9108ebSHasso Tepper 	 * if we are using credit based flow control, we may
4250a9108ebSHasso Tepper 	 * want to send some credits..
4260a9108ebSHasso Tepper 	 */
4270a9108ebSHasso Tepper 	if (dlc->rd_state == RFCOMM_DLC_OPEN
4280a9108ebSHasso Tepper 	    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
4290a9108ebSHasso Tepper 		rfcomm_dlc_start(dlc);
4300a9108ebSHasso Tepper 
4310a9108ebSHasso Tepper 	return 0;
4320a9108ebSHasso Tepper }
4330a9108ebSHasso Tepper 
4340a9108ebSHasso Tepper /*
4350a9108ebSHasso Tepper  * rfcomm_setopt(dlc, option, addr)
4360a9108ebSHasso Tepper  *
4370a9108ebSHasso Tepper  * set DLC options
4380a9108ebSHasso Tepper  */
4390a9108ebSHasso Tepper int
rfcomm_setopt(struct rfcomm_dlc * dlc,int opt,void * addr)4400a9108ebSHasso Tepper rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
4410a9108ebSHasso Tepper {
4420a9108ebSHasso Tepper 	int mode, err = 0;
4430a9108ebSHasso Tepper 	uint16_t mtu;
4440a9108ebSHasso Tepper 
4450a9108ebSHasso Tepper 	switch (opt) {
4460a9108ebSHasso Tepper 	case SO_RFCOMM_MTU:
4470a9108ebSHasso Tepper 		mtu = *(uint16_t *)addr;
4480a9108ebSHasso Tepper 		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
4490a9108ebSHasso Tepper 			err = EINVAL;
4500a9108ebSHasso Tepper 		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
4510a9108ebSHasso Tepper 			dlc->rd_mtu = mtu;
4520a9108ebSHasso Tepper 		else
4530a9108ebSHasso Tepper 			err = EBUSY;
4540a9108ebSHasso Tepper 
4550a9108ebSHasso Tepper 		break;
4560a9108ebSHasso Tepper 
4570a9108ebSHasso Tepper 	case SO_RFCOMM_LM:
4580a9108ebSHasso Tepper 		mode = *(int *)addr;
4590a9108ebSHasso Tepper 		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
4600a9108ebSHasso Tepper 
4610a9108ebSHasso Tepper 		if (mode & RFCOMM_LM_SECURE)
4620a9108ebSHasso Tepper 			mode |= RFCOMM_LM_ENCRYPT;
4630a9108ebSHasso Tepper 
4640a9108ebSHasso Tepper 		if (mode & RFCOMM_LM_ENCRYPT)
4650a9108ebSHasso Tepper 			mode |= RFCOMM_LM_AUTH;
4660a9108ebSHasso Tepper 
4670a9108ebSHasso Tepper 		dlc->rd_mode = mode;
4680a9108ebSHasso Tepper 
4690a9108ebSHasso Tepper 		if (dlc->rd_state == RFCOMM_DLC_OPEN)
4700a9108ebSHasso Tepper 			err = rfcomm_dlc_setmode(dlc);
4710a9108ebSHasso Tepper 
4720a9108ebSHasso Tepper 		break;
4730a9108ebSHasso Tepper 
4740a9108ebSHasso Tepper 	default:
4750a9108ebSHasso Tepper 		err = ENOPROTOOPT;
4760a9108ebSHasso Tepper 		break;
4770a9108ebSHasso Tepper 	}
4780a9108ebSHasso Tepper 	return err;
4790a9108ebSHasso Tepper }
4800a9108ebSHasso Tepper 
4810a9108ebSHasso Tepper 
4820a9108ebSHasso Tepper int
rfcomm_setopt2(struct rfcomm_dlc * dlc,int opt,struct socket * so,struct sockopt * sopt)4830a9108ebSHasso Tepper rfcomm_setopt2(struct rfcomm_dlc *dlc, int opt, struct socket *so,
4840a9108ebSHasso Tepper     struct sockopt *sopt)
4850a9108ebSHasso Tepper {
4860a9108ebSHasso Tepper 	int mode, err = 0;
4870a9108ebSHasso Tepper 	uint16_t mtu;
4880a9108ebSHasso Tepper 
4890a9108ebSHasso Tepper 	switch (opt) {
4900a9108ebSHasso Tepper 	case SO_RFCOMM_MTU:
491d82b71f8SAggelos Economopoulos 		err = soopt_to_kbuf(sopt, &mtu, sizeof(uint16_t),
4920a9108ebSHasso Tepper 		    sizeof(uint16_t));
4930a9108ebSHasso Tepper 		if (err) break;
4940a9108ebSHasso Tepper 
4950a9108ebSHasso Tepper 		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
4960a9108ebSHasso Tepper 			err = EINVAL;
4970a9108ebSHasso Tepper 		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
4980a9108ebSHasso Tepper 			dlc->rd_mtu = mtu;
4990a9108ebSHasso Tepper 		else
5000a9108ebSHasso Tepper 			err = EBUSY;
5010a9108ebSHasso Tepper 
5020a9108ebSHasso Tepper 		break;
5030a9108ebSHasso Tepper 
5040a9108ebSHasso Tepper 	case SO_RFCOMM_LM:
505d82b71f8SAggelos Economopoulos 		err = soopt_to_kbuf(sopt, &mode, sizeof(int), sizeof(int));
5060a9108ebSHasso Tepper 		if (err) break;
5070a9108ebSHasso Tepper 
5080a9108ebSHasso Tepper 		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
5090a9108ebSHasso Tepper 
5100a9108ebSHasso Tepper 		if (mode & RFCOMM_LM_SECURE)
5110a9108ebSHasso Tepper 			mode |= RFCOMM_LM_ENCRYPT;
5120a9108ebSHasso Tepper 
5130a9108ebSHasso Tepper 		if (mode & RFCOMM_LM_ENCRYPT)
5140a9108ebSHasso Tepper 			mode |= RFCOMM_LM_AUTH;
5150a9108ebSHasso Tepper 
5160a9108ebSHasso Tepper 		dlc->rd_mode = mode;
5170a9108ebSHasso Tepper 
5180a9108ebSHasso Tepper 		if (dlc->rd_state == RFCOMM_DLC_OPEN)
5190a9108ebSHasso Tepper 			err = rfcomm_dlc_setmode(dlc);
5200a9108ebSHasso Tepper 
5210a9108ebSHasso Tepper 		break;
5220a9108ebSHasso Tepper 
5230a9108ebSHasso Tepper 	default:
5240a9108ebSHasso Tepper 		err = ENOPROTOOPT;
5250a9108ebSHasso Tepper 		break;
5260a9108ebSHasso Tepper 	}
5270a9108ebSHasso Tepper 	return err;
5280a9108ebSHasso Tepper }
5290a9108ebSHasso Tepper 
5300a9108ebSHasso Tepper /*
5310a9108ebSHasso Tepper  * rfcomm_getopt(dlc, option, addr)
5320a9108ebSHasso Tepper  *
5330a9108ebSHasso Tepper  * get DLC options
5340a9108ebSHasso Tepper  */
5350a9108ebSHasso Tepper int
rfcomm_getopt(struct rfcomm_dlc * dlc,int opt,void * addr)5360a9108ebSHasso Tepper rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
5370a9108ebSHasso Tepper {
5380a9108ebSHasso Tepper 	struct rfcomm_fc_info *fc;
5390a9108ebSHasso Tepper 
5400a9108ebSHasso Tepper 	switch (opt) {
5410a9108ebSHasso Tepper 	case SO_RFCOMM_MTU:
5420a9108ebSHasso Tepper 		*(uint16_t *)addr = dlc->rd_mtu;
5430a9108ebSHasso Tepper 		return sizeof(uint16_t);
5440a9108ebSHasso Tepper 
5450a9108ebSHasso Tepper 	case SO_RFCOMM_FC_INFO:
5460a9108ebSHasso Tepper 		fc = addr;
5470a9108ebSHasso Tepper 		memset(fc, 0, sizeof(*fc));
5480a9108ebSHasso Tepper 		fc->lmodem = dlc->rd_lmodem;
5490a9108ebSHasso Tepper 		fc->rmodem = dlc->rd_rmodem;
5500a9108ebSHasso Tepper 		fc->tx_cred = max(dlc->rd_txcred, 0xff);
5510a9108ebSHasso Tepper 		fc->rx_cred = max(dlc->rd_rxcred, 0xff);
5520a9108ebSHasso Tepper 		if (dlc->rd_session
5530a9108ebSHasso Tepper 		    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
5540a9108ebSHasso Tepper 			fc->cfc = 1;
5550a9108ebSHasso Tepper 
5560a9108ebSHasso Tepper 		return sizeof(*fc);
5570a9108ebSHasso Tepper 
5580a9108ebSHasso Tepper 	case SO_RFCOMM_LM:
5590a9108ebSHasso Tepper 		*(int *)addr = dlc->rd_mode;
5600a9108ebSHasso Tepper 		return sizeof(int);
5610a9108ebSHasso Tepper 
5620a9108ebSHasso Tepper 	default:
5630a9108ebSHasso Tepper 		break;
5640a9108ebSHasso Tepper 	}
5650a9108ebSHasso Tepper 
5660a9108ebSHasso Tepper 	return 0;
5670a9108ebSHasso Tepper }
568