bnep.c revision 1.1 1 /* $NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 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.1 2008/08/17 13:20:57 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 return true;
172 }
173
174 static bool
175 bnep_recv_extension(packet_t *pkt)
176 {
177 exthdr_t *eh;
178 size_t len;
179 uint8_t type, size;
180
181 do {
182 if (pkt->len < 2)
183 return false;
184
185 type = pkt->ptr[0];
186 size = pkt->ptr[1];
187
188 if (pkt->len < size + 2)
189 return false;
190
191 switch (type) {
192 case BNEP_EXTENSION_CONTROL:
193 len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
194 if (len != size)
195 log_err("ignored spurious data in exthdr");
196
197 break;
198
199 default:
200 /* Unknown extension headers in data packets */
201 /* SHALL be forwarded irrespective of any */
202 /* network protocol or multicast filter settings */
203 /* and any local filtering policy. */
204
205 eh = malloc(sizeof(exthdr_t));
206 if (eh == NULL) {
207 log_err("exthdr malloc() failed: %m");
208 break;
209 }
210
211 eh->ptr = pkt->ptr;
212 eh->len = size;
213 STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
214 break;
215 }
216
217 packet_adj(pkt, size + 2);
218 } while (BNEP_TYPE_EXT(type));
219
220 return true;
221 }
222
223 static size_t
224 bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
225 {
226 uint8_t type;
227 size_t len;
228
229 if (size-- < 1)
230 return 0;
231
232 type = *ptr++;
233
234 switch (type) {
235 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
236 len = bnep_recv_control_command_not_understood(chan, ptr, size);
237 break;
238
239 case BNEP_SETUP_CONNECTION_REQUEST:
240 if (isext)
241 return 0; /* not allowed in extension headers */
242
243 len = bnep_recv_setup_connection_req(chan, ptr, size);
244 break;
245
246 case BNEP_SETUP_CONNECTION_RESPONSE:
247 if (isext)
248 return 0; /* not allowed in extension headers */
249
250 len = bnep_recv_setup_connection_rsp(chan, ptr, size);
251 break;
252
253 case BNEP_FILTER_NET_TYPE_SET:
254 len = bnep_recv_filter_net_type_set(chan, ptr, size);
255 break;
256
257 case BNEP_FILTER_NET_TYPE_RESPONSE:
258 len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
259 break;
260
261 case BNEP_FILTER_MULTI_ADDR_SET:
262 len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
263 break;
264
265 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
266 len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
267 break;
268
269 default:
270 len = 0;
271 break;
272 }
273
274 if (len == 0)
275 bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
276
277 return len;
278 }
279
280 static size_t
281 bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
282 {
283 uint8_t type;
284
285 if (size < 1)
286 return 0;
287
288 type = *ptr++;
289 log_err("received Control Command Not Understood (0x%2.2x)", type);
290
291 /* we didn't send any reserved commands, just cut them off */
292 channel_close(chan);
293
294 return 1;
295 }
296
297 static size_t
298 bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
299 {
300 uint8_t len, off;
301 int src, dst, rsp;
302
303 if (size < 1)
304 return 0;
305
306 len = *ptr++;
307 if (size < (len * 2 + 1))
308 return 0;
309
310 if (chan->state != CHANNEL_WAIT_CONNECT_REQ
311 && chan->state != CHANNEL_OPEN) {
312 log_debug("ignored");
313 return (len * 2 + 1);
314 }
315
316 if (len == 2)
317 off = 2;
318 else if (len == 4)
319 off = 0;
320 else if (len == 16)
321 off = 0;
322 else {
323 rsp = BNEP_SETUP_INVALID_UUID_SIZE;
324 goto done;
325 }
326
327 if (memcmp(ptr, NAP_UUID + off, len) == 0)
328 dst = SDP_SERVICE_CLASS_NAP;
329 else if (memcmp(ptr, GN_UUID + off, len) == 0)
330 dst = SDP_SERVICE_CLASS_GN;
331 else if (memcmp(ptr, PANU_UUID + off, len) == 0)
332 dst = SDP_SERVICE_CLASS_PANU;
333 else
334 dst = 0;
335
336 if (dst != service_class) {
337 rsp = BNEP_SETUP_INVALID_DST_UUID;
338 goto done;
339 }
340
341 ptr += len;
342
343 if (memcmp(ptr, PANU_UUID + off, len) == 0)
344 src = SDP_SERVICE_CLASS_NAP;
345 else if (memcmp(ptr, GN_UUID + off, len) == 0)
346 src = SDP_SERVICE_CLASS_GN;
347 else if (memcmp(ptr, NAP_UUID + off, len) == 0)
348 src = SDP_SERVICE_CLASS_PANU;
349 else
350 src = 0;
351
352 if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
353 || src == 0) {
354 rsp = BNEP_SETUP_INVALID_SRC_UUID;
355 goto done;
356 }
357
358 rsp = BNEP_SETUP_SUCCESS;
359 chan->state = CHANNEL_OPEN;
360 channel_timeout(chan, 0);
361
362 done:
363 log_debug("addr %s response 0x%2.2x",
364 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
365
366 bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
367 return (len * 2 + 1);
368 }
369
370 static size_t
371 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
372 {
373 int rsp;
374
375 if (size < 2)
376 return 0;
377
378 rsp = be16dec(ptr);
379
380 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
381 log_debug("ignored");
382 return 2;
383 }
384
385 log_debug("addr %s response 0x%2.2x",
386 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
387
388 if (rsp == BNEP_SETUP_SUCCESS) {
389 chan->state = CHANNEL_OPEN;
390 channel_timeout(chan, 0);
391 } else {
392 channel_close(chan);
393 }
394
395 return 2;
396 }
397
398 static size_t
399 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
400 {
401 pfilter_t *pf;
402 int i, len, nf, rsp;
403
404 if (size < 2)
405 return 0;
406
407 len = be16dec(ptr);
408 ptr += 2;
409
410 if (size < (len + 2))
411 return 0;
412
413 if (chan->state != CHANNEL_OPEN) {
414 log_debug("ignored");
415 return (len + 2);
416 }
417
418 nf = len / 4;
419 pf = malloc(nf * sizeof(pfilter_t));
420 if (pf == NULL) {
421 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
422 goto done;
423 }
424
425 log_debug("nf = %d", nf);
426
427 for (i = 0; i < nf; i++) {
428 pf[i].start = be16dec(ptr);
429 ptr += 2;
430 pf[i].end = be16dec(ptr);
431 ptr += 2;
432
433 if (pf[i].start > pf[i].end) {
434 free(pf);
435 rsp = BNEP_FILTER_INVALID_RANGE;
436 goto done;
437 }
438
439 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
440 }
441
442 if (chan->pfilter)
443 free(chan->pfilter);
444
445 chan->pfilter = pf;
446 chan->npfilter = nf;
447
448 rsp = BNEP_FILTER_SUCCESS;
449
450 done:
451 log_debug("addr %s response 0x%2.2x",
452 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
453
454 bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
455 return (len + 2);
456 }
457
458 static size_t
459 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
460 {
461 int rsp;
462
463 if (size < 2)
464 return 0;
465
466 if (chan->state != CHANNEL_OPEN) {
467 log_debug("ignored");
468 return 2;
469 }
470
471 rsp = be16dec(ptr);
472
473 log_debug("addr %s response 0x%2.2x",
474 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
475
476 /* we did not send any filter_net_type_set message */
477 return 2;
478 }
479
480 static size_t
481 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
482 {
483 mfilter_t *mf;
484 int i, len, nf, rsp;
485
486 if (size < 2)
487 return 0;
488
489 len = be16dec(ptr);
490 ptr += 2;
491
492 if (size < (len + 2))
493 return 0;
494
495 if (chan->state != CHANNEL_OPEN) {
496 log_debug("ignored");
497 return (len + 2);
498 }
499
500 nf = len / (ETHER_ADDR_LEN * 2);
501 mf = malloc(nf * sizeof(mfilter_t));
502 if (mf == NULL) {
503 rsp = BNEP_FILTER_TOO_MANY_FILTERS;
504 goto done;
505 }
506
507 log_debug("nf = %d", nf);
508
509 for (i = 0; i < nf; i++) {
510 memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
511 ptr += ETHER_ADDR_LEN;
512
513 memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
514 ptr += ETHER_ADDR_LEN;
515
516 if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
517 free(mf);
518 rsp = BNEP_FILTER_INVALID_RANGE;
519 goto done;
520 }
521
522 log_debug("pf[%d] = "
523 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
524 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
525 mf[i].start[0], mf[i].start[1], mf[i].start[2],
526 mf[i].start[3], mf[i].start[4], mf[i].start[5],
527 mf[i].end[0], mf[i].end[1], mf[i].end[2],
528 mf[i].end[3], mf[i].end[4], mf[i].end[5]);
529 }
530
531 if (chan->mfilter)
532 free(chan->mfilter);
533
534 chan->mfilter = mf;
535 chan->nmfilter = nf;
536
537 rsp = BNEP_FILTER_SUCCESS;
538
539 done:
540 log_debug("addr %s response 0x%2.2x",
541 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
542
543 bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
544 return (len + 2);
545 }
546
547 static size_t
548 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
549 {
550 int rsp;
551
552 if (size < 2)
553 return false;
554
555 if (chan->state != CHANNEL_OPEN) {
556 log_debug("ignored");
557 return 2;
558 }
559
560 rsp = be16dec(ptr);
561 log_debug("addr %s response 0x%2.2x",
562 ether_ntoa((struct ether_addr *)chan->raddr), rsp);
563
564 /* we did not send any filter_multi_addr_set message */
565 return 2;
566 }
567
568 void
569 bnep_send_control(channel_t *chan, uint8_t type, ...)
570 {
571 packet_t *pkt;
572 uint8_t *p;
573 va_list ap;
574
575 _DIAGASSERT(chan->state != CHANNEL_CLOSED);
576
577 pkt = packet_alloc(chan);
578 if (pkt == NULL)
579 return;
580
581 p = pkt->ptr;
582 va_start(ap, type);
583
584 *p++ = BNEP_CONTROL;
585 *p++ = type;
586
587 switch(type) {
588 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
589 *p++ = va_arg(ap, int);
590 break;
591
592 case BNEP_SETUP_CONNECTION_REQUEST:
593 *p++ = va_arg(ap, int);
594 be16enc(p, va_arg(ap, int));
595 p += 2;
596 be16enc(p, va_arg(ap, int));
597 p += 2;
598 break;
599
600 case BNEP_SETUP_CONNECTION_RESPONSE:
601 case BNEP_FILTER_NET_TYPE_RESPONSE:
602 case BNEP_FILTER_MULTI_ADDR_RESPONSE:
603 be16enc(p, va_arg(ap, int));
604 p += 2;
605 break;
606
607 case BNEP_FILTER_NET_TYPE_SET: /* TODO */
608 case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
609 default:
610 log_err("Can't send control type 0x%2.2x", type);
611 break;
612 }
613
614 va_end(ap);
615 pkt->len = p - pkt->ptr;
616
617 channel_put(chan, pkt);
618 packet_free(pkt);
619 }
620
621 /*
622 * BNEP send packet routine
623 * return true if packet can be removed from queue
624 */
625 bool
626 bnep_send(channel_t *chan, packet_t *pkt)
627 {
628 struct iovec iov[2];
629 uint8_t *p, *type, *proto;
630 exthdr_t *eh;
631 bool src, dst;
632 size_t nw;
633
634 if (pkt->type == NULL) {
635 iov[0].iov_base = pkt->ptr;
636 iov[0].iov_len = pkt->len;
637 iov[1].iov_base = NULL;
638 iov[1].iov_len = 0;
639 } else {
640 p = chan->sendbuf;
641
642 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
643 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
644
645 type = p;
646 p += 1;
647
648 if (dst && src)
649 *type = BNEP_GENERAL_ETHERNET;
650 else if (dst && !src)
651 *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
652 else if (!dst && src)
653 *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
654 else /* (!dst && !src) */
655 *type = BNEP_COMPRESSED_ETHERNET;
656
657 if (dst) {
658 memcpy(p, pkt->dst, ETHER_ADDR_LEN);
659 p += ETHER_ADDR_LEN;
660 }
661
662 if (src) {
663 memcpy(p, pkt->src, ETHER_ADDR_LEN);
664 p += ETHER_ADDR_LEN;
665 }
666
667 proto = p;
668 memcpy(p, pkt->type, ETHER_TYPE_LEN);
669 p += ETHER_TYPE_LEN;
670
671 STAILQ_FOREACH(eh, &pkt->extlist, next) {
672 if (p + eh->len > chan->sendbuf + chan->mtu)
673 break;
674
675 *type |= BNEP_EXT;
676 type = p;
677
678 memcpy(p, eh->ptr, eh->len);
679 p += eh->len;
680 }
681
682 *type &= ~BNEP_EXT;
683
684 iov[0].iov_base = chan->sendbuf;
685 iov[0].iov_len = (p - chan->sendbuf);
686
687 if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
688 && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
689 iov[1].iov_base = pkt->ptr;
690 iov[1].iov_len = pkt->len;
691 } else if (be16dec(proto) == ETHERTYPE_VLAN
692 && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
693 iov[1].iov_base = pkt->ptr;
694 iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
695 } else {
696 iov[1].iov_base = NULL;
697 iov[1].iov_len = 0;
698 memset(proto, 0, ETHER_TYPE_LEN);
699 }
700 }
701
702 if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
703 log_err("packet exceeded MTU (dropped)");
704 return false;
705 }
706
707 nw = writev(chan->fd, iov, __arraycount(iov));
708 return (nw > 0);
709 }
710
711 static bool
712 bnep_pfilter(channel_t *chan, packet_t *pkt)
713 {
714 int proto, i;
715
716 proto = be16dec(pkt->type);
717 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
718 if (pkt->len < 4)
719 return false;
720
721 proto = be16dec(pkt->ptr + 2);
722 }
723
724 for (i = 0; i < chan->npfilter; i++) {
725 if (chan->pfilter[i].start <= proto
726 && chan->pfilter[i].end >=proto)
727 return true;
728 }
729
730 return false;
731 }
732
733 static bool
734 bnep_mfilter(channel_t *chan, packet_t *pkt)
735 {
736 int i;
737
738 if (!ETHER_IS_MULTICAST(pkt->dst))
739 return true;
740
741 for (i = 0; i < chan->nmfilter; i++) {
742 if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
743 && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
744 return true;
745 }
746
747 return false;
748 }
749