xref: /netbsd-src/usr.sbin/btpand/bnep.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
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