Home | History | Annotate | Line # | Download | only in netbt
rfcomm_upper.c revision 1.11
      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