Home | History | Annotate | Line # | Download | only in netbt
rfcomm_upper.c revision 1.10
      1 /*	$NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 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.10 2007/11/20 20:25:57 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/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 != NULL);
     69 	KASSERT(proto != NULL);
     70 	KASSERT(upper != NULL);
     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, 0);
     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_SEND_UA:
    232 		err = rfcomm_session_send_frame(rs,
    233 				RFCOMM_FRAME_DM, dlc->rd_dlci);
    234 
    235 		/* fall through */
    236 	case RFCOMM_DLC_WAIT_SESSION:
    237 	case RFCOMM_DLC_WAIT_CONNECT:
    238 	case RFCOMM_DLC_WAIT_SEND_SABM:
    239 		rfcomm_dlc_close(dlc, 0);
    240 		break;
    241 
    242 	case RFCOMM_DLC_OPEN:
    243 		if (dlc->rd_txbuf != NULL && linger != 0) {
    244 			dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
    245 			break;
    246 		}
    247 
    248 		/* else fall through */
    249 	case RFCOMM_DLC_WAIT_RECV_UA:
    250 		dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
    251 		err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
    252 							dlc->rd_dlci);
    253 		callout_schedule(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
    254 		break;
    255 
    256 	case RFCOMM_DLC_WAIT_DISCONNECT:
    257 		err = EALREADY;
    258 		break;
    259 
    260 	default:
    261 		UNKNOWN(dlc->rd_state);
    262 		break;
    263 	}
    264 
    265 	return err;
    266 }
    267 
    268 /*
    269  * rfcomm_detach(handle)
    270  *
    271  * detach RFCOMM DLC from handle
    272  */
    273 int
    274 rfcomm_detach(struct rfcomm_dlc **handle)
    275 {
    276 	struct rfcomm_dlc *dlc = *handle;
    277 
    278 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
    279 		rfcomm_dlc_close(dlc, 0);
    280 
    281 	if (dlc->rd_txbuf != NULL) {
    282 		m_freem(dlc->rd_txbuf);
    283 		dlc->rd_txbuf = NULL;
    284 	}
    285 
    286 	dlc->rd_upper = NULL;
    287 	*handle = NULL;
    288 
    289 	/*
    290 	 * If callout is invoking we can't free the DLC so
    291 	 * mark it and let the callout release it.
    292 	 */
    293 	if (callout_invoking(&dlc->rd_timeout))
    294 		dlc->rd_flags |= RFCOMM_DLC_DETACH;
    295 	else {
    296 		callout_destroy(&dlc->rd_timeout);
    297 		free(dlc, M_BLUETOOTH);
    298 	}
    299 
    300 	return 0;
    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 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, option, addr)
    438  *
    439  * set DLC options
    440  */
    441 int
    442 rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
    443 {
    444 	int mode, err = 0;
    445 	uint16_t mtu;
    446 
    447 	switch (opt) {
    448 	case SO_RFCOMM_MTU:
    449 		mtu = *(uint16_t *)addr;
    450 		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
    451 			err = EINVAL;
    452 		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
    453 			dlc->rd_mtu = mtu;
    454 		else
    455 			err = EBUSY;
    456 
    457 		break;
    458 
    459 	case SO_RFCOMM_LM:
    460 		mode = *(int *)addr;
    461 		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
    462 
    463 		if (mode & RFCOMM_LM_SECURE)
    464 			mode |= RFCOMM_LM_ENCRYPT;
    465 
    466 		if (mode & RFCOMM_LM_ENCRYPT)
    467 			mode |= RFCOMM_LM_AUTH;
    468 
    469 		dlc->rd_mode = mode;
    470 
    471 		if (dlc->rd_state == RFCOMM_DLC_OPEN)
    472 			err = rfcomm_dlc_setmode(dlc);
    473 
    474 		break;
    475 
    476 	default:
    477 		err = ENOPROTOOPT;
    478 		break;
    479 	}
    480 	return err;
    481 }
    482 
    483 /*
    484  * rfcomm_getopt(dlc, option, addr)
    485  *
    486  * get DLC options
    487  */
    488 int
    489 rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
    490 {
    491 	struct rfcomm_fc_info *fc;
    492 
    493 	switch (opt) {
    494 	case SO_RFCOMM_MTU:
    495 		*(uint16_t *)addr = dlc->rd_mtu;
    496 		return sizeof(uint16_t);
    497 
    498 	case SO_RFCOMM_FC_INFO:
    499 		fc = addr;
    500 		memset(fc, 0, sizeof(*fc));
    501 		fc->lmodem = dlc->rd_lmodem;
    502 		fc->rmodem = dlc->rd_rmodem;
    503 		fc->tx_cred = max(dlc->rd_txcred, 0xff);
    504 		fc->rx_cred = max(dlc->rd_rxcred, 0xff);
    505 		if (dlc->rd_session
    506 		    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
    507 			fc->cfc = 1;
    508 
    509 		return sizeof(*fc);
    510 
    511 	case SO_RFCOMM_LM:
    512 		*(int *)addr = dlc->rd_mode;
    513 		return sizeof(int);
    514 
    515 	default:
    516 		break;
    517 	}
    518 
    519 	return 0;
    520 }
    521