1 /* $NetBSD: bnep.c,v 1.3 2009/02/04 19:24:18 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.3 2009/02/04 19:24:18 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, size; 179 uint8_t type; 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 size_t len; 301 uint8_t off; 302 int src, dst, rsp; 303 304 if (size < 1) 305 return 0; 306 307 len = *ptr++; 308 if (size < (len * 2 + 1)) 309 return 0; 310 311 if (chan->state != CHANNEL_WAIT_CONNECT_REQ 312 && chan->state != CHANNEL_OPEN) { 313 log_debug("ignored"); 314 return (len * 2 + 1); 315 } 316 317 if (len == 2) 318 off = 2; 319 else if (len == 4) 320 off = 0; 321 else if (len == 16) 322 off = 0; 323 else { 324 rsp = BNEP_SETUP_INVALID_UUID_SIZE; 325 goto done; 326 } 327 328 if (memcmp(ptr, NAP_UUID + off, len) == 0) 329 dst = SDP_SERVICE_CLASS_NAP; 330 else if (memcmp(ptr, GN_UUID + off, len) == 0) 331 dst = SDP_SERVICE_CLASS_GN; 332 else if (memcmp(ptr, PANU_UUID + off, len) == 0) 333 dst = SDP_SERVICE_CLASS_PANU; 334 else 335 dst = 0; 336 337 if (dst != service_class) { 338 rsp = BNEP_SETUP_INVALID_DST_UUID; 339 goto done; 340 } 341 342 ptr += len; 343 344 if (memcmp(ptr, NAP_UUID + off, len) == 0) 345 src = SDP_SERVICE_CLASS_NAP; 346 else if (memcmp(ptr, GN_UUID + off, len) == 0) 347 src = SDP_SERVICE_CLASS_GN; 348 else if (memcmp(ptr, PANU_UUID + off, len) == 0) 349 src = SDP_SERVICE_CLASS_PANU; 350 else 351 src = 0; 352 353 if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU) 354 || src == 0) { 355 rsp = BNEP_SETUP_INVALID_SRC_UUID; 356 goto done; 357 } 358 359 rsp = BNEP_SETUP_SUCCESS; 360 chan->state = CHANNEL_OPEN; 361 channel_timeout(chan, 0); 362 363 done: 364 log_debug("addr %s response 0x%2.2x", 365 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 366 367 bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp); 368 return (len * 2 + 1); 369 } 370 371 static size_t 372 bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size) 373 { 374 int rsp; 375 376 if (size < 2) 377 return 0; 378 379 rsp = be16dec(ptr); 380 381 if (chan->state != CHANNEL_WAIT_CONNECT_RSP) { 382 log_debug("ignored"); 383 return 2; 384 } 385 386 log_debug("addr %s response 0x%2.2x", 387 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 388 389 if (rsp == BNEP_SETUP_SUCCESS) { 390 chan->state = CHANNEL_OPEN; 391 channel_timeout(chan, 0); 392 } else { 393 channel_close(chan); 394 } 395 396 return 2; 397 } 398 399 static size_t 400 bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size) 401 { 402 pfilter_t *pf; 403 int i, nf, rsp; 404 size_t len; 405 406 if (size < 2) 407 return 0; 408 409 len = be16dec(ptr); 410 ptr += 2; 411 412 if (size < (len + 2)) 413 return 0; 414 415 if (chan->state != CHANNEL_OPEN) { 416 log_debug("ignored"); 417 return (len + 2); 418 } 419 420 nf = len / 4; 421 pf = malloc(nf * sizeof(pfilter_t)); 422 if (pf == NULL) { 423 rsp = BNEP_FILTER_TOO_MANY_FILTERS; 424 goto done; 425 } 426 427 log_debug("nf = %d", nf); 428 429 for (i = 0; i < nf; i++) { 430 pf[i].start = be16dec(ptr); 431 ptr += 2; 432 pf[i].end = be16dec(ptr); 433 ptr += 2; 434 435 if (pf[i].start > pf[i].end) { 436 free(pf); 437 rsp = BNEP_FILTER_INVALID_RANGE; 438 goto done; 439 } 440 441 log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end); 442 } 443 444 if (chan->pfilter) 445 free(chan->pfilter); 446 447 chan->pfilter = pf; 448 chan->npfilter = nf; 449 450 rsp = BNEP_FILTER_SUCCESS; 451 452 done: 453 log_debug("addr %s response 0x%2.2x", 454 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 455 456 bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp); 457 return (len + 2); 458 } 459 460 static size_t 461 bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size) 462 { 463 int rsp; 464 465 if (size < 2) 466 return 0; 467 468 if (chan->state != CHANNEL_OPEN) { 469 log_debug("ignored"); 470 return 2; 471 } 472 473 rsp = be16dec(ptr); 474 475 log_debug("addr %s response 0x%2.2x", 476 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 477 478 /* we did not send any filter_net_type_set message */ 479 return 2; 480 } 481 482 static size_t 483 bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size) 484 { 485 mfilter_t *mf; 486 int i, nf, rsp; 487 size_t len; 488 489 if (size < 2) 490 return 0; 491 492 len = be16dec(ptr); 493 ptr += 2; 494 495 if (size < (len + 2)) 496 return 0; 497 498 if (chan->state != CHANNEL_OPEN) { 499 log_debug("ignored"); 500 return (len + 2); 501 } 502 503 nf = len / (ETHER_ADDR_LEN * 2); 504 mf = malloc(nf * sizeof(mfilter_t)); 505 if (mf == NULL) { 506 rsp = BNEP_FILTER_TOO_MANY_FILTERS; 507 goto done; 508 } 509 510 log_debug("nf = %d", nf); 511 512 for (i = 0; i < nf; i++) { 513 memcpy(mf[i].start, ptr, ETHER_ADDR_LEN); 514 ptr += ETHER_ADDR_LEN; 515 516 memcpy(mf[i].end, ptr, ETHER_ADDR_LEN); 517 ptr += ETHER_ADDR_LEN; 518 519 if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) { 520 free(mf); 521 rsp = BNEP_FILTER_INVALID_RANGE; 522 goto done; 523 } 524 525 log_debug("pf[%d] = " 526 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " 527 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i, 528 mf[i].start[0], mf[i].start[1], mf[i].start[2], 529 mf[i].start[3], mf[i].start[4], mf[i].start[5], 530 mf[i].end[0], mf[i].end[1], mf[i].end[2], 531 mf[i].end[3], mf[i].end[4], mf[i].end[5]); 532 } 533 534 if (chan->mfilter) 535 free(chan->mfilter); 536 537 chan->mfilter = mf; 538 chan->nmfilter = nf; 539 540 rsp = BNEP_FILTER_SUCCESS; 541 542 done: 543 log_debug("addr %s response 0x%2.2x", 544 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 545 546 bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp); 547 return (len + 2); 548 } 549 550 static size_t 551 bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size) 552 { 553 int rsp; 554 555 if (size < 2) 556 return false; 557 558 if (chan->state != CHANNEL_OPEN) { 559 log_debug("ignored"); 560 return 2; 561 } 562 563 rsp = be16dec(ptr); 564 log_debug("addr %s response 0x%2.2x", 565 ether_ntoa((struct ether_addr *)chan->raddr), rsp); 566 567 /* we did not send any filter_multi_addr_set message */ 568 return 2; 569 } 570 571 void 572 bnep_send_control(channel_t *chan, uint8_t type, ...) 573 { 574 packet_t *pkt; 575 uint8_t *p; 576 va_list ap; 577 578 _DIAGASSERT(chan->state != CHANNEL_CLOSED); 579 580 pkt = packet_alloc(chan); 581 if (pkt == NULL) 582 return; 583 584 p = pkt->ptr; 585 va_start(ap, type); 586 587 *p++ = BNEP_CONTROL; 588 *p++ = type; 589 590 switch(type) { 591 case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD: 592 *p++ = va_arg(ap, int); 593 break; 594 595 case BNEP_SETUP_CONNECTION_REQUEST: 596 *p++ = va_arg(ap, int); 597 be16enc(p, va_arg(ap, int)); 598 p += 2; 599 be16enc(p, va_arg(ap, int)); 600 p += 2; 601 break; 602 603 case BNEP_SETUP_CONNECTION_RESPONSE: 604 case BNEP_FILTER_NET_TYPE_RESPONSE: 605 case BNEP_FILTER_MULTI_ADDR_RESPONSE: 606 be16enc(p, va_arg(ap, int)); 607 p += 2; 608 break; 609 610 case BNEP_FILTER_NET_TYPE_SET: /* TODO */ 611 case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */ 612 default: 613 log_err("Can't send control type 0x%2.2x", type); 614 break; 615 } 616 617 va_end(ap); 618 pkt->len = p - pkt->ptr; 619 620 channel_put(chan, pkt); 621 packet_free(pkt); 622 } 623 624 /* 625 * BNEP send packet routine 626 * return true if packet can be removed from queue 627 */ 628 bool 629 bnep_send(channel_t *chan, packet_t *pkt) 630 { 631 struct iovec iov[2]; 632 uint8_t *p, *type, *proto; 633 exthdr_t *eh; 634 bool src, dst; 635 size_t nw; 636 637 if (pkt->type == NULL) { 638 iov[0].iov_base = pkt->ptr; 639 iov[0].iov_len = pkt->len; 640 iov[1].iov_base = NULL; 641 iov[1].iov_len = 0; 642 } else { 643 p = chan->sendbuf; 644 645 dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0); 646 src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0); 647 648 type = p; 649 p += 1; 650 651 if (dst && src) 652 *type = BNEP_GENERAL_ETHERNET; 653 else if (dst && !src) 654 *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY; 655 else if (!dst && src) 656 *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY; 657 else /* (!dst && !src) */ 658 *type = BNEP_COMPRESSED_ETHERNET; 659 660 if (dst) { 661 memcpy(p, pkt->dst, ETHER_ADDR_LEN); 662 p += ETHER_ADDR_LEN; 663 } 664 665 if (src) { 666 memcpy(p, pkt->src, ETHER_ADDR_LEN); 667 p += ETHER_ADDR_LEN; 668 } 669 670 proto = p; 671 memcpy(p, pkt->type, ETHER_TYPE_LEN); 672 p += ETHER_TYPE_LEN; 673 674 STAILQ_FOREACH(eh, &pkt->extlist, next) { 675 if (p + eh->len > chan->sendbuf + chan->mtu) 676 break; 677 678 *type |= BNEP_EXT; 679 type = p; 680 681 memcpy(p, eh->ptr, eh->len); 682 p += eh->len; 683 } 684 685 *type &= ~BNEP_EXT; 686 687 iov[0].iov_base = chan->sendbuf; 688 iov[0].iov_len = (p - chan->sendbuf); 689 690 if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt)) 691 && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) { 692 iov[1].iov_base = pkt->ptr; 693 iov[1].iov_len = pkt->len; 694 } else if (be16dec(proto) == ETHERTYPE_VLAN 695 && pkt->len >= ETHER_VLAN_ENCAP_LEN) { 696 iov[1].iov_base = pkt->ptr; 697 iov[1].iov_len = ETHER_VLAN_ENCAP_LEN; 698 } else { 699 iov[1].iov_base = NULL; 700 iov[1].iov_len = 0; 701 memset(proto, 0, ETHER_TYPE_LEN); 702 } 703 } 704 705 if (iov[0].iov_len + iov[1].iov_len > chan->mtu) { 706 log_err("packet exceeded MTU (dropped)"); 707 return false; 708 } 709 710 nw = writev(chan->fd, iov, __arraycount(iov)); 711 return (nw > 0); 712 } 713 714 static bool 715 bnep_pfilter(channel_t *chan, packet_t *pkt) 716 { 717 int proto, i; 718 719 proto = be16dec(pkt->type); 720 if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */ 721 if (pkt->len < 4) 722 return false; 723 724 proto = be16dec(pkt->ptr + 2); 725 } 726 727 for (i = 0; i < chan->npfilter; i++) { 728 if (chan->pfilter[i].start <= proto 729 && chan->pfilter[i].end >=proto) 730 return true; 731 } 732 733 return false; 734 } 735 736 static bool 737 bnep_mfilter(channel_t *chan, packet_t *pkt) 738 { 739 int i; 740 741 if (!ETHER_IS_MULTICAST(pkt->dst)) 742 return true; 743 744 for (i = 0; i < chan->nmfilter; i++) { 745 if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0 746 && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0) 747 return true; 748 } 749 750 return false; 751 } 752