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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to