Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / lwip / standalone / TapInterface.c
1 /*
2  *
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.
7  *    All rights reserved.
8  *
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
12  *
13  *        http://www.apache.org/licenses/LICENSE-2.0
14  *
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.
20  */
21
22 /**
23  *    @file
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
28  *      interfaces.
29  *
30  *      The APIs in this module used by the setup and intialization
31  *      code of applications are:
32  *
33  *        1. TapInterface_Init
34  *        2. TapInterface_SetupNetif
35  *        3. TapInterface_Select
36  *
37  *      and are generally used in the order listed.
38  *
39  *                               .------------------------------------------.
40  *                               |                                          |
41  *               .--.------------|               Application                |
42  *      .--------|--|--------.   |      .           .             .         |
43  *      |        V  V        |   '------+-----------+-------------+---------'
44  *      |                    |          |           |             |
45  *      |        LwIP        |   .------|-----------|-------------+---------.
46  *      |                    |   |      V           V             V         |
47  *      | .----------------. |   |  .-------. .------------. .---------.    |
48  *      | |                | |   |  | Init  | | SetupNetif | | Select  |--. |
49  *      | |                | |   |  '-------' '------------' '---------'  | |
50  *      | |     netif      | |   |                                        | |
51  *      | |                | |   |    .-------------.  .-------------.    | |
52  *      | | .------------. | |   |    |  Low Level  |  |  Low Level  |    | |
53  *      | | | linkoutput +-|-+---+----+>   Output   |  |    Input   <+----| |
54  *      | | '------------' | |   |    |      .      |  |      ^      |    | |
55  *      | |                | |   |    '------+------'  '------|------'    | |
56  *      | | .------------. | |   |           |                |           | |
57  *      | | |   input   <+-+-+---+-----------|----------------|-----------' |
58  *      | | '------------' | |   |           |                |             |
59  *      | '----------------' |   |   .-------|----------------+---------.   |
60  *      '--------------------'   |   |       V                '         |   |
61  *                               |   |         File Descriptor          |   |
62  *                               |   |                ^                 |   |
63  *                               |   '----------------|-----------------'   |
64  *                               '--------------------|---------------------'
65  *                                                    |
66  *                                 .------------------|-------------------.
67  *                                 |                  |                   |
68  *                                 |   .--------------|---------------.   |
69  *                                 |   | .------------|-------------. |   |
70  *                                 |   | |            V             | |   |
71  *                                 |   | |  TUN/TAP Shim Interface  | |   |
72  *                                 |   | |                          | |   |
73  *                                 |   | '--------------------------' |   |
74  *                                 |   |                              |   |
75  *                                 |   |        TUN/TAP Driver        |   |
76  *                                 |   |                              |   |
77  *                                 |   '------------------------------'   |
78  *                                 |                                      |
79  *                                 |               Host OS                |
80  *                                 |                                      |
81  *                                 '--------------------------------------'
82  *
83  *      This file was originally adapted from 'contrib/ports/unix/port/
84  *      netif/tapif.c' in the LwIP distribution.
85  *
86  */
87
88 /*-----------------------------------------------------------------------------------*/
89 /*
90  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
91  * All rights reserved.
92  *
93  * Redistribution and use in source and binary forms, with or without modification,
94  * are permitted provided that the following conditions are met:
95  *
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.
103  *
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
113  * OF SUCH DAMAGE.
114  *
115  * This file is part of the lwIP TCP/IP stack.
116  *
117  * Author: Adam Dunkels <adam@sics.se>
118  *
119  */
120
121 #include "TapInterface.h"
122
123 #include <errno.h>
124 #include <fcntl.h>
125 #include <netinet/in.h>
126 #include <stdio.h>
127 #include <stdlib.h>
128 #include <string.h>
129 #include <sys/ioctl.h>
130 #include <sys/socket.h>
131 #include <sys/time.h>
132 #include <sys/types.h>
133 #include <sys/uio.h>
134 #include <unistd.h>
135
136 #if defined(linux)
137 #include <linux/if.h>
138 #include <linux/if_tun.h>
139 #include <sys/ioctl.h>
140 #define DEVTAP "/dev/net/tun"
141
142 #elif defined(openbsd)
143 #define DEVTAP "/dev/tun0"
144
145 #else /* freebsd, cygwin? */
146 #include <net/if.h>
147 #define DEVTAP "/dev/tap0"
148 #endif
149
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>
155
156 /* Global Variables */
157
158 static const size_t kMacLength = sizeof(((TapInterface *) (0))->macAddr);
159
160 /**
161  *  This is the LwIP TUN/TAP shim interface low level output method.
162  *
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
166  *  interface.
167  *
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.
171  *
172  *  @param[in]  buf        A pointer to the packet buffer containing the
173  *                         output to drive onto the shim interface.
174  *
175  *  @retval  #ERR_OK       on successfully driving the buffer onto the
176  *                         shim interface.
177  *
178  *  @retval  #ERR_MEM      if an encapsulation buffer cannot be allocated.
179  *
180  *  @retval  #ERR_BUF      if the allocated encapsulation buffer is not big
181  *                         enough to encapsulate the output data.
182  *
183  *  @retval  #ERR_IF       if the output data cannot be driven onto the shim
184  *                         interface.
185  *
186  *  @sa #TapInterface_SetupNetif
187  *
188  */
189 static err_t TapInterface_low_level_output(struct netif * netif, struct pbuf * buf)
190 {
191     const TapInterface * tapif = (const TapInterface *) (netif->state);
192     err_t retval               = ERR_OK;
193     struct pbuf * outBuf;
194     int written;
195
196     if (buf->tot_len > buf->len)
197     {
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);
200         if (outBuf == NULL)
201         {
202             fprintf(stderr, "TapInterface: Failed to allocate buffer\n");
203             retval = ERR_MEM;
204             goto done;
205         }
206
207         // Fail if the buffer is not big enough to hold the output data.
208         if (outBuf->tot_len != outBuf->len)
209         {
210             fprintf(stderr, "TapInterface: Output data bigger than single PBUF\n");
211             retval = ERR_BUF;
212             goto done;
213         }
214
215         // Reserve the space needed by WICED for its buffer management.
216         pbuf_header(outBuf, -PBUF_LINK_ENCAPSULATION_HLEN);
217
218         // Copy output data to the new buffer.
219         retval = pbuf_copy(outBuf, buf);
220         if (retval != ERR_OK)
221             goto done;
222     }
223
224     // Otherwise send using the supplied buffer.
225     else
226         outBuf = buf;
227
228     written = write(tapif->fd, outBuf->payload, outBuf->tot_len);
229     if (written == -1)
230     {
231         snmp_inc_ifoutdiscards(netif);
232         perror("TapInterface: write failed");
233         retval = ERR_IF;
234     }
235     else
236     {
237         snmp_add_ifoutoctets(netif, written);
238     }
239
240 done:
241     if (outBuf != NULL && outBuf != buf)
242         pbuf_free(outBuf);
243
244     return retval;
245 }
246
247 /**
248  *  This is the LwIP TUN/TAP shim interface low level input method.
249  *
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.
253  *
254  *  @param[in]  tapif      A pointer to the LwIP TUN/TAP shim interface
255  *                         from which to read pending input.
256  *
257  *  @param[in]  netif      A pointer to the LwIP native interface
258  *                         associated with the TUN/TAP shim interface.
259  *
260  *  @returns  A pointer to the buffer containing the read input on
261  *  success; otherwise, NULL on error.
262  *
263  *  @sa #TapInterface_Select
264  *
265  */
266 static struct pbuf * TapInterface_low_level_input(TapInterface * tapif, struct netif * netif)
267 {
268     struct pbuf *p, *q;
269     u16_t len;
270     char buf[2048];
271     char * bufptr;
272
273     /* Obtain the size of the packet and put it into the "len"
274      variable. */
275     len = read(tapif->fd, buf, sizeof(buf));
276     snmp_add_ifinoctets(netif, len);
277
278     /* We allocate a pbuf chain of pbufs from the pool. */
279     p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
280
281     if (p != NULL)
282     {
283         /* We iterate over the pbuf chain until we have read the entire
284        packet into the pbuf. */
285         bufptr = &buf[0];
286         for (q = p; q != NULL; q = q->next)
287         {
288             /* Read enough bytes to fill this pbuf in the chain. The
289          available data in the pbuf is given by the q->len
290          variable. */
291             /* read data into(q->payload, q->len); */
292             memcpy(q->payload, bufptr, q->len);
293             bufptr += q->len;
294         }
295         /* acknowledge that packet has been read(); */
296     }
297     else
298     {
299         /* drop packet(); */
300         snmp_inc_ifindiscards(netif);
301         printf("Could not allocate pbufs\n");
302     }
303
304     return p;
305 }
306
307 /**
308  *  LwIP netif_add setup callback function for LwIP TUN/TAP shim
309  *  interfaces.
310  *
311  *  The interface mimics / effects an Ethernet-like interface and,
312  *  consequently, reuses and leverages existing LwIP low-level APIs
313  *  for such interfaces.
314  *
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
318  *  callback.
319  *
320  *  @param[in,out] netif  A pointer to the LwIP netif associated with the
321  *                        TUN/TAP shim interface.
322  *
323  *  @retval  #ERR_OK  on successfully setting up the TUN/TAP interface.
324  *
325  *  @sa #TapInterface_Init
326  *  @sa #TapInterface_Select
327  *
328  */
329 err_t TapInterface_SetupNetif(struct netif * netif)
330 {
331     const TapInterface * tapif = (const TapInterface *) (netif->state);
332
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.
336      */
337
338     netif->name[0] = tapif->interfaceName[0];
339     netif->name[1] = tapif->interfaceName[1];
340     netif->output  = etharp_output;
341 #if LWIP_IPV6
342     netif->output_ip6 = ethip6_output;
343 #endif /* LWIP_IPV6 */
344     netif->linkoutput = TapInterface_low_level_output;
345     netif->mtu        = 1500;
346
347     netif->flags |= (NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP);
348 #if LWIP_IPV4
349     netif->flags |= (NETIF_FLAG_IGMP);
350 #endif
351 #if LWIP_IPV6
352     netif->flags |= (NETIF_FLAG_MLD6);
353 #endif
354
355     netif->hwaddr_len = kMacLength;
356
357     memcpy(netif->hwaddr, tapif->macAddr, kMacLength);
358
359     return ERR_OK;
360 }
361
362 /**
363  *  Establish an LwIP TUN/TAP interface on the underlying host OS with
364  *  the specified name.
365  *
366  *  This interface should be invoked before either \c #TapInterface_SetupNetif
367  *  or \c #TapInterface_Select are invoked.
368  *
369  *  @param[out]  tapif          A pointer to storage for the established
370  *                              TUN/TAP interface details.
371  *
372  *  @param[in]   interfaceName  A pointer to a NULL-terminated C string
373  *                              containing the name of the TUN/TAP interface.
374  *
375  *  @param[in]   macAddr        An optional pointer to the MAC address to be
376  *                              used for the TUN/TAP interface.
377  *
378  *  @retval  #ERR_OK            on successfully establishing the TUN/TAP
379  *                              interface.
380  *
381  *  @retval  #ERR_ARG           if \c tapif is NULL or if \c interfaceName is
382  *                              too long.
383  *
384  *  @retval  #ERR_IF            if the OS-specific TUN/TAP driver cannot be
385  *                              opened or if the requested TUN/TAP device
386  *                              cannot be created.
387  *
388  *  @sa #TapInterface_SetupNetif
389  *  @sa #TapInterface_Select
390  *
391  */
392 err_t TapInterface_Init(TapInterface * tapif, const char * interfaceName, u8_t * macAddr)
393 {
394 #if defined(linux)
395     struct ifreq ifr;
396 #endif
397
398     /* The TUN/TAP interface storage pointer is required; error out if
399      * it hasn't been provided.
400      */
401
402     if (tapif == NULL)
403         return ERR_ARG;
404
405     /* Set the TUN/TAP interface storage to initial defaults.
406      */
407
408     memset(tapif, 0, sizeof(*tapif));
409     tapif->fd = -1;
410
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.
414      */
415
416     tapif->interfaceName = interfaceName;
417
418     if (macAddr != NULL)
419     {
420         memcpy(tapif->macAddr, macAddr, kMacLength);
421     }
422     else
423     {
424         const u32_t pid = htonl((u32_t) getpid());
425         memset(tapif->macAddr, 0, kMacLength);
426         memcpy(tapif->macAddr + 2, &pid, sizeof(pid));
427     }
428
429     /* Attempt to open the OS-specific TUN/TAP driver control interface.
430      */
431
432     tapif->fd = open(DEVTAP, O_RDWR);
433     if (tapif->fd == -1)
434     {
435         perror("TapInterface: unable to open " DEVTAP);
436         return ERR_IF;
437     }
438
439 #if defined(linux)
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).
443      */
444
445     memset(&ifr, 0, sizeof(ifr));
446     ifr.ifr_flags = (IFF_TAP | IFF_NO_PI);
447
448     if (strlen(tapif->interfaceName) >= sizeof(ifr.ifr_name))
449     {
450         perror("TapInterface: invalid device name");
451         return ERR_ARG;
452     }
453
454     strcpy(ifr.ifr_name, tapif->interfaceName);
455
456     if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0)
457     {
458         perror("TapInterface: ioctl(TUNSETIFF) failed");
459         return ERR_IF;
460     }
461
462 #else
463 #warning "The LwIP TAP/TUN interface may not be fully-supported on your platform."
464 #endif /* defined(linux) */
465
466     return ERR_OK;
467 }
468
469 /**
470  *  Check the LwIP TUN/TAP shim interface to see if any input / read
471  *  activity is pending and, if there is, process it.
472  *
473  *  @param[in]  tapif      An array of  LwIP TUN/TAP shim interfaces
474  *                         to check and, if necessary, to process the
475  *                         input for.
476  *
477  *  @param[in]  netif      An array of the LwIP native interfaces
478  *                         associated with the TUN/TAP shim interface.
479  *
480  *  @param[in]  sleepTime  The interval that the call should block for
481  *                         waiting for input.
482  *
483  *  @param[in]  numIntfs   The number of elements in the tapif and netif arrays.
484  *
485  *  @retval  >= 0 on a successful check and/or processing of pending input.
486  *
487  *  @retval  -EINVAL if either \c tapif or \c netif are NULL.
488  *
489  *  @sa #TapInterface_Init
490  *  @sa #TapInterface_SetupNetif
491  *
492  */
493 int TapInterface_Select(TapInterface * tapif, struct netif * netif, struct timeval sleepTime, size_t numIntfs)
494 {
495     fd_set readfds;
496     int ret;
497     size_t j;
498
499     if ((tapif == NULL) || (netif == NULL) || (numIntfs == 0))
500     {
501         return -EINVAL;
502     }
503
504     FD_ZERO(&readfds);
505
506     for (j = 0; j < numIntfs; j++)
507     {
508         FD_SET(tapif[j].fd, &readfds);
509     }
510
511     ret = select(tapif[numIntfs - 1].fd + 1, &readfds, NULL, NULL, &sleepTime);
512     if (ret > 0)
513     {
514         for (j = 0; j < numIntfs; j++)
515         {
516             if (!FD_ISSET(tapif[j].fd, &readfds))
517                 continue;
518
519             struct pbuf * p = TapInterface_low_level_input(&(tapif[j]), &(netif[j]));
520             if (p != NULL)
521             {
522 #if LINK_STATS
523                 lwip_stats.link.recv++;
524 #endif /* LINK_STATS */
525
526                 netif[j].input(p, &(netif[j]));
527             }
528         }
529     }
530
531     return ret;
532 }