xref: /btstack/platform/posix/btstack_network_posix.c (revision 398a95ec8e0d408db97ed8e80c67c74e30698a03)
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;
8684693d68SMatthias 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";
9184693d68SMatthias 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";
9784693d68SMatthias 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;
123*398a95ecSMatthias Ringwald     len = read(ds->source.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;
17584693d68SMatthias 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     }
18384693d68SMatthias Ringwald     strcpy(tap_dev_name, ifr.ifr_name);
184f7ab42a5SMatthias Ringwald #endif
185f7ab42a5SMatthias Ringwald #ifdef __APPLE__
18684693d68SMatthias 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));
19984693d68SMatthias 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 /**
25884693d68SMatthias Ringwald  * @brief Get network name after network was activated
25984693d68SMatthias Ringwald  * @note e.g. tapX on Linux, might not be useful on all platforms
26084693d68SMatthias Ringwald  * @returns network name
26184693d68SMatthias Ringwald  */
26284693d68SMatthias Ringwald const char * btstack_network_get_name(void){
26384693d68SMatthias Ringwald     return tap_dev_name;
26484693d68SMatthias Ringwald }
26584693d68SMatthias Ringwald 
26684693d68SMatthias 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 }
307