17718ced0SMaksim Yevmenkin /* $NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */
27718ced0SMaksim Yevmenkin
37718ced0SMaksim Yevmenkin /*-
4*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni *
67718ced0SMaksim Yevmenkin * Copyright (c) 2008 Iain Hibbert
77718ced0SMaksim Yevmenkin * All rights reserved.
87718ced0SMaksim Yevmenkin *
97718ced0SMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without
107718ced0SMaksim Yevmenkin * modification, are permitted provided that the following conditions
117718ced0SMaksim Yevmenkin * are met:
127718ced0SMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright
137718ced0SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer.
147718ced0SMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright
157718ced0SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the
167718ced0SMaksim Yevmenkin * documentation and/or other materials provided with the distribution.
177718ced0SMaksim Yevmenkin *
187718ced0SMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
197718ced0SMaksim Yevmenkin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
207718ced0SMaksim Yevmenkin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
217718ced0SMaksim Yevmenkin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
227718ced0SMaksim Yevmenkin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
237718ced0SMaksim Yevmenkin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
247718ced0SMaksim Yevmenkin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
257718ced0SMaksim Yevmenkin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
267718ced0SMaksim Yevmenkin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
277718ced0SMaksim Yevmenkin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287718ced0SMaksim Yevmenkin */
297718ced0SMaksim Yevmenkin
307718ced0SMaksim Yevmenkin
317718ced0SMaksim Yevmenkin #include <sys/cdefs.h>
327718ced0SMaksim Yevmenkin __RCSID("$NetBSD: bnep.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
337718ced0SMaksim Yevmenkin
347718ced0SMaksim Yevmenkin #include <sys/uio.h>
358d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
367718ced0SMaksim Yevmenkin #include <bluetooth.h>
377718ced0SMaksim Yevmenkin #include <sdp.h>
387718ced0SMaksim Yevmenkin #include <stdarg.h>
397718ced0SMaksim Yevmenkin #include <string.h>
407718ced0SMaksim Yevmenkin #include <unistd.h>
417718ced0SMaksim Yevmenkin
427718ced0SMaksim Yevmenkin #include "btpand.h"
437718ced0SMaksim Yevmenkin #include "bnep.h"
447718ced0SMaksim Yevmenkin
457718ced0SMaksim Yevmenkin static bool bnep_recv_extension(packet_t *);
467718ced0SMaksim Yevmenkin static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
477718ced0SMaksim Yevmenkin static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
487718ced0SMaksim Yevmenkin static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
497718ced0SMaksim Yevmenkin static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
507718ced0SMaksim Yevmenkin static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
517718ced0SMaksim Yevmenkin static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
527718ced0SMaksim Yevmenkin static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
537718ced0SMaksim Yevmenkin static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
547718ced0SMaksim Yevmenkin
557718ced0SMaksim Yevmenkin static bool bnep_pfilter(channel_t *, packet_t *);
567718ced0SMaksim Yevmenkin static bool bnep_mfilter(channel_t *, packet_t *);
577718ced0SMaksim Yevmenkin
587718ced0SMaksim Yevmenkin static uint8_t NAP_UUID[] = {
597718ced0SMaksim Yevmenkin 0x00, 0x00, 0x11, 0x16,
607718ced0SMaksim Yevmenkin 0x00, 0x00,
617718ced0SMaksim Yevmenkin 0x10, 0x00,
627718ced0SMaksim Yevmenkin 0x80, 0x00,
637718ced0SMaksim Yevmenkin 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
647718ced0SMaksim Yevmenkin };
657718ced0SMaksim Yevmenkin
667718ced0SMaksim Yevmenkin static uint8_t GN_UUID[] = {
677718ced0SMaksim Yevmenkin 0x00, 0x00, 0x11, 0x17,
687718ced0SMaksim Yevmenkin 0x00, 0x00,
697718ced0SMaksim Yevmenkin 0x10, 0x00,
707718ced0SMaksim Yevmenkin 0x80, 0x00,
717718ced0SMaksim Yevmenkin 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
727718ced0SMaksim Yevmenkin };
737718ced0SMaksim Yevmenkin
747718ced0SMaksim Yevmenkin static uint8_t PANU_UUID[] = {
757718ced0SMaksim Yevmenkin 0x00, 0x00, 0x11, 0x15,
767718ced0SMaksim Yevmenkin 0x00, 0x00,
777718ced0SMaksim Yevmenkin 0x10, 0x00,
787718ced0SMaksim Yevmenkin 0x80, 0x00,
797718ced0SMaksim Yevmenkin 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
807718ced0SMaksim Yevmenkin };
817718ced0SMaksim Yevmenkin
827718ced0SMaksim Yevmenkin /*
837718ced0SMaksim Yevmenkin * receive BNEP packet
847718ced0SMaksim Yevmenkin * return true if packet is to be forwarded
857718ced0SMaksim Yevmenkin */
867718ced0SMaksim Yevmenkin bool
bnep_recv(packet_t * pkt)877718ced0SMaksim Yevmenkin bnep_recv(packet_t *pkt)
887718ced0SMaksim Yevmenkin {
897718ced0SMaksim Yevmenkin size_t len;
907718ced0SMaksim Yevmenkin uint8_t type;
917718ced0SMaksim Yevmenkin
927718ced0SMaksim Yevmenkin if (pkt->len < 1)
937718ced0SMaksim Yevmenkin return false;
947718ced0SMaksim Yevmenkin
957718ced0SMaksim Yevmenkin type = pkt->ptr[0];
967718ced0SMaksim Yevmenkin packet_adj(pkt, 1);
977718ced0SMaksim Yevmenkin
987718ced0SMaksim Yevmenkin switch (BNEP_TYPE(type)) {
997718ced0SMaksim Yevmenkin case BNEP_GENERAL_ETHERNET:
1007718ced0SMaksim Yevmenkin if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
1017718ced0SMaksim Yevmenkin log_debug("dropped short packet (type 0x%2.2x)", type);
1027718ced0SMaksim Yevmenkin return false;
1037718ced0SMaksim Yevmenkin }
1047718ced0SMaksim Yevmenkin
1057718ced0SMaksim Yevmenkin pkt->dst = pkt->ptr;
1067718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_ADDR_LEN);
1077718ced0SMaksim Yevmenkin pkt->src = pkt->ptr;
1087718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_ADDR_LEN);
1097718ced0SMaksim Yevmenkin pkt->type = pkt->ptr;
1107718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_TYPE_LEN);
1117718ced0SMaksim Yevmenkin break;
1127718ced0SMaksim Yevmenkin
1137718ced0SMaksim Yevmenkin case BNEP_CONTROL:
1147718ced0SMaksim Yevmenkin len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
1157718ced0SMaksim Yevmenkin if (len == 0)
1167718ced0SMaksim Yevmenkin return false;
1177718ced0SMaksim Yevmenkin
1187718ced0SMaksim Yevmenkin packet_adj(pkt, len);
1197718ced0SMaksim Yevmenkin break;
1207718ced0SMaksim Yevmenkin
1217718ced0SMaksim Yevmenkin case BNEP_COMPRESSED_ETHERNET:
1227718ced0SMaksim Yevmenkin if (pkt->len < ETHER_TYPE_LEN) {
1237718ced0SMaksim Yevmenkin log_debug("dropped short packet (type 0x%2.2x)", type);
1247718ced0SMaksim Yevmenkin return false;
1257718ced0SMaksim Yevmenkin }
1267718ced0SMaksim Yevmenkin
1277718ced0SMaksim Yevmenkin pkt->dst = pkt->chan->laddr;
1287718ced0SMaksim Yevmenkin pkt->src = pkt->chan->raddr;
1297718ced0SMaksim Yevmenkin pkt->type = pkt->ptr;
1307718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_TYPE_LEN);
1317718ced0SMaksim Yevmenkin break;
1327718ced0SMaksim Yevmenkin
1337718ced0SMaksim Yevmenkin case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
1347718ced0SMaksim Yevmenkin if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
1357718ced0SMaksim Yevmenkin log_debug("dropped short packet (type 0x%2.2x)", type);
1367718ced0SMaksim Yevmenkin return false;
1377718ced0SMaksim Yevmenkin }
1387718ced0SMaksim Yevmenkin
1397718ced0SMaksim Yevmenkin pkt->dst = pkt->chan->laddr;
1407718ced0SMaksim Yevmenkin pkt->src = pkt->ptr;
1417718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_ADDR_LEN);
1427718ced0SMaksim Yevmenkin pkt->type = pkt->ptr;
1437718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_TYPE_LEN);
1447718ced0SMaksim Yevmenkin break;
1457718ced0SMaksim Yevmenkin
1467718ced0SMaksim Yevmenkin case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
1477718ced0SMaksim Yevmenkin if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
1487718ced0SMaksim Yevmenkin log_debug("dropped short packet (type 0x%2.2x)", type);
1497718ced0SMaksim Yevmenkin return false;
1507718ced0SMaksim Yevmenkin }
1517718ced0SMaksim Yevmenkin
1527718ced0SMaksim Yevmenkin pkt->dst = pkt->ptr;
1537718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_ADDR_LEN);
1547718ced0SMaksim Yevmenkin pkt->src = pkt->chan->raddr;
1557718ced0SMaksim Yevmenkin pkt->type = pkt->ptr;
1567718ced0SMaksim Yevmenkin packet_adj(pkt, ETHER_TYPE_LEN);
1577718ced0SMaksim Yevmenkin break;
1587718ced0SMaksim Yevmenkin
1597718ced0SMaksim Yevmenkin default:
1607718ced0SMaksim Yevmenkin /*
1617718ced0SMaksim Yevmenkin * Any packet containing a reserved BNEP
1627718ced0SMaksim Yevmenkin * header packet type SHALL be dropped.
1637718ced0SMaksim Yevmenkin */
1647718ced0SMaksim Yevmenkin
1657718ced0SMaksim Yevmenkin log_debug("dropped packet with reserved type 0x%2.2x", type);
1667718ced0SMaksim Yevmenkin return false;
1677718ced0SMaksim Yevmenkin }
1687718ced0SMaksim Yevmenkin
1697718ced0SMaksim Yevmenkin if (BNEP_TYPE_EXT(type)
1707718ced0SMaksim Yevmenkin && !bnep_recv_extension(pkt))
1717718ced0SMaksim Yevmenkin return false; /* invalid extensions */
1727718ced0SMaksim Yevmenkin
1737718ced0SMaksim Yevmenkin if (BNEP_TYPE(type) == BNEP_CONTROL
1747718ced0SMaksim Yevmenkin || pkt->chan->state != CHANNEL_OPEN)
1757718ced0SMaksim Yevmenkin return false; /* no forwarding */
1767718ced0SMaksim Yevmenkin
1777718ced0SMaksim Yevmenkin return true;
1787718ced0SMaksim Yevmenkin }
1797718ced0SMaksim Yevmenkin
1807718ced0SMaksim Yevmenkin static bool
bnep_recv_extension(packet_t * pkt)1817718ced0SMaksim Yevmenkin bnep_recv_extension(packet_t *pkt)
1827718ced0SMaksim Yevmenkin {
1837718ced0SMaksim Yevmenkin exthdr_t *eh;
1847718ced0SMaksim Yevmenkin size_t len, size;
1857718ced0SMaksim Yevmenkin uint8_t type;
1867718ced0SMaksim Yevmenkin
1877718ced0SMaksim Yevmenkin do {
1887718ced0SMaksim Yevmenkin if (pkt->len < 2)
1897718ced0SMaksim Yevmenkin return false;
1907718ced0SMaksim Yevmenkin
1917718ced0SMaksim Yevmenkin type = pkt->ptr[0];
1927718ced0SMaksim Yevmenkin size = pkt->ptr[1];
1937718ced0SMaksim Yevmenkin
1947718ced0SMaksim Yevmenkin if (pkt->len < size + 2)
1957718ced0SMaksim Yevmenkin return false;
1967718ced0SMaksim Yevmenkin
1977718ced0SMaksim Yevmenkin switch (type) {
1987718ced0SMaksim Yevmenkin case BNEP_EXTENSION_CONTROL:
1997718ced0SMaksim Yevmenkin len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
2007718ced0SMaksim Yevmenkin if (len != size)
2017718ced0SMaksim Yevmenkin log_err("ignored spurious data in exthdr");
2027718ced0SMaksim Yevmenkin
2037718ced0SMaksim Yevmenkin break;
2047718ced0SMaksim Yevmenkin
2057718ced0SMaksim Yevmenkin default:
2067718ced0SMaksim Yevmenkin /* Unknown extension headers in data packets */
2077718ced0SMaksim Yevmenkin /* SHALL be forwarded irrespective of any */
2087718ced0SMaksim Yevmenkin /* network protocol or multicast filter settings */
2097718ced0SMaksim Yevmenkin /* and any local filtering policy. */
2107718ced0SMaksim Yevmenkin
2117718ced0SMaksim Yevmenkin eh = malloc(sizeof(exthdr_t));
2127718ced0SMaksim Yevmenkin if (eh == NULL) {
2137718ced0SMaksim Yevmenkin log_err("exthdr malloc() failed: %m");
2147718ced0SMaksim Yevmenkin break;
2157718ced0SMaksim Yevmenkin }
2167718ced0SMaksim Yevmenkin
2177718ced0SMaksim Yevmenkin eh->ptr = pkt->ptr;
2187718ced0SMaksim Yevmenkin eh->len = size;
2197718ced0SMaksim Yevmenkin STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
2207718ced0SMaksim Yevmenkin break;
2217718ced0SMaksim Yevmenkin }
2227718ced0SMaksim Yevmenkin
2237718ced0SMaksim Yevmenkin packet_adj(pkt, size + 2);
2247718ced0SMaksim Yevmenkin } while (BNEP_TYPE_EXT(type));
2257718ced0SMaksim Yevmenkin
2267718ced0SMaksim Yevmenkin return true;
2277718ced0SMaksim Yevmenkin }
2287718ced0SMaksim Yevmenkin
2297718ced0SMaksim Yevmenkin static size_t
bnep_recv_control(channel_t * chan,uint8_t * ptr,size_t size,bool isext)2307718ced0SMaksim Yevmenkin bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
2317718ced0SMaksim Yevmenkin {
2327718ced0SMaksim Yevmenkin uint8_t type;
2337718ced0SMaksim Yevmenkin size_t len;
2347718ced0SMaksim Yevmenkin
2357718ced0SMaksim Yevmenkin if (size-- < 1)
2367718ced0SMaksim Yevmenkin return 0;
2377718ced0SMaksim Yevmenkin
2387718ced0SMaksim Yevmenkin type = *ptr++;
2397718ced0SMaksim Yevmenkin
2407718ced0SMaksim Yevmenkin switch (type) {
2417718ced0SMaksim Yevmenkin case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
2427718ced0SMaksim Yevmenkin len = bnep_recv_control_command_not_understood(chan, ptr, size);
2437718ced0SMaksim Yevmenkin break;
2447718ced0SMaksim Yevmenkin
2457718ced0SMaksim Yevmenkin case BNEP_SETUP_CONNECTION_REQUEST:
2467718ced0SMaksim Yevmenkin if (isext)
2477718ced0SMaksim Yevmenkin return 0; /* not allowed in extension headers */
2487718ced0SMaksim Yevmenkin
2497718ced0SMaksim Yevmenkin len = bnep_recv_setup_connection_req(chan, ptr, size);
2507718ced0SMaksim Yevmenkin break;
2517718ced0SMaksim Yevmenkin
2527718ced0SMaksim Yevmenkin case BNEP_SETUP_CONNECTION_RESPONSE:
2537718ced0SMaksim Yevmenkin if (isext)
2547718ced0SMaksim Yevmenkin return 0; /* not allowed in extension headers */
2557718ced0SMaksim Yevmenkin
2567718ced0SMaksim Yevmenkin len = bnep_recv_setup_connection_rsp(chan, ptr, size);
2577718ced0SMaksim Yevmenkin break;
2587718ced0SMaksim Yevmenkin
2597718ced0SMaksim Yevmenkin case BNEP_FILTER_NET_TYPE_SET:
2607718ced0SMaksim Yevmenkin len = bnep_recv_filter_net_type_set(chan, ptr, size);
2617718ced0SMaksim Yevmenkin break;
2627718ced0SMaksim Yevmenkin
2637718ced0SMaksim Yevmenkin case BNEP_FILTER_NET_TYPE_RESPONSE:
2647718ced0SMaksim Yevmenkin len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
2657718ced0SMaksim Yevmenkin break;
2667718ced0SMaksim Yevmenkin
2677718ced0SMaksim Yevmenkin case BNEP_FILTER_MULTI_ADDR_SET:
2687718ced0SMaksim Yevmenkin len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
2697718ced0SMaksim Yevmenkin break;
2707718ced0SMaksim Yevmenkin
2717718ced0SMaksim Yevmenkin case BNEP_FILTER_MULTI_ADDR_RESPONSE:
2727718ced0SMaksim Yevmenkin len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
2737718ced0SMaksim Yevmenkin break;
2747718ced0SMaksim Yevmenkin
2757718ced0SMaksim Yevmenkin default:
2767718ced0SMaksim Yevmenkin len = 0;
2777718ced0SMaksim Yevmenkin break;
2787718ced0SMaksim Yevmenkin }
2797718ced0SMaksim Yevmenkin
2807718ced0SMaksim Yevmenkin if (len == 0)
2817718ced0SMaksim Yevmenkin bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
2827718ced0SMaksim Yevmenkin
2837718ced0SMaksim Yevmenkin return len;
2847718ced0SMaksim Yevmenkin }
2857718ced0SMaksim Yevmenkin
2867718ced0SMaksim Yevmenkin static size_t
bnep_recv_control_command_not_understood(channel_t * chan,uint8_t * ptr,size_t size)2877718ced0SMaksim Yevmenkin bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
2887718ced0SMaksim Yevmenkin {
2897718ced0SMaksim Yevmenkin uint8_t type;
2907718ced0SMaksim Yevmenkin
2917718ced0SMaksim Yevmenkin if (size < 1)
2927718ced0SMaksim Yevmenkin return 0;
2937718ced0SMaksim Yevmenkin
2947718ced0SMaksim Yevmenkin type = *ptr++;
2957718ced0SMaksim Yevmenkin log_err("received Control Command Not Understood (0x%2.2x)", type);
2967718ced0SMaksim Yevmenkin
2977718ced0SMaksim Yevmenkin /* we didn't send any reserved commands, just cut them off */
2987718ced0SMaksim Yevmenkin channel_close(chan);
2997718ced0SMaksim Yevmenkin
3007718ced0SMaksim Yevmenkin return 1;
3017718ced0SMaksim Yevmenkin }
3027718ced0SMaksim Yevmenkin
3037718ced0SMaksim Yevmenkin static size_t
bnep_recv_setup_connection_req(channel_t * chan,uint8_t * ptr,size_t size)3047718ced0SMaksim Yevmenkin bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
3057718ced0SMaksim Yevmenkin {
3067718ced0SMaksim Yevmenkin uint8_t off;
3077718ced0SMaksim Yevmenkin int src, dst, rsp;
3087718ced0SMaksim Yevmenkin size_t len;
3097718ced0SMaksim Yevmenkin
3107718ced0SMaksim Yevmenkin if (size < 1)
3117718ced0SMaksim Yevmenkin return 0;
3127718ced0SMaksim Yevmenkin
3137718ced0SMaksim Yevmenkin len = *ptr++;
3147718ced0SMaksim Yevmenkin if (size < (len * 2 + 1))
3157718ced0SMaksim Yevmenkin return 0;
3167718ced0SMaksim Yevmenkin
3177718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_WAIT_CONNECT_REQ
3187718ced0SMaksim Yevmenkin && chan->state != CHANNEL_OPEN) {
3197718ced0SMaksim Yevmenkin log_debug("ignored");
3207718ced0SMaksim Yevmenkin return (len * 2 + 1);
3217718ced0SMaksim Yevmenkin }
3227718ced0SMaksim Yevmenkin
3237718ced0SMaksim Yevmenkin if (len == 2)
3247718ced0SMaksim Yevmenkin off = 2;
3257718ced0SMaksim Yevmenkin else if (len == 4)
3267718ced0SMaksim Yevmenkin off = 0;
3277718ced0SMaksim Yevmenkin else if (len == 16)
3287718ced0SMaksim Yevmenkin off = 0;
3297718ced0SMaksim Yevmenkin else {
3307718ced0SMaksim Yevmenkin rsp = BNEP_SETUP_INVALID_UUID_SIZE;
3317718ced0SMaksim Yevmenkin goto done;
3327718ced0SMaksim Yevmenkin }
3337718ced0SMaksim Yevmenkin
3347718ced0SMaksim Yevmenkin if (memcmp(ptr, NAP_UUID + off, len) == 0)
3357718ced0SMaksim Yevmenkin dst = SDP_SERVICE_CLASS_NAP;
3367718ced0SMaksim Yevmenkin else if (memcmp(ptr, GN_UUID + off, len) == 0)
3377718ced0SMaksim Yevmenkin dst = SDP_SERVICE_CLASS_GN;
3387718ced0SMaksim Yevmenkin else if (memcmp(ptr, PANU_UUID + off, len) == 0)
3397718ced0SMaksim Yevmenkin dst = SDP_SERVICE_CLASS_PANU;
3407718ced0SMaksim Yevmenkin else
3417718ced0SMaksim Yevmenkin dst = 0;
3427718ced0SMaksim Yevmenkin
3437718ced0SMaksim Yevmenkin if (dst != service_class) {
3447718ced0SMaksim Yevmenkin rsp = BNEP_SETUP_INVALID_DST_UUID;
3457718ced0SMaksim Yevmenkin goto done;
3467718ced0SMaksim Yevmenkin }
3477718ced0SMaksim Yevmenkin
3487718ced0SMaksim Yevmenkin ptr += len;
3497718ced0SMaksim Yevmenkin
3507718ced0SMaksim Yevmenkin if (memcmp(ptr, NAP_UUID + off, len) == 0)
3517718ced0SMaksim Yevmenkin src = SDP_SERVICE_CLASS_NAP;
3527718ced0SMaksim Yevmenkin else if (memcmp(ptr, GN_UUID + off, len) == 0)
3537718ced0SMaksim Yevmenkin src = SDP_SERVICE_CLASS_GN;
3547718ced0SMaksim Yevmenkin else if (memcmp(ptr, PANU_UUID + off, len) == 0)
3557718ced0SMaksim Yevmenkin src = SDP_SERVICE_CLASS_PANU;
3567718ced0SMaksim Yevmenkin else
3577718ced0SMaksim Yevmenkin src = 0;
3587718ced0SMaksim Yevmenkin
3597718ced0SMaksim Yevmenkin if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
3607718ced0SMaksim Yevmenkin || src == 0) {
3617718ced0SMaksim Yevmenkin rsp = BNEP_SETUP_INVALID_SRC_UUID;
3627718ced0SMaksim Yevmenkin goto done;
3637718ced0SMaksim Yevmenkin }
3647718ced0SMaksim Yevmenkin
3657718ced0SMaksim Yevmenkin rsp = BNEP_SETUP_SUCCESS;
3667718ced0SMaksim Yevmenkin chan->state = CHANNEL_OPEN;
3677718ced0SMaksim Yevmenkin channel_timeout(chan, 0);
3687718ced0SMaksim Yevmenkin
3697718ced0SMaksim Yevmenkin done:
3707718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
3717718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
3727718ced0SMaksim Yevmenkin
3737718ced0SMaksim Yevmenkin bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
3747718ced0SMaksim Yevmenkin return (len * 2 + 1);
3757718ced0SMaksim Yevmenkin }
3767718ced0SMaksim Yevmenkin
3777718ced0SMaksim Yevmenkin static size_t
bnep_recv_setup_connection_rsp(channel_t * chan,uint8_t * ptr,size_t size)3787718ced0SMaksim Yevmenkin bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
3797718ced0SMaksim Yevmenkin {
3807718ced0SMaksim Yevmenkin int rsp;
3817718ced0SMaksim Yevmenkin
3827718ced0SMaksim Yevmenkin if (size < 2)
3837718ced0SMaksim Yevmenkin return 0;
3847718ced0SMaksim Yevmenkin
3857718ced0SMaksim Yevmenkin rsp = be16dec(ptr);
3867718ced0SMaksim Yevmenkin
3877718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
3887718ced0SMaksim Yevmenkin log_debug("ignored");
3897718ced0SMaksim Yevmenkin return 2;
3907718ced0SMaksim Yevmenkin }
3917718ced0SMaksim Yevmenkin
3927718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
3937718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
3947718ced0SMaksim Yevmenkin
3957718ced0SMaksim Yevmenkin if (rsp == BNEP_SETUP_SUCCESS) {
3967718ced0SMaksim Yevmenkin chan->state = CHANNEL_OPEN;
3977718ced0SMaksim Yevmenkin channel_timeout(chan, 0);
3987718ced0SMaksim Yevmenkin } else {
3997718ced0SMaksim Yevmenkin channel_close(chan);
4007718ced0SMaksim Yevmenkin }
4017718ced0SMaksim Yevmenkin
4027718ced0SMaksim Yevmenkin return 2;
4037718ced0SMaksim Yevmenkin }
4047718ced0SMaksim Yevmenkin
4057718ced0SMaksim Yevmenkin static size_t
bnep_recv_filter_net_type_set(channel_t * chan,uint8_t * ptr,size_t size)4067718ced0SMaksim Yevmenkin bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
4077718ced0SMaksim Yevmenkin {
4087718ced0SMaksim Yevmenkin pfilter_t *pf;
4097718ced0SMaksim Yevmenkin int i, nf, rsp;
4107718ced0SMaksim Yevmenkin size_t len;
4117718ced0SMaksim Yevmenkin
4127718ced0SMaksim Yevmenkin if (size < 2)
4137718ced0SMaksim Yevmenkin return 0;
4147718ced0SMaksim Yevmenkin
4157718ced0SMaksim Yevmenkin len = be16dec(ptr);
4167718ced0SMaksim Yevmenkin ptr += 2;
4177718ced0SMaksim Yevmenkin
4187718ced0SMaksim Yevmenkin if (size < (len + 2))
4197718ced0SMaksim Yevmenkin return 0;
4207718ced0SMaksim Yevmenkin
4217718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_OPEN) {
4227718ced0SMaksim Yevmenkin log_debug("ignored");
4237718ced0SMaksim Yevmenkin return (len + 2);
4247718ced0SMaksim Yevmenkin }
4257718ced0SMaksim Yevmenkin
4267718ced0SMaksim Yevmenkin nf = len / 4;
4277718ced0SMaksim Yevmenkin pf = malloc(nf * sizeof(pfilter_t));
4287718ced0SMaksim Yevmenkin if (pf == NULL) {
4297718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_TOO_MANY_FILTERS;
4307718ced0SMaksim Yevmenkin goto done;
4317718ced0SMaksim Yevmenkin }
4327718ced0SMaksim Yevmenkin
4337718ced0SMaksim Yevmenkin log_debug("nf = %d", nf);
4347718ced0SMaksim Yevmenkin
4357718ced0SMaksim Yevmenkin for (i = 0; i < nf; i++) {
4367718ced0SMaksim Yevmenkin pf[i].start = be16dec(ptr);
4377718ced0SMaksim Yevmenkin ptr += 2;
4387718ced0SMaksim Yevmenkin pf[i].end = be16dec(ptr);
4397718ced0SMaksim Yevmenkin ptr += 2;
4407718ced0SMaksim Yevmenkin
4417718ced0SMaksim Yevmenkin if (pf[i].start > pf[i].end) {
4427718ced0SMaksim Yevmenkin free(pf);
4437718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_INVALID_RANGE;
4447718ced0SMaksim Yevmenkin goto done;
4457718ced0SMaksim Yevmenkin }
4467718ced0SMaksim Yevmenkin
4477718ced0SMaksim Yevmenkin log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
4487718ced0SMaksim Yevmenkin }
4497718ced0SMaksim Yevmenkin
4507718ced0SMaksim Yevmenkin if (chan->pfilter)
4517718ced0SMaksim Yevmenkin free(chan->pfilter);
4527718ced0SMaksim Yevmenkin
4537718ced0SMaksim Yevmenkin chan->pfilter = pf;
4547718ced0SMaksim Yevmenkin chan->npfilter = nf;
4557718ced0SMaksim Yevmenkin
4567718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_SUCCESS;
4577718ced0SMaksim Yevmenkin
4587718ced0SMaksim Yevmenkin done:
4597718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
4607718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
4617718ced0SMaksim Yevmenkin
4627718ced0SMaksim Yevmenkin bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
4637718ced0SMaksim Yevmenkin return (len + 2);
4647718ced0SMaksim Yevmenkin }
4657718ced0SMaksim Yevmenkin
4667718ced0SMaksim Yevmenkin static size_t
bnep_recv_filter_net_type_rsp(channel_t * chan,uint8_t * ptr,size_t size)4677718ced0SMaksim Yevmenkin bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
4687718ced0SMaksim Yevmenkin {
4697718ced0SMaksim Yevmenkin int rsp;
4707718ced0SMaksim Yevmenkin
4717718ced0SMaksim Yevmenkin if (size < 2)
4727718ced0SMaksim Yevmenkin return 0;
4737718ced0SMaksim Yevmenkin
4747718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_OPEN) {
4757718ced0SMaksim Yevmenkin log_debug("ignored");
4767718ced0SMaksim Yevmenkin return 2;
4777718ced0SMaksim Yevmenkin }
4787718ced0SMaksim Yevmenkin
4797718ced0SMaksim Yevmenkin rsp = be16dec(ptr);
4807718ced0SMaksim Yevmenkin
4817718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
4827718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
4837718ced0SMaksim Yevmenkin
4847718ced0SMaksim Yevmenkin /* we did not send any filter_net_type_set message */
4857718ced0SMaksim Yevmenkin return 2;
4867718ced0SMaksim Yevmenkin }
4877718ced0SMaksim Yevmenkin
4887718ced0SMaksim Yevmenkin static size_t
bnep_recv_filter_multi_addr_set(channel_t * chan,uint8_t * ptr,size_t size)4897718ced0SMaksim Yevmenkin bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
4907718ced0SMaksim Yevmenkin {
4917718ced0SMaksim Yevmenkin mfilter_t *mf;
4927718ced0SMaksim Yevmenkin int i, nf, rsp;
4937718ced0SMaksim Yevmenkin size_t len;
4947718ced0SMaksim Yevmenkin
4957718ced0SMaksim Yevmenkin if (size < 2)
4967718ced0SMaksim Yevmenkin return 0;
4977718ced0SMaksim Yevmenkin
4987718ced0SMaksim Yevmenkin len = be16dec(ptr);
4997718ced0SMaksim Yevmenkin ptr += 2;
5007718ced0SMaksim Yevmenkin
5017718ced0SMaksim Yevmenkin if (size < (len + 2))
5027718ced0SMaksim Yevmenkin return 0;
5037718ced0SMaksim Yevmenkin
5047718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_OPEN) {
5057718ced0SMaksim Yevmenkin log_debug("ignored");
5067718ced0SMaksim Yevmenkin return (len + 2);
5077718ced0SMaksim Yevmenkin }
5087718ced0SMaksim Yevmenkin
5097718ced0SMaksim Yevmenkin nf = len / (ETHER_ADDR_LEN * 2);
5107718ced0SMaksim Yevmenkin mf = malloc(nf * sizeof(mfilter_t));
5117718ced0SMaksim Yevmenkin if (mf == NULL) {
5127718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_TOO_MANY_FILTERS;
5137718ced0SMaksim Yevmenkin goto done;
5147718ced0SMaksim Yevmenkin }
5157718ced0SMaksim Yevmenkin
5167718ced0SMaksim Yevmenkin log_debug("nf = %d", nf);
5177718ced0SMaksim Yevmenkin
5187718ced0SMaksim Yevmenkin for (i = 0; i < nf; i++) {
5197718ced0SMaksim Yevmenkin memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
5207718ced0SMaksim Yevmenkin ptr += ETHER_ADDR_LEN;
5217718ced0SMaksim Yevmenkin
5227718ced0SMaksim Yevmenkin memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
5237718ced0SMaksim Yevmenkin ptr += ETHER_ADDR_LEN;
5247718ced0SMaksim Yevmenkin
5257718ced0SMaksim Yevmenkin if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
5267718ced0SMaksim Yevmenkin free(mf);
5277718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_INVALID_RANGE;
5287718ced0SMaksim Yevmenkin goto done;
5297718ced0SMaksim Yevmenkin }
5307718ced0SMaksim Yevmenkin
5317718ced0SMaksim Yevmenkin log_debug("pf[%d] = "
5327718ced0SMaksim Yevmenkin "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
5337718ced0SMaksim Yevmenkin "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
5347718ced0SMaksim Yevmenkin mf[i].start[0], mf[i].start[1], mf[i].start[2],
5357718ced0SMaksim Yevmenkin mf[i].start[3], mf[i].start[4], mf[i].start[5],
5367718ced0SMaksim Yevmenkin mf[i].end[0], mf[i].end[1], mf[i].end[2],
5377718ced0SMaksim Yevmenkin mf[i].end[3], mf[i].end[4], mf[i].end[5]);
5387718ced0SMaksim Yevmenkin }
5397718ced0SMaksim Yevmenkin
5407718ced0SMaksim Yevmenkin if (chan->mfilter)
5417718ced0SMaksim Yevmenkin free(chan->mfilter);
5427718ced0SMaksim Yevmenkin
5437718ced0SMaksim Yevmenkin chan->mfilter = mf;
5447718ced0SMaksim Yevmenkin chan->nmfilter = nf;
5457718ced0SMaksim Yevmenkin
5467718ced0SMaksim Yevmenkin rsp = BNEP_FILTER_SUCCESS;
5477718ced0SMaksim Yevmenkin
5487718ced0SMaksim Yevmenkin done:
5497718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
5507718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
5517718ced0SMaksim Yevmenkin
5527718ced0SMaksim Yevmenkin bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
5537718ced0SMaksim Yevmenkin return (len + 2);
5547718ced0SMaksim Yevmenkin }
5557718ced0SMaksim Yevmenkin
5567718ced0SMaksim Yevmenkin static size_t
bnep_recv_filter_multi_addr_rsp(channel_t * chan,uint8_t * ptr,size_t size)5577718ced0SMaksim Yevmenkin bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
5587718ced0SMaksim Yevmenkin {
5597718ced0SMaksim Yevmenkin int rsp;
5607718ced0SMaksim Yevmenkin
5617718ced0SMaksim Yevmenkin if (size < 2)
5627718ced0SMaksim Yevmenkin return false;
5637718ced0SMaksim Yevmenkin
5647718ced0SMaksim Yevmenkin if (chan->state != CHANNEL_OPEN) {
5657718ced0SMaksim Yevmenkin log_debug("ignored");
5667718ced0SMaksim Yevmenkin return 2;
5677718ced0SMaksim Yevmenkin }
5687718ced0SMaksim Yevmenkin
5697718ced0SMaksim Yevmenkin rsp = be16dec(ptr);
5707718ced0SMaksim Yevmenkin log_debug("addr %s response 0x%2.2x",
5717718ced0SMaksim Yevmenkin ether_ntoa((struct ether_addr *)chan->raddr), rsp);
5727718ced0SMaksim Yevmenkin
5737718ced0SMaksim Yevmenkin /* we did not send any filter_multi_addr_set message */
5747718ced0SMaksim Yevmenkin return 2;
5757718ced0SMaksim Yevmenkin }
5767718ced0SMaksim Yevmenkin
5777718ced0SMaksim Yevmenkin void
bnep_send_control(channel_t * chan,unsigned type,...)5787fcdc815SDimitry Andric bnep_send_control(channel_t *chan, unsigned type, ...)
5797718ced0SMaksim Yevmenkin {
5807718ced0SMaksim Yevmenkin packet_t *pkt;
5817718ced0SMaksim Yevmenkin uint8_t *p;
5827718ced0SMaksim Yevmenkin va_list ap;
5837718ced0SMaksim Yevmenkin
5847718ced0SMaksim Yevmenkin assert(chan->state != CHANNEL_CLOSED);
5857718ced0SMaksim Yevmenkin
5867718ced0SMaksim Yevmenkin pkt = packet_alloc(chan);
5877718ced0SMaksim Yevmenkin if (pkt == NULL)
5887718ced0SMaksim Yevmenkin return;
5897718ced0SMaksim Yevmenkin
5907718ced0SMaksim Yevmenkin p = pkt->ptr;
5917718ced0SMaksim Yevmenkin va_start(ap, type);
5927718ced0SMaksim Yevmenkin
5937718ced0SMaksim Yevmenkin *p++ = BNEP_CONTROL;
5947fcdc815SDimitry Andric *p++ = (uint8_t)type;
5957718ced0SMaksim Yevmenkin
5967718ced0SMaksim Yevmenkin switch(type) {
5977718ced0SMaksim Yevmenkin case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
5987718ced0SMaksim Yevmenkin *p++ = va_arg(ap, int);
5997718ced0SMaksim Yevmenkin break;
6007718ced0SMaksim Yevmenkin
6017718ced0SMaksim Yevmenkin case BNEP_SETUP_CONNECTION_REQUEST:
6027718ced0SMaksim Yevmenkin *p++ = va_arg(ap, int);
6037718ced0SMaksim Yevmenkin be16enc(p, va_arg(ap, int));
6047718ced0SMaksim Yevmenkin p += 2;
6057718ced0SMaksim Yevmenkin be16enc(p, va_arg(ap, int));
6067718ced0SMaksim Yevmenkin p += 2;
6077718ced0SMaksim Yevmenkin break;
6087718ced0SMaksim Yevmenkin
6097718ced0SMaksim Yevmenkin case BNEP_SETUP_CONNECTION_RESPONSE:
6107718ced0SMaksim Yevmenkin case BNEP_FILTER_NET_TYPE_RESPONSE:
6117718ced0SMaksim Yevmenkin case BNEP_FILTER_MULTI_ADDR_RESPONSE:
6127718ced0SMaksim Yevmenkin be16enc(p, va_arg(ap, int));
6137718ced0SMaksim Yevmenkin p += 2;
6147718ced0SMaksim Yevmenkin break;
6157718ced0SMaksim Yevmenkin
6167718ced0SMaksim Yevmenkin case BNEP_FILTER_NET_TYPE_SET: /* TODO */
6177718ced0SMaksim Yevmenkin case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
6187718ced0SMaksim Yevmenkin default:
6197718ced0SMaksim Yevmenkin log_err("Can't send control type 0x%2.2x", type);
6207718ced0SMaksim Yevmenkin break;
6217718ced0SMaksim Yevmenkin }
6227718ced0SMaksim Yevmenkin
6237718ced0SMaksim Yevmenkin va_end(ap);
6247718ced0SMaksim Yevmenkin pkt->len = p - pkt->ptr;
6257718ced0SMaksim Yevmenkin
6267718ced0SMaksim Yevmenkin channel_put(chan, pkt);
6277718ced0SMaksim Yevmenkin packet_free(pkt);
6287718ced0SMaksim Yevmenkin }
6297718ced0SMaksim Yevmenkin
6307718ced0SMaksim Yevmenkin /*
6317718ced0SMaksim Yevmenkin * BNEP send packet routine
6327718ced0SMaksim Yevmenkin * return true if packet can be removed from queue
6337718ced0SMaksim Yevmenkin */
6347718ced0SMaksim Yevmenkin bool
bnep_send(channel_t * chan,packet_t * pkt)6357718ced0SMaksim Yevmenkin bnep_send(channel_t *chan, packet_t *pkt)
6367718ced0SMaksim Yevmenkin {
6377718ced0SMaksim Yevmenkin struct iovec iov[2];
6387718ced0SMaksim Yevmenkin uint8_t *p, *type, *proto;
6397718ced0SMaksim Yevmenkin exthdr_t *eh;
6407718ced0SMaksim Yevmenkin bool src, dst;
6417718ced0SMaksim Yevmenkin size_t nw;
6427718ced0SMaksim Yevmenkin
6437718ced0SMaksim Yevmenkin if (pkt->type == NULL) {
6447718ced0SMaksim Yevmenkin iov[0].iov_base = pkt->ptr;
6457718ced0SMaksim Yevmenkin iov[0].iov_len = pkt->len;
6467718ced0SMaksim Yevmenkin iov[1].iov_base = NULL;
6477718ced0SMaksim Yevmenkin iov[1].iov_len = 0;
6487718ced0SMaksim Yevmenkin } else {
6497718ced0SMaksim Yevmenkin p = chan->sendbuf;
6507718ced0SMaksim Yevmenkin
6517718ced0SMaksim Yevmenkin dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
6527718ced0SMaksim Yevmenkin src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
6537718ced0SMaksim Yevmenkin
6547718ced0SMaksim Yevmenkin type = p;
6557718ced0SMaksim Yevmenkin p += 1;
6567718ced0SMaksim Yevmenkin
6577718ced0SMaksim Yevmenkin if (dst && src)
6587718ced0SMaksim Yevmenkin *type = BNEP_GENERAL_ETHERNET;
6597718ced0SMaksim Yevmenkin else if (dst && !src)
6607718ced0SMaksim Yevmenkin *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
6617718ced0SMaksim Yevmenkin else if (!dst && src)
6627718ced0SMaksim Yevmenkin *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
6637718ced0SMaksim Yevmenkin else /* (!dst && !src) */
6647718ced0SMaksim Yevmenkin *type = BNEP_COMPRESSED_ETHERNET;
6657718ced0SMaksim Yevmenkin
6667718ced0SMaksim Yevmenkin if (dst) {
6677718ced0SMaksim Yevmenkin memcpy(p, pkt->dst, ETHER_ADDR_LEN);
6687718ced0SMaksim Yevmenkin p += ETHER_ADDR_LEN;
6697718ced0SMaksim Yevmenkin }
6707718ced0SMaksim Yevmenkin
6717718ced0SMaksim Yevmenkin if (src) {
6727718ced0SMaksim Yevmenkin memcpy(p, pkt->src, ETHER_ADDR_LEN);
6737718ced0SMaksim Yevmenkin p += ETHER_ADDR_LEN;
6747718ced0SMaksim Yevmenkin }
6757718ced0SMaksim Yevmenkin
6767718ced0SMaksim Yevmenkin proto = p;
6777718ced0SMaksim Yevmenkin memcpy(p, pkt->type, ETHER_TYPE_LEN);
6787718ced0SMaksim Yevmenkin p += ETHER_TYPE_LEN;
6797718ced0SMaksim Yevmenkin
6807718ced0SMaksim Yevmenkin STAILQ_FOREACH(eh, &pkt->extlist, next) {
6817718ced0SMaksim Yevmenkin if (p + eh->len > chan->sendbuf + chan->mtu)
6827718ced0SMaksim Yevmenkin break;
6837718ced0SMaksim Yevmenkin
6847718ced0SMaksim Yevmenkin *type |= BNEP_EXT;
6857718ced0SMaksim Yevmenkin type = p;
6867718ced0SMaksim Yevmenkin
6877718ced0SMaksim Yevmenkin memcpy(p, eh->ptr, eh->len);
6887718ced0SMaksim Yevmenkin p += eh->len;
6897718ced0SMaksim Yevmenkin }
6907718ced0SMaksim Yevmenkin
6917718ced0SMaksim Yevmenkin *type &= ~BNEP_EXT;
6927718ced0SMaksim Yevmenkin
6937718ced0SMaksim Yevmenkin iov[0].iov_base = chan->sendbuf;
6947718ced0SMaksim Yevmenkin iov[0].iov_len = (p - chan->sendbuf);
6957718ced0SMaksim Yevmenkin
6967718ced0SMaksim Yevmenkin if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
6977718ced0SMaksim Yevmenkin && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
6987718ced0SMaksim Yevmenkin iov[1].iov_base = pkt->ptr;
6997718ced0SMaksim Yevmenkin iov[1].iov_len = pkt->len;
7007718ced0SMaksim Yevmenkin } else if (be16dec(proto) == ETHERTYPE_VLAN
7017718ced0SMaksim Yevmenkin && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
7027718ced0SMaksim Yevmenkin iov[1].iov_base = pkt->ptr;
7037718ced0SMaksim Yevmenkin iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
7047718ced0SMaksim Yevmenkin } else {
7057718ced0SMaksim Yevmenkin iov[1].iov_base = NULL;
7067718ced0SMaksim Yevmenkin iov[1].iov_len = 0;
7077718ced0SMaksim Yevmenkin memset(proto, 0, ETHER_TYPE_LEN);
7087718ced0SMaksim Yevmenkin }
7097718ced0SMaksim Yevmenkin }
7107718ced0SMaksim Yevmenkin
7117718ced0SMaksim Yevmenkin if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
7127718ced0SMaksim Yevmenkin log_err("packet exceeded MTU (dropped)");
7137718ced0SMaksim Yevmenkin return false;
7147718ced0SMaksim Yevmenkin }
7157718ced0SMaksim Yevmenkin
7167718ced0SMaksim Yevmenkin nw = writev(chan->fd, iov, __arraycount(iov));
7177718ced0SMaksim Yevmenkin return (nw > 0);
7187718ced0SMaksim Yevmenkin }
7197718ced0SMaksim Yevmenkin
7207718ced0SMaksim Yevmenkin static bool
bnep_pfilter(channel_t * chan,packet_t * pkt)7217718ced0SMaksim Yevmenkin bnep_pfilter(channel_t *chan, packet_t *pkt)
7227718ced0SMaksim Yevmenkin {
7237718ced0SMaksim Yevmenkin int proto, i;
7247718ced0SMaksim Yevmenkin
7257718ced0SMaksim Yevmenkin proto = be16dec(pkt->type);
7267718ced0SMaksim Yevmenkin if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
7277718ced0SMaksim Yevmenkin if (pkt->len < 4)
7287718ced0SMaksim Yevmenkin return false;
7297718ced0SMaksim Yevmenkin
7307718ced0SMaksim Yevmenkin proto = be16dec(pkt->ptr + 2);
7317718ced0SMaksim Yevmenkin }
7327718ced0SMaksim Yevmenkin
7337718ced0SMaksim Yevmenkin for (i = 0; i < chan->npfilter; i++) {
7347718ced0SMaksim Yevmenkin if (chan->pfilter[i].start <= proto
7357718ced0SMaksim Yevmenkin && chan->pfilter[i].end >=proto)
7367718ced0SMaksim Yevmenkin return true;
7377718ced0SMaksim Yevmenkin }
7387718ced0SMaksim Yevmenkin
7397718ced0SMaksim Yevmenkin return false;
7407718ced0SMaksim Yevmenkin }
7417718ced0SMaksim Yevmenkin
7427718ced0SMaksim Yevmenkin static bool
bnep_mfilter(channel_t * chan,packet_t * pkt)7437718ced0SMaksim Yevmenkin bnep_mfilter(channel_t *chan, packet_t *pkt)
7447718ced0SMaksim Yevmenkin {
7457718ced0SMaksim Yevmenkin int i;
7467718ced0SMaksim Yevmenkin
7477718ced0SMaksim Yevmenkin if (!ETHER_IS_MULTICAST(pkt->dst))
7487718ced0SMaksim Yevmenkin return true;
7497718ced0SMaksim Yevmenkin
7507718ced0SMaksim Yevmenkin for (i = 0; i < chan->nmfilter; i++) {
7517718ced0SMaksim Yevmenkin if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
7527718ced0SMaksim Yevmenkin && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
7537718ced0SMaksim Yevmenkin return true;
7547718ced0SMaksim Yevmenkin }
7557718ced0SMaksim Yevmenkin
7567718ced0SMaksim Yevmenkin return false;
7577718ced0SMaksim Yevmenkin }
758