1 /* $NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2008 Iain Hibbert
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
35 #define L2CAP_SOCKET_CHECKED
36 #include <bluetooth.h>
45 static bool bnep_recv_extension(packet_t *);
46 static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
47 static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
48 static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
49 static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
50 static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
51 static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
52 static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
53 static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
55 static bool bnep_pfilter(channel_t *, packet_t *);
56 static bool bnep_mfilter(channel_t *, packet_t *);
58 static uint8_t NAP_UUID[] = {
59 0x00, 0x00, 0x11, 0x16,
63 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
66 static uint8_t GN_UUID[] = {
67 0x00, 0x00, 0x11, 0x17,
71 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
74 static uint8_t PANU_UUID[] = {
75 0x00, 0x00, 0x11, 0x15,
79 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
84 * return true if packet is to be forwarded
87 bnep_recv(packet_t *pkt)
98 switch (BNEP_TYPE(type)) {
99 case BNEP_GENERAL_ETHERNET:
100 if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
101 log_debug("dropped short packet (type 0x%2.2x)", type);
106 packet_adj(pkt, ETHER_ADDR_LEN);
108 packet_adj(pkt, ETHER_ADDR_LEN);
109 pkt->type = pkt->ptr;
110 packet_adj(pkt, ETHER_TYPE_LEN);
114 len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
118 packet_adj(pkt, len);
121 case BNEP_COMPRESSED_ETHERNET:
122 if (pkt->len < ETHER_TYPE_LEN) {
123 log_debug("dropped short packet (type 0x%2.2x)", type);
127 pkt->dst = pkt->chan->laddr;
128 pkt->src = pkt->chan->raddr;
129 pkt->type = pkt->ptr;
130 packet_adj(pkt, ETHER_TYPE_LEN);
133 case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
134 if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
135 log_debug("dropped short packet (type 0x%2.2x)", type);
139 pkt->dst = pkt->chan->laddr;
141 packet_adj(pkt, ETHER_ADDR_LEN);
142 pkt->type = pkt->ptr;
143 packet_adj(pkt, ETHER_TYPE_LEN);
146 case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
147 if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
148 log_debug("dropped short packet (type 0x%2.2x)", type);
153 packet_adj(pkt, ETHER_ADDR_LEN);
154 pkt->src = pkt->chan->raddr;
155 pkt->type = pkt->ptr;
156 packet_adj(pkt, ETHER_TYPE_LEN);
161 * Any packet containing a reserved BNEP
162 * header packet type SHALL be dropped.
165 log_debug("dropped packet with reserved type 0x%2.2x", type);
169 if (BNEP_TYPE_EXT(type)
170 && !bnep_recv_extension(pkt))
171 return false; /* invalid extensions */
173 if (BNEP_TYPE(type) == BNEP_CONTROL
174 || pkt->chan->state != CHANNEL_OPEN)
175 return false; /* no forwarding */
181 bnep_recv_extension(packet_t *pkt)
194 if (pkt->len < size + 2)
198 case BNEP_EXTENSION_CONTROL:
199 len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
201 log_err("ignored spurious data in exthdr");
206 /* Unknown extension headers in data packets */
207 /* SHALL be forwarded irrespective of any */
208 /* network protocol or multicast filter settings */
209 /* and any local filtering policy. */
211 eh = malloc(sizeof(exthdr_t));
213 log_err("exthdr malloc() failed: %m");
219 STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
223 packet_adj(pkt, size + 2);
224 } while (BNEP_TYPE_EXT(type));
230 bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
241 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
242 len = bnep_recv_control_command_not_understood(chan, ptr, size);
245 case BNEP_SETUP_CONNECTION_REQUEST:
247 return 0; /* not allowed in extension headers */
249 len = bnep_recv_setup_connection_req(chan, ptr, size);
252 case BNEP_SETUP_CONNECTION_RESPONSE:
254 return 0; /* not allowed in extension headers */
256 len = bnep_recv_setup_connection_rsp(chan, ptr, size);
259 case BNEP_FILTER_NET_TYPE_SET:
260 len = bnep_recv_filter_net_type_set(chan, ptr, size);
263 case BNEP_FILTER_NET_TYPE_RESPONSE:
264 len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
267 case BNEP_FILTER_MULTI_ADDR_SET:
268 len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
271 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
272 len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
281 bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
287 bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
295 log_err("received Control Command Not Understood (0x%2.2x)", type);
297 /* we didn't send any reserved commands, just cut them off */
304 bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
314 if (size < (len * 2 + 1))
317 if (chan->state != CHANNEL_WAIT_CONNECT_REQ
318 && chan->state != CHANNEL_OPEN) {
319 log_debug("ignored");
320 return (len * 2 + 1);
330 rsp = BNEP_SETUP_INVALID_UUID_SIZE;
334 if (memcmp(ptr, NAP_UUID + off, len) == 0)
335 dst = SDP_SERVICE_CLASS_NAP;
336 else if (memcmp(ptr, GN_UUID + off, len) == 0)
337 dst = SDP_SERVICE_CLASS_GN;
338 else if (memcmp(ptr, PANU_UUID + off, len) == 0)
339 dst = SDP_SERVICE_CLASS_PANU;
343 if (dst != service_class) {
344 rsp = BNEP_SETUP_INVALID_DST_UUID;
350 if (memcmp(ptr, NAP_UUID + off, len) == 0)
351 src = SDP_SERVICE_CLASS_NAP;
352 else if (memcmp(ptr, GN_UUID + off, len) == 0)
353 src = SDP_SERVICE_CLASS_GN;
354 else if (memcmp(ptr, PANU_UUID + off, len) == 0)
355 src = SDP_SERVICE_CLASS_PANU;
359 if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
361 rsp = BNEP_SETUP_INVALID_SRC_UUID;
365 rsp = BNEP_SETUP_SUCCESS;
366 chan->state = CHANNEL_OPEN;
367 channel_timeout(chan, 0);
370 log_debug("addr %s response 0x%2.2x",
371 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
373 bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
374 return (len * 2 + 1);
378 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
387 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
388 log_debug("ignored");
392 log_debug("addr %s response 0x%2.2x",
393 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
395 if (rsp == BNEP_SETUP_SUCCESS) {
396 chan->state = CHANNEL_OPEN;
397 channel_timeout(chan, 0);
406 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
418 if (size < (len + 2))
421 if (chan->state != CHANNEL_OPEN) {
422 log_debug("ignored");
427 pf = malloc(nf * sizeof(pfilter_t));
429 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
433 log_debug("nf = %d", nf);
435 for (i = 0; i < nf; i++) {
436 pf[i].start = be16dec(ptr);
438 pf[i].end = be16dec(ptr);
441 if (pf[i].start > pf[i].end) {
443 rsp = BNEP_FILTER_INVALID_RANGE;
447 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
456 rsp = BNEP_FILTER_SUCCESS;
459 log_debug("addr %s response 0x%2.2x",
460 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
462 bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
467 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
474 if (chan->state != CHANNEL_OPEN) {
475 log_debug("ignored");
481 log_debug("addr %s response 0x%2.2x",
482 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
484 /* we did not send any filter_net_type_set message */
489 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
501 if (size < (len + 2))
504 if (chan->state != CHANNEL_OPEN) {
505 log_debug("ignored");
509 nf = len / (ETHER_ADDR_LEN * 2);
510 mf = malloc(nf * sizeof(mfilter_t));
512 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
516 log_debug("nf = %d", nf);
518 for (i = 0; i < nf; i++) {
519 memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
520 ptr += ETHER_ADDR_LEN;
522 memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
523 ptr += ETHER_ADDR_LEN;
525 if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
527 rsp = BNEP_FILTER_INVALID_RANGE;
531 log_debug("pf[%d] = "
532 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
533 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
534 mf[i].start[0], mf[i].start[1], mf[i].start[2],
535 mf[i].start[3], mf[i].start[4], mf[i].start[5],
536 mf[i].end[0], mf[i].end[1], mf[i].end[2],
537 mf[i].end[3], mf[i].end[4], mf[i].end[5]);
546 rsp = BNEP_FILTER_SUCCESS;
549 log_debug("addr %s response 0x%2.2x",
550 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
552 bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
557 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
564 if (chan->state != CHANNEL_OPEN) {
565 log_debug("ignored");
570 log_debug("addr %s response 0x%2.2x",
571 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
573 /* we did not send any filter_multi_addr_set message */
578 bnep_send_control(channel_t *chan, unsigned type, ...)
584 assert(chan->state != CHANNEL_CLOSED);
586 pkt = packet_alloc(chan);
594 *p++ = (uint8_t)type;
597 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
598 *p++ = va_arg(ap, int);
601 case BNEP_SETUP_CONNECTION_REQUEST:
602 *p++ = va_arg(ap, int);
603 be16enc(p, va_arg(ap, int));
605 be16enc(p, va_arg(ap, int));
609 case BNEP_SETUP_CONNECTION_RESPONSE:
610 case BNEP_FILTER_NET_TYPE_RESPONSE:
611 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
612 be16enc(p, va_arg(ap, int));
616 case BNEP_FILTER_NET_TYPE_SET: /* TODO */
617 case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
619 log_err("Can't send control type 0x%2.2x", type);
624 pkt->len = p - pkt->ptr;
626 channel_put(chan, pkt);
631 * BNEP send packet routine
632 * return true if packet can be removed from queue
635 bnep_send(channel_t *chan, packet_t *pkt)
638 uint8_t *p, *type, *proto;
643 if (pkt->type == NULL) {
644 iov[0].iov_base = pkt->ptr;
645 iov[0].iov_len = pkt->len;
646 iov[1].iov_base = NULL;
651 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
652 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
658 *type = BNEP_GENERAL_ETHERNET;
659 else if (dst && !src)
660 *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
661 else if (!dst && src)
662 *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
663 else /* (!dst && !src) */
664 *type = BNEP_COMPRESSED_ETHERNET;
667 memcpy(p, pkt->dst, ETHER_ADDR_LEN);
672 memcpy(p, pkt->src, ETHER_ADDR_LEN);
677 memcpy(p, pkt->type, ETHER_TYPE_LEN);
680 STAILQ_FOREACH(eh, &pkt->extlist, next) {
681 if (p + eh->len > chan->sendbuf + chan->mtu)
687 memcpy(p, eh->ptr, eh->len);
693 iov[0].iov_base = chan->sendbuf;
694 iov[0].iov_len = (p - chan->sendbuf);
696 if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
697 && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
698 iov[1].iov_base = pkt->ptr;
699 iov[1].iov_len = pkt->len;
700 } else if (be16dec(proto) == ETHERTYPE_VLAN
701 && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
702 iov[1].iov_base = pkt->ptr;
703 iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
705 iov[1].iov_base = NULL;
707 memset(proto, 0, ETHER_TYPE_LEN);
711 if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
712 log_err("packet exceeded MTU (dropped)");
716 nw = writev(chan->fd, iov, __arraycount(iov));
721 bnep_pfilter(channel_t *chan, packet_t *pkt)
725 proto = be16dec(pkt->type);
726 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
730 proto = be16dec(pkt->ptr + 2);
733 for (i = 0; i < chan->npfilter; i++) {
734 if (chan->pfilter[i].start <= proto
735 && chan->pfilter[i].end >=proto)
743 bnep_mfilter(channel_t *chan, packet_t *pkt)
747 if (!ETHER_IS_MULTICAST(pkt->dst))
750 for (i = 0; i < chan->nmfilter; i++) {
751 if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
752 && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)