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 38f7ab42a5SMatthias Ringwald #define __BTSTACK_FILE__ "btstack_network.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> 54f7ab42a5SMatthias Ringwald #include <stdint.h> 55f7ab42a5SMatthias Ringwald #include <stdio.h> 56f7ab42a5SMatthias Ringwald #include <stdlib.h> 57f7ab42a5SMatthias Ringwald #include <string.h> 58f7ab42a5SMatthias Ringwald #include <unistd.h> 59f7ab42a5SMatthias Ringwald 60f7ab42a5SMatthias Ringwald #include <net/if_arp.h> 61f7ab42a5SMatthias Ringwald 62f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 63f7ab42a5SMatthias Ringwald #include <net/if.h> 64f7ab42a5SMatthias Ringwald #include <net/if_types.h> 65f7ab42a5SMatthias Ringwald 66f7ab42a5SMatthias Ringwald #include <netinet/if_ether.h> 67f7ab42a5SMatthias Ringwald #include <netinet/in.h> 68f7ab42a5SMatthias Ringwald #endif 69f7ab42a5SMatthias Ringwald 70f7ab42a5SMatthias Ringwald #include <sys/ioctl.h> 71f7ab42a5SMatthias Ringwald #include <sys/param.h> 72f7ab42a5SMatthias Ringwald #include <sys/socket.h> 73f7ab42a5SMatthias Ringwald #include <sys/stat.h> 74f7ab42a5SMatthias Ringwald #include <sys/types.h> 75f7ab42a5SMatthias Ringwald 76f7ab42a5SMatthias Ringwald #ifdef __linux 77f7ab42a5SMatthias Ringwald #include <linux/if.h> 78f7ab42a5SMatthias Ringwald #include <linux/if_tun.h> 79f7ab42a5SMatthias Ringwald #endif 80f7ab42a5SMatthias Ringwald 81f7ab42a5SMatthias Ringwald #include "btstack.h" 82f7ab42a5SMatthias Ringwald 83f7ab42a5SMatthias Ringwald static int tap_fd = -1; 84f7ab42a5SMatthias Ringwald static uint8_t network_buffer[BNEP_MTU_MIN]; 85f7ab42a5SMatthias Ringwald static size_t network_buffer_len = 0; 86*84693d68SMatthias Ringwald static char tap_dev_name[16]; 87f7ab42a5SMatthias Ringwald 88f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 89f7ab42a5SMatthias Ringwald // tuntaposx provides fixed set of tapX devices 90f7ab42a5SMatthias Ringwald static const char * tap_dev = "/dev/tap0"; 91*84693d68SMatthias Ringwald static const char * tap_dev_name_template = "tap0"; 92f7ab42a5SMatthias Ringwald #endif 93f7ab42a5SMatthias Ringwald 94f7ab42a5SMatthias Ringwald #ifdef __linux 95f7ab42a5SMatthias Ringwald // Linux uses single control device to bring up tunX or tapX interface 96f7ab42a5SMatthias Ringwald static const char * tap_dev = "/dev/net/tun"; 97*84693d68SMatthias Ringwald static const char * tap_dev_name_template = "bnep%d"; 98f7ab42a5SMatthias Ringwald #endif 99f7ab42a5SMatthias Ringwald 100f7ab42a5SMatthias Ringwald static btstack_data_source_t tap_dev_ds; 101f7ab42a5SMatthias Ringwald 102f7ab42a5SMatthias Ringwald static void (*btstack_network_send_packet_callback)(const uint8_t * packet, uint16_t size); 103f7ab42a5SMatthias Ringwald 104f7ab42a5SMatthias Ringwald /* 105f7ab42a5SMatthias Ringwald * @text Listing processTapData shows how a packet is received from the TAP network interface 106f7ab42a5SMatthias Ringwald * and forwarded over the BNEP connection. 107f7ab42a5SMatthias Ringwald * 108f7ab42a5SMatthias Ringwald * After successfully reading a network packet, the call to 109f7ab42a5SMatthias Ringwald * the *bnep_can_send_packet_now* function checks, if BTstack can forward 110f7ab42a5SMatthias Ringwald * a network packet now. If that's not possible, the received data stays 111f7ab42a5SMatthias Ringwald * in the network buffer and the data source elements is removed from the 112f7ab42a5SMatthias Ringwald * run loop. The *process_tap_dev_data* function will not be called until 113f7ab42a5SMatthias Ringwald * the data source is registered again. This provides a basic flow control. 114f7ab42a5SMatthias Ringwald */ 115f7ab42a5SMatthias Ringwald 116f7ab42a5SMatthias Ringwald /* LISTING_START(processTapData): Process incoming network packets */ 117f7ab42a5SMatthias Ringwald static void process_tap_dev_data(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) 118f7ab42a5SMatthias Ringwald { 119f7ab42a5SMatthias Ringwald UNUSED(ds); 120f7ab42a5SMatthias Ringwald UNUSED(callback_type); 121f7ab42a5SMatthias Ringwald 122f7ab42a5SMatthias Ringwald ssize_t len; 123f7ab42a5SMatthias Ringwald len = read(ds->fd, network_buffer, sizeof(network_buffer)); 124f7ab42a5SMatthias Ringwald if (len <= 0){ 125f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error while reading: %s\n", strerror(errno)); 126f7ab42a5SMatthias Ringwald return; 127f7ab42a5SMatthias Ringwald } 128f7ab42a5SMatthias Ringwald 129f7ab42a5SMatthias Ringwald network_buffer_len = len; 130f7ab42a5SMatthias Ringwald 131f7ab42a5SMatthias Ringwald // disable reading from netif 132f7ab42a5SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 133f7ab42a5SMatthias Ringwald 134f7ab42a5SMatthias Ringwald // let client now 135f7ab42a5SMatthias Ringwald (*btstack_network_send_packet_callback)(network_buffer, network_buffer_len); 136f7ab42a5SMatthias Ringwald } 137f7ab42a5SMatthias Ringwald 138f7ab42a5SMatthias Ringwald /** 139f7ab42a5SMatthias Ringwald * @brief Initialize network interface 140f7ab42a5SMatthias Ringwald * @param send_packet_callback 141f7ab42a5SMatthias Ringwald */ 142f7ab42a5SMatthias Ringwald void btstack_network_init(void (*send_packet_callback)(const uint8_t * packet, uint16_t size)){ 143f7ab42a5SMatthias Ringwald btstack_network_send_packet_callback = send_packet_callback; 144f7ab42a5SMatthias Ringwald } 145f7ab42a5SMatthias Ringwald 146f7ab42a5SMatthias Ringwald /** 147f7ab42a5SMatthias Ringwald * @text This code requries a TUN/TAP interface to connect the Bluetooth network interface 148f7ab42a5SMatthias Ringwald * with the native system. It has been tested on Linux and OS X, but should work on any 149f7ab42a5SMatthias Ringwald * system that provides TUN/TAP with minor modifications. 150f7ab42a5SMatthias Ringwald * 151f7ab42a5SMatthias Ringwald * On Linux, TUN/TAP is available by default. On OS X, tuntaposx from 152f7ab42a5SMatthias Ringwald * http://tuntaposx.sourceforge.net needs to be installed. 153f7ab42a5SMatthias Ringwald * 154f7ab42a5SMatthias Ringwald * The *tap_alloc* function sets up a virtual network interface with the given Bluetooth Address. 155f7ab42a5SMatthias Ringwald * It is rather low-level as it sets up and configures a network interface. 156f7ab42a5SMatthias Ringwald * 157f7ab42a5SMatthias Ringwald * @brief Bring up network interfacd 158f7ab42a5SMatthias Ringwald * @param network_address 159f7ab42a5SMatthias Ringwald * @return 0 if ok 160f7ab42a5SMatthias Ringwald */ 161f7ab42a5SMatthias Ringwald int btstack_network_up(bd_addr_t network_address){ 162f7ab42a5SMatthias Ringwald 163f7ab42a5SMatthias Ringwald struct ifreq ifr; 164f7ab42a5SMatthias Ringwald int fd_dev; 165f7ab42a5SMatthias Ringwald int fd_socket; 166f7ab42a5SMatthias Ringwald 167f7ab42a5SMatthias Ringwald if( (fd_dev = open(tap_dev, O_RDWR)) < 0 ) { 168f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error opening %s: %s\n", tap_dev, strerror(errno)); 169f7ab42a5SMatthias Ringwald return -1; 170f7ab42a5SMatthias Ringwald } 171f7ab42a5SMatthias Ringwald 172f7ab42a5SMatthias Ringwald #ifdef __linux 173f7ab42a5SMatthias Ringwald memset(&ifr, 0, sizeof(ifr)); 174f7ab42a5SMatthias Ringwald ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 175*84693d68SMatthias Ringwald strncpy(ifr.ifr_name, tap_dev_name_template, IFNAMSIZ); // device name pattern 176f7ab42a5SMatthias Ringwald 177f7ab42a5SMatthias Ringwald int err; 178f7ab42a5SMatthias Ringwald if( (err = ioctl(fd_dev, TUNSETIFF, (void *) &ifr)) < 0 ) { 179f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting device name: %s\n", strerror(errno)); 180f7ab42a5SMatthias Ringwald close(fd_dev); 181f7ab42a5SMatthias Ringwald return -1; 182f7ab42a5SMatthias Ringwald } 183*84693d68SMatthias Ringwald strcpy(tap_dev_name, ifr.ifr_name); 184f7ab42a5SMatthias Ringwald #endif 185f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 186*84693d68SMatthias Ringwald strcpy(tap_dev_name, tap_dev_name_template); 187f7ab42a5SMatthias Ringwald #endif 188f7ab42a5SMatthias Ringwald 189f7ab42a5SMatthias Ringwald fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 190f7ab42a5SMatthias Ringwald if (fd_socket < 0) { 191f7ab42a5SMatthias Ringwald close(fd_dev); 192f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error opening netlink socket: %s\n", strerror(errno)); 193f7ab42a5SMatthias Ringwald return -1; 194f7ab42a5SMatthias Ringwald } 195f7ab42a5SMatthias Ringwald 196f7ab42a5SMatthias Ringwald // Configure the MAC address of the newly created bnep(x) 197f7ab42a5SMatthias Ringwald // device to the local bd_address 198f7ab42a5SMatthias Ringwald memset (&ifr, 0, sizeof(struct ifreq)); 199*84693d68SMatthias Ringwald strcpy(ifr.ifr_name, tap_dev_name); 200f7ab42a5SMatthias Ringwald #ifdef __linux 201f7ab42a5SMatthias Ringwald ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 202f7ab42a5SMatthias Ringwald memcpy(ifr.ifr_hwaddr.sa_data, network_address, sizeof(bd_addr_t)); 203f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFHWADDR, &ifr) == -1) { 204f7ab42a5SMatthias Ringwald close(fd_dev); 205f7ab42a5SMatthias Ringwald close(fd_socket); 206f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting hw addr: %s\n", strerror(errno)); 207f7ab42a5SMatthias Ringwald exit(1); 208f7ab42a5SMatthias Ringwald return -1; 209f7ab42a5SMatthias Ringwald } 210f7ab42a5SMatthias Ringwald #endif 211f7ab42a5SMatthias Ringwald #ifdef __APPLE__ 212f7ab42a5SMatthias Ringwald ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; 213f7ab42a5SMatthias Ringwald ifr.ifr_addr.sa_family = AF_LINK; 214f7ab42a5SMatthias Ringwald (void)memcpy(ifr.ifr_addr.sa_data, network_address, ETHER_ADDR_LEN); 215f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFLLADDR, &ifr) == -1) { 216f7ab42a5SMatthias Ringwald close(fd_dev); 217f7ab42a5SMatthias Ringwald close(fd_socket); 218f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error setting hw addr: %s\n", strerror(errno)); 219f7ab42a5SMatthias Ringwald exit(1); 220f7ab42a5SMatthias Ringwald return -1; 221f7ab42a5SMatthias Ringwald } 222f7ab42a5SMatthias Ringwald #endif 223f7ab42a5SMatthias Ringwald 224f7ab42a5SMatthias Ringwald // Bring the interface up 225f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCGIFFLAGS, &ifr) == -1) { 226f7ab42a5SMatthias Ringwald close(fd_dev); 227f7ab42a5SMatthias Ringwald close(fd_socket); 228f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error reading interface flags: %s\n", strerror(errno)); 229f7ab42a5SMatthias Ringwald return -1; 230f7ab42a5SMatthias Ringwald } 231f7ab42a5SMatthias Ringwald 232f7ab42a5SMatthias Ringwald if ((ifr.ifr_flags & IFF_UP) == 0) { 233f7ab42a5SMatthias Ringwald ifr.ifr_flags |= IFF_UP; 234f7ab42a5SMatthias Ringwald 235f7ab42a5SMatthias Ringwald if (ioctl(fd_socket, SIOCSIFFLAGS, &ifr) == -1) { 236f7ab42a5SMatthias Ringwald close(fd_dev); 237f7ab42a5SMatthias Ringwald close(fd_socket); 238f7ab42a5SMatthias Ringwald fprintf(stderr, "TAP: Error set IFF_UP: %s\n", strerror(errno)); 239f7ab42a5SMatthias Ringwald return -1; 240f7ab42a5SMatthias Ringwald } 241f7ab42a5SMatthias Ringwald } 242f7ab42a5SMatthias Ringwald 243f7ab42a5SMatthias Ringwald close(fd_socket); 244f7ab42a5SMatthias Ringwald 245f7ab42a5SMatthias Ringwald tap_fd = fd_dev; 246f7ab42a5SMatthias Ringwald log_info("BNEP device \"%s\" allocated", tap_dev_name); 247f7ab42a5SMatthias Ringwald 248f7ab42a5SMatthias Ringwald /* Create and register a new runloop data source */ 249f7ab42a5SMatthias Ringwald btstack_run_loop_set_data_source_fd(&tap_dev_ds, tap_fd); 250f7ab42a5SMatthias Ringwald btstack_run_loop_set_data_source_handler(&tap_dev_ds, &process_tap_dev_data); 251f7ab42a5SMatthias Ringwald btstack_run_loop_add_data_source(&tap_dev_ds); 252f7ab42a5SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 253f7ab42a5SMatthias Ringwald 254f7ab42a5SMatthias Ringwald return 0;; 255f7ab42a5SMatthias Ringwald } 256f7ab42a5SMatthias Ringwald 257f7ab42a5SMatthias Ringwald /** 258*84693d68SMatthias Ringwald * @brief Get network name after network was activated 259*84693d68SMatthias Ringwald * @note e.g. tapX on Linux, might not be useful on all platforms 260*84693d68SMatthias Ringwald * @returns network name 261*84693d68SMatthias Ringwald */ 262*84693d68SMatthias Ringwald const char * btstack_network_get_name(void){ 263*84693d68SMatthias Ringwald return tap_dev_name; 264*84693d68SMatthias Ringwald } 265*84693d68SMatthias Ringwald 266*84693d68SMatthias Ringwald /** 267f7ab42a5SMatthias Ringwald * @brief Bring up network interfacd 268f7ab42a5SMatthias Ringwald * @param network_address 269f7ab42a5SMatthias Ringwald * @return 0 if ok 270f7ab42a5SMatthias Ringwald */ 271f7ab42a5SMatthias Ringwald int btstack_network_down(void){ 272f7ab42a5SMatthias Ringwald log_info("BNEP channel closed"); 273f7ab42a5SMatthias Ringwald btstack_run_loop_remove_data_source(&tap_dev_ds); 274f7ab42a5SMatthias Ringwald tap_fd = -1; 275f7ab42a5SMatthias Ringwald return 0; 276f7ab42a5SMatthias Ringwald } 277f7ab42a5SMatthias Ringwald 278f7ab42a5SMatthias Ringwald /** 279f7ab42a5SMatthias Ringwald * @brief Receive packet on network interface, e.g., forward packet to TCP/IP stack 280f7ab42a5SMatthias Ringwald * @param packet 281f7ab42a5SMatthias Ringwald * @param size 282f7ab42a5SMatthias Ringwald */ 283f7ab42a5SMatthias Ringwald void btstack_network_process_packet(const uint8_t * packet, uint16_t size){ 284f7ab42a5SMatthias Ringwald 285f7ab42a5SMatthias Ringwald if (tap_fd < 0) return; 286f7ab42a5SMatthias Ringwald // Write out the ethernet frame to the tap device 287f7ab42a5SMatthias Ringwald 288f7ab42a5SMatthias Ringwald int rc = write(tap_fd, packet, size); 289f7ab42a5SMatthias Ringwald if (rc < 0) { 290f7ab42a5SMatthias Ringwald log_error("TAP: Could not write to TAP device: %s", strerror(errno)); 291f7ab42a5SMatthias Ringwald } else 292f7ab42a5SMatthias Ringwald if (rc != size) { 293f7ab42a5SMatthias Ringwald log_error("TAP: Package written only partially %d of %d bytes", rc, size); 294f7ab42a5SMatthias Ringwald } 295f7ab42a5SMatthias Ringwald } 296f7ab42a5SMatthias Ringwald 297f7ab42a5SMatthias Ringwald /** 298f7ab42a5SMatthias Ringwald * @brief Notify network interface that packet from send_packet_callback was sent and the next packet can be delivered. 299f7ab42a5SMatthias Ringwald */ 300f7ab42a5SMatthias Ringwald void btstack_network_packet_sent(void){ 301f7ab42a5SMatthias Ringwald 302f7ab42a5SMatthias Ringwald network_buffer_len = 0; 303f7ab42a5SMatthias Ringwald 304f7ab42a5SMatthias Ringwald // Re-enable the tap device data source 305f7ab42a5SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&tap_dev_ds, DATA_SOURCE_CALLBACK_READ); 306f7ab42a5SMatthias Ringwald } 307f7ab42a5SMatthias Ringwald 308f7ab42a5SMatthias Ringwald 309