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