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