bnep.c revision 305287
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/* $FreeBSD: stable/11/usr.sbin/bluetooth/btpand/bnep.c 305287 2016-09-02 17:24:16Z dim $ */
29
30#include <sys/cdefs.h>
31__RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
32
33#include <sys/uio.h>
34#define L2CAP_SOCKET_CHECKED
35#include <bluetooth.h>
36#include <sdp.h>
37#include <stdarg.h>
38#include <string.h>
39#include <unistd.h>
40
41#include "btpand.h"
42#include "bnep.h"
43
44static bool bnep_recv_extension(packet_t *);
45static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
46static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
47static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
48static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
49static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
50static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
51static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
52static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
53
54static bool bnep_pfilter(channel_t *, packet_t *);
55static bool bnep_mfilter(channel_t *, packet_t *);
56
57static uint8_t NAP_UUID[] = {
58	0x00, 0x00, 0x11, 0x16,
59	0x00, 0x00,
60	0x10, 0x00,
61	0x80, 0x00,
62	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
63};
64
65static uint8_t GN_UUID[] = {
66	0x00, 0x00, 0x11, 0x17,
67	0x00, 0x00,
68	0x10, 0x00,
69	0x80, 0x00,
70	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
71};
72
73static uint8_t PANU_UUID[] = {
74	0x00, 0x00, 0x11, 0x15,
75	0x00, 0x00,
76	0x10, 0x00,
77	0x80, 0x00,
78	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
79};
80
81/*
82 * receive BNEP packet
83 * return true if packet is to be forwarded
84 */
85bool
86bnep_recv(packet_t *pkt)
87{
88	size_t len;
89	uint8_t type;
90
91	if (pkt->len < 1)
92		return false;
93
94	type = pkt->ptr[0];
95	packet_adj(pkt, 1);
96
97	switch (BNEP_TYPE(type)) {
98	case BNEP_GENERAL_ETHERNET:
99		if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
100			log_debug("dropped short packet (type 0x%2.2x)", type);
101			return false;
102		}
103
104		pkt->dst = pkt->ptr;
105		packet_adj(pkt, ETHER_ADDR_LEN);
106		pkt->src = pkt->ptr;
107		packet_adj(pkt, ETHER_ADDR_LEN);
108		pkt->type = pkt->ptr;
109		packet_adj(pkt, ETHER_TYPE_LEN);
110		break;
111
112	case BNEP_CONTROL:
113		len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
114		if (len == 0)
115			return false;
116
117		packet_adj(pkt, len);
118		break;
119
120	case BNEP_COMPRESSED_ETHERNET:
121		if (pkt->len < ETHER_TYPE_LEN) {
122			log_debug("dropped short packet (type 0x%2.2x)", type);
123			return false;
124		}
125
126		pkt->dst = pkt->chan->laddr;
127		pkt->src = pkt->chan->raddr;
128		pkt->type = pkt->ptr;
129		packet_adj(pkt, ETHER_TYPE_LEN);
130		break;
131
132	case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
133		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
134			log_debug("dropped short packet (type 0x%2.2x)", type);
135			return false;
136		}
137
138		pkt->dst = pkt->chan->laddr;
139		pkt->src = pkt->ptr;
140		packet_adj(pkt, ETHER_ADDR_LEN);
141		pkt->type = pkt->ptr;
142		packet_adj(pkt, ETHER_TYPE_LEN);
143		break;
144
145	case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
146		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
147			log_debug("dropped short packet (type 0x%2.2x)", type);
148			return false;
149		}
150
151		pkt->dst = pkt->ptr;
152		packet_adj(pkt, ETHER_ADDR_LEN);
153		pkt->src = pkt->chan->raddr;
154		pkt->type = pkt->ptr;
155		packet_adj(pkt, ETHER_TYPE_LEN);
156		break;
157
158	default:
159		/*
160		 * Any packet containing a reserved BNEP
161		 * header packet type SHALL be dropped.
162		 */
163
164		log_debug("dropped packet with reserved type 0x%2.2x", type);
165		return false;
166	}
167
168	if (BNEP_TYPE_EXT(type)
169	    && !bnep_recv_extension(pkt))
170		return false;	/* invalid extensions */
171
172	if (BNEP_TYPE(type) == BNEP_CONTROL
173	    || pkt->chan->state != CHANNEL_OPEN)
174		return false;	/* no forwarding */
175
176	return true;
177}
178
179static bool
180bnep_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
228static size_t
229bnep_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
285static size_t
286bnep_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 cut them off */
297	channel_close(chan);
298
299	return 1;
300}
301
302static size_t
303bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
304{
305	uint8_t off;
306	int src, dst, rsp;
307	size_t len;
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
368done:
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
376static size_t
377bnep_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		channel_close(chan);
399	}
400
401	return 2;
402}
403
404static size_t
405bnep_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
457done:
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
465static size_t
466bnep_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
480	log_debug("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
487static size_t
488bnep_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
547done:
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
555static size_t
556bnep_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	log_debug("addr %s response 0x%2.2x",
570	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
571
572	/* we did not send any filter_multi_addr_set message */
573	return 2;
574}
575
576void
577bnep_send_control(channel_t *chan, unsigned type, ...)
578{
579	packet_t *pkt;
580	uint8_t *p;
581	va_list ap;
582
583	assert(chan->state != CHANNEL_CLOSED);
584
585	pkt = packet_alloc(chan);
586	if (pkt == NULL)
587		return;
588
589	p = pkt->ptr;
590	va_start(ap, type);
591
592	*p++ = BNEP_CONTROL;
593	*p++ = (uint8_t)type;
594
595	switch(type) {
596	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
597		*p++ = va_arg(ap, int);
598		break;
599
600	case BNEP_SETUP_CONNECTION_REQUEST:
601		*p++ = va_arg(ap, int);
602		be16enc(p, va_arg(ap, int));
603		p += 2;
604		be16enc(p, va_arg(ap, int));
605		p += 2;
606		break;
607
608	case BNEP_SETUP_CONNECTION_RESPONSE:
609	case BNEP_FILTER_NET_TYPE_RESPONSE:
610	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
611		be16enc(p, va_arg(ap, int));
612		p += 2;
613		break;
614
615	case BNEP_FILTER_NET_TYPE_SET:		/* TODO */
616	case BNEP_FILTER_MULTI_ADDR_SET:	/* TODO */
617	default:
618		log_err("Can't send control type 0x%2.2x", type);
619		break;
620	}
621
622	va_end(ap);
623	pkt->len = p - pkt->ptr;
624
625	channel_put(chan, pkt);
626	packet_free(pkt);
627}
628
629/*
630 * BNEP send packet routine
631 * return true if packet can be removed from queue
632 */
633bool
634bnep_send(channel_t *chan, packet_t *pkt)
635{
636	struct iovec iov[2];
637	uint8_t *p, *type, *proto;
638	exthdr_t *eh;
639	bool src, dst;
640	size_t nw;
641
642	if (pkt->type == NULL) {
643		iov[0].iov_base = pkt->ptr;
644		iov[0].iov_len = pkt->len;
645		iov[1].iov_base = NULL;
646		iov[1].iov_len = 0;
647	} else {
648		p = chan->sendbuf;
649
650		dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
651		src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
652
653		type = p;
654		p += 1;
655
656		if (dst && src)
657			*type = BNEP_GENERAL_ETHERNET;
658		else if (dst && !src)
659			*type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
660		else if (!dst && src)
661			*type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
662		else /* (!dst && !src) */
663			*type = BNEP_COMPRESSED_ETHERNET;
664
665		if (dst) {
666			memcpy(p, pkt->dst, ETHER_ADDR_LEN);
667			p += ETHER_ADDR_LEN;
668		}
669
670		if (src) {
671			memcpy(p, pkt->src, ETHER_ADDR_LEN);
672			p += ETHER_ADDR_LEN;
673		}
674
675		proto = p;
676		memcpy(p, pkt->type, ETHER_TYPE_LEN);
677		p += ETHER_TYPE_LEN;
678
679		STAILQ_FOREACH(eh, &pkt->extlist, next) {
680			if (p + eh->len > chan->sendbuf + chan->mtu)
681				break;
682
683			*type |= BNEP_EXT;
684			type = p;
685
686			memcpy(p, eh->ptr, eh->len);
687			p += eh->len;
688		}
689
690		*type &= ~BNEP_EXT;
691
692		iov[0].iov_base = chan->sendbuf;
693		iov[0].iov_len = (p - chan->sendbuf);
694
695		if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
696		    && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
697			iov[1].iov_base = pkt->ptr;
698			iov[1].iov_len = pkt->len;
699		} else if (be16dec(proto) == ETHERTYPE_VLAN
700		    && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
701			iov[1].iov_base = pkt->ptr;
702			iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
703		} else {
704			iov[1].iov_base = NULL;
705			iov[1].iov_len = 0;
706			memset(proto, 0, ETHER_TYPE_LEN);
707		}
708	}
709
710	if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
711		log_err("packet exceeded MTU (dropped)");
712		return false;
713	}
714
715	nw = writev(chan->fd, iov, __arraycount(iov));
716	return (nw > 0);
717}
718
719static bool
720bnep_pfilter(channel_t *chan, packet_t *pkt)
721{
722	int proto, i;
723
724	proto = be16dec(pkt->type);
725	if (proto == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
726		if (pkt->len < 4)
727			return false;
728
729		proto = be16dec(pkt->ptr + 2);
730	}
731
732	for (i = 0; i < chan->npfilter; i++) {
733		if (chan->pfilter[i].start <= proto
734		    && chan->pfilter[i].end >=proto)
735			return true;
736	}
737
738	return false;
739}
740
741static bool
742bnep_mfilter(channel_t *chan, packet_t *pkt)
743{
744	int i;
745
746	if (!ETHER_IS_MULTICAST(pkt->dst))
747		return true;
748
749	for (i = 0; i < chan->nmfilter; i++) {
750		if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
751		    && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
752			return true;
753	}
754
755	return false;
756}
757