btstack_network_posix.c 9.6 KB

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