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