No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / btpand / bnep.c
blobf690f3e144180b66b636eee7189bb7194602e361
1 /* $NetBSD: bnep.c,v 1.7 2009/05/12 19:57:59 plunky Exp $ */
3 /*-
4 * Copyright (c) 2008 Iain Hibbert
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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>
32 #include <sdp.h>
33 #include <stdarg.h>
34 #include <string.h>
36 #include "btpand.h"
37 #include "bnep.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,
54 0x00, 0x00,
55 0x10, 0x00,
56 0x80, 0x00,
57 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
60 static uint8_t GN_UUID[] = {
61 0x00, 0x00, 0x11, 0x17,
62 0x00, 0x00,
63 0x10, 0x00,
64 0x80, 0x00,
65 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
68 static uint8_t PANU_UUID[] = {
69 0x00, 0x00, 0x11, 0x15,
70 0x00, 0x00,
71 0x10, 0x00,
72 0x80, 0x00,
73 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
77 * receive BNEP packet
78 * return true if packet is to be forwarded
80 bool
81 bnep_recv(packet_t *pkt)
83 size_t len;
84 uint8_t type;
86 if (pkt->len < 1)
87 return false;
89 type = pkt->ptr[0];
90 packet_adj(pkt, 1);
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);
96 return false;
99 pkt->dst = pkt->ptr;
100 packet_adj(pkt, ETHER_ADDR_LEN);
101 pkt->src = pkt->ptr;
102 packet_adj(pkt, ETHER_ADDR_LEN);
103 pkt->type = pkt->ptr;
104 packet_adj(pkt, ETHER_TYPE_LEN);
105 break;
107 case BNEP_CONTROL:
108 len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
109 if (len == 0)
110 return false;
112 packet_adj(pkt, len);
113 break;
115 case BNEP_COMPRESSED_ETHERNET:
116 if (pkt->len < ETHER_TYPE_LEN) {
117 log_debug("dropped short packet (type 0x%2.2x)", type);
118 return false;
121 pkt->dst = pkt->chan->laddr;
122 pkt->src = pkt->chan->raddr;
123 pkt->type = pkt->ptr;
124 packet_adj(pkt, ETHER_TYPE_LEN);
125 break;
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);
130 return false;
133 pkt->dst = pkt->chan->laddr;
134 pkt->src = pkt->ptr;
135 packet_adj(pkt, ETHER_ADDR_LEN);
136 pkt->type = pkt->ptr;
137 packet_adj(pkt, ETHER_TYPE_LEN);
138 break;
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);
143 return false;
146 pkt->dst = pkt->ptr;
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);
151 break;
153 default:
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);
160 return false;
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);
176 return true;
179 static bool
180 bnep_recv_extension(packet_t *pkt)
182 exthdr_t *eh;
183 size_t len, size;
184 uint8_t type;
186 do {
187 if (pkt->len < 2)
188 return false;
190 type = pkt->ptr[0];
191 size = pkt->ptr[1];
193 if (pkt->len < size + 2)
194 return false;
196 switch (type) {
197 case BNEP_EXTENSION_CONTROL:
198 len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
199 if (len != size)
200 log_err("ignored spurious data in exthdr");
202 break;
204 default:
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));
211 if (eh == NULL) {
212 log_err("exthdr malloc() failed: %m");
213 break;
216 eh->ptr = pkt->ptr;
217 eh->len = size;
218 STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
219 break;
222 packet_adj(pkt, size + 2);
223 } while (BNEP_TYPE_EXT(type));
225 return true;
228 static size_t
229 bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
231 uint8_t type;
232 size_t len;
234 if (size-- < 1)
235 return 0;
237 type = *ptr++;
239 switch (type) {
240 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
241 len = bnep_recv_control_command_not_understood(chan, ptr, size);
242 break;
244 case BNEP_SETUP_CONNECTION_REQUEST:
245 if (isext)
246 return 0; /* not allowed in extension headers */
248 len = bnep_recv_setup_connection_req(chan, ptr, size);
249 break;
251 case BNEP_SETUP_CONNECTION_RESPONSE:
252 if (isext)
253 return 0; /* not allowed in extension headers */
255 len = bnep_recv_setup_connection_rsp(chan, ptr, size);
256 break;
258 case BNEP_FILTER_NET_TYPE_SET:
259 len = bnep_recv_filter_net_type_set(chan, ptr, size);
260 break;
262 case BNEP_FILTER_NET_TYPE_RESPONSE:
263 len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
264 break;
266 case BNEP_FILTER_MULTI_ADDR_SET:
267 len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
268 break;
270 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
271 len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
272 break;
274 default:
275 len = 0;
276 break;
279 if (len == 0)
280 bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
282 return len;
285 static size_t
286 bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
288 uint8_t type;
290 if (size < 1)
291 return 0;
293 type = *ptr++;
294 log_err("received Control Command Not Understood (0x%2.2x)", type);
296 /* we didn't send any reserved commands, just shut them down */
297 chan->down(chan);
299 return 1;
302 static size_t
303 bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
305 size_t len;
306 uint8_t off;
307 int src, dst, rsp;
309 if (size < 1)
310 return 0;
312 len = *ptr++;
313 if (size < (len * 2 + 1))
314 return 0;
316 if (chan->state != CHANNEL_WAIT_CONNECT_REQ
317 && chan->state != CHANNEL_OPEN) {
318 log_debug("ignored");
319 return (len * 2 + 1);
322 if (len == 2)
323 off = 2;
324 else if (len == 4)
325 off = 0;
326 else if (len == 16)
327 off = 0;
328 else {
329 rsp = BNEP_SETUP_INVALID_UUID_SIZE;
330 goto done;
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;
339 else
340 dst = 0;
342 if (dst != service_class) {
343 rsp = BNEP_SETUP_INVALID_DST_UUID;
344 goto done;
347 ptr += len;
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;
355 else
356 src = 0;
358 if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
359 || src == 0) {
360 rsp = BNEP_SETUP_INVALID_SRC_UUID;
361 goto done;
364 rsp = BNEP_SETUP_SUCCESS;
365 chan->state = CHANNEL_OPEN;
366 channel_timeout(chan, 0);
368 done:
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);
376 static size_t
377 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
379 int rsp;
381 if (size < 2)
382 return 0;
384 rsp = be16dec(ptr);
386 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
387 log_debug("ignored");
388 return 2;
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);
397 } else {
398 chan->down(chan);
401 return 2;
404 static size_t
405 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
407 pfilter_t *pf;
408 int i, nf, rsp;
409 size_t len;
411 if (size < 2)
412 return 0;
414 len = be16dec(ptr);
415 ptr += 2;
417 if (size < (len + 2))
418 return 0;
420 if (chan->state != CHANNEL_OPEN) {
421 log_debug("ignored");
422 return (len + 2);
425 nf = len / 4;
426 pf = malloc(nf * sizeof(pfilter_t));
427 if (pf == NULL) {
428 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
429 goto done;
432 log_debug("nf = %d", nf);
434 for (i = 0; i < nf; i++) {
435 pf[i].start = be16dec(ptr);
436 ptr += 2;
437 pf[i].end = be16dec(ptr);
438 ptr += 2;
440 if (pf[i].start > pf[i].end) {
441 free(pf);
442 rsp = BNEP_FILTER_INVALID_RANGE;
443 goto done;
446 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
449 if (chan->pfilter)
450 free(chan->pfilter);
452 chan->pfilter = pf;
453 chan->npfilter = nf;
455 rsp = BNEP_FILTER_SUCCESS;
457 done:
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);
462 return (len + 2);
465 static size_t
466 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
468 int rsp;
470 if (size < 2)
471 return 0;
473 if (chan->state != CHANNEL_OPEN) {
474 log_debug("ignored");
475 return 2;
478 rsp = be16dec(ptr);
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 */
484 return 2;
487 static size_t
488 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
490 mfilter_t *mf;
491 int i, nf, rsp;
492 size_t len;
494 if (size < 2)
495 return 0;
497 len = be16dec(ptr);
498 ptr += 2;
500 if (size < (len + 2))
501 return 0;
503 if (chan->state != CHANNEL_OPEN) {
504 log_debug("ignored");
505 return (len + 2);
508 nf = len / (ETHER_ADDR_LEN * 2);
509 mf = malloc(nf * sizeof(mfilter_t));
510 if (mf == NULL) {
511 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
512 goto done;
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) {
525 free(mf);
526 rsp = BNEP_FILTER_INVALID_RANGE;
527 goto done;
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]);
539 if (chan->mfilter)
540 free(chan->mfilter);
542 chan->mfilter = mf;
543 chan->nmfilter = nf;
545 rsp = BNEP_FILTER_SUCCESS;
547 done:
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);
552 return (len + 2);
555 static size_t
556 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
558 int rsp;
560 if (size < 2)
561 return false;
563 if (chan->state != CHANNEL_OPEN) {
564 log_debug("ignored");
565 return 2;
568 rsp = be16dec(ptr);
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 */
574 return 2;
577 void
578 bnep_send_control(channel_t *chan, uint8_t type, ...)
580 packet_t *pkt;
581 uint8_t *p;
582 va_list ap;
584 assert(chan->state != CHANNEL_CLOSED);
586 pkt = packet_alloc(chan);
587 if (pkt == NULL)
588 return;
590 p = pkt->ptr;
591 va_start(ap, type);
593 *p++ = BNEP_CONTROL;
594 *p++ = type;
596 switch(type) {
597 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
598 *p++ = va_arg(ap, int);
599 break;
601 case BNEP_SETUP_CONNECTION_REQUEST:
602 *p++ = va_arg(ap, int);
603 be16enc(p, va_arg(ap, int));
604 p += 2;
605 be16enc(p, va_arg(ap, int));
606 p += 2;
607 break;
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));
613 p += 2;
614 break;
616 case BNEP_FILTER_NET_TYPE_SET: /* TODO */
617 case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
618 default:
619 log_err("Can't send control type 0x%2.2x", type);
620 break;
623 va_end(ap);
624 pkt->len = p - pkt->ptr;
626 channel_put(chan, pkt);
627 packet_free(pkt);
631 * BNEP send packet routine
632 * return true if packet can be removed from queue
634 bool
635 bnep_send(channel_t *chan, packet_t *pkt)
637 struct iovec iov[2];
638 uint8_t *p, *type, *proto;
639 exthdr_t *eh;
640 bool src, dst;
641 size_t nw;
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;
647 iov[1].iov_len = 0;
648 } else {
649 p = chan->sendbuf;
651 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
652 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
654 type = p;
655 p += 1;
657 if (dst && src)
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;
666 if (dst) {
667 memcpy(p, pkt->dst, ETHER_ADDR_LEN);
668 p += ETHER_ADDR_LEN;
671 if (src) {
672 memcpy(p, pkt->src, ETHER_ADDR_LEN);
673 p += ETHER_ADDR_LEN;
676 proto = p;
677 memcpy(p, pkt->type, ETHER_TYPE_LEN);
678 p += ETHER_TYPE_LEN;
680 STAILQ_FOREACH(eh, &pkt->extlist, next) {
681 if (p + eh->len > chan->sendbuf + chan->mtu)
682 break;
684 *type |= BNEP_EXT;
685 type = p;
687 memcpy(p, eh->ptr, eh->len);
688 p += eh->len;
691 *type &= ~BNEP_EXT;
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;
704 } else {
705 iov[1].iov_base = NULL;
706 iov[1].iov_len = 0;
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)");
713 return false;
716 nw = writev(chan->fd, iov, __arraycount(iov));
717 return (nw > 0);
720 static bool
721 bnep_pfilter(channel_t *chan, packet_t *pkt)
723 int proto, i;
725 proto = be16dec(pkt->type);
726 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
727 if (pkt->len < 4)
728 return false;
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)
736 return true;
739 return false;
742 static bool
743 bnep_mfilter(channel_t *chan, packet_t *pkt)
745 int i;
747 if (!ETHER_IS_MULTICAST(pkt->dst))
748 return true;
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)
753 return true;
756 return false;