1 /* $NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */
4 * Copyright (c) 2008 Iain Hibbert
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
34 #define L2CAP_SOCKET_CHECKED
35 #include <bluetooth.h>
44 static bool bnep_recv_extension(packet_t *);
45 static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
46 static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
47 static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
48 static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
49 static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
50 static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
51 static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
52 static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
54 static bool bnep_pfilter(channel_t *, packet_t *);
55 static bool bnep_mfilter(channel_t *, packet_t *);
57 static uint8_t NAP_UUID[] = {
58 0x00, 0x00, 0x11, 0x16,
62 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
65 static uint8_t GN_UUID[] = {
66 0x00, 0x00, 0x11, 0x17,
70 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
73 static uint8_t PANU_UUID[] = {
74 0x00, 0x00, 0x11, 0x15,
78 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
83 * return true if packet is to be forwarded
86 bnep_recv(packet_t *pkt)
97 switch (BNEP_TYPE(type)) {
98 case BNEP_GENERAL_ETHERNET:
99 if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
100 log_debug("dropped short packet (type 0x%2.2x)", type);
105 packet_adj(pkt, ETHER_ADDR_LEN);
107 packet_adj(pkt, ETHER_ADDR_LEN);
108 pkt->type = pkt->ptr;
109 packet_adj(pkt, ETHER_TYPE_LEN);
113 len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
117 packet_adj(pkt, len);
120 case BNEP_COMPRESSED_ETHERNET:
121 if (pkt->len < ETHER_TYPE_LEN) {
122 log_debug("dropped short packet (type 0x%2.2x)", type);
126 pkt->dst = pkt->chan->laddr;
127 pkt->src = pkt->chan->raddr;
128 pkt->type = pkt->ptr;
129 packet_adj(pkt, ETHER_TYPE_LEN);
132 case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
133 if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
134 log_debug("dropped short packet (type 0x%2.2x)", type);
138 pkt->dst = pkt->chan->laddr;
140 packet_adj(pkt, ETHER_ADDR_LEN);
141 pkt->type = pkt->ptr;
142 packet_adj(pkt, ETHER_TYPE_LEN);
145 case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
146 if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
147 log_debug("dropped short packet (type 0x%2.2x)", type);
152 packet_adj(pkt, ETHER_ADDR_LEN);
153 pkt->src = pkt->chan->raddr;
154 pkt->type = pkt->ptr;
155 packet_adj(pkt, ETHER_TYPE_LEN);
160 * Any packet containing a reserved BNEP
161 * header packet type SHALL be dropped.
164 log_debug("dropped packet with reserved type 0x%2.2x", type);
168 if (BNEP_TYPE_EXT(type)
169 && !bnep_recv_extension(pkt))
170 return false; /* invalid extensions */
172 if (BNEP_TYPE(type) == BNEP_CONTROL
173 || pkt->chan->state != CHANNEL_OPEN)
174 return false; /* no forwarding */
180 bnep_recv_extension(packet_t *pkt)
193 if (pkt->len < size + 2)
197 case BNEP_EXTENSION_CONTROL:
198 len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
200 log_err("ignored spurious data in exthdr");
205 /* Unknown extension headers in data packets */
206 /* SHALL be forwarded irrespective of any */
207 /* network protocol or multicast filter settings */
208 /* and any local filtering policy. */
210 eh = malloc(sizeof(exthdr_t));
212 log_err("exthdr malloc() failed: %m");
218 STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
222 packet_adj(pkt, size + 2);
223 } while (BNEP_TYPE_EXT(type));
229 bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
240 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
241 len = bnep_recv_control_command_not_understood(chan, ptr, size);
244 case BNEP_SETUP_CONNECTION_REQUEST:
246 return 0; /* not allowed in extension headers */
248 len = bnep_recv_setup_connection_req(chan, ptr, size);
251 case BNEP_SETUP_CONNECTION_RESPONSE:
253 return 0; /* not allowed in extension headers */
255 len = bnep_recv_setup_connection_rsp(chan, ptr, size);
258 case BNEP_FILTER_NET_TYPE_SET:
259 len = bnep_recv_filter_net_type_set(chan, ptr, size);
262 case BNEP_FILTER_NET_TYPE_RESPONSE:
263 len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
266 case BNEP_FILTER_MULTI_ADDR_SET:
267 len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
270 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
271 len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
280 bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
286 bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
294 log_err("received Control Command Not Understood (0x%2.2x)", type);
296 /* we didn't send any reserved commands, just cut them off */
303 bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
313 if (size < (len * 2 + 1))
316 if (chan->state != CHANNEL_WAIT_CONNECT_REQ
317 && chan->state != CHANNEL_OPEN) {
318 log_debug("ignored");
319 return (len * 2 + 1);
329 rsp = BNEP_SETUP_INVALID_UUID_SIZE;
333 if (memcmp(ptr, NAP_UUID + off, len) == 0)
334 dst = SDP_SERVICE_CLASS_NAP;
335 else if (memcmp(ptr, GN_UUID + off, len) == 0)
336 dst = SDP_SERVICE_CLASS_GN;
337 else if (memcmp(ptr, PANU_UUID + off, len) == 0)
338 dst = SDP_SERVICE_CLASS_PANU;
342 if (dst != service_class) {
343 rsp = BNEP_SETUP_INVALID_DST_UUID;
349 if (memcmp(ptr, NAP_UUID + off, len) == 0)
350 src = SDP_SERVICE_CLASS_NAP;
351 else if (memcmp(ptr, GN_UUID + off, len) == 0)
352 src = SDP_SERVICE_CLASS_GN;
353 else if (memcmp(ptr, PANU_UUID + off, len) == 0)
354 src = SDP_SERVICE_CLASS_PANU;
358 if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
360 rsp = BNEP_SETUP_INVALID_SRC_UUID;
364 rsp = BNEP_SETUP_SUCCESS;
365 chan->state = CHANNEL_OPEN;
366 channel_timeout(chan, 0);
369 log_debug("addr %s response 0x%2.2x",
370 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
372 bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
373 return (len * 2 + 1);
377 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
386 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
387 log_debug("ignored");
391 log_debug("addr %s response 0x%2.2x",
392 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
394 if (rsp == BNEP_SETUP_SUCCESS) {
395 chan->state = CHANNEL_OPEN;
396 channel_timeout(chan, 0);
405 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
417 if (size < (len + 2))
420 if (chan->state != CHANNEL_OPEN) {
421 log_debug("ignored");
426 pf = malloc(nf * sizeof(pfilter_t));
428 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
432 log_debug("nf = %d", nf);
434 for (i = 0; i < nf; i++) {
435 pf[i].start = be16dec(ptr);
437 pf[i].end = be16dec(ptr);
440 if (pf[i].start > pf[i].end) {
442 rsp = BNEP_FILTER_INVALID_RANGE;
446 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
455 rsp = BNEP_FILTER_SUCCESS;
458 log_debug("addr %s response 0x%2.2x",
459 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
461 bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
466 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
473 if (chan->state != CHANNEL_OPEN) {
474 log_debug("ignored");
480 log_debug("addr %s response 0x%2.2x",
481 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
483 /* we did not send any filter_net_type_set message */
488 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
500 if (size < (len + 2))
503 if (chan->state != CHANNEL_OPEN) {
504 log_debug("ignored");
508 nf = len / (ETHER_ADDR_LEN * 2);
509 mf = malloc(nf * sizeof(mfilter_t));
511 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
515 log_debug("nf = %d", nf);
517 for (i = 0; i < nf; i++) {
518 memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
519 ptr += ETHER_ADDR_LEN;
521 memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
522 ptr += ETHER_ADDR_LEN;
524 if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
526 rsp = BNEP_FILTER_INVALID_RANGE;
530 log_debug("pf[%d] = "
531 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
532 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
533 mf[i].start[0], mf[i].start[1], mf[i].start[2],
534 mf[i].start[3], mf[i].start[4], mf[i].start[5],
535 mf[i].end[0], mf[i].end[1], mf[i].end[2],
536 mf[i].end[3], mf[i].end[4], mf[i].end[5]);
545 rsp = BNEP_FILTER_SUCCESS;
548 log_debug("addr %s response 0x%2.2x",
549 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
551 bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
556 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
563 if (chan->state != CHANNEL_OPEN) {
564 log_debug("ignored");
569 log_debug("addr %s response 0x%2.2x",
570 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
572 /* we did not send any filter_multi_addr_set message */
577 bnep_send_control(channel_t *chan, unsigned type, ...)
583 assert(chan->state != CHANNEL_CLOSED);
585 pkt = packet_alloc(chan);
593 *p++ = (uint8_t)type;
596 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
597 *p++ = va_arg(ap, int);
600 case BNEP_SETUP_CONNECTION_REQUEST:
601 *p++ = va_arg(ap, int);
602 be16enc(p, va_arg(ap, int));
604 be16enc(p, va_arg(ap, int));
608 case BNEP_SETUP_CONNECTION_RESPONSE:
609 case BNEP_FILTER_NET_TYPE_RESPONSE:
610 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
611 be16enc(p, va_arg(ap, int));
615 case BNEP_FILTER_NET_TYPE_SET: /* TODO */
616 case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
618 log_err("Can't send control type 0x%2.2x", type);
623 pkt->len = p - pkt->ptr;
625 channel_put(chan, pkt);
630 * BNEP send packet routine
631 * return true if packet can be removed from queue
634 bnep_send(channel_t *chan, packet_t *pkt)
637 uint8_t *p, *type, *proto;
642 if (pkt->type == NULL) {
643 iov[0].iov_base = pkt->ptr;
644 iov[0].iov_len = pkt->len;
645 iov[1].iov_base = NULL;
650 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
651 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
657 *type = BNEP_GENERAL_ETHERNET;
658 else if (dst && !src)
659 *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
660 else if (!dst && src)
661 *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
662 else /* (!dst && !src) */
663 *type = BNEP_COMPRESSED_ETHERNET;
666 memcpy(p, pkt->dst, ETHER_ADDR_LEN);
671 memcpy(p, pkt->src, ETHER_ADDR_LEN);
676 memcpy(p, pkt->type, ETHER_TYPE_LEN);
679 STAILQ_FOREACH(eh, &pkt->extlist, next) {
680 if (p + eh->len > chan->sendbuf + chan->mtu)
686 memcpy(p, eh->ptr, eh->len);
692 iov[0].iov_base = chan->sendbuf;
693 iov[0].iov_len = (p - chan->sendbuf);
695 if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
696 && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
697 iov[1].iov_base = pkt->ptr;
698 iov[1].iov_len = pkt->len;
699 } else if (be16dec(proto) == ETHERTYPE_VLAN
700 && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
701 iov[1].iov_base = pkt->ptr;
702 iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
704 iov[1].iov_base = NULL;
706 memset(proto, 0, ETHER_TYPE_LEN);
710 if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
711 log_err("packet exceeded MTU (dropped)");
715 nw = writev(chan->fd, iov, __arraycount(iov));
720 bnep_pfilter(channel_t *chan, packet_t *pkt)
724 proto = be16dec(pkt->type);
725 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
729 proto = be16dec(pkt->ptr + 2);
732 for (i = 0; i < chan->npfilter; i++) {
733 if (chan->pfilter[i].start <= proto
734 && chan->pfilter[i].end >=proto)
742 bnep_mfilter(channel_t *chan, packet_t *pkt)
746 if (!ETHER_IS_MULTICAST(pkt->dst))
749 for (i = 0; i < chan->nmfilter; i++) {
750 if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
751 && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)