1*f7ab42a5SMatthias Ringwald /* 2*f7ab42a5SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*f7ab42a5SMatthias Ringwald * 4*f7ab42a5SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*f7ab42a5SMatthias Ringwald * modification, are permitted provided that the following conditions 6*f7ab42a5SMatthias Ringwald * are met: 7*f7ab42a5SMatthias Ringwald * 8*f7ab42a5SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*f7ab42a5SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*f7ab42a5SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*f7ab42a5SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*f7ab42a5SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*f7ab42a5SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*f7ab42a5SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*f7ab42a5SMatthias Ringwald * from this software without specific prior written permission. 16*f7ab42a5SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*f7ab42a5SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*f7ab42a5SMatthias Ringwald * monetary gain. 19*f7ab42a5SMatthias Ringwald * 20*f7ab42a5SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*f7ab42a5SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*f7ab42a5SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*f7ab42a5SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*f7ab42a5SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*f7ab42a5SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*f7ab42a5SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*f7ab42a5SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*f7ab42a5SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*f7ab42a5SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*f7ab42a5SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*f7ab42a5SMatthias Ringwald * SUCH DAMAGE. 32*f7ab42a5SMatthias Ringwald * 33*f7ab42a5SMatthias Ringwald * Please inquire about commercial licensing options at 34*f7ab42a5SMatthias Ringwald * [email protected] 35*f7ab42a5SMatthias Ringwald * 36*f7ab42a5SMatthias Ringwald */ 37*f7ab42a5SMatthias Ringwald 38*f7ab42a5SMatthias Ringwald #define __BTSTACK_FILE__ "btstack_network.c" 39*f7ab42a5SMatthias Ringwald 40*f7ab42a5SMatthias Ringwald /* 41*f7ab42a5SMatthias Ringwald * btstack_network.c 42*f7ab42a5SMatthias Ringwald * Implementation of the btstack_network.h interface for POSIX systems 43*f7ab42a5SMatthias Ringwald */ 44*f7ab42a5SMatthias Ringwald 45*f7ab42a5SMatthias Ringwald 46*f7ab42a5SMatthias Ringwald #include "btstack_network.h" 47*f7ab42a5SMatthias Ringwald 48*f7ab42a5SMatthias Ringwald #include "btstack_config.h" 49*f7ab42a5SMatthias Ringwald 50*f7ab42a5SMatthias Ringwald #include <arpa/inet.h> 51*f7ab42a5SMatthias Ringwald #include <errno.h> 52*f7ab42a5SMatthias Ringwald #include <fcntl.h> 53*f7ab42a5SMatthias Ringwald #include <ifaddrs.h> 54*f7ab42a5SMatthias Ringwald #include <stdint.h> 55*f7ab42a5SMatthias Ringwald #include <stdio.h> 56*f7ab42a5SMatthias Ringwald #include <stdlib.h> 57*f7ab42a5SMatthias Ringwald #include <string.h> 58*f7ab42a5SMatthias Ringwald #include <unistd.h> 59*f7ab42a5SMatthias Ringwald 60*f7ab42a5SMatthias Ringwald #include <net/if_arp.h> 61*f7ab42a5SMatthias Ringwald 62*f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 63*f7ab42a5SMatthias Ringwald #include <net/if.h> 64*f7ab42a5SMatthias Ringwald #include <net/if_types.h> 65*f7ab42a5SMatthias Ringwald 66*f7ab42a5SMatthias Ringwald #include <netinet/if_ether.h> 67*f7ab42a5SMatthias Ringwald #include <netinet/in.h> 68*f7ab42a5SMatthias Ringwald #endif 69*f7ab42a5SMatthias Ringwald 70*f7ab42a5SMatthias Ringwald #include <sys/ioctl.h> 71*f7ab42a5SMatthias Ringwald #include <sys/param.h> 72*f7ab42a5SMatthias Ringwald #include <sys/socket.h> 73*f7ab42a5SMatthias Ringwald #include <sys/stat.h> 74*f7ab42a5SMatthias Ringwald #include <sys/types.h> 75*f7ab42a5SMatthias Ringwald 76*f7ab42a5SMatthias Ringwald #ifdef __linux 77*f7ab42a5SMatthias Ringwald #include <linux/if.h> 78*f7ab42a5SMatthias Ringwald #include <linux/if_tun.h> 79*f7ab42a5SMatthias Ringwald #endif 80*f7ab42a5SMatthias Ringwald 81*f7ab42a5SMatthias Ringwald #include "btstack.h" 82*f7ab42a5SMatthias Ringwald 83*f7ab42a5SMatthias Ringwald static int tap_fd = -1; 84*f7ab42a5SMatthias Ringwald static uint8_t network_buffer[BNEP_MTU_MIN]; 85*f7ab42a5SMatthias Ringwald static size_t network_buffer_len = 0; 86*f7ab42a5SMatthias Ringwald 87*f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 88*f7ab42a5SMatthias Ringwald // tuntaposx provides fixed set of tapX devices 89*f7ab42a5SMatthias Ringwald static const char * tap_dev = "/dev/tap0"; 90*f7ab42a5SMatthias Ringwald static char tap_dev_name[16] = "tap0"; 91*f7ab42a5SMatthias Ringwald #endif 92*f7ab42a5SMatthias Ringwald 93*f7ab42a5SMatthias Ringwald #ifdef __linux 94*f7ab42a5SMatthias Ringwald // Linux uses single control device to bring up tunX or tapX interface 95*f7ab42a5SMatthias Ringwald static const char * tap_dev = "/dev/net/tun"; 96*f7ab42a5SMatthias Ringwald static char tap_dev_name[16] = "bnep%d"; 97*f7ab42a5SMatthias Ringwald #endif 98*f7ab42a5SMatthias Ringwald 99*f7ab42a5SMatthias Ringwald static btstack_data_source_t tap_dev_ds; 100*f7ab42a5SMatthias Ringwald 101*f7ab42a5SMatthias Ringwald static void (*btstack_network_send_packet_callback)(const uint8_t * packet, uint16_t size); 102*f7ab42a5SMatthias Ringwald 103*f7ab42a5SMatthias Ringwald /* 104*f7ab42a5SMatthias Ringwald * @text Listing processTapData shows how a packet is received from the TAP network interface 105*f7ab42a5SMatthias Ringwald * and forwarded over the BNEP connection. 106*f7ab42a5SMatthias Ringwald * 107*f7ab42a5SMatthias Ringwald * After successfully reading a network packet, the call to 108*f7ab42a5SMatthias Ringwald * the *bnep_can_send_packet_now* function checks, if BTstack can forward 109*f7ab42a5SMatthias Ringwald * a network packet now. If that's not possible, the received data stays 110*f7ab42a5SMatthias Ringwald * in the network buffer and the data source elements is removed from the 111*f7ab42a5SMatthias Ringwald * run loop. The *process_tap_dev_data* function will not be called until 112*f7ab42a5SMatthias Ringwald * the data source is registered again. This provides a basic flow control. 113*f7ab42a5SMatthias Ringwald */ 114*f7ab42a5SMatthias Ringwald 115*f7ab42a5SMatthias Ringwald /* LISTING_START(processTapData): Process incoming network packets */ 116*f7ab42a5SMatthias Ringwald static void process_tap_dev_data(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) 117*f7ab42a5SMatthias Ringwald { 118*f7ab42a5SMatthias Ringwald UNUSED(ds); 119*f7ab42a5SMatthias Ringwald UNUSED(callback_type); 120*f7ab42a5SMatthias Ringwald 121*f7ab42a5SMatthias Ringwald ssize_t len; 122*f7ab42a5SMatthias Ringwald len = read(ds->fd, network_buffer, sizeof(network_buffer)); 123*f7ab42a5SMatthias Ringwald if (len <= 0){ 124*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error while reading: %s\n", strerror(errno)); 125*f7ab42a5SMatthias Ringwald return; 126*f7ab42a5SMatthias Ringwald } 127*f7ab42a5SMatthias Ringwald 128*f7ab42a5SMatthias Ringwald network_buffer_len = len; 129*f7ab42a5SMatthias Ringwald 130*f7ab42a5SMatthias Ringwald // disable reading from netif 131*f7ab42a5SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 132*f7ab42a5SMatthias Ringwald 133*f7ab42a5SMatthias Ringwald // let client now 134*f7ab42a5SMatthias Ringwald (*btstack_network_send_packet_callback)(network_buffer, network_buffer_len); 135*f7ab42a5SMatthias Ringwald } 136*f7ab42a5SMatthias Ringwald 137*f7ab42a5SMatthias Ringwald /** 138*f7ab42a5SMatthias Ringwald * @brief Initialize network interface 139*f7ab42a5SMatthias Ringwald * @param send_packet_callback 140*f7ab42a5SMatthias Ringwald */ 141*f7ab42a5SMatthias Ringwald void btstack_network_init(void (*send_packet_callback)(const uint8_t * packet, uint16_t size)){ 142*f7ab42a5SMatthias Ringwald btstack_network_send_packet_callback = send_packet_callback; 143*f7ab42a5SMatthias Ringwald } 144*f7ab42a5SMatthias Ringwald 145*f7ab42a5SMatthias Ringwald /** 146*f7ab42a5SMatthias Ringwald * @text This code requries a TUN/TAP interface to connect the Bluetooth network interface 147*f7ab42a5SMatthias Ringwald * with the native system. It has been tested on Linux and OS X, but should work on any 148*f7ab42a5SMatthias Ringwald * system that provides TUN/TAP with minor modifications. 149*f7ab42a5SMatthias Ringwald * 150*f7ab42a5SMatthias Ringwald * On Linux, TUN/TAP is available by default. On OS X, tuntaposx from 151*f7ab42a5SMatthias Ringwald * http://tuntaposx.sourceforge.net needs to be installed. 152*f7ab42a5SMatthias Ringwald * 153*f7ab42a5SMatthias Ringwald * The *tap_alloc* function sets up a virtual network interface with the given Bluetooth Address. 154*f7ab42a5SMatthias Ringwald * It is rather low-level as it sets up and configures a network interface. 155*f7ab42a5SMatthias Ringwald * 156*f7ab42a5SMatthias Ringwald * @brief Bring up network interfacd 157*f7ab42a5SMatthias Ringwald * @param network_address 158*f7ab42a5SMatthias Ringwald * @return 0 if ok 159*f7ab42a5SMatthias Ringwald */ 160*f7ab42a5SMatthias Ringwald int btstack_network_up(bd_addr_t network_address){ 161*f7ab42a5SMatthias Ringwald 162*f7ab42a5SMatthias Ringwald struct ifreq ifr; 163*f7ab42a5SMatthias Ringwald int fd_dev; 164*f7ab42a5SMatthias Ringwald int fd_socket; 165*f7ab42a5SMatthias Ringwald char * dev; 166*f7ab42a5SMatthias Ringwald 167*f7ab42a5SMatthias Ringwald if( (fd_dev = open(tap_dev, O_RDWR)) < 0 ) { 168*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error opening %s: %s\n", tap_dev, strerror(errno)); 169*f7ab42a5SMatthias Ringwald return -1; 170*f7ab42a5SMatthias Ringwald } 171*f7ab42a5SMatthias Ringwald 172*f7ab42a5SMatthias Ringwald #ifdef __linux 173*f7ab42a5SMatthias Ringwald memset(&ifr, 0, sizeof(ifr)); 174*f7ab42a5SMatthias Ringwald 175*f7ab42a5SMatthias Ringwald ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 176*f7ab42a5SMatthias Ringwald if( *dev ) { 177*f7ab42a5SMatthias Ringwald strncpy(ifr.ifr_name, dev, IFNAMSIZ); 178*f7ab42a5SMatthias Ringwald } 179*f7ab42a5SMatthias Ringwald 180*f7ab42a5SMatthias Ringwald int err; 181*f7ab42a5SMatthias Ringwald if( (err = ioctl(fd_dev, TUNSETIFF, (void *) &ifr)) < 0 ) { 182*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting device name: %s\n", strerror(errno)); 183*f7ab42a5SMatthias Ringwald close(fd_dev); 184*f7ab42a5SMatthias Ringwald return -1; 185*f7ab42a5SMatthias Ringwald } 186*f7ab42a5SMatthias Ringwald dev = ifr.ifr_name; 187*f7ab42a5SMatthias Ringwald #endif 188*f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 189*f7ab42a5SMatthias Ringwald dev = tap_dev_name; 190*f7ab42a5SMatthias Ringwald #endif 191*f7ab42a5SMatthias Ringwald 192*f7ab42a5SMatthias Ringwald fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 193*f7ab42a5SMatthias Ringwald if (fd_socket < 0) { 194*f7ab42a5SMatthias Ringwald close(fd_dev); 195*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error opening netlink socket: %s\n", strerror(errno)); 196*f7ab42a5SMatthias Ringwald return -1; 197*f7ab42a5SMatthias Ringwald } 198*f7ab42a5SMatthias Ringwald 199*f7ab42a5SMatthias Ringwald // Configure the MAC address of the newly created bnep(x) 200*f7ab42a5SMatthias Ringwald // device to the local bd_address 201*f7ab42a5SMatthias Ringwald memset (&ifr, 0, sizeof(struct ifreq)); 202*f7ab42a5SMatthias Ringwald strcpy(ifr.ifr_name, dev); 203*f7ab42a5SMatthias Ringwald #ifdef __linux 204*f7ab42a5SMatthias Ringwald ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 205*f7ab42a5SMatthias Ringwald memcpy(ifr.ifr_hwaddr.sa_data, network_address, sizeof(bd_addr_t)); 206*f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFHWADDR, &ifr) == -1) { 207*f7ab42a5SMatthias Ringwald close(fd_dev); 208*f7ab42a5SMatthias Ringwald close(fd_socket); 209*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting hw addr: %s\n", strerror(errno)); 210*f7ab42a5SMatthias Ringwald exit(1); 211*f7ab42a5SMatthias Ringwald return -1; 212*f7ab42a5SMatthias Ringwald } 213*f7ab42a5SMatthias Ringwald #endif 214*f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 215*f7ab42a5SMatthias Ringwald ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; 216*f7ab42a5SMatthias Ringwald ifr.ifr_addr.sa_family = AF_LINK; 217*f7ab42a5SMatthias Ringwald (void)memcpy(ifr.ifr_addr.sa_data, network_address, ETHER_ADDR_LEN); 218*f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFLLADDR, &ifr) == -1) { 219*f7ab42a5SMatthias Ringwald close(fd_dev); 220*f7ab42a5SMatthias Ringwald close(fd_socket); 221*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting hw addr: %s\n", strerror(errno)); 222*f7ab42a5SMatthias Ringwald exit(1); 223*f7ab42a5SMatthias Ringwald return -1; 224*f7ab42a5SMatthias Ringwald } 225*f7ab42a5SMatthias Ringwald #endif 226*f7ab42a5SMatthias Ringwald 227*f7ab42a5SMatthias Ringwald // Bring the interface up 228*f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCGIFFLAGS, &ifr) == -1) { 229*f7ab42a5SMatthias Ringwald close(fd_dev); 230*f7ab42a5SMatthias Ringwald close(fd_socket); 231*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error reading interface flags: %s\n", strerror(errno)); 232*f7ab42a5SMatthias Ringwald return -1; 233*f7ab42a5SMatthias Ringwald } 234*f7ab42a5SMatthias Ringwald 235*f7ab42a5SMatthias Ringwald if ((ifr.ifr_flags & IFF_UP) == 0) { 236*f7ab42a5SMatthias Ringwald ifr.ifr_flags |= IFF_UP; 237*f7ab42a5SMatthias Ringwald 238*f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFFLAGS, &ifr) == -1) { 239*f7ab42a5SMatthias Ringwald close(fd_dev); 240*f7ab42a5SMatthias Ringwald close(fd_socket); 241*f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error set IFF_UP: %s\n", strerror(errno)); 242*f7ab42a5SMatthias Ringwald return -1; 243*f7ab42a5SMatthias Ringwald } 244*f7ab42a5SMatthias Ringwald } 245*f7ab42a5SMatthias Ringwald 246*f7ab42a5SMatthias Ringwald close(fd_socket); 247*f7ab42a5SMatthias Ringwald 248*f7ab42a5SMatthias Ringwald tap_fd = fd_dev; 249*f7ab42a5SMatthias Ringwald log_info("BNEP device \"%s\" allocated", tap_dev_name); 250*f7ab42a5SMatthias Ringwald 251*f7ab42a5SMatthias Ringwald /* Create and register a new runloop data source */ 252*f7ab42a5SMatthias Ringwald btstack_run_loop_set_data_source_fd(&tap_dev_ds, tap_fd); 253*f7ab42a5SMatthias Ringwald btstack_run_loop_set_data_source_handler(&tap_dev_ds, &process_tap_dev_data); 254*f7ab42a5SMatthias Ringwald btstack_run_loop_add_data_source(&tap_dev_ds); 255*f7ab42a5SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 256*f7ab42a5SMatthias Ringwald 257*f7ab42a5SMatthias Ringwald return 0;; 258*f7ab42a5SMatthias Ringwald } 259*f7ab42a5SMatthias Ringwald 260*f7ab42a5SMatthias Ringwald /** 261*f7ab42a5SMatthias Ringwald * @brief Bring up network interfacd 262*f7ab42a5SMatthias Ringwald * @param network_address 263*f7ab42a5SMatthias Ringwald * @return 0 if ok 264*f7ab42a5SMatthias Ringwald */ 265*f7ab42a5SMatthias Ringwald int btstack_network_down(void){ 266*f7ab42a5SMatthias Ringwald log_info("BNEP channel closed"); 267*f7ab42a5SMatthias Ringwald btstack_run_loop_remove_data_source(&tap_dev_ds); 268*f7ab42a5SMatthias Ringwald tap_fd = -1; 269*f7ab42a5SMatthias Ringwald return 0; 270*f7ab42a5SMatthias Ringwald } 271*f7ab42a5SMatthias Ringwald 272*f7ab42a5SMatthias Ringwald /** 273*f7ab42a5SMatthias Ringwald * @brief Receive packet on network interface, e.g., forward packet to TCP/IP stack 274*f7ab42a5SMatthias Ringwald * @param packet 275*f7ab42a5SMatthias Ringwald * @param size 276*f7ab42a5SMatthias Ringwald */ 277*f7ab42a5SMatthias Ringwald void btstack_network_process_packet(const uint8_t * packet, uint16_t size){ 278*f7ab42a5SMatthias Ringwald 279*f7ab42a5SMatthias Ringwald if (tap_fd < 0) return; 280*f7ab42a5SMatthias Ringwald // Write out the ethernet frame to the tap device 281*f7ab42a5SMatthias Ringwald 282*f7ab42a5SMatthias Ringwald int rc = write(tap_fd, packet, size); 283*f7ab42a5SMatthias Ringwald if (rc < 0) { 284*f7ab42a5SMatthias Ringwald log_error("TAP: Could not write to TAP device: %s", strerror(errno)); 285*f7ab42a5SMatthias Ringwald } else 286*f7ab42a5SMatthias Ringwald if (rc != size) { 287*f7ab42a5SMatthias Ringwald log_error("TAP: Package written only partially %d of %d bytes", rc, size); 288*f7ab42a5SMatthias Ringwald } 289*f7ab42a5SMatthias Ringwald } 290*f7ab42a5SMatthias Ringwald 291*f7ab42a5SMatthias Ringwald /** 292*f7ab42a5SMatthias Ringwald * @brief Notify network interface that packet from send_packet_callback was sent and the next packet can be delivered. 293*f7ab42a5SMatthias Ringwald */ 294*f7ab42a5SMatthias Ringwald void btstack_network_packet_sent(void){ 295*f7ab42a5SMatthias Ringwald 296*f7ab42a5SMatthias Ringwald network_buffer_len = 0; 297*f7ab42a5SMatthias Ringwald 298*f7ab42a5SMatthias Ringwald // Re-enable the tap device data source 299*f7ab42a5SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 300*f7ab42a5SMatthias Ringwald } 301*f7ab42a5SMatthias Ringwald 302*f7ab42a5SMatthias Ringwald 303