3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2018 Google LLC.
5 * Copyright (c) 2014-2017 Nest Labs, Inc.
6 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
24 * This file implements a TUN/TAP interface shim for LwIP, used
25 * when running LwIP on non-LWIP-native platforms such as BSD
26 * sockets, to interface with host OS network interfaces on such
27 * platforms and the Internet, accessed via those host OS network
30 * The APIs in this module used by the setup and intialization
31 * code of applications are:
33 * 1. TapInterface_Init
34 * 2. TapInterface_SetupNetif
35 * 3. TapInterface_Select
37 * and are generally used in the order listed.
39 * .------------------------------------------.
41 * .--.------------| Application |
42 * .--------|--|--------. | . . . |
43 * | V V | '------+-----------+-------------+---------'
45 * | LwIP | .------|-----------|-------------+---------.
47 * | .----------------. | | .-------. .------------. .---------. |
48 * | | | | | | Init | | SetupNetif | | Select |--. |
49 * | | | | | '-------' '------------' '---------' | |
51 * | | | | | .-------------. .-------------. | |
52 * | | .------------. | | | | Low Level | | Low Level | | |
53 * | | | linkoutput +-|-+---+----+> Output | | Input <+----| |
54 * | | '------------' | | | | . | | ^ | | |
55 * | | | | | '------+------' '------|------' | |
56 * | | .------------. | | | | | | |
57 * | | | input <+-+-+---+-----------|----------------|-----------' |
58 * | | '------------' | | | | | |
59 * | '----------------' | | .-------|----------------+---------. |
60 * '--------------------' | | V ' | |
61 * | | File Descriptor | |
63 * | '----------------|-----------------' |
64 * '--------------------|---------------------'
66 * .------------------|-------------------.
68 * | .--------------|---------------. |
69 * | | .------------|-------------. | |
71 * | | | TUN/TAP Shim Interface | | |
73 * | | '--------------------------' | |
75 * | | TUN/TAP Driver | |
77 * | '------------------------------' |
81 * '--------------------------------------'
83 * This file was originally adapted from 'contrib/ports/unix/port/
84 * netif/tapif.c' in the LwIP distribution.
88 /*-----------------------------------------------------------------------------------*/
90 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
91 * All rights reserved.
93 * Redistribution and use in source and binary forms, with or without modification,
94 * are permitted provided that the following conditions are met:
96 * 1. Redistributions of source code must retain the above copyright notice,
97 * this list of conditions and the following disclaimer.
98 * 2. Redistributions in binary form must reproduce the above copyright notice,
99 * this list of conditions and the following disclaimer in the documentation
100 * and/or other materials provided with the distribution.
101 * 3. The name of the author may not be used to endorse or promote products
102 * derived from this software without specific prior written permission.
104 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
105 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
106 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
107 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
108 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
109 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
110 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
111 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
112 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
115 * This file is part of the lwIP TCP/IP stack.
117 * Author: Adam Dunkels <adam@sics.se>
121 #include "TapInterface.h"
125 #include <netinet/in.h>
129 #include <sys/ioctl.h>
130 #include <sys/socket.h>
131 #include <sys/time.h>
132 #include <sys/types.h>
137 #include <linux/if.h>
138 #include <linux/if_tun.h>
139 #include <sys/ioctl.h>
140 #define DEVTAP "/dev/net/tun"
142 #elif defined(openbsd)
143 #define DEVTAP "/dev/tun0"
145 #else /* freebsd, cygwin? */
147 #define DEVTAP "/dev/tap0"
150 #include <lwip/ethip6.h>
151 #include <lwip/mem.h>
152 #include <lwip/snmp.h>
153 #include <lwip/stats.h>
154 #include <netif/etharp.h>
156 /* Global Variables */
158 static const size_t kMacLength = sizeof(((TapInterface *) (0))->macAddr);
161 * This is the LwIP TUN/TAP shim interface low level output method.
163 * When the native LwIP stack has output for its native interface, \c
164 * netif, associated with the LwIP TUN/TAP shim interface, LwIP
165 * invokes this method to drive the specified buffer to the shim
168 * @param[in] netif A pointer to the LwIP native interface
169 * associated with the TUN/TAP shim interface
170 * onto which the output should be driven.
172 * @param[in] buf A pointer to the packet buffer containing the
173 * output to drive onto the shim interface.
175 * @retval #ERR_OK on successfully driving the buffer onto the
178 * @retval #ERR_MEM if an encapsulation buffer cannot be allocated.
180 * @retval #ERR_BUF if the allocated encapsulation buffer is not big
181 * enough to encapsulate the output data.
183 * @retval #ERR_IF if the output data cannot be driven onto the shim
186 * @sa #TapInterface_SetupNetif
189 static err_t TapInterface_low_level_output(struct netif * netif, struct pbuf * buf)
191 const TapInterface * tapif = (const TapInterface *) (netif->state);
192 err_t retval = ERR_OK;
193 struct pbuf * outBuf;
196 if (buf->tot_len > buf->len)
198 // Allocate a buffer from the buffer pool. Fail if none available.
199 outBuf = pbuf_alloc(PBUF_RAW, buf->tot_len + PBUF_LINK_ENCAPSULATION_HLEN, PBUF_POOL);
202 fprintf(stderr, "TapInterface: Failed to allocate buffer\n");
207 // Fail if the buffer is not big enough to hold the output data.
208 if (outBuf->tot_len != outBuf->len)
210 fprintf(stderr, "TapInterface: Output data bigger than single PBUF\n");
215 // Reserve the space needed by WICED for its buffer management.
216 pbuf_header(outBuf, -PBUF_LINK_ENCAPSULATION_HLEN);
218 // Copy output data to the new buffer.
219 retval = pbuf_copy(outBuf, buf);
220 if (retval != ERR_OK)
224 // Otherwise send using the supplied buffer.
228 written = write(tapif->fd, outBuf->payload, outBuf->tot_len);
231 snmp_inc_ifoutdiscards(netif);
232 perror("TapInterface: write failed");
237 snmp_add_ifoutoctets(netif, written);
241 if (outBuf != NULL && outBuf != buf)
248 * This is the LwIP TUN/TAP shim interface low level input method.
250 * When input has been identified as pending on the LwIP TUN/TAP shim
251 * interface, this API allocates a buffer and reads the packet from
252 * the underlying host OS into the buffer and returns it.
254 * @param[in] tapif A pointer to the LwIP TUN/TAP shim interface
255 * from which to read pending input.
257 * @param[in] netif A pointer to the LwIP native interface
258 * associated with the TUN/TAP shim interface.
260 * @returns A pointer to the buffer containing the read input on
261 * success; otherwise, NULL on error.
263 * @sa #TapInterface_Select
266 static struct pbuf * TapInterface_low_level_input(TapInterface * tapif, struct netif * netif)
273 /* Obtain the size of the packet and put it into the "len"
275 len = read(tapif->fd, buf, sizeof(buf));
276 snmp_add_ifinoctets(netif, len);
278 /* We allocate a pbuf chain of pbufs from the pool. */
279 p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
283 /* We iterate over the pbuf chain until we have read the entire
284 packet into the pbuf. */
286 for (q = p; q != NULL; q = q->next)
288 /* Read enough bytes to fill this pbuf in the chain. The
289 available data in the pbuf is given by the q->len
291 /* read data into(q->payload, q->len); */
292 memcpy(q->payload, bufptr, q->len);
295 /* acknowledge that packet has been read(); */
300 snmp_inc_ifindiscards(netif);
301 printf("Could not allocate pbufs\n");
308 * LwIP netif_add setup callback function for LwIP TUN/TAP shim
311 * The interface mimics / effects an Ethernet-like interface and,
312 * consequently, reuses and leverages existing LwIP low-level APIs
313 * for such interfaces.
315 * This interface should / will be called by LwIP's netif_add
316 * function for a LwIP TUN/TAP shim interface. \c #TapInterface_Init
317 * should have been called prior to invoking netif_add with this
320 * @param[in,out] netif A pointer to the LwIP netif associated with the
321 * TUN/TAP shim interface.
323 * @retval #ERR_OK on successfully setting up the TUN/TAP interface.
325 * @sa #TapInterface_Init
326 * @sa #TapInterface_Select
329 err_t TapInterface_SetupNetif(struct netif * netif)
331 const TapInterface * tapif = (const TapInterface *) (netif->state);
333 /* As far as LwIP is concerned, the network interface is an
334 * Ethernet-like interface, so set it up accordingly, reusing
335 * existing LwIP APIs for such interfaces where possible.
338 netif->name[0] = tapif->interfaceName[0];
339 netif->name[1] = tapif->interfaceName[1];
340 netif->output = etharp_output;
342 netif->output_ip6 = ethip6_output;
343 #endif /* LWIP_IPV6 */
344 netif->linkoutput = TapInterface_low_level_output;
347 netif->flags |= (NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP);
349 netif->flags |= (NETIF_FLAG_IGMP);
352 netif->flags |= (NETIF_FLAG_MLD6);
355 netif->hwaddr_len = kMacLength;
357 memcpy(netif->hwaddr, tapif->macAddr, kMacLength);
363 * Establish an LwIP TUN/TAP interface on the underlying host OS with
364 * the specified name.
366 * This interface should be invoked before either \c #TapInterface_SetupNetif
367 * or \c #TapInterface_Select are invoked.
369 * @param[out] tapif A pointer to storage for the established
370 * TUN/TAP interface details.
372 * @param[in] interfaceName A pointer to a NULL-terminated C string
373 * containing the name of the TUN/TAP interface.
375 * @param[in] macAddr An optional pointer to the MAC address to be
376 * used for the TUN/TAP interface.
378 * @retval #ERR_OK on successfully establishing the TUN/TAP
381 * @retval #ERR_ARG if \c tapif is NULL or if \c interfaceName is
384 * @retval #ERR_IF if the OS-specific TUN/TAP driver cannot be
385 * opened or if the requested TUN/TAP device
388 * @sa #TapInterface_SetupNetif
389 * @sa #TapInterface_Select
392 err_t TapInterface_Init(TapInterface * tapif, const char * interfaceName, u8_t * macAddr)
398 /* The TUN/TAP interface storage pointer is required; error out if
399 * it hasn't been provided.
405 /* Set the TUN/TAP interface storage to initial defaults.
408 memset(tapif, 0, sizeof(*tapif));
411 /* Intialize the TUN/TAP interface name and MAC address. If the
412 * optional MAC address was not provided, use the current process
413 * identifier as a MAC address.
416 tapif->interfaceName = interfaceName;
420 memcpy(tapif->macAddr, macAddr, kMacLength);
424 const u32_t pid = htonl((u32_t) getpid());
425 memset(tapif->macAddr, 0, kMacLength);
426 memcpy(tapif->macAddr + 2, &pid, sizeof(pid));
429 /* Attempt to open the OS-specific TUN/TAP driver control interface.
432 tapif->fd = open(DEVTAP, O_RDWR);
435 perror("TapInterface: unable to open " DEVTAP);
440 /* On Linux, prepare and issue the TUNSETIFF ioctl to establish a
441 * TAP interface (IFF_TAP) with the previously-specified name and
442 * no packet information (IFF_NO_PI).
445 memset(&ifr, 0, sizeof(ifr));
446 ifr.ifr_flags = (IFF_TAP | IFF_NO_PI);
448 if (strlen(tapif->interfaceName) >= sizeof(ifr.ifr_name))
450 perror("TapInterface: invalid device name");
454 strcpy(ifr.ifr_name, tapif->interfaceName);
456 if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0)
458 perror("TapInterface: ioctl(TUNSETIFF) failed");
463 #warning "The LwIP TAP/TUN interface may not be fully-supported on your platform."
464 #endif /* defined(linux) */
470 * Check the LwIP TUN/TAP shim interface to see if any input / read
471 * activity is pending and, if there is, process it.
473 * @param[in] tapif An array of LwIP TUN/TAP shim interfaces
474 * to check and, if necessary, to process the
477 * @param[in] netif An array of the LwIP native interfaces
478 * associated with the TUN/TAP shim interface.
480 * @param[in] sleepTime The interval that the call should block for
483 * @param[in] numIntfs The number of elements in the tapif and netif arrays.
485 * @retval >= 0 on a successful check and/or processing of pending input.
487 * @retval -EINVAL if either \c tapif or \c netif are NULL.
489 * @sa #TapInterface_Init
490 * @sa #TapInterface_SetupNetif
493 int TapInterface_Select(TapInterface * tapif, struct netif * netif, struct timeval sleepTime, size_t numIntfs)
499 if ((tapif == NULL) || (netif == NULL) || (numIntfs == 0))
506 for (j = 0; j < numIntfs; j++)
508 FD_SET(tapif[j].fd, &readfds);
511 ret = select(tapif[numIntfs - 1].fd + 1, &readfds, NULL, NULL, &sleepTime);
514 for (j = 0; j < numIntfs; j++)
516 if (!FD_ISSET(tapif[j].fd, &readfds))
519 struct pbuf * p = TapInterface_low_level_input(&(tapif[j]), &(netif[j]));
523 lwip_stats.link.recv++;
524 #endif /* LINK_STATS */
526 netif[j].input(p, &(netif[j]));