1 /* $NetBSD: bnep.c,v 1.7 2009/05/12 19:57:59 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.
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: bnep.c,v 1.7 2009/05/12 19:57:59 plunky Exp $");
31 #include <bluetooth.h>
39 static bool bnep_recv_extension(packet_t
*);
40 static size_t bnep_recv_control(channel_t
*, uint8_t *, size_t, bool);
41 static size_t bnep_recv_control_command_not_understood(channel_t
*, uint8_t *, size_t);
42 static size_t bnep_recv_setup_connection_req(channel_t
*, uint8_t *, size_t);
43 static size_t bnep_recv_setup_connection_rsp(channel_t
*, uint8_t *, size_t);
44 static size_t bnep_recv_filter_net_type_set(channel_t
*, uint8_t *, size_t);
45 static size_t bnep_recv_filter_net_type_rsp(channel_t
*, uint8_t *, size_t);
46 static size_t bnep_recv_filter_multi_addr_set(channel_t
*, uint8_t *, size_t);
47 static size_t bnep_recv_filter_multi_addr_rsp(channel_t
*, uint8_t *, size_t);
49 static bool bnep_pfilter(channel_t
*, packet_t
*);
50 static bool bnep_mfilter(channel_t
*, packet_t
*);
52 static uint8_t NAP_UUID
[] = {
53 0x00, 0x00, 0x11, 0x16,
57 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
60 static uint8_t GN_UUID
[] = {
61 0x00, 0x00, 0x11, 0x17,
65 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
68 static uint8_t PANU_UUID
[] = {
69 0x00, 0x00, 0x11, 0x15,
73 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
78 * return true if packet is to be forwarded
81 bnep_recv(packet_t
*pkt
)
92 switch (BNEP_TYPE(type
)) {
93 case BNEP_GENERAL_ETHERNET
:
94 if (pkt
->len
< (ETHER_ADDR_LEN
* 2) + ETHER_TYPE_LEN
) {
95 log_debug("dropped short packet (type 0x%2.2x)", type
);
100 packet_adj(pkt
, ETHER_ADDR_LEN
);
102 packet_adj(pkt
, ETHER_ADDR_LEN
);
103 pkt
->type
= pkt
->ptr
;
104 packet_adj(pkt
, ETHER_TYPE_LEN
);
108 len
= bnep_recv_control(pkt
->chan
, pkt
->ptr
, pkt
->len
, false);
112 packet_adj(pkt
, len
);
115 case BNEP_COMPRESSED_ETHERNET
:
116 if (pkt
->len
< ETHER_TYPE_LEN
) {
117 log_debug("dropped short packet (type 0x%2.2x)", type
);
121 pkt
->dst
= pkt
->chan
->laddr
;
122 pkt
->src
= pkt
->chan
->raddr
;
123 pkt
->type
= pkt
->ptr
;
124 packet_adj(pkt
, ETHER_TYPE_LEN
);
127 case BNEP_COMPRESSED_ETHERNET_SRC_ONLY
:
128 if (pkt
->len
< ETHER_ADDR_LEN
+ ETHER_TYPE_LEN
) {
129 log_debug("dropped short packet (type 0x%2.2x)", type
);
133 pkt
->dst
= pkt
->chan
->laddr
;
135 packet_adj(pkt
, ETHER_ADDR_LEN
);
136 pkt
->type
= pkt
->ptr
;
137 packet_adj(pkt
, ETHER_TYPE_LEN
);
140 case BNEP_COMPRESSED_ETHERNET_DST_ONLY
:
141 if (pkt
->len
< ETHER_ADDR_LEN
+ ETHER_TYPE_LEN
) {
142 log_debug("dropped short packet (type 0x%2.2x)", type
);
147 packet_adj(pkt
, ETHER_ADDR_LEN
);
148 pkt
->src
= pkt
->chan
->raddr
;
149 pkt
->type
= pkt
->ptr
;
150 packet_adj(pkt
, ETHER_TYPE_LEN
);
155 * Any packet containing a reserved BNEP
156 * header packet type SHALL be dropped.
159 log_debug("dropped packet with reserved type 0x%2.2x", type
);
163 if (BNEP_TYPE_EXT(type
)
164 && !bnep_recv_extension(pkt
))
165 return false; /* invalid extensions */
167 if (BNEP_TYPE(type
) == BNEP_CONTROL
168 || pkt
->chan
->state
!= CHANNEL_OPEN
)
169 return false; /* no forwarding */
171 if (pkt
->len
> ETHER_MAX_LEN
)
172 log_debug("received long packet "
173 "(type=0x%2.2x, proto=0x%4.4x, len=%zu)",
174 type
, be16dec(pkt
->type
), pkt
->len
);
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 shut them down */
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");
479 if (rsp
!= BNEP_FILTER_SUCCESS
)
480 log_err("filter_net_type: 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 if (rsp
!= BNEP_FILTER_SUCCESS
)
570 log_err("filter_multi_addr: 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
, uint8_t type
, ...)
584 assert(chan
->state
!= CHANNEL_CLOSED
);
586 pkt
= packet_alloc(chan
);
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)