bnep.c revision 1.8 1 /* $NetBSD: bnep.c,v 1.8 2009/05/12 21:08:30 plunky Exp $ */
2
3 /*-
4 * Copyright (c) 2008 Iain Hibbert
5 * All rights reserved.
6 *
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.
15 *
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.
26 */
27
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: bnep.c,v 1.8 2009/05/12 21:08:30 plunky Exp $");
30
31 #include <bluetooth.h>
32 #include <sdp.h>
33 #include <stdarg.h>
34 #include <string.h>
35
36 #include "btpand.h"
37 #include "bnep.h"
38
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);
48
49 static bool bnep_pfilter(channel_t *, packet_t *);
50 static bool bnep_mfilter(channel_t *, packet_t *);
51
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
58 };
59
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,
66 };
67
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
74 };
75
76 /*
77 * receive BNEP packet
78 * return true if packet is to be forwarded
79 */
80 bool
81 bnep_recv(packet_t *pkt)
82 {
83 size_t len;
84 uint8_t type;
85
86 if (pkt->len < 1)
87 return false;
88
89 type = pkt->ptr[0];
90 packet_adj(pkt, 1);
91
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;
97 }
98
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;
106
107 case BNEP_CONTROL:
108 len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
109 if (len == 0)
110 return false;
111
112 packet_adj(pkt, len);
113 break;
114
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;
119 }
120
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;
126
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;
131 }
132
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;
139
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;
144 }
145
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;
152
153 default:
154 /*
155 * Any packet containing a reserved BNEP
156 * header packet type SHALL be dropped.
157 */
158
159 log_debug("dropped packet with reserved type 0x%2.2x", type);
160 return false;
161 }
162
163 if (BNEP_TYPE_EXT(type)
164 && !bnep_recv_extension(pkt))
165 return false; /* invalid extensions */
166
167 if (BNEP_TYPE(type) == BNEP_CONTROL
168 || pkt->chan->state != CHANNEL_OPEN)
169 return false; /* no forwarding */
170
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);
175
176 return true;
177 }
178
179 static bool
180 bnep_recv_extension(packet_t *pkt)
181 {
182 exthdr_t *eh;
183 size_t len, size;
184 uint8_t type;
185
186 do {
187 if (pkt->len < 2)
188 return false;
189
190 type = pkt->ptr[0];
191 size = pkt->ptr[1];
192
193 if (pkt->len < size + 2)
194 return false;
195
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");
201
202 break;
203
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. */
209
210 eh = malloc(sizeof(exthdr_t));
211 if (eh == NULL) {
212 log_err("exthdr malloc() failed: %m");
213 break;
214 }
215
216 eh->ptr = pkt->ptr;
217 eh->len = size;
218 STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
219 break;
220 }
221
222 packet_adj(pkt, size + 2);
223 } while (BNEP_TYPE_EXT(type));
224
225 return true;
226 }
227
228 static size_t
229 bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
230 {
231 uint8_t type;
232 size_t len;
233
234 if (size-- < 1)
235 return 0;
236
237 type = *ptr++;
238
239 switch (type) {
240 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
241 len = bnep_recv_control_command_not_understood(chan, ptr, size);
242 break;
243
244 case BNEP_SETUP_CONNECTION_REQUEST:
245 if (isext)
246 return 0; /* not allowed in extension headers */
247
248 len = bnep_recv_setup_connection_req(chan, ptr, size);
249 break;
250
251 case BNEP_SETUP_CONNECTION_RESPONSE:
252 if (isext)
253 return 0; /* not allowed in extension headers */
254
255 len = bnep_recv_setup_connection_rsp(chan, ptr, size);
256 break;
257
258 case BNEP_FILTER_NET_TYPE_SET:
259 len = bnep_recv_filter_net_type_set(chan, ptr, size);
260 break;
261
262 case BNEP_FILTER_NET_TYPE_RESPONSE:
263 len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
264 break;
265
266 case BNEP_FILTER_MULTI_ADDR_SET:
267 len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
268 break;
269
270 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
271 len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
272 break;
273
274 default:
275 len = 0;
276 break;
277 }
278
279 if (len == 0)
280 bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
281
282 return len;
283 }
284
285 static size_t
286 bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
287 {
288 uint8_t type;
289
290 if (size < 1)
291 return 0;
292
293 type = *ptr++;
294 log_err("received Control Command Not Understood (0x%2.2x)", type);
295
296 /* we didn't send any reserved commands, just shut them down */
297 chan->down(chan);
298
299 return 1;
300 }
301
302 static size_t
303 bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
304 {
305 size_t len;
306 uint8_t off;
307 int src, dst, rsp;
308
309 if (size < 1)
310 return 0;
311
312 len = *ptr++;
313 if (size < (len * 2 + 1))
314 return 0;
315
316 if (chan->state != CHANNEL_WAIT_CONNECT_REQ
317 && chan->state != CHANNEL_OPEN) {
318 log_debug("ignored");
319 return (len * 2 + 1);
320 }
321
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;
331 }
332
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;
341
342 if (dst != service_class) {
343 rsp = BNEP_SETUP_INVALID_DST_UUID;
344 goto done;
345 }
346
347 ptr += len;
348
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;
357
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;
362 }
363
364 rsp = BNEP_SETUP_SUCCESS;
365 chan->state = CHANNEL_OPEN;
366 channel_timeout(chan, 0);
367
368 done:
369 log_debug("addr %s response 0x%2.2x",
370 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
371
372 bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
373 return (len * 2 + 1);
374 }
375
376 static size_t
377 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
378 {
379 int rsp;
380
381 if (size < 2)
382 return 0;
383
384 rsp = be16dec(ptr);
385
386 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
387 log_debug("ignored");
388 return 2;
389 }
390
391 log_debug("addr %s response 0x%2.2x",
392 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
393
394 if (rsp == BNEP_SETUP_SUCCESS) {
395 chan->state = CHANNEL_OPEN;
396 channel_timeout(chan, 0);
397 } else {
398 chan->down(chan);
399 }
400
401 return 2;
402 }
403
404 static size_t
405 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
406 {
407 pfilter_t *pf;
408 int i, nf, rsp;
409 size_t len;
410
411 if (size < 2)
412 return 0;
413
414 len = be16dec(ptr);
415 ptr += 2;
416
417 if (size < (len + 2))
418 return 0;
419
420 if (chan->state != CHANNEL_OPEN) {
421 log_debug("ignored");
422 return (len + 2);
423 }
424
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;
430 }
431
432 log_debug("nf = %d", nf);
433
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;
439
440 if (pf[i].start > pf[i].end) {
441 free(pf);
442 rsp = BNEP_FILTER_INVALID_RANGE;
443 goto done;
444 }
445
446 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
447 }
448
449 if (chan->pfilter)
450 free(chan->pfilter);
451
452 chan->pfilter = pf;
453 chan->npfilter = nf;
454
455 rsp = BNEP_FILTER_SUCCESS;
456
457 done:
458 log_debug("addr %s response 0x%2.2x",
459 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
460
461 bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
462 return (len + 2);
463 }
464
465 static size_t
466 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
467 {
468 int rsp;
469
470 if (size < 2)
471 return 0;
472
473 if (chan->state != CHANNEL_OPEN) {
474 log_debug("ignored");
475 return 2;
476 }
477
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);
482
483 /* we did not send any filter_net_type_set message */
484 return 2;
485 }
486
487 static size_t
488 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
489 {
490 mfilter_t *mf;
491 int i, nf, rsp;
492 size_t len;
493
494 if (size < 2)
495 return 0;
496
497 len = be16dec(ptr);
498 ptr += 2;
499
500 if (size < (len + 2))
501 return 0;
502
503 if (chan->state != CHANNEL_OPEN) {
504 log_debug("ignored");
505 return (len + 2);
506 }
507
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;
513 }
514
515 log_debug("nf = %d", nf);
516
517 for (i = 0; i < nf; i++) {
518 memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
519 ptr += ETHER_ADDR_LEN;
520
521 memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
522 ptr += ETHER_ADDR_LEN;
523
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;
528 }
529
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]);
537 }
538
539 if (chan->mfilter)
540 free(chan->mfilter);
541
542 chan->mfilter = mf;
543 chan->nmfilter = nf;
544
545 rsp = BNEP_FILTER_SUCCESS;
546
547 done:
548 log_debug("addr %s response 0x%2.2x",
549 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
550
551 bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
552 return (len + 2);
553 }
554
555 static size_t
556 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
557 {
558 int rsp;
559
560 if (size < 2)
561 return false;
562
563 if (chan->state != CHANNEL_OPEN) {
564 log_debug("ignored");
565 return 2;
566 }
567
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);
572
573 /* we did not send any filter_multi_addr_set message */
574 return 2;
575 }
576
577 void
578 bnep_send_control(channel_t *chan, uint8_t type, ...)
579 {
580 packet_t *pkt;
581 uint8_t *p;
582 va_list ap;
583
584 assert(chan->state != CHANNEL_CLOSED);
585
586 pkt = packet_alloc(chan);
587 if (pkt == NULL)
588 return;
589
590 p = pkt->ptr;
591 va_start(ap, type);
592
593 *p++ = BNEP_CONTROL;
594 *p++ = type;
595
596 switch(type) {
597 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
598 *p++ = va_arg(ap, int);
599 break;
600
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;
608
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;
615
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;
621 }
622
623 va_end(ap);
624 pkt->len = p - pkt->ptr;
625
626 channel_put(chan, pkt);
627 packet_free(pkt);
628 }
629
630 /*
631 * BNEP send packet routine
632 * return true if packet can be removed from queue
633 */
634 bool
635 bnep_send(channel_t *chan, packet_t *pkt)
636 {
637 struct iovec iov[2];
638 uint8_t *p, *type, *proto;
639 exthdr_t *eh;
640 bool src, dst;
641 size_t nw;
642
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;
650
651 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
652 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
653
654 type = p;
655 p += 1;
656
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;
665
666 if (dst) {
667 memcpy(p, pkt->dst, ETHER_ADDR_LEN);
668 p += ETHER_ADDR_LEN;
669 }
670
671 if (src) {
672 memcpy(p, pkt->src, ETHER_ADDR_LEN);
673 p += ETHER_ADDR_LEN;
674 }
675
676 proto = p;
677 memcpy(p, pkt->type, ETHER_TYPE_LEN);
678 p += ETHER_TYPE_LEN;
679
680 STAILQ_FOREACH(eh, &pkt->extlist, next) {
681 if (p + eh->len > chan->sendbuf + chan->mtu)
682 break;
683
684 *type |= BNEP_EXT;
685 type = p;
686
687 memcpy(p, eh->ptr, eh->len);
688 p += eh->len;
689 }
690
691 *type &= ~BNEP_EXT;
692
693 iov[0].iov_base = chan->sendbuf;
694 iov[0].iov_len = (p - chan->sendbuf);
695
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);
708 }
709 }
710
711 if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
712 log_err("packet exceeded MTU (dropped)");
713 return false;
714 }
715
716 nw = writev(chan->fd, iov, __arraycount(iov));
717 return (nw > 0);
718 }
719
720 static bool
721 bnep_pfilter(channel_t *chan, packet_t *pkt)
722 {
723 int proto, i;
724
725 proto = be16dec(pkt->type);
726 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
727 if (pkt->len < 4)
728 return false;
729
730 proto = be16dec(pkt->ptr + 2);
731 }
732
733 for (i = 0; i < chan->npfilter; i++) {
734 if (chan->pfilter[i].start <= proto
735 && chan->pfilter[i].end >=proto)
736 return true;
737 }
738
739 return false;
740 }
741
742 static bool
743 bnep_mfilter(channel_t *chan, packet_t *pkt)
744 {
745 int i;
746
747 if (!ETHER_IS_MULTICAST(pkt->dst))
748 return true;
749
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;
754 }
755
756 return false;
757 }
758