Home | History | Annotate | Line # | Download | only in netbt
rfcomm_upper.c revision 1.14
      1 /*	$NetBSD: rfcomm_upper.c,v 1.14 2014/05/19 02:51:24 rmind 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.14 2014/05/19 02:51:24 rmind 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(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 = kmem_zalloc(sizeof(struct rfcomm_dlc), KM_SLEEP);
     74 
     75 	dlc->rd_state = RFCOMM_DLC_CLOSED;
     76 	dlc->rd_mtu = rfcomm_mtu_default;
     77 
     78 	dlc->rd_proto = proto;
     79 	dlc->rd_upper = upper;
     80 
     81 	dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
     82 	dlc->rd_laddr.bt_family = AF_BLUETOOTH;
     83 	dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
     84 
     85 	dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
     86 	dlc->rd_raddr.bt_family = AF_BLUETOOTH;
     87 	dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
     88 
     89 	dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
     90 
     91 	callout_init(&dlc->rd_timeout, 0);
     92 	callout_setfunc(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
     93 
     94 	*handle = dlc;
     95 	return 0;
     96 }
     97 
     98 /*
     99  * rfcomm_bind(dlc, sockaddr)
    100  *
    101  * bind DLC to local address
    102  */
    103 int
    104 rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
    105 {
    106 
    107 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
    108 		return EINVAL;
    109 
    110 	memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
    111 	return 0;
    112 }
    113 
    114 /*
    115  * rfcomm_sockaddr(dlc, sockaddr)
    116  *
    117  * return local address
    118  */
    119 int
    120 rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
    121 {
    122 
    123 	memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
    124 	return 0;
    125 }
    126 
    127 /*
    128  * rfcomm_connect(dlc, sockaddr)
    129  *
    130  * Initiate connection of RFCOMM DLC to remote address.
    131  */
    132 int
    133 rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
    134 {
    135 	struct rfcomm_session *rs;
    136 	int err = 0;
    137 
    138 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
    139 		return EISCONN;
    140 
    141 	memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
    142 
    143 	if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
    144 	    || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
    145 	    || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
    146 		return EDESTADDRREQ;
    147 
    148 	if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
    149 		dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
    150 	else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
    151 	    && (dlc->rd_raddr.bt_psm < 0x1001
    152 	    || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
    153 		return EINVAL;
    154 
    155 	/*
    156 	 * We are allowed only one RFCOMM session between any 2 Bluetooth
    157 	 * devices, so see if there is a session already otherwise create
    158 	 * one and set it connecting.
    159 	 */
    160 	rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
    161 	if (rs == NULL) {
    162 		rs = rfcomm_session_alloc(&rfcomm_session_active,
    163 						&dlc->rd_laddr);
    164 		if (rs == NULL)
    165 			return ENOMEM;
    166 
    167 		rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
    168 		rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
    169 
    170 		err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
    171 		if (err) {
    172 			rfcomm_session_free(rs);
    173 			return err;
    174 		}
    175 
    176 		/*
    177 		 * This session will start up automatically when its
    178 		 * L2CAP channel is connected.
    179 		 */
    180 	}
    181 
    182 	/* construct DLC */
    183 	dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
    184 	if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
    185 		return EBUSY;
    186 
    187 	l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
    188 
    189 	/*
    190 	 * attach the DLC to the session and start it off
    191 	 */
    192 	dlc->rd_session = rs;
    193 	dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
    194 	LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
    195 
    196 	if (rs->rs_state == RFCOMM_SESSION_OPEN)
    197 		err = rfcomm_dlc_connect(dlc);
    198 
    199 	return err;
    200 }
    201 
    202 /*
    203  * rfcomm_peeraddr(dlc, sockaddr)
    204  *
    205  * return remote address
    206  */
    207 int
    208 rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
    209 {
    210 
    211 	memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
    212 	return 0;
    213 }
    214 
    215 /*
    216  * rfcomm_disconnect(dlc, linger)
    217  *
    218  * disconnect RFCOMM DLC
    219  */
    220 int
    221 rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
    222 {
    223 	struct rfcomm_session *rs = dlc->rd_session;
    224 	int err = 0;
    225 
    226 	KASSERT(dlc != NULL);
    227 
    228 	switch (dlc->rd_state) {
    229 	case RFCOMM_DLC_CLOSED:
    230 	case RFCOMM_DLC_LISTEN:
    231 		return EINVAL;
    232 
    233 	case RFCOMM_DLC_WAIT_SEND_UA:
    234 		err = rfcomm_session_send_frame(rs,
    235 				RFCOMM_FRAME_DM, dlc->rd_dlci);
    236 
    237 		/* fall through */
    238 	case RFCOMM_DLC_WAIT_SESSION:
    239 	case RFCOMM_DLC_WAIT_CONNECT:
    240 	case RFCOMM_DLC_WAIT_SEND_SABM:
    241 		rfcomm_dlc_close(dlc, 0);
    242 		break;
    243 
    244 	case RFCOMM_DLC_OPEN:
    245 		if (dlc->rd_txbuf != NULL && linger != 0) {
    246 			dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
    247 			break;
    248 		}
    249 
    250 		/* else fall through */
    251 	case RFCOMM_DLC_WAIT_RECV_UA:
    252 		dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
    253 		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
    254 							dlc->rd_dlci);
    255 		callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
    256 		break;
    257 
    258 	case RFCOMM_DLC_WAIT_DISCONNECT:
    259 		err = EALREADY;
    260 		break;
    261 
    262 	default:
    263 		UNKNOWN(dlc->rd_state);
    264 		break;
    265 	}
    266 
    267 	return err;
    268 }
    269 
    270 /*
    271  * rfcomm_detach(handle)
    272  *
    273  * detach RFCOMM DLC from handle
    274  */
    275 void
    276 rfcomm_detach(struct rfcomm_dlc **handle)
    277 {
    278 	struct rfcomm_dlc *dlc = *handle;
    279 
    280 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
    281 		rfcomm_dlc_close(dlc, 0);
    282 
    283 	if (dlc->rd_txbuf != NULL) {
    284 		m_freem(dlc->rd_txbuf);
    285 		dlc->rd_txbuf = NULL;
    286 	}
    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_free(dlc, sizeof(*dlc));
    300 	}
    301 }
    302 
    303 /*
    304  * rfcomm_listen(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(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(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(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(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(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(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(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 = max(dlc->rd_txcred, 0xff);
    508 		fc.rx_cred = max(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