Home | History | Annotate | Line # | Download | only in btpand
bnep.c revision 1.1
      1  1.1  plunky /*	$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky 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.1  plunky __RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky 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.1  plunky 	return true;
    172  1.1  plunky }
    173  1.1  plunky 
    174  1.1  plunky static bool
    175  1.1  plunky bnep_recv_extension(packet_t *pkt)
    176  1.1  plunky {
    177  1.1  plunky 	exthdr_t *eh;
    178  1.1  plunky 	size_t len;
    179  1.1  plunky 	uint8_t type, size;
    180  1.1  plunky 
    181  1.1  plunky 	do {
    182  1.1  plunky 		if (pkt->len < 2)
    183  1.1  plunky 			return false;
    184  1.1  plunky 
    185  1.1  plunky 		type = pkt->ptr[0];
    186  1.1  plunky 		size = pkt->ptr[1];
    187  1.1  plunky 
    188  1.1  plunky 		if (pkt->len < size + 2)
    189  1.1  plunky 			return false;
    190  1.1  plunky 
    191  1.1  plunky 		switch (type) {
    192  1.1  plunky 		case BNEP_EXTENSION_CONTROL:
    193  1.1  plunky 			len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
    194  1.1  plunky 			if (len != size)
    195  1.1  plunky 				log_err("ignored spurious data in exthdr");
    196  1.1  plunky 
    197  1.1  plunky 			break;
    198  1.1  plunky 
    199  1.1  plunky 		default:
    200  1.1  plunky 			/* Unknown extension headers in data packets	 */
    201  1.1  plunky 			/* SHALL be forwarded irrespective of any	 */
    202  1.1  plunky 			/* network protocol or multicast filter settings */
    203  1.1  plunky 			/* and any local filtering policy.		 */
    204  1.1  plunky 
    205  1.1  plunky 			eh = malloc(sizeof(exthdr_t));
    206  1.1  plunky 			if (eh == NULL) {
    207  1.1  plunky 				log_err("exthdr malloc() failed: %m");
    208  1.1  plunky 				break;
    209  1.1  plunky 			}
    210  1.1  plunky 
    211  1.1  plunky 			eh->ptr = pkt->ptr;
    212  1.1  plunky 			eh->len = size;
    213  1.1  plunky 			STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
    214  1.1  plunky 			break;
    215  1.1  plunky 		}
    216  1.1  plunky 
    217  1.1  plunky 		packet_adj(pkt, size + 2);
    218  1.1  plunky 	} while (BNEP_TYPE_EXT(type));
    219  1.1  plunky 
    220  1.1  plunky 	return true;
    221  1.1  plunky }
    222  1.1  plunky 
    223  1.1  plunky static size_t
    224  1.1  plunky bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
    225  1.1  plunky {
    226  1.1  plunky 	uint8_t type;
    227  1.1  plunky 	size_t len;
    228  1.1  plunky 
    229  1.1  plunky 	if (size-- < 1)
    230  1.1  plunky 		return 0;
    231  1.1  plunky 
    232  1.1  plunky 	type = *ptr++;
    233  1.1  plunky 
    234  1.1  plunky 	switch (type) {
    235  1.1  plunky 	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
    236  1.1  plunky 		len = bnep_recv_control_command_not_understood(chan, ptr, size);
    237  1.1  plunky 		break;
    238  1.1  plunky 
    239  1.1  plunky 	case BNEP_SETUP_CONNECTION_REQUEST:
    240  1.1  plunky 		if (isext)
    241  1.1  plunky 			return 0;	/* not allowed in extension headers */
    242  1.1  plunky 
    243  1.1  plunky 		len = bnep_recv_setup_connection_req(chan, ptr, size);
    244  1.1  plunky 		break;
    245  1.1  plunky 
    246  1.1  plunky 	case BNEP_SETUP_CONNECTION_RESPONSE:
    247  1.1  plunky 		if (isext)
    248  1.1  plunky 			return 0;	/* not allowed in extension headers */
    249  1.1  plunky 
    250  1.1  plunky 		len = bnep_recv_setup_connection_rsp(chan, ptr, size);
    251  1.1  plunky 		break;
    252  1.1  plunky 
    253  1.1  plunky 	case BNEP_FILTER_NET_TYPE_SET:
    254  1.1  plunky 		len = bnep_recv_filter_net_type_set(chan, ptr, size);
    255  1.1  plunky 		break;
    256  1.1  plunky 
    257  1.1  plunky 	case BNEP_FILTER_NET_TYPE_RESPONSE:
    258  1.1  plunky 		len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
    259  1.1  plunky 		break;
    260  1.1  plunky 
    261  1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_SET:
    262  1.1  plunky 		len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
    263  1.1  plunky 		break;
    264  1.1  plunky 
    265  1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
    266  1.1  plunky 		len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
    267  1.1  plunky 		break;
    268  1.1  plunky 
    269  1.1  plunky 	default:
    270  1.1  plunky 		len = 0;
    271  1.1  plunky 		break;
    272  1.1  plunky 	}
    273  1.1  plunky 
    274  1.1  plunky 	if (len == 0)
    275  1.1  plunky 		bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
    276  1.1  plunky 
    277  1.1  plunky 	return len;
    278  1.1  plunky }
    279  1.1  plunky 
    280  1.1  plunky static size_t
    281  1.1  plunky bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
    282  1.1  plunky {
    283  1.1  plunky 	uint8_t type;
    284  1.1  plunky 
    285  1.1  plunky 	if (size < 1)
    286  1.1  plunky 		return 0;
    287  1.1  plunky 
    288  1.1  plunky 	type = *ptr++;
    289  1.1  plunky 	log_err("received Control Command Not Understood (0x%2.2x)", type);
    290  1.1  plunky 
    291  1.1  plunky 	/* we didn't send any reserved commands, just cut them off */
    292  1.1  plunky 	channel_close(chan);
    293  1.1  plunky 
    294  1.1  plunky 	return 1;
    295  1.1  plunky }
    296  1.1  plunky 
    297  1.1  plunky static size_t
    298  1.1  plunky bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
    299  1.1  plunky {
    300  1.1  plunky 	uint8_t len, off;
    301  1.1  plunky 	int src, dst, rsp;
    302  1.1  plunky 
    303  1.1  plunky 	if (size < 1)
    304  1.1  plunky 		return 0;
    305  1.1  plunky 
    306  1.1  plunky 	len = *ptr++;
    307  1.1  plunky 	if (size < (len * 2 + 1))
    308  1.1  plunky 		return 0;
    309  1.1  plunky 
    310  1.1  plunky 	if (chan->state != CHANNEL_WAIT_CONNECT_REQ
    311  1.1  plunky 	    && chan->state != CHANNEL_OPEN) {
    312  1.1  plunky 		log_debug("ignored");
    313  1.1  plunky 		return (len * 2 + 1);
    314  1.1  plunky 	}
    315  1.1  plunky 
    316  1.1  plunky 	if (len == 2)
    317  1.1  plunky 		off = 2;
    318  1.1  plunky 	else if (len == 4)
    319  1.1  plunky 		off = 0;
    320  1.1  plunky 	else if (len == 16)
    321  1.1  plunky 		off = 0;
    322  1.1  plunky 	else {
    323  1.1  plunky 		rsp = BNEP_SETUP_INVALID_UUID_SIZE;
    324  1.1  plunky 		goto done;
    325  1.1  plunky 	}
    326  1.1  plunky 
    327  1.1  plunky 	if (memcmp(ptr, NAP_UUID + off, len) == 0)
    328  1.1  plunky 		dst = SDP_SERVICE_CLASS_NAP;
    329  1.1  plunky 	else if (memcmp(ptr, GN_UUID + off, len) == 0)
    330  1.1  plunky 		dst = SDP_SERVICE_CLASS_GN;
    331  1.1  plunky 	else if (memcmp(ptr, PANU_UUID + off, len) == 0)
    332  1.1  plunky 		dst = SDP_SERVICE_CLASS_PANU;
    333  1.1  plunky 	else
    334  1.1  plunky 		dst = 0;
    335  1.1  plunky 
    336  1.1  plunky 	if (dst != service_class) {
    337  1.1  plunky 		rsp = BNEP_SETUP_INVALID_DST_UUID;
    338  1.1  plunky 		goto done;
    339  1.1  plunky 	}
    340  1.1  plunky 
    341  1.1  plunky 	ptr += len;
    342  1.1  plunky 
    343  1.1  plunky 	if (memcmp(ptr, PANU_UUID + off, len) == 0)
    344  1.1  plunky 		src = SDP_SERVICE_CLASS_NAP;
    345  1.1  plunky 	else if (memcmp(ptr, GN_UUID + off, len) == 0)
    346  1.1  plunky 		src = SDP_SERVICE_CLASS_GN;
    347  1.1  plunky 	else if (memcmp(ptr, NAP_UUID + off, len) == 0)
    348  1.1  plunky 		src = SDP_SERVICE_CLASS_PANU;
    349  1.1  plunky 	else
    350  1.1  plunky 		src = 0;
    351  1.1  plunky 
    352  1.1  plunky 	if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
    353  1.1  plunky 	    || src == 0) {
    354  1.1  plunky 		rsp = BNEP_SETUP_INVALID_SRC_UUID;
    355  1.1  plunky 		goto done;
    356  1.1  plunky 	}
    357  1.1  plunky 
    358  1.1  plunky 	rsp = BNEP_SETUP_SUCCESS;
    359  1.1  plunky 	chan->state = CHANNEL_OPEN;
    360  1.1  plunky 	channel_timeout(chan, 0);
    361  1.1  plunky 
    362  1.1  plunky done:
    363  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    364  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    365  1.1  plunky 
    366  1.1  plunky 	bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
    367  1.1  plunky 	return (len * 2 + 1);
    368  1.1  plunky }
    369  1.1  plunky 
    370  1.1  plunky static size_t
    371  1.1  plunky bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    372  1.1  plunky {
    373  1.1  plunky 	int rsp;
    374  1.1  plunky 
    375  1.1  plunky 	if (size < 2)
    376  1.1  plunky 		return 0;
    377  1.1  plunky 
    378  1.1  plunky 	rsp = be16dec(ptr);
    379  1.1  plunky 
    380  1.1  plunky 	if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
    381  1.1  plunky 		log_debug("ignored");
    382  1.1  plunky 		return 2;
    383  1.1  plunky 	}
    384  1.1  plunky 
    385  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    386  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    387  1.1  plunky 
    388  1.1  plunky 	if (rsp == BNEP_SETUP_SUCCESS) {
    389  1.1  plunky 		chan->state = CHANNEL_OPEN;
    390  1.1  plunky 		channel_timeout(chan, 0);
    391  1.1  plunky 	} else {
    392  1.1  plunky 		channel_close(chan);
    393  1.1  plunky 	}
    394  1.1  plunky 
    395  1.1  plunky 	return 2;
    396  1.1  plunky }
    397  1.1  plunky 
    398  1.1  plunky static size_t
    399  1.1  plunky bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
    400  1.1  plunky {
    401  1.1  plunky 	pfilter_t *pf;
    402  1.1  plunky 	int i, len, nf, rsp;
    403  1.1  plunky 
    404  1.1  plunky 	if (size < 2)
    405  1.1  plunky 		return 0;
    406  1.1  plunky 
    407  1.1  plunky 	len = be16dec(ptr);
    408  1.1  plunky 	ptr += 2;
    409  1.1  plunky 
    410  1.1  plunky 	if (size < (len + 2))
    411  1.1  plunky 		return 0;
    412  1.1  plunky 
    413  1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    414  1.1  plunky 		log_debug("ignored");
    415  1.1  plunky 		return (len + 2);
    416  1.1  plunky 	}
    417  1.1  plunky 
    418  1.1  plunky 	nf = len / 4;
    419  1.1  plunky 	pf = malloc(nf * sizeof(pfilter_t));
    420  1.1  plunky 	if (pf == NULL) {
    421  1.1  plunky 		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
    422  1.1  plunky 		goto done;
    423  1.1  plunky 	}
    424  1.1  plunky 
    425  1.1  plunky 	log_debug("nf = %d", nf);
    426  1.1  plunky 
    427  1.1  plunky 	for (i = 0; i < nf; i++) {
    428  1.1  plunky 		pf[i].start = be16dec(ptr);
    429  1.1  plunky 		ptr += 2;
    430  1.1  plunky 		pf[i].end = be16dec(ptr);
    431  1.1  plunky 		ptr += 2;
    432  1.1  plunky 
    433  1.1  plunky 		if (pf[i].start > pf[i].end) {
    434  1.1  plunky 			free(pf);
    435  1.1  plunky 			rsp = BNEP_FILTER_INVALID_RANGE;
    436  1.1  plunky 			goto done;
    437  1.1  plunky 		}
    438  1.1  plunky 
    439  1.1  plunky 		log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
    440  1.1  plunky 	}
    441  1.1  plunky 
    442  1.1  plunky 	if (chan->pfilter)
    443  1.1  plunky 		free(chan->pfilter);
    444  1.1  plunky 
    445  1.1  plunky 	chan->pfilter = pf;
    446  1.1  plunky 	chan->npfilter = nf;
    447  1.1  plunky 
    448  1.1  plunky 	rsp = BNEP_FILTER_SUCCESS;
    449  1.1  plunky 
    450  1.1  plunky done:
    451  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    452  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    453  1.1  plunky 
    454  1.1  plunky 	bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
    455  1.1  plunky 	return (len + 2);
    456  1.1  plunky }
    457  1.1  plunky 
    458  1.1  plunky static size_t
    459  1.1  plunky bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    460  1.1  plunky {
    461  1.1  plunky 	int rsp;
    462  1.1  plunky 
    463  1.1  plunky 	if (size < 2)
    464  1.1  plunky 		return 0;
    465  1.1  plunky 
    466  1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    467  1.1  plunky 		log_debug("ignored");
    468  1.1  plunky 		return 2;
    469  1.1  plunky 	}
    470  1.1  plunky 
    471  1.1  plunky 	rsp = be16dec(ptr);
    472  1.1  plunky 
    473  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    474  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    475  1.1  plunky 
    476  1.1  plunky 	/* we did not send any filter_net_type_set message */
    477  1.1  plunky 	return 2;
    478  1.1  plunky }
    479  1.1  plunky 
    480  1.1  plunky static size_t
    481  1.1  plunky bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
    482  1.1  plunky {
    483  1.1  plunky 	mfilter_t *mf;
    484  1.1  plunky 	int i, len, nf, rsp;
    485  1.1  plunky 
    486  1.1  plunky 	if (size < 2)
    487  1.1  plunky 		return 0;
    488  1.1  plunky 
    489  1.1  plunky 	len = be16dec(ptr);
    490  1.1  plunky 	ptr += 2;
    491  1.1  plunky 
    492  1.1  plunky 	if (size < (len + 2))
    493  1.1  plunky 		return 0;
    494  1.1  plunky 
    495  1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    496  1.1  plunky 		log_debug("ignored");
    497  1.1  plunky 		return (len + 2);
    498  1.1  plunky 	}
    499  1.1  plunky 
    500  1.1  plunky 	nf = len / (ETHER_ADDR_LEN * 2);
    501  1.1  plunky 	mf = malloc(nf * sizeof(mfilter_t));
    502  1.1  plunky 	if (mf == NULL) {
    503  1.1  plunky 		rsp = BNEP_FILTER_TOO_MANY_FILTERS;
    504  1.1  plunky 		goto done;
    505  1.1  plunky 	}
    506  1.1  plunky 
    507  1.1  plunky 	log_debug("nf = %d", nf);
    508  1.1  plunky 
    509  1.1  plunky 	for (i = 0; i < nf; i++) {
    510  1.1  plunky 		memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
    511  1.1  plunky 		ptr += ETHER_ADDR_LEN;
    512  1.1  plunky 
    513  1.1  plunky 		memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
    514  1.1  plunky 		ptr += ETHER_ADDR_LEN;
    515  1.1  plunky 
    516  1.1  plunky 		if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
    517  1.1  plunky 			free(mf);
    518  1.1  plunky 			rsp = BNEP_FILTER_INVALID_RANGE;
    519  1.1  plunky 			goto done;
    520  1.1  plunky 		}
    521  1.1  plunky 
    522  1.1  plunky 		log_debug("pf[%d] = "
    523  1.1  plunky 		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
    524  1.1  plunky 		    "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
    525  1.1  plunky 		    mf[i].start[0], mf[i].start[1], mf[i].start[2],
    526  1.1  plunky 		    mf[i].start[3], mf[i].start[4], mf[i].start[5],
    527  1.1  plunky 		    mf[i].end[0], mf[i].end[1], mf[i].end[2],
    528  1.1  plunky 		    mf[i].end[3], mf[i].end[4], mf[i].end[5]);
    529  1.1  plunky 	}
    530  1.1  plunky 
    531  1.1  plunky 	if (chan->mfilter)
    532  1.1  plunky 		free(chan->mfilter);
    533  1.1  plunky 
    534  1.1  plunky 	chan->mfilter = mf;
    535  1.1  plunky 	chan->nmfilter = nf;
    536  1.1  plunky 
    537  1.1  plunky 	rsp = BNEP_FILTER_SUCCESS;
    538  1.1  plunky 
    539  1.1  plunky done:
    540  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    541  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    542  1.1  plunky 
    543  1.1  plunky 	bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
    544  1.1  plunky 	return (len + 2);
    545  1.1  plunky }
    546  1.1  plunky 
    547  1.1  plunky static size_t
    548  1.1  plunky bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
    549  1.1  plunky {
    550  1.1  plunky 	int rsp;
    551  1.1  plunky 
    552  1.1  plunky 	if (size < 2)
    553  1.1  plunky 		return false;
    554  1.1  plunky 
    555  1.1  plunky 	if (chan->state != CHANNEL_OPEN) {
    556  1.1  plunky 		log_debug("ignored");
    557  1.1  plunky 		return 2;
    558  1.1  plunky 	}
    559  1.1  plunky 
    560  1.1  plunky 	rsp = be16dec(ptr);
    561  1.1  plunky 	log_debug("addr %s response 0x%2.2x",
    562  1.1  plunky 	    ether_ntoa((struct ether_addr *)chan->raddr), rsp);
    563  1.1  plunky 
    564  1.1  plunky 	/* we did not send any filter_multi_addr_set message */
    565  1.1  plunky 	return 2;
    566  1.1  plunky }
    567  1.1  plunky 
    568  1.1  plunky void
    569  1.1  plunky bnep_send_control(channel_t *chan, uint8_t type, ...)
    570  1.1  plunky {
    571  1.1  plunky 	packet_t *pkt;
    572  1.1  plunky 	uint8_t *p;
    573  1.1  plunky 	va_list ap;
    574  1.1  plunky 
    575  1.1  plunky 	_DIAGASSERT(chan->state != CHANNEL_CLOSED);
    576  1.1  plunky 
    577  1.1  plunky 	pkt = packet_alloc(chan);
    578  1.1  plunky 	if (pkt == NULL)
    579  1.1  plunky 		return;
    580  1.1  plunky 
    581  1.1  plunky 	p = pkt->ptr;
    582  1.1  plunky 	va_start(ap, type);
    583  1.1  plunky 
    584  1.1  plunky 	*p++ = BNEP_CONTROL;
    585  1.1  plunky 	*p++ = type;
    586  1.1  plunky 
    587  1.1  plunky 	switch(type) {
    588  1.1  plunky 	case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
    589  1.1  plunky 		*p++ = va_arg(ap, int);
    590  1.1  plunky 		break;
    591  1.1  plunky 
    592  1.1  plunky 	case BNEP_SETUP_CONNECTION_REQUEST:
    593  1.1  plunky 		*p++ = va_arg(ap, int);
    594  1.1  plunky 		be16enc(p, va_arg(ap, int));
    595  1.1  plunky 		p += 2;
    596  1.1  plunky 		be16enc(p, va_arg(ap, int));
    597  1.1  plunky 		p += 2;
    598  1.1  plunky 		break;
    599  1.1  plunky 
    600  1.1  plunky 	case BNEP_SETUP_CONNECTION_RESPONSE:
    601  1.1  plunky 	case BNEP_FILTER_NET_TYPE_RESPONSE:
    602  1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_RESPONSE:
    603  1.1  plunky 		be16enc(p, va_arg(ap, int));
    604  1.1  plunky 		p += 2;
    605  1.1  plunky 		break;
    606  1.1  plunky 
    607  1.1  plunky 	case BNEP_FILTER_NET_TYPE_SET:		/* TODO */
    608  1.1  plunky 	case BNEP_FILTER_MULTI_ADDR_SET:	/* TODO */
    609  1.1  plunky 	default:
    610  1.1  plunky 		log_err("Can't send control type 0x%2.2x", type);
    611  1.1  plunky 		break;
    612  1.1  plunky 	}
    613  1.1  plunky 
    614  1.1  plunky 	va_end(ap);
    615  1.1  plunky 	pkt->len = p - pkt->ptr;
    616  1.1  plunky 
    617  1.1  plunky 	channel_put(chan, pkt);
    618  1.1  plunky 	packet_free(pkt);
    619  1.1  plunky }
    620  1.1  plunky 
    621  1.1  plunky /*
    622  1.1  plunky  * BNEP send packet routine
    623  1.1  plunky  * return true if packet can be removed from queue
    624  1.1  plunky  */
    625  1.1  plunky bool
    626  1.1  plunky bnep_send(channel_t *chan, packet_t *pkt)
    627  1.1  plunky {
    628  1.1  plunky 	struct iovec iov[2];
    629  1.1  plunky 	uint8_t *p, *type, *proto;
    630  1.1  plunky 	exthdr_t *eh;
    631  1.1  plunky 	bool src, dst;
    632  1.1  plunky 	size_t nw;
    633  1.1  plunky 
    634  1.1  plunky 	if (pkt->type == NULL) {
    635  1.1  plunky 		iov[0].iov_base = pkt->ptr;
    636  1.1  plunky 		iov[0].iov_len = pkt->len;
    637  1.1  plunky 		iov[1].iov_base = NULL;
    638  1.1  plunky 		iov[1].iov_len = 0;
    639  1.1  plunky 	} else {
    640  1.1  plunky 		p = chan->sendbuf;
    641  1.1  plunky 
    642  1.1  plunky 		dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
    643  1.1  plunky 		src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
    644  1.1  plunky 
    645  1.1  plunky 		type = p;
    646  1.1  plunky 		p += 1;
    647  1.1  plunky 
    648  1.1  plunky 		if (dst && src)
    649  1.1  plunky 			*type = BNEP_GENERAL_ETHERNET;
    650  1.1  plunky 		else if (dst && !src)
    651  1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
    652  1.1  plunky 		else if (!dst && src)
    653  1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
    654  1.1  plunky 		else /* (!dst && !src) */
    655  1.1  plunky 			*type = BNEP_COMPRESSED_ETHERNET;
    656  1.1  plunky 
    657  1.1  plunky 		if (dst) {
    658  1.1  plunky 			memcpy(p, pkt->dst, ETHER_ADDR_LEN);
    659  1.1  plunky 			p += ETHER_ADDR_LEN;
    660  1.1  plunky 		}
    661  1.1  plunky 
    662  1.1  plunky 		if (src) {
    663  1.1  plunky 			memcpy(p, pkt->src, ETHER_ADDR_LEN);
    664  1.1  plunky 			p += ETHER_ADDR_LEN;
    665  1.1  plunky 		}
    666  1.1  plunky 
    667  1.1  plunky 		proto = p;
    668  1.1  plunky 		memcpy(p, pkt->type, ETHER_TYPE_LEN);
    669  1.1  plunky 		p += ETHER_TYPE_LEN;
    670  1.1  plunky 
    671  1.1  plunky 		STAILQ_FOREACH(eh, &pkt->extlist, next) {
    672  1.1  plunky 			if (p + eh->len > chan->sendbuf + chan->mtu)
    673  1.1  plunky 				break;
    674  1.1  plunky 
    675  1.1  plunky 			*type |= BNEP_EXT;
    676  1.1  plunky 			type = p;
    677  1.1  plunky 
    678  1.1  plunky 			memcpy(p, eh->ptr, eh->len);
    679  1.1  plunky 			p += eh->len;
    680  1.1  plunky 		}
    681  1.1  plunky 
    682  1.1  plunky 		*type &= ~BNEP_EXT;
    683  1.1  plunky 
    684  1.1  plunky 		iov[0].iov_base = chan->sendbuf;
    685  1.1  plunky 		iov[0].iov_len = (p - chan->sendbuf);
    686  1.1  plunky 
    687  1.1  plunky 		if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
    688  1.1  plunky 		    && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
    689  1.1  plunky 			iov[1].iov_base = pkt->ptr;
    690  1.1  plunky 			iov[1].iov_len = pkt->len;
    691  1.1  plunky 		} else if (be16dec(proto) == ETHERTYPE_VLAN
    692  1.1  plunky 		    && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
    693  1.1  plunky 			iov[1].iov_base = pkt->ptr;
    694  1.1  plunky 			iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
    695  1.1  plunky 		} else {
    696  1.1  plunky 			iov[1].iov_base = NULL;
    697  1.1  plunky 			iov[1].iov_len = 0;
    698  1.1  plunky 			memset(proto, 0, ETHER_TYPE_LEN);
    699  1.1  plunky 		}
    700  1.1  plunky 	}
    701  1.1  plunky 
    702  1.1  plunky 	if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
    703  1.1  plunky 		log_err("packet exceeded MTU (dropped)");
    704  1.1  plunky 		return false;
    705  1.1  plunky 	}
    706  1.1  plunky 
    707  1.1  plunky 	nw = writev(chan->fd, iov, __arraycount(iov));
    708  1.1  plunky 	return (nw > 0);
    709  1.1  plunky }
    710  1.1  plunky 
    711  1.1  plunky static bool
    712  1.1  plunky bnep_pfilter(channel_t *chan, packet_t *pkt)
    713  1.1  plunky {
    714  1.1  plunky 	int proto, i;
    715  1.1  plunky 
    716  1.1  plunky 	proto = be16dec(pkt->type);
    717  1.1  plunky 	if (proto == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
    718  1.1  plunky 		if (pkt->len < 4)
    719  1.1  plunky 			return false;
    720  1.1  plunky 
    721  1.1  plunky 		proto = be16dec(pkt->ptr + 2);
    722  1.1  plunky 	}
    723  1.1  plunky 
    724  1.1  plunky 	for (i = 0; i < chan->npfilter; i++) {
    725  1.1  plunky 		if (chan->pfilter[i].start <= proto
    726  1.1  plunky 		    && chan->pfilter[i].end >=proto)
    727  1.1  plunky 			return true;
    728  1.1  plunky 	}
    729  1.1  plunky 
    730  1.1  plunky 	return false;
    731  1.1  plunky }
    732  1.1  plunky 
    733  1.1  plunky static bool
    734  1.1  plunky bnep_mfilter(channel_t *chan, packet_t *pkt)
    735  1.1  plunky {
    736  1.1  plunky 	int i;
    737  1.1  plunky 
    738  1.1  plunky 	if (!ETHER_IS_MULTICAST(pkt->dst))
    739  1.1  plunky 		return true;
    740  1.1  plunky 
    741  1.1  plunky 	for (i = 0; i < chan->nmfilter; i++) {
    742  1.1  plunky 		if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
    743  1.1  plunky 		    && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
    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