Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Jan 2009 22:23:21 +0000 (UTC)
From:      Maksim Yevmenkin <emax@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r187938 - head/usr.sbin/bluetooth/btpand
Message-ID:  <200901302223.n0UMNLIC004956@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emax
Date: Fri Jan 30 22:23:21 2009
New Revision: 187938
URL: http://svn.freebsd.org/changeset/base/187938

Log:
  Add btpand(8) daemon from NetBSD. This daemon provides support for
  Bluetooth Network Access Point (NAP), Group Ad-hoc Network (GN) and
  Personal Area Network User (PANU) profiles.
  
  Obtained from:	NetBSD
  MFC after:	1 month

Added:
  head/usr.sbin/bluetooth/btpand/
  head/usr.sbin/bluetooth/btpand/Makefile   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/bnep.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/bnep.h   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/btpand.8   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/btpand.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/btpand.h   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/channel.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/client.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/event.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/event.h   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/packet.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/sdp.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/sdp.h   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/server.c   (contents, props changed)
  head/usr.sbin/bluetooth/btpand/tap.c   (contents, props changed)

Added: head/usr.sbin/bluetooth/btpand/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/btpand/Makefile	Fri Jan 30 22:23:21 2009	(r187938)
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2 2008/08/18 08:25:32 plunky Exp $
+# $FreeBSD$
+
+PROG=	btpand
+MAN=	btpand.8
+SRCS=	btpand.c bnep.c channel.c client.c event.c packet.c server.c sdp.c tap.c
+
+WARNS?=	3
+
+DPADD+=	${LIBBLUETOOTH} ${LIBSDP} ${LIBUTIL}
+LDADD+=	-lbluetooth -lsdp -lutil
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/bluetooth/btpand/bnep.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/btpand/bnep.c	Fri Jan 30 22:23:21 2009	(r187938)
@@ -0,0 +1,755 @@
+/*	$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
+
+#include <sys/uio.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "btpand.h"
+#include "bnep.h"
+
+static bool bnep_recv_extension(packet_t *);
+static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
+static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
+static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
+
+static bool bnep_pfilter(channel_t *, packet_t *);
+static bool bnep_mfilter(channel_t *, packet_t *);
+
+static uint8_t NAP_UUID[] = {
+	0x00, 0x00, 0x11, 0x16,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+static uint8_t GN_UUID[] = {
+	0x00, 0x00, 0x11, 0x17,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+};
+
+static uint8_t PANU_UUID[] = {
+	0x00, 0x00, 0x11, 0x15,
+	0x00, 0x00,
+	0x10, 0x00,
+	0x80, 0x00,
+	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+/*
+ * receive BNEP packet
+ * return true if packet is to be forwarded
+ */
+bool
+bnep_recv(packet_t *pkt)
+{
+	size_t len;
+	uint8_t type;
+
+	if (pkt->len < 1)
+		return false;
+
+	type = pkt->ptr[0];
+	packet_adj(pkt, 1);
+
+	switch (BNEP_TYPE(type)) {
+	case BNEP_GENERAL_ETHERNET:
+		if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->src = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_CONTROL:
+		len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
+		if (len == 0)
+			return false;
+
+		packet_adj(pkt, len);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET:
+		if (pkt->len < ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->chan->laddr;
+		pkt->src = pkt->chan->raddr;
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
+		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->chan->laddr;
+		pkt->src = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
+		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
+			log_debug("dropped short packet (type 0x%2.2x)", type);
+			return false;
+		}
+
+		pkt->dst = pkt->ptr;
+		packet_adj(pkt, ETHER_ADDR_LEN);
+		pkt->src = pkt->chan->raddr;
+		pkt->type = pkt->ptr;
+		packet_adj(pkt, ETHER_TYPE_LEN);
+		break;
+
+	default:
+		/*
+		 * Any packet containing a reserved BNEP
+		 * header packet type SHALL be dropped.
+		 */
+
+		log_debug("dropped packet with reserved type 0x%2.2x", type);
+		return false;
+	}
+
+	if (BNEP_TYPE_EXT(type)
+	    && !bnep_recv_extension(pkt))
+		return false;	/* invalid extensions */
+
+	if (BNEP_TYPE(type) == BNEP_CONTROL
+	    || pkt->chan->state != CHANNEL_OPEN)
+		return false;	/* no forwarding */
+
+	return true;
+}
+
+static bool
+bnep_recv_extension(packet_t *pkt)
+{
+	exthdr_t *eh;
+	size_t len, size;
+	uint8_t type;
+
+	do {
+		if (pkt->len < 2)
+			return false;
+
+		type = pkt->ptr[0];
+		size = pkt->ptr[1];
+
+		if (pkt->len < size + 2)
+			return false;
+
+		switch (type) {
+		case BNEP_EXTENSION_CONTROL:
+			len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
+			if (len != size)
+				log_err("ignored spurious data in exthdr");
+
+			break;
+
+		default:
+			/* Unknown extension headers in data packets	 */
+			/* SHALL be forwarded irrespective of any	 */
+			/* network protocol or multicast filter settings */
+			/* and any local filtering policy.		 */
+
+			eh = malloc(sizeof(exthdr_t));
+			if (eh == NULL) {
+				log_err("exthdr malloc() failed: %m");
+				break;
+			}
+
+			eh->ptr = pkt->ptr;
+			eh->len = size;
+			STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
+			break;
+		}
+
+		packet_adj(pkt, size + 2);
+	} while (BNEP_TYPE_EXT(type));
+
+	return true;
+}
+
+static size_t
+bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
+{
+	uint8_t type;
+	size_t len;
+
+	if (size-- < 1)
+		return 0;
+
+	type = *ptr++;
+
+	switch (type) {
+	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+		len = bnep_recv_control_command_not_understood(chan, ptr, size);
+		break;
+
+	case BNEP_SETUP_CONNECTION_REQUEST:
+		if (isext)
+			return 0;	/* not allowed in extension headers */
+
+		len = bnep_recv_setup_connection_req(chan, ptr, size);
+		break;
+
+	case BNEP_SETUP_CONNECTION_RESPONSE:
+		if (isext)
+			return 0;	/* not allowed in extension headers */
+
+		len = bnep_recv_setup_connection_rsp(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_NET_TYPE_SET:
+		len = bnep_recv_filter_net_type_set(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_NET_TYPE_RESPONSE:
+		len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_MULTI_ADDR_SET:
+		len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
+		break;
+
+	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
+		len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
+		break;
+
+	default:
+		len = 0;
+		break;
+	}
+
+	if (len == 0)
+		bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
+
+	return len;
+}
+
+static size_t
+bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	uint8_t type;
+
+	if (size < 1)
+		return 0;
+
+	type = *ptr++;
+	log_err("received Control Command Not Understood (0x%2.2x)", type);
+
+	/* we didn't send any reserved commands, just cut them off */
+	channel_close(chan);
+
+	return 1;
+}
+
+static size_t
+bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	uint8_t off;
+	int src, dst, rsp;
+	size_t len;
+
+	if (size < 1)
+		return 0;
+
+	len = *ptr++;
+	if (size < (len * 2 + 1))
+		return 0;
+
+	if (chan->state != CHANNEL_WAIT_CONNECT_REQ
+	    && chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len * 2 + 1);
+	}
+
+	if (len == 2)
+		off = 2;
+	else if (len == 4)
+		off = 0;
+	else if (len == 16)
+		off = 0;
+	else {
+		rsp = BNEP_SETUP_INVALID_UUID_SIZE;
+		goto done;
+	}
+
+	if (memcmp(ptr, NAP_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_NAP;
+	else if (memcmp(ptr, GN_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_GN;
+	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
+		dst = SDP_SERVICE_CLASS_PANU;
+	else
+		dst = 0;
+
+	if (dst != service_class) {
+		rsp = BNEP_SETUP_INVALID_DST_UUID;
+		goto done;
+	}
+
+	ptr += len;
+
+	if (memcmp(ptr, NAP_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_NAP;
+	else if (memcmp(ptr, GN_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_GN;
+	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
+		src = SDP_SERVICE_CLASS_PANU;
+	else
+		src = 0;
+
+	if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
+	    || src == 0) {
+		rsp = BNEP_SETUP_INVALID_SRC_UUID;
+		goto done;
+	}
+
+	rsp = BNEP_SETUP_SUCCESS;
+	chan->state = CHANNEL_OPEN;
+	channel_timeout(chan, 0);
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
+	return (len * 2 + 1);
+}
+
+static size_t
+bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return 0;
+
+	rsp = be16dec(ptr);
+
+	if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	if (rsp == BNEP_SETUP_SUCCESS) {
+		chan->state = CHANNEL_OPEN;
+		channel_timeout(chan, 0);
+	} else {
+		channel_close(chan);
+	}
+
+	return 2;
+}
+
+static size_t
+bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	pfilter_t *pf;
+	int i, nf, rsp;
+	size_t len;
+
+	if (size < 2)
+		return 0;
+
+	len = be16dec(ptr);
+	ptr += 2;
+
+	if (size < (len + 2))
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len + 2);
+	}
+
+	nf = len / 4;
+	pf = malloc(nf * sizeof(pfilter_t));
+	if (pf == NULL) {
+		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
+		goto done;
+	}
+
+	log_debug("nf = %d", nf);
+
+	for (i = 0; i < nf; i++) {
+		pf[i].start = be16dec(ptr);
+		ptr += 2;
+		pf[i].end = be16dec(ptr);
+		ptr += 2;
+
+		if (pf[i].start > pf[i].end) {
+			free(pf);
+			rsp = BNEP_FILTER_INVALID_RANGE;
+			goto done;
+		}
+
+		log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
+	}
+
+	if (chan->pfilter)
+		free(chan->pfilter);
+
+	chan->pfilter = pf;
+	chan->npfilter = nf;
+
+	rsp = BNEP_FILTER_SUCCESS;
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
+	return (len + 2);
+}
+
+static size_t
+bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	rsp = be16dec(ptr);
+
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	/* we did not send any filter_net_type_set message */
+	return 2;
+}
+
+static size_t
+bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	mfilter_t *mf;
+	int i, nf, rsp;
+	size_t len;
+
+	if (size < 2)
+		return 0;
+
+	len = be16dec(ptr);
+	ptr += 2;
+
+	if (size < (len + 2))
+		return 0;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return (len + 2);
+	}
+
+	nf = len / (ETHER_ADDR_LEN * 2);
+	mf = malloc(nf * sizeof(mfilter_t));
+	if (mf == NULL) {
+		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
+		goto done;
+	}
+
+	log_debug("nf = %d", nf);
+
+	for (i = 0; i < nf; i++) {
+		memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
+		ptr += ETHER_ADDR_LEN;
+
+		memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
+		ptr += ETHER_ADDR_LEN;
+
+		if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
+			free(mf);
+			rsp = BNEP_FILTER_INVALID_RANGE;
+			goto done;
+		}
+
+		log_debug("pf[%d] = "
+		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
+		    mf[i].start[0], mf[i].start[1], mf[i].start[2],
+		    mf[i].start[3], mf[i].start[4], mf[i].start[5],
+		    mf[i].end[0], mf[i].end[1], mf[i].end[2],
+		    mf[i].end[3], mf[i].end[4], mf[i].end[5]);
+	}
+
+	if (chan->mfilter)
+		free(chan->mfilter);
+
+	chan->mfilter = mf;
+	chan->nmfilter = nf;
+
+	rsp = BNEP_FILTER_SUCCESS;
+
+done:
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
+	return (len + 2);
+}
+
+static size_t
+bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
+{
+	int rsp;
+
+	if (size < 2)
+		return false;
+
+	if (chan->state != CHANNEL_OPEN) {
+		log_debug("ignored");
+		return 2;
+	}
+
+	rsp = be16dec(ptr);
+	log_debug("addr %s response 0x%2.2x",
+	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
+
+	/* we did not send any filter_multi_addr_set message */
+	return 2;
+}
+
+void
+bnep_send_control(channel_t *chan, uint8_t type, ...)
+{
+	packet_t *pkt;
+	uint8_t *p;
+	va_list ap;
+
+	assert(chan->state != CHANNEL_CLOSED);
+
+	pkt = packet_alloc(chan);
+	if (pkt == NULL)
+		return;
+
+	p = pkt->ptr;
+	va_start(ap, type);
+
+	*p++ = BNEP_CONTROL;
+	*p++ = type;
+
+	switch(type) {
+	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+		*p++ = va_arg(ap, int);
+		break;
+
+	case BNEP_SETUP_CONNECTION_REQUEST:
+		*p++ = va_arg(ap, int);
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		break;
+
+	case BNEP_SETUP_CONNECTION_RESPONSE:
+	case BNEP_FILTER_NET_TYPE_RESPONSE:
+	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
+		be16enc(p, va_arg(ap, int));
+		p += 2;
+		break;
+
+	case BNEP_FILTER_NET_TYPE_SET:		/* TODO */
+	case BNEP_FILTER_MULTI_ADDR_SET:	/* TODO */
+	default:
+		log_err("Can't send control type 0x%2.2x", type);
+		break;
+	}
+
+	va_end(ap);
+	pkt->len = p - pkt->ptr;
+
+	channel_put(chan, pkt);
+	packet_free(pkt);
+}
+
+/*
+ * BNEP send packet routine
+ * return true if packet can be removed from queue
+ */
+bool
+bnep_send(channel_t *chan, packet_t *pkt)
+{
+	struct iovec iov[2];
+	uint8_t *p, *type, *proto;
+	exthdr_t *eh;
+	bool src, dst;
+	size_t nw;
+
+	if (pkt->type == NULL) {
+		iov[0].iov_base = pkt->ptr;
+		iov[0].iov_len = pkt->len;
+		iov[1].iov_base = NULL;
+		iov[1].iov_len = 0;
+	} else {
+		p = chan->sendbuf;
+
+		dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
+		src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
+
+		type = p;
+		p += 1;
+
+		if (dst && src)
+			*type = BNEP_GENERAL_ETHERNET;
+		else if (dst && !src)
+			*type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
+		else if (!dst && src)
+			*type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
+		else /* (!dst && !src) */
+			*type = BNEP_COMPRESSED_ETHERNET;
+
+		if (dst) {
+			memcpy(p, pkt->dst, ETHER_ADDR_LEN);
+			p += ETHER_ADDR_LEN;
+		}
+
+		if (src) {
+			memcpy(p, pkt->src, ETHER_ADDR_LEN);
+			p += ETHER_ADDR_LEN;
+		}
+
+		proto = p;
+		memcpy(p, pkt->type, ETHER_TYPE_LEN);
+		p += ETHER_TYPE_LEN;
+
+		STAILQ_FOREACH(eh, &pkt->extlist, next) {
+			if (p + eh->len > chan->sendbuf + chan->mtu)
+				break;
+
+			*type |= BNEP_EXT;
+			type = p;
+
+			memcpy(p, eh->ptr, eh->len);
+			p += eh->len;
+		}
+
+		*type &= ~BNEP_EXT;
+
+		iov[0].iov_base = chan->sendbuf;
+		iov[0].iov_len = (p - chan->sendbuf);
+
+		if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
+		    && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
+			iov[1].iov_base = pkt->ptr;
+			iov[1].iov_len = pkt->len;
+		} else if (be16dec(proto) == ETHERTYPE_VLAN
+		    && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
+			iov[1].iov_base = pkt->ptr;
+			iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
+		} else {
+			iov[1].iov_base = NULL;
+			iov[1].iov_len = 0;
+			memset(proto, 0, ETHER_TYPE_LEN);
+		}
+	}
+
+	if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
+		log_err("packet exceeded MTU (dropped)");
+		return false;
+	}
+
+	nw = writev(chan->fd, iov, __arraycount(iov));
+	return (nw > 0);
+}
+
+static bool
+bnep_pfilter(channel_t *chan, packet_t *pkt)
+{
+	int proto, i;
+
+	proto = be16dec(pkt->type);
+	if (proto == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
+		if (pkt->len < 4)
+			return false;
+
+		proto = be16dec(pkt->ptr + 2);
+	}
+
+	for (i = 0; i < chan->npfilter; i++) {
+		if (chan->pfilter[i].start <= proto
+		    && chan->pfilter[i].end >=proto)
+			return true;
+	}
+
+	return false;
+}
+
+static bool
+bnep_mfilter(channel_t *chan, packet_t *pkt)
+{
+	int i;
+
+	if (!ETHER_IS_MULTICAST(pkt->dst))
+		return true;
+
+	for (i = 0; i < chan->nmfilter; i++) {
+		if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
+		    && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
+			return true;
+	}
+
+	return false;
+}

Added: head/usr.sbin/bluetooth/btpand/bnep.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/btpand/bnep.h	Fri Jan 30 22:23:21 2009	(r187938)
@@ -0,0 +1,72 @@
+/*	$NetBSD: bnep.h,v 1.1 2008/08/17 13:20:57 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2008 Iain Hibbert
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $FreeBSD$ */
+
+/*
+ * Constants defined in the Bluetooth Network Encapsulation
+ * Protocol (BNEP) specification v1.0
+ */
+
+#define	BNEP_MTU_MIN		1691
+
+#define BNEP_EXT		0x80
+#define	BNEP_TYPE(x)		((x) & 0x7f)
+#define BNEP_TYPE_EXT(x)	(((x) & BNEP_EXT) == BNEP_EXT)
+
+/* BNEP packet types */
+#define	BNEP_GENERAL_ETHERNET			0x00
+#define	BNEP_CONTROL				0x01
+#define	BNEP_COMPRESSED_ETHERNET		0x02
+#define	BNEP_COMPRESSED_ETHERNET_SRC_ONLY	0x03
+#define	BNEP_COMPRESSED_ETHERNET_DST_ONLY	0x04
+
+/* BNEP extension header types */
+#define	BNEP_EXTENSION_CONTROL			0x00
+
+/* BNEP control types */
+#define	BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD	0x00
+#define	BNEP_SETUP_CONNECTION_REQUEST		0x01
+#define	BNEP_SETUP_CONNECTION_RESPONSE		0x02
+#define	BNEP_FILTER_NET_TYPE_SET		0x03
+#define	BNEP_FILTER_NET_TYPE_RESPONSE		0x04
+#define	BNEP_FILTER_MULTI_ADDR_SET		0x05
+#define	BNEP_FILTER_MULTI_ADDR_RESPONSE		0x06
+
+/* BNEP setup response codes */
+#define	BNEP_SETUP_SUCCESS		0x0000
+#define	BNEP_SETUP_INVALID_SRC_UUID	0x0001
+#define	BNEP_SETUP_INVALID_DST_UUID	0x0002
+#define	BNEP_SETUP_INVALID_UUID_SIZE	0x0003
+#define	BNEP_SETUP_NOT_ALLOWED		0x0004
+
+/* BNEP filter return codes */
+#define	BNEP_FILTER_SUCCESS		0x0000
+#define	BNEP_FILTER_UNSUPPORTED_REQUEST	0x0001
+#define	BNEP_FILTER_INVALID_RANGE	0x0002
+#define	BNEP_FILTER_TOO_MANY_FILTERS	0x0003
+#define	BNEP_FILTER_SECURITY_FAILURE	0x0004

Added: head/usr.sbin/bluetooth/btpand/btpand.8
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/btpand/btpand.8	Fri Jan 30 22:23:21 2009	(r187938)
@@ -0,0 +1,241 @@
+.\" $NetBSD: btpand.8,v 1.3 2008/08/17 14:43:07 plunky Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 2008 Iain Hibbert
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 17, 2008
+.Dt BTPAND 8
+.Os
+.Sh NAME
+.Nm btpand
+.Nd Bluetooth PAN daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl i Ar ifname
+.Op Fl m Ar mode
+.Fl a Ar addr
+.Fl d Ar device
+.Brq Fl s Ar service | Fl S Ar service Op Fl p Ar psm
+.Nm
+.Op Fl c Ar path
+.Op Fl i Ar ifname
+.Op Fl l Ar limit
+.Op Fl m Ar mode
+.Op Fl p Ar psm
+.Fl d Ar device
+.Brq Fl s Ar service | Fl S Ar service
+.Sh DESCRIPTION
+The
+.Nm
+daemon handles Bluetooth Personal Area Networking services
+in the system.
+It can operate in client mode as a Personal Area Networking User
+.Pq PANU
+or in server mode as Network Access Point
+.Pq NAP ,
+Group ad-hoc Network
+.Pq GN
+or PANU host.
+.Nm
+connects to the system via a
+.Xr tap 4
+virtual Ethernet device and forwards Ethernet packets to
+remote Bluetooth devices using the Bluetooth Network Encapsulation
+Protocol
+.Pq BNEP .
+.Pp
+The PANU client is the device that uses either the NAP or GN
+service, or can talk directly to a PANU host in a crossover
+cable fashion.
+.Pp
+A GN host forwards Ethernet packets to each of the connected PAN
+users as needed but does not provide access to any additional networks.
+.Pp
+The NAP service provides some of the features of an Ethernet bridge,
+with the NAP host forwarding Ethernet packets between each of the
+connected PAN users, and a different network
+media.
+.Pp
+Note, the only differences between NAP and GN services as implemented by
+.Nm
+are in the SDP service record.
+The bridging of packets by the NAP must be configured separately.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl a Ar address"
+.It Fl a Ar address
+In client mode, address of remote server.
+May be given as BDADDR or name, in which case
+.Nm
+will attempt to resolve the address via the
+.Xr bt_gethostbyname 3
+call.
+.It Fl c Ar path
+In server mode, specify
+.Ar path
+to the
+.Xr sdpd 8
+control socket.
+The default path is
+.Pa /var/run/sdp .
+.It Fl d Ar device
+Restrict connections to the local
+.Ar device .
+May be given as BDADDR or name, in which case
+.Nm
+will attempt to resolve the address via the
+.Xr bt_devaddr 3
+call.
+.Nm
+will set the
+.Xr tap 4
+interface physical address to the BDADDR
+of the Bluetooth radio.
+.It Fl i Ar ifname
+.Nm
+uses the
+.Xr tap 4
+driver to create a new network interface for use.
+Use this option to select a specific
+.Xr tap 4
+device interface which must already be created.
+.It Fl l Ar limit
+In server mode, limit the number of simultaneous connections.
+The default limit is 7 for NAP and GN servers,
+and 1 for a PANU server.
+.It Fl m Ar mode
+Set L2CAP connection link mode.
+Supported modes are:
+.Pp
+.Bl -tag -compact
+.It auth
+require devices to be paired.
+.It encrypt
+auth, plus enable encryption.
+.It secure
+encryption, plus change of link key.
+.El
+.Pp
+NOT YET SUPPORTED.
+Use global device settings to set authentication and encryption.
+.It Fl p Ar psm
+Use an alternative L2CAP Protocol/Service Multiplexer
+.Pq PSM
+for server mode or client mode
+.Pq when not using Service Discovery .
+The default PSM for BNEP is 15
+.Pq 0x000f .

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901302223.n0UMNLIC004956>