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