Home | History | Annotate | Line # | Download | only in btpand
bnep.c revision 1.8.2.1
      1  1.8.2.1  bouyer /*	$NetBSD: bnep.c,v 1.8.2.1 2011/02/08 16:20:13 bouyer Exp $	*/
      2      1.1  plunky 
      3      1.1  plunky /*-
      4      1.1  plunky  * Copyright (c) 2008 Iain Hibbert
      5      1.1  plunky  * All rights reserved.
      6      1.1  plunky  *
      7      1.1  plunky  * Redistribution and use in source and binary forms, with or without
      8      1.1  plunky  * modification, are permitted provided that the following conditions
      9      1.1  plunky  * are met:
     10      1.1  plunky  * 1. Redistributions of source code must retain the above copyright
     11      1.1  plunky  *    notice, this list of conditions and the following disclaimer.
     12      1.1  plunky  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1  plunky  *    notice, this list of conditions and the following disclaimer in the
     14      1.1  plunky  *    documentation and/or other materials provided with the distribution.
     15      1.1  plunky  *
     16      1.1  plunky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17      1.1  plunky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18      1.1  plunky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19      1.1  plunky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20      1.1  plunky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21      1.1  plunky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22      1.1  plunky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23      1.1  plunky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24      1.1  plunky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25      1.1  plunky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26      1.1  plunky  */
     27      1.1  plunky 
     28      1.1  plunky #include <sys/cdefs.h>
     29  1.8.2.1  bouyer __RCSID("$NetBSD: bnep.c,v 1.8.2.1 2011/02/08 16:20:13 bouyer Exp $");
     30      1.1  plunky 
     31      1.1  plunky #include <bluetooth.h>
     32      1.1  plunky #include <sdp.h>
     33      1.1  plunky #include <stdarg.h>
     34      1.1  plunky #include <string.h>
     35      1.1  plunky 
     36      1.1  plunky #include "btpand.h"
     37      1.1  plunky #include "bnep.h"
     38      1.1  plunky 
     39      1.1  plunky static bool bnep_recv_extension(packet_t *);
     40      1.1  plunky static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
     41      1.1  plunky static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
     42      1.1  plunky static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
     43      1.1  plunky static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
     44      1.1  plunky static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
     45      1.1  plunky static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
     46      1.1  plunky static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
     47      1.1  plunky static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
     48      1.1  plunky 
     49      1.1  plunky static bool bnep_pfilter(channel_t *, packet_t *);
     50      1.1  plunky static bool bnep_mfilter(channel_t *, packet_t *);
     51      1.1  plunky 
     52      1.1  plunky static uint8_t NAP_UUID[] = {
     53      1.1  plunky 	0x00, 0x00, 0x11, 0x16,
     54      1.1  plunky 	0x00, 0x00,
     55      1.1  plunky 	0x10, 0x00,
     56      1.1  plunky 	0x80, 0x00,
     57      1.1  plunky 	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
     58      1.1  plunky };
     59      1.1  plunky 
     60      1.1  plunky static uint8_t GN_UUID[] = {
     61      1.1  plunky 	0x00, 0x00, 0x11, 0x17,
     62      1.1  plunky 	0x00, 0x00,
     63      1.1  plunky 	0x10, 0x00,
     64      1.1  plunky 	0x80, 0x00,
     65      1.1  plunky 	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
     66      1.1  plunky };
     67      1.1  plunky 
     68      1.1  plunky static uint8_t PANU_UUID[] = {
     69      1.1  plunky 	0x00, 0x00, 0x11, 0x15,
     70      1.1  plunky 	0x00, 0x00,
     71      1.1  plunky 	0x10, 0x00,
     72      1.1  plunky 	0x80, 0x00,
     73      1.1  plunky 	0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
     74      1.1  plunky };
     75      1.1  plunky 
     76      1.1  plunky /*
     77      1.1  plunky  * receive BNEP packet
     78      1.1  plunky  * return true if packet is to be forwarded
     79      1.1  plunky  */
     80      1.1  plunky bool
     81      1.1  plunky bnep_recv(packet_t *pkt)
     82      1.1  plunky {
     83      1.1  plunky 	size_t len;
     84      1.1  plunky 	uint8_t type;
     85      1.1  plunky 
     86      1.1  plunky 	if (pkt->len < 1)
     87      1.1  plunky 		return false;
     88      1.1  plunky 
     89      1.1  plunky 	type = pkt->ptr[0];
     90      1.1  plunky 	packet_adj(pkt, 1);
     91      1.1  plunky 
     92      1.1  plunky 	switch (BNEP_TYPE(type)) {
     93      1.1  plunky 	case BNEP_GENERAL_ETHERNET:
     94      1.1  plunky 		if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
     95      1.1  plunky 			log_debug("dropped short packet (type 0x%2.2x)", type);
     96      1.1  plunky 			return false;
     97      1.1  plunky 		}
     98      1.1  plunky 
     99      1.1  plunky 		pkt->dst = pkt->ptr;
    100      1.1  plunky 		packet_adj(pkt, ETHER_ADDR_LEN);
    101      1.1  plunky 		pkt->src = pkt->ptr;
    102      1.1  plunky 		packet_adj(pkt, ETHER_ADDR_LEN);
    103      1.1  plunky 		pkt->type = pkt->ptr;
    104      1.1  plunky 		packet_adj(pkt, ETHER_TYPE_LEN);
    105      1.1  plunky 		break;
    106      1.1  plunky 
    107      1.1  plunky 	case BNEP_CONTROL:
    108      1.1  plunky 		len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
    109      1.1  plunky 		if (len == 0)
    110      1.1  plunky 			return false;
    111      1.1  plunky 
    112      1.1  plunky 		packet_adj(pkt, len);
    113      1.1  plunky 		break;
    114      1.1  plunky 
    115      1.1  plunky 	case BNEP_COMPRESSED_ETHERNET:
    116      1.1  plunky 		if (pkt->len < ETHER_TYPE_LEN) {
    117      1.1  plunky 			log_debug("dropped short packet (type 0x%2.2x)", type);
    118      1.1  plunky 			return false;
    119      1.1  plunky 		}
    120      1.1  plunky 
    121      1.1  plunky 		pkt->dst = pkt->chan->laddr;
    122      1.1  plunky 		pkt->src = pkt->chan->raddr;
    123      1.1  plunky 		pkt->type = pkt->ptr;
    124      1.1  plunky 		packet_adj(pkt, ETHER_TYPE_LEN);
    125      1.1  plunky 		break;
    126      1.1  plunky 
    127      1.1  plunky 	case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
    128      1.1  plunky 		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
    129      1.1  plunky 			log_debug("dropped short packet (type 0x%2.2x)", type);
    130      1.1  plunky 			return false;
    131      1.1  plunky 		}
    132      1.1  plunky 
    133      1.1  plunky 		pkt->dst = pkt->chan->laddr;
    134      1.1  plunky 		pkt->src = pkt->ptr;
    135      1.1  plunky 		packet_adj(pkt, ETHER_ADDR_LEN);
    136      1.1  plunky 		pkt->type = pkt->ptr;
    137      1.1  plunky 		packet_adj(pkt, ETHER_TYPE_LEN);
    138      1.1  plunky 		break;
    139      1.1  plunky 
    140      1.1  plunky 	case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
    141      1.1  plunky 		if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
    142      1.1  plunky 			log_debug("dropped short packet (type 0x%2.2x)", type);
    143      1.1  plunky 			return false;
    144      1.1  plunky 		}
    145      1.1  plunky 
    146      1.1  plunky 		pkt->dst = pkt->ptr;
    147      1.1  plunky 		packet_adj(pkt, ETHER_ADDR_LEN);
    148      1.1  plunky 		pkt->src = pkt->chan->raddr;
    149      1.1  plunky 		pkt->type = pkt->ptr;
    150      1.1  plunky 		packet_adj(pkt, ETHER_TYPE_LEN);
    151      1.1  plunky 		break;
    152      1.1  plunky 
    153      1.1  plunky 	default:
    154      1.1  plunky 		/*
    155      1.1  plunky 		 * Any packet containing a reserved BNEP
    156      1.1  plunky 		 * header packet type SHALL be dropped.
    157      1.1  plunky 		 */
    158      1.1  plunky 
    159      1.1  plunky 		log_debug("dropped packet with reserved type 0x%2.2x", type);
    160      1.1  plunky 		return false;
    161      1.1  plunky 	}
    162      1.1  plunky 
    163      1.1  plunky 	if (BNEP_TYPE_EXT(type)
    164      1.1  plunky 	    && !bnep_recv_extension(pkt))
    165      1.1  plunky 		return false;	/* invalid extensions */
    166      1.1  plunky 
    167      1.1  plunky 	if (BNEP_TYPE(type) == BNEP_CONTROL
    168      1.1  plunky 	    || pkt->chan->state != CHANNEL_OPEN)
    169      1.1  plunky 		return false;	/* no forwarding */
    170      1.1  plunky 
    171      1.5  plunky 	if (pkt->len > ETHER_MAX_LEN)
    172      1.5  plunky 		log_debug("received long packet "
    173      1.6  kefren 			  "(type=0x%2.2x, proto=0x%4.4x, len=%zu)",
    174      1.5  plunky 		    	  type, be16dec(pkt->type), pkt->len);
    175      1.5  plunky 
    176      1.1  plunky 	return true;
    177      1.1  plunky }
    178      1.1  plunky 
    179      1.1  plunky static bool
    180      1.1  plunky bnep_recv_extension(packet_t *pkt)
    181      1.1  plunky {
    182      1.1  plunky 	exthdr_t *eh;
    183      1.3  plunky 	size_t len, size;
    184      1.3  plunky 	uint8_t type;
    185      1.1  plunky 
    186      1.1  plunky 	do {
    187      1.1  plunky 		if (pkt->len < 2)
    188      1.1  plunky 			return false;
    189      1.1  plunky 
    190      1.1  plunky 		type = pkt->ptr[0];
    191      1.1  plunky 		size = pkt->ptr[1];
    192      1.1  plunky 
    193      1.1  plunky 		if (pkt->len < size + 2)
    194      1.1  plunky 			return false;
    195      1.1  plunky 
    196      1.1  plunky 		switch (type) {
    197      1.1  plunky 		case BNEP_EXTENSION_CONTROL:
    198      1.1  plunky 			len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
    199      1.1  plunky 			if (len != size)
    200      1.1  plunky 				log_err("ignored spurious data in exthdr");
    201      1.1  plunky 
    202      1.1  plunky 			break;
    203      1.1  plunky 
    204      1.1  plunky 		default:
    205      1.1  plunky 			/* Unknown extension headers in data packets	 */
    206      1.1  plunky 			/* SHALL be forwarded irrespective of any	 */
    207      1.1  plunky 			/* network protocol or multicast filter settings */
    208      1.1  plunky 			/* and any local filtering policy.		 */
    209      1.1  plunky 
    210      1.1  plunky 			eh = malloc(sizeof(exthdr_t));
    211      1.1  plunky 			if (eh == NULL) {
    212      1.1  plunky 				log_err("exthdr malloc() failed: %m");
    213      1.1  plunky 				break;
    214      1.1  plunky 			}
    215      1.1  plunky 
    216      1.1  plunky 			eh->ptr = pkt->ptr;
    217      1.1  plunky 			eh->len = size;
    218      1.1  plunky 			STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
    219      1.1  plunky 			break;
    220      1.1  plunky 		}
    221      1.1  plunky 
    222      1.1  plunky 		packet_adj(pkt, size + 2);
    223      1.1  plunky 	} while (BNEP_TYPE_EXT(type));
    224      1.1  plunky 
    225      1.1  plunky 	return true;
    226      1.1  plunky }
    227      1.1  plunky 
    228      1.1  plunky static size_t
    229      1.1  plunky bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
    230      1.1  plunky {
    231      1.1  plunky 	uint8_t type;
    232      1.1  plunky 	size_t len;
    233      1.1  plunky 
    234      1.1  plunky 	if (size-- < 1)
    235      1.1  plunky 		return 0;
    236      1.1  plunky 
    237      1.1  plunky 	type = *ptr++;
    238      1.1  plunky 
    239      1.1  plunky 	switch (type) {
    240      1.1  plunky 	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
    241      1.1  plunky 		len = bnep_recv_control_command_not_understood(chan, ptr, size);
    242      1.1  plunky 		break;
    243      1.1  plunky 
    244      1.1  plunky 	case BNEP_SETUP_CONNECTION_REQUEST:
    245      1.1  plunky 		if (isext)
    246      1.1  plunky 			return 0;	/* not allowed in extension headers */
    247      1.1  plunky 
    248      1.1  plunky 		len = bnep_recv_setup_connection_req(chan, ptr, size);
    249      1.1  plunky 		break;
    250      1.1  plunky 
    251      1.1  plunky 	case BNEP_SETUP_CONNECTION_RESPONSE:
    252      1.1  plunky 		if (isext)
    253      1.1  plunky 			return 0;	/* not allowed in extension headers */
    254      1.1  plunky 
    255      1.1  plunky 		len = bnep_recv_setup_connection_rsp(chan, ptr, size);
    256      1.1  plunky 		break;
    257      1.1  plunky 
    258      1.1  plunky 	case BNEP_FILTER_NET_TYPE_SET:
    259      1.1  plunky 		len = bnep_recv_filter_net_type_set(chan, ptr, size);
    260      1.1  plunky 		break;
    261      1.1  plunky 
    262      1.1  plunky 	case BNEP_FILTER_NET_TYPE_RESPONSE:
    263      1.1  plunky 		len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
    264      1.1  plunky 		break;
    265      1.1  plunky 
    266      1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_SET:
    267      1.1  plunky 		len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
    268      1.1  plunky 		break;
    269      1.1  plunky 
    270      1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
    271      1.1  plunky 		len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
    272      1.1  plunky 		break;
    273      1.1  plunky 
    274      1.1  plunky 	default:
    275      1.1  plunky 		len = 0;
    276      1.1  plunky 		break;
    277      1.1  plunky 	}
    278      1.1  plunky 
    279      1.1  plunky 	if (len == 0)
    280      1.1  plunky 		bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
    281      1.1  plunky 
    282      1.1  plunky 	return len;
    283      1.1  plunky }
    284      1.1  plunky 
    285      1.1  plunky static size_t
    286      1.1  plunky bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
    287      1.1  plunky {
    288      1.1  plunky 	uint8_t type;
    289      1.1  plunky 
    290      1.1  plunky 	if (size < 1)
    291      1.1  plunky 		return 0;
    292      1.1  plunky 
    293      1.1  plunky 	type = *ptr++;
    294      1.1  plunky 	log_err("received Control Command Not Understood (0x%2.2x)", type);
    295      1.1  plunky 
    296      1.8  plunky 	/* we didn't send any reserved commands, just shut them down */
    297      1.8  plunky 	chan->down(chan);
    298      1.1  plunky 
    299      1.1  plunky 	return 1;
    300      1.1  plunky }
    301      1.1  plunky 
    302      1.1  plunky static size_t
    303      1.1  plunky bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
    304      1.1  plunky {
    305      1.3  plunky 	size_t len;
    306      1.3  plunky 	uint8_t off;
    307      1.1  plunky 	int src, dst, rsp;
    308      1.1  plunky 
    309      1.1  plunky 	if (size < 1)
    310      1.1  plunky 		return 0;
    311      1.1  plunky 
    312      1.1  plunky 	len = *ptr++;
    313      1.1  plunky 	if (size < (len * 2 + 1))
    314      1.1  plunky 		return 0;
    315      1.1  plunky 
    316      1.1  plunky 	if (chan->state != CHANNEL_WAIT_CONNECT_REQ
    317      1.1  plunky 	    && chan->state != CHANNEL_OPEN) {
    318      1.1  plunky 		log_debug("ignored");
    319      1.1  plunky 		return (len * 2 + 1);
    320      1.1  plunky 	}
    321      1.1  plunky 
    322      1.1  plunky 	if (len == 2)
    323      1.1  plunky 		off = 2;
    324      1.1  plunky 	else if (len == 4)
    325      1.1  plunky 		off = 0;
    326      1.1  plunky 	else if (len == 16)
    327      1.1  plunky 		off = 0;
    328      1.1  plunky 	else {
    329      1.1  plunky 		rsp = BNEP_SETUP_INVALID_UUID_SIZE;
    330      1.1  plunky 		goto done;
    331      1.1  plunky 	}
    332      1.1  plunky 
    333      1.1  plunky 	if (memcmp(ptr, NAP_UUID + off, len) == 0)
    334      1.1  plunky 		dst = SDP_SERVICE_CLASS_NAP;
    335      1.1  plunky 	else if (memcmp(ptr, GN_UUID + off, len) == 0)
    336      1.1  plunky 		dst = SDP_SERVICE_CLASS_GN;
    337      1.1  plunky 	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
    338      1.1  plunky 		dst = SDP_SERVICE_CLASS_PANU;
    339      1.1  plunky 	else
    340      1.1  plunky 		dst = 0;
    341      1.1  plunky 
    342      1.1  plunky 	if (dst != service_class) {
    343      1.1  plunky 		rsp = BNEP_SETUP_INVALID_DST_UUID;
    344      1.1  plunky 		goto done;
    345      1.1  plunky 	}
    346      1.1  plunky 
    347      1.1  plunky 	ptr += len;
    348      1.1  plunky 
    349      1.2  plunky 	if (memcmp(ptr, NAP_UUID + off, len) == 0)
    350      1.1  plunky 		src = SDP_SERVICE_CLASS_NAP;
    351      1.1  plunky 	else if (memcmp(ptr, GN_UUID + off, len) == 0)
    352      1.1  plunky 		src = SDP_SERVICE_CLASS_GN;
    353      1.2  plunky 	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
    354      1.1  plunky 		src = SDP_SERVICE_CLASS_PANU;
    355      1.1  plunky 	else
    356      1.1  plunky 		src = 0;
    357      1.1  plunky 
    358      1.1  plunky 	if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
    359      1.1  plunky 	    || src == 0) {
    360      1.1  plunky 		rsp = BNEP_SETUP_INVALID_SRC_UUID;
    361      1.1  plunky 		goto done;
    362      1.1  plunky 	}
    363      1.1  plunky 
    364      1.1  plunky 	rsp = BNEP_SETUP_SUCCESS;
    365      1.1  plunky 	chan->state = CHANNEL_OPEN;
    366      1.1  plunky 	channel_timeout(chan, 0);
    367      1.1  plunky 
    368      1.1  plunky done:
    369      1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    370      1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    371      1.1  plunky 
    372      1.1  plunky 	bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
    373  1.8.2.1  bouyer 	if (rsp == BNEP_SETUP_SUCCESS) {
    374  1.8.2.1  bouyer 		bnep_send_control(chan, BNEP_FILTER_NET_TYPE_SET);
    375  1.8.2.1  bouyer 		bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_SET);
    376  1.8.2.1  bouyer 	}
    377      1.1  plunky 	return (len * 2 + 1);
    378      1.1  plunky }
    379      1.1  plunky 
    380      1.1  plunky static size_t
    381      1.1  plunky bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    382      1.1  plunky {
    383      1.1  plunky 	int rsp;
    384      1.1  plunky 
    385      1.1  plunky 	if (size < 2)
    386      1.1  plunky 		return 0;
    387      1.1  plunky 
    388      1.1  plunky 	rsp = be16dec(ptr);
    389      1.1  plunky 
    390      1.1  plunky 	if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
    391      1.1  plunky 		log_debug("ignored");
    392      1.1  plunky 		return 2;
    393      1.1  plunky 	}
    394      1.1  plunky 
    395      1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    396      1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    397      1.1  plunky 
    398      1.1  plunky 	if (rsp == BNEP_SETUP_SUCCESS) {
    399      1.1  plunky 		chan->state = CHANNEL_OPEN;
    400      1.1  plunky 		channel_timeout(chan, 0);
    401  1.8.2.1  bouyer 		bnep_send_control(chan, BNEP_FILTER_NET_TYPE_SET);
    402  1.8.2.1  bouyer 		bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_SET);
    403      1.1  plunky 	} else {
    404      1.8  plunky 		chan->down(chan);
    405      1.1  plunky 	}
    406      1.1  plunky 
    407      1.1  plunky 	return 2;
    408      1.1  plunky }
    409      1.1  plunky 
    410      1.1  plunky static size_t
    411      1.1  plunky bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
    412      1.1  plunky {
    413      1.1  plunky 	pfilter_t *pf;
    414      1.3  plunky 	int i, nf, rsp;
    415      1.3  plunky 	size_t len;
    416      1.1  plunky 
    417      1.1  plunky 	if (size < 2)
    418      1.1  plunky 		return 0;
    419      1.1  plunky 
    420      1.1  plunky 	len = be16dec(ptr);
    421      1.1  plunky 	ptr += 2;
    422      1.1  plunky 
    423      1.1  plunky 	if (size < (len + 2))
    424      1.1  plunky 		return 0;
    425      1.1  plunky 
    426      1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    427      1.1  plunky 		log_debug("ignored");
    428      1.1  plunky 		return (len + 2);
    429      1.1  plunky 	}
    430      1.1  plunky 
    431      1.1  plunky 	nf = len / 4;
    432      1.1  plunky 	pf = malloc(nf * sizeof(pfilter_t));
    433      1.1  plunky 	if (pf == NULL) {
    434      1.1  plunky 		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
    435      1.1  plunky 		goto done;
    436      1.1  plunky 	}
    437      1.1  plunky 
    438      1.1  plunky 	log_debug("nf = %d", nf);
    439      1.1  plunky 
    440      1.1  plunky 	for (i = 0; i < nf; i++) {
    441      1.1  plunky 		pf[i].start = be16dec(ptr);
    442      1.1  plunky 		ptr += 2;
    443      1.1  plunky 		pf[i].end = be16dec(ptr);
    444      1.1  plunky 		ptr += 2;
    445      1.1  plunky 
    446      1.1  plunky 		if (pf[i].start > pf[i].end) {
    447      1.1  plunky 			free(pf);
    448      1.1  plunky 			rsp = BNEP_FILTER_INVALID_RANGE;
    449      1.1  plunky 			goto done;
    450      1.1  plunky 		}
    451      1.1  plunky 
    452      1.1  plunky 		log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
    453      1.1  plunky 	}
    454      1.1  plunky 
    455      1.1  plunky 	if (chan->pfilter)
    456      1.1  plunky 		free(chan->pfilter);
    457      1.1  plunky 
    458      1.1  plunky 	chan->pfilter = pf;
    459      1.1  plunky 	chan->npfilter = nf;
    460      1.1  plunky 
    461      1.1  plunky 	rsp = BNEP_FILTER_SUCCESS;
    462      1.1  plunky 
    463      1.1  plunky done:
    464      1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    465      1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    466      1.1  plunky 
    467      1.1  plunky 	bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
    468      1.1  plunky 	return (len + 2);
    469      1.1  plunky }
    470      1.1  plunky 
    471      1.1  plunky static size_t
    472      1.1  plunky bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    473      1.1  plunky {
    474      1.1  plunky 	int rsp;
    475      1.1  plunky 
    476      1.1  plunky 	if (size < 2)
    477      1.1  plunky 		return 0;
    478      1.1  plunky 
    479      1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    480      1.1  plunky 		log_debug("ignored");
    481      1.1  plunky 		return 2;
    482      1.1  plunky 	}
    483      1.1  plunky 
    484      1.1  plunky 	rsp = be16dec(ptr);
    485      1.7  plunky 	if (rsp != BNEP_FILTER_SUCCESS)
    486      1.7  plunky 		log_err("filter_net_type: addr %s response 0x%2.2x",
    487      1.7  plunky 		    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    488      1.1  plunky 
    489      1.1  plunky 	return 2;
    490      1.1  plunky }
    491      1.1  plunky 
    492      1.1  plunky static size_t
    493      1.1  plunky bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
    494      1.1  plunky {
    495      1.1  plunky 	mfilter_t *mf;
    496      1.3  plunky 	int i, nf, rsp;
    497      1.3  plunky 	size_t len;
    498      1.1  plunky 
    499      1.1  plunky 	if (size < 2)
    500      1.1  plunky 		return 0;
    501      1.1  plunky 
    502      1.1  plunky 	len = be16dec(ptr);
    503      1.1  plunky 	ptr += 2;
    504      1.1  plunky 
    505      1.1  plunky 	if (size < (len + 2))
    506      1.1  plunky 		return 0;
    507      1.1  plunky 
    508      1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    509      1.1  plunky 		log_debug("ignored");
    510      1.1  plunky 		return (len + 2);
    511      1.1  plunky 	}
    512      1.1  plunky 
    513      1.1  plunky 	nf = len / (ETHER_ADDR_LEN * 2);
    514      1.1  plunky 	mf = malloc(nf * sizeof(mfilter_t));
    515      1.1  plunky 	if (mf == NULL) {
    516      1.1  plunky 		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
    517      1.1  plunky 		goto done;
    518      1.1  plunky 	}
    519      1.1  plunky 
    520      1.1  plunky 	log_debug("nf = %d", nf);
    521      1.1  plunky 
    522      1.1  plunky 	for (i = 0; i < nf; i++) {
    523      1.1  plunky 		memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
    524      1.1  plunky 		ptr += ETHER_ADDR_LEN;
    525      1.1  plunky 
    526      1.1  plunky 		memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
    527      1.1  plunky 		ptr += ETHER_ADDR_LEN;
    528      1.1  plunky 
    529      1.1  plunky 		if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
    530      1.1  plunky 			free(mf);
    531      1.1  plunky 			rsp = BNEP_FILTER_INVALID_RANGE;
    532      1.1  plunky 			goto done;
    533      1.1  plunky 		}
    534      1.1  plunky 
    535      1.1  plunky 		log_debug("pf[%d] = "
    536      1.1  plunky 		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
    537      1.1  plunky 		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
    538      1.1  plunky 		    mf[i].start[0], mf[i].start[1], mf[i].start[2],
    539      1.1  plunky 		    mf[i].start[3], mf[i].start[4], mf[i].start[5],
    540      1.1  plunky 		    mf[i].end[0], mf[i].end[1], mf[i].end[2],
    541      1.1  plunky 		    mf[i].end[3], mf[i].end[4], mf[i].end[5]);
    542      1.1  plunky 	}
    543      1.1  plunky 
    544      1.1  plunky 	if (chan->mfilter)
    545      1.1  plunky 		free(chan->mfilter);
    546      1.1  plunky 
    547      1.1  plunky 	chan->mfilter = mf;
    548      1.1  plunky 	chan->nmfilter = nf;
    549      1.1  plunky 
    550      1.1  plunky 	rsp = BNEP_FILTER_SUCCESS;
    551      1.1  plunky 
    552      1.1  plunky done:
    553      1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    554      1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    555      1.1  plunky 
    556      1.1  plunky 	bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
    557      1.1  plunky 	return (len + 2);
    558      1.1  plunky }
    559      1.1  plunky 
    560      1.1  plunky static size_t
    561      1.1  plunky bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    562      1.1  plunky {
    563      1.1  plunky 	int rsp;
    564      1.1  plunky 
    565      1.1  plunky 	if (size < 2)
    566      1.1  plunky 		return false;
    567      1.1  plunky 
    568      1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    569      1.1  plunky 		log_debug("ignored");
    570      1.1  plunky 		return 2;
    571      1.1  plunky 	}
    572      1.1  plunky 
    573      1.1  plunky 	rsp = be16dec(ptr);
    574      1.7  plunky 	if (rsp != BNEP_FILTER_SUCCESS)
    575      1.7  plunky 		log_err("filter_multi_addr: addr %s response 0x%2.2x",
    576      1.7  plunky 		    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    577      1.1  plunky 
    578      1.1  plunky 	return 2;
    579      1.1  plunky }
    580      1.1  plunky 
    581      1.1  plunky void
    582      1.1  plunky bnep_send_control(channel_t *chan, uint8_t type, ...)
    583      1.1  plunky {
    584      1.1  plunky 	packet_t *pkt;
    585      1.1  plunky 	uint8_t *p;
    586      1.1  plunky 	va_list ap;
    587      1.1  plunky 
    588      1.4  plunky 	assert(chan->state != CHANNEL_CLOSED);
    589      1.1  plunky 
    590      1.1  plunky 	pkt = packet_alloc(chan);
    591      1.1  plunky 	if (pkt == NULL)
    592      1.1  plunky 		return;
    593      1.1  plunky 
    594      1.1  plunky 	p = pkt->ptr;
    595      1.1  plunky 	va_start(ap, type);
    596      1.1  plunky 
    597      1.1  plunky 	*p++ = BNEP_CONTROL;
    598      1.1  plunky 	*p++ = type;
    599      1.1  plunky 
    600      1.1  plunky 	switch(type) {
    601      1.1  plunky 	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
    602      1.1  plunky 		*p++ = va_arg(ap, int);
    603      1.1  plunky 		break;
    604      1.1  plunky 
    605      1.1  plunky 	case BNEP_SETUP_CONNECTION_REQUEST:
    606      1.1  plunky 		*p++ = va_arg(ap, int);
    607      1.1  plunky 		be16enc(p, va_arg(ap, int));
    608      1.1  plunky 		p += 2;
    609      1.1  plunky 		be16enc(p, va_arg(ap, int));
    610      1.1  plunky 		p += 2;
    611      1.1  plunky 		break;
    612      1.1  plunky 
    613      1.1  plunky 	case BNEP_SETUP_CONNECTION_RESPONSE:
    614      1.1  plunky 	case BNEP_FILTER_NET_TYPE_RESPONSE:
    615      1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
    616      1.1  plunky 		be16enc(p, va_arg(ap, int));
    617      1.1  plunky 		p += 2;
    618      1.1  plunky 		break;
    619      1.1  plunky 
    620  1.8.2.1  bouyer 	case BNEP_FILTER_NET_TYPE_SET:
    621  1.8.2.1  bouyer 	case BNEP_FILTER_MULTI_ADDR_SET:
    622  1.8.2.1  bouyer 		be16enc(p, 0);	/* just clear filters for now */
    623  1.8.2.1  bouyer 		p += 2;
    624  1.8.2.1  bouyer 		break;
    625  1.8.2.1  bouyer 
    626      1.1  plunky 	default:
    627      1.1  plunky 		log_err("Can't send control type 0x%2.2x", type);
    628      1.1  plunky 		break;
    629      1.1  plunky 	}
    630      1.1  plunky 
    631      1.1  plunky 	va_end(ap);
    632      1.1  plunky 	pkt->len = p - pkt->ptr;
    633      1.1  plunky 
    634      1.1  plunky 	channel_put(chan, pkt);
    635      1.1  plunky 	packet_free(pkt);
    636      1.1  plunky }
    637      1.1  plunky 
    638      1.1  plunky /*
    639      1.1  plunky  * BNEP send packet routine
    640      1.1  plunky  * return true if packet can be removed from queue
    641      1.1  plunky  */
    642      1.1  plunky bool
    643      1.1  plunky bnep_send(channel_t *chan, packet_t *pkt)
    644      1.1  plunky {
    645      1.1  plunky 	struct iovec iov[2];
    646      1.1  plunky 	uint8_t *p, *type, *proto;
    647      1.1  plunky 	exthdr_t *eh;
    648      1.1  plunky 	bool src, dst;
    649      1.1  plunky 	size_t nw;
    650      1.1  plunky 
    651      1.1  plunky 	if (pkt->type == NULL) {
    652      1.1  plunky 		iov[0].iov_base = pkt->ptr;
    653      1.1  plunky 		iov[0].iov_len = pkt->len;
    654      1.1  plunky 		iov[1].iov_base = NULL;
    655      1.1  plunky 		iov[1].iov_len = 0;
    656      1.1  plunky 	} else {
    657      1.1  plunky 		p = chan->sendbuf;
    658      1.1  plunky 
    659      1.1  plunky 		dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
    660      1.1  plunky 		src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
    661      1.1  plunky 
    662      1.1  plunky 		type = p;
    663      1.1  plunky 		p += 1;
    664      1.1  plunky 
    665      1.1  plunky 		if (dst && src)
    666      1.1  plunky 			*type = BNEP_GENERAL_ETHERNET;
    667      1.1  plunky 		else if (dst && !src)
    668      1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
    669      1.1  plunky 		else if (!dst && src)
    670      1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
    671      1.1  plunky 		else /* (!dst && !src) */
    672      1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET;
    673      1.1  plunky 
    674      1.1  plunky 		if (dst) {
    675      1.1  plunky 			memcpy(p, pkt->dst, ETHER_ADDR_LEN);
    676      1.1  plunky 			p += ETHER_ADDR_LEN;
    677      1.1  plunky 		}
    678      1.1  plunky 
    679      1.1  plunky 		if (src) {
    680      1.1  plunky 			memcpy(p, pkt->src, ETHER_ADDR_LEN);
    681      1.1  plunky 			p += ETHER_ADDR_LEN;
    682      1.1  plunky 		}
    683      1.1  plunky 
    684      1.1  plunky 		proto = p;
    685      1.1  plunky 		memcpy(p, pkt->type, ETHER_TYPE_LEN);
    686      1.1  plunky 		p += ETHER_TYPE_LEN;
    687      1.1  plunky 
    688      1.1  plunky 		STAILQ_FOREACH(eh, &pkt->extlist, next) {
    689      1.1  plunky 			if (p + eh->len > chan->sendbuf + chan->mtu)
    690      1.1  plunky 				break;
    691      1.1  plunky 
    692      1.1  plunky 			*type |= BNEP_EXT;
    693      1.1  plunky 			type = p;
    694      1.1  plunky 
    695      1.1  plunky 			memcpy(p, eh->ptr, eh->len);
    696      1.1  plunky 			p += eh->len;
    697      1.1  plunky 		}
    698      1.1  plunky 
    699      1.1  plunky 		*type &= ~BNEP_EXT;
    700      1.1  plunky 
    701      1.1  plunky 		iov[0].iov_base = chan->sendbuf;
    702      1.1  plunky 		iov[0].iov_len = (p - chan->sendbuf);
    703      1.1  plunky 
    704      1.1  plunky 		if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
    705      1.1  plunky 		    && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
    706      1.1  plunky 			iov[1].iov_base = pkt->ptr;
    707      1.1  plunky 			iov[1].iov_len = pkt->len;
    708      1.1  plunky 		} else if (be16dec(proto) == ETHERTYPE_VLAN
    709      1.1  plunky 		    && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
    710      1.1  plunky 			iov[1].iov_base = pkt->ptr;
    711      1.1  plunky 			iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
    712      1.1  plunky 		} else {
    713      1.1  plunky 			iov[1].iov_base = NULL;
    714      1.1  plunky 			iov[1].iov_len = 0;
    715      1.1  plunky 			memset(proto, 0, ETHER_TYPE_LEN);
    716      1.1  plunky 		}
    717      1.1  plunky 	}
    718      1.1  plunky 
    719      1.1  plunky 	if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
    720      1.1  plunky 		log_err("packet exceeded MTU (dropped)");
    721      1.1  plunky 		return false;
    722      1.1  plunky 	}
    723      1.1  plunky 
    724      1.1  plunky 	nw = writev(chan->fd, iov, __arraycount(iov));
    725      1.1  plunky 	return (nw > 0);
    726      1.1  plunky }
    727      1.1  plunky 
    728      1.1  plunky static bool
    729      1.1  plunky bnep_pfilter(channel_t *chan, packet_t *pkt)
    730      1.1  plunky {
    731      1.1  plunky 	int proto, i;
    732      1.1  plunky 
    733      1.1  plunky 	proto = be16dec(pkt->type);
    734      1.1  plunky 	if (proto == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
    735      1.1  plunky 		if (pkt->len < 4)
    736      1.1  plunky 			return false;
    737      1.1  plunky 
    738      1.1  plunky 		proto = be16dec(pkt->ptr + 2);
    739      1.1  plunky 	}
    740      1.1  plunky 
    741      1.1  plunky 	for (i = 0; i < chan->npfilter; i++) {
    742      1.1  plunky 		if (chan->pfilter[i].start <= proto
    743      1.1  plunky 		    && chan->pfilter[i].end >=proto)
    744      1.1  plunky 			return true;
    745      1.1  plunky 	}
    746      1.1  plunky 
    747      1.1  plunky 	return false;
    748      1.1  plunky }
    749      1.1  plunky 
    750      1.1  plunky static bool
    751      1.1  plunky bnep_mfilter(channel_t *chan, packet_t *pkt)
    752      1.1  plunky {
    753      1.1  plunky 	int i;
    754      1.1  plunky 
    755      1.1  plunky 	if (!ETHER_IS_MULTICAST(pkt->dst))
    756      1.1  plunky 		return true;
    757      1.1  plunky 
    758      1.1  plunky 	for (i = 0; i < chan->nmfilter; i++) {
    759      1.1  plunky 		if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
    760      1.1  plunky 		    && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
    761      1.1  plunky 			return true;
    762      1.1  plunky 	}
    763      1.1  plunky 
    764      1.1  plunky 	return false;
    765      1.1  plunky }
    766