xref: /btstack/3rd-party/lwip/core/src/core/netif.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
1 /**
2  * @file
3  * lwIP network interface abstraction
4  *
5  * @defgroup netif Network interface (NETIF)
6  * @ingroup callbackstyle_api
7  *
8  * @defgroup netif_ip4 IPv4 address handling
9  * @ingroup netif
10  *
11  * @defgroup netif_ip6 IPv6 address handling
12  * @ingroup netif
13  *
14  * @defgroup netif_cd Client data handling
15  * Store data (void*) on a netif for application usage.
16  * @see @ref LWIP_NUM_NETIF_CLIENT_DATA
17  * @ingroup netif
18  */
19 
20 /*
21  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
22  * All rights reserved.
23  *
24  * Redistribution and use in source and binary forms, with or without modification,
25  * are permitted provided that the following conditions are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright notice,
28  *    this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright notice,
30  *    this list of conditions and the following disclaimer in the documentation
31  *    and/or other materials provided with the distribution.
32  * 3. The name of the author may not be used to endorse or promote products
33  *    derived from this software without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
38  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
43  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
44  * OF SUCH DAMAGE.
45  *
46  * This file is part of the lwIP TCP/IP stack.
47  *
48  * Author: Adam Dunkels <[email protected]>
49  */
50 
51 #include "lwip/opt.h"
52 
53 #include <string.h> /* memset */
54 #include <stdlib.h> /* atoi */
55 
56 #include "lwip/def.h"
57 #include "lwip/ip_addr.h"
58 #include "lwip/ip6_addr.h"
59 #include "lwip/netif.h"
60 #include "lwip/priv/tcp_priv.h"
61 #include "lwip/udp.h"
62 #include "lwip/priv/raw_priv.h"
63 #include "lwip/snmp.h"
64 #include "lwip/igmp.h"
65 #include "lwip/etharp.h"
66 #include "lwip/stats.h"
67 #include "lwip/sys.h"
68 #include "lwip/ip.h"
69 #if ENABLE_LOOPBACK
70 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
71 #include "lwip/tcpip.h"
72 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
73 #endif /* ENABLE_LOOPBACK */
74 
75 #include "netif/ethernet.h"
76 
77 #if LWIP_AUTOIP
78 #include "lwip/autoip.h"
79 #endif /* LWIP_AUTOIP */
80 #if LWIP_DHCP
81 #include "lwip/dhcp.h"
82 #endif /* LWIP_DHCP */
83 #if LWIP_ACD
84 #include "lwip/acd.h"
85 #endif /* LWIP_ACD */
86 #if LWIP_IPV6_DHCP6
87 #include "lwip/dhcp6.h"
88 #endif /* LWIP_IPV6_DHCP6 */
89 #if LWIP_IPV6_MLD
90 #include "lwip/mld6.h"
91 #endif /* LWIP_IPV6_MLD */
92 #if LWIP_IPV6
93 #include "lwip/nd6.h"
94 #endif
95 
96 #if LWIP_NETIF_STATUS_CALLBACK
97 #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
98 #else
99 #define NETIF_STATUS_CALLBACK(n)
100 #endif /* LWIP_NETIF_STATUS_CALLBACK */
101 
102 #if LWIP_NETIF_LINK_CALLBACK
103 #define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
104 #else
105 #define NETIF_LINK_CALLBACK(n)
106 #endif /* LWIP_NETIF_LINK_CALLBACK */
107 
108 #if LWIP_NETIF_EXT_STATUS_CALLBACK
109 static netif_ext_callback_t *ext_callback;
110 #endif
111 
112 #if !LWIP_SINGLE_NETIF
113 struct netif *netif_list;
114 #endif /* !LWIP_SINGLE_NETIF */
115 struct netif *netif_default;
116 
117 #define netif_index_to_num(index)   ((index) - 1)
118 static u8_t netif_num;
119 
120 #if LWIP_NUM_NETIF_CLIENT_DATA > 0
121 static u8_t netif_client_id;
122 #endif
123 
124 #define NETIF_REPORT_TYPE_IPV4  0x01
125 #define NETIF_REPORT_TYPE_IPV6  0x02
126 static void netif_issue_reports(struct netif *netif, u8_t report_type);
127 
128 #if LWIP_IPV6
129 static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr);
130 #endif /* LWIP_IPV6 */
131 #if LWIP_IPV4
132 static err_t netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr);
133 #endif /* LWIP_IPV4 */
134 
135 #if LWIP_HAVE_LOOPIF
136 #if LWIP_IPV4
137 static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr);
138 #endif
139 #if LWIP_IPV6
140 static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr);
141 #endif
142 
143 
144 static struct netif loop_netif;
145 
146 #if LWIP_TESTMODE
netif_get_loopif(void)147 struct netif* netif_get_loopif(void)
148 {
149   return &loop_netif;
150 }
151 #endif
152 
153 
154 /**
155  * Initialize a lwip network interface structure for a loopback interface
156  *
157  * @param netif the lwip network interface structure for this loopif
158  * @return ERR_OK if the loopif is initialized
159  *         ERR_MEM if private data couldn't be allocated
160  */
161 static err_t
netif_loopif_init(struct netif * netif)162 netif_loopif_init(struct netif *netif)
163 {
164   LWIP_ASSERT("netif_loopif_init: invalid netif", netif != NULL);
165 
166   /* initialize the snmp variables and counters inside the struct netif
167    * ifSpeed: no assumption can be made!
168    */
169   MIB2_INIT_NETIF(netif, snmp_ifType_softwareLoopback, 0);
170 
171   netif->name[0] = 'l';
172   netif->name[1] = 'o';
173 #if LWIP_IPV4
174   netif->output = netif_loop_output_ipv4;
175 #endif
176 #if LWIP_IPV6
177   netif->output_ip6 = netif_loop_output_ipv6;
178 #endif
179 #if LWIP_LOOPIF_MULTICAST
180   netif_set_flags(netif, NETIF_FLAG_IGMP);
181 #endif
182   NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_DISABLE_ALL);
183   return ERR_OK;
184 }
185 #endif /* LWIP_HAVE_LOOPIF */
186 
187 void
netif_init(void)188 netif_init(void)
189 {
190 #if LWIP_HAVE_LOOPIF
191 #if LWIP_IPV4
192 #define LOOPIF_ADDRINIT &loop_ipaddr, &loop_netmask, &loop_gw,
193   ip4_addr_t loop_ipaddr, loop_netmask, loop_gw;
194   IP4_ADDR(&loop_gw, 127, 0, 0, 1);
195   IP4_ADDR(&loop_ipaddr, 127, 0, 0, 1);
196   IP4_ADDR(&loop_netmask, 255, 0, 0, 0);
197 #else /* LWIP_IPV4 */
198 #define LOOPIF_ADDRINIT
199 #endif /* LWIP_IPV4 */
200 
201 #if NO_SYS
202   netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, ip_input);
203 #else  /* NO_SYS */
204   netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input);
205 #endif /* NO_SYS */
206 
207 #if LWIP_IPV6
208   IP_ADDR6_HOST(loop_netif.ip6_addr, 0, 0, 0, 0x00000001UL);
209   loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID;
210 #endif /* LWIP_IPV6 */
211 
212   netif_set_link_up(&loop_netif);
213   netif_set_up(&loop_netif);
214 
215 #endif /* LWIP_HAVE_LOOPIF */
216 }
217 
218 /**
219  * @ingroup lwip_nosys
220  * Forwards a received packet for input processing with
221  * ethernet_input() or ip_input() depending on netif flags.
222  * Don't call directly, pass to netif_add() and call
223  * netif->input().
224  * Only works if the netif driver correctly sets
225  * NETIF_FLAG_ETHARP and/or NETIF_FLAG_ETHERNET flag!
226  */
227 err_t
netif_input(struct pbuf * p,struct netif * inp)228 netif_input(struct pbuf *p, struct netif *inp)
229 {
230   LWIP_ASSERT_CORE_LOCKED();
231 
232   LWIP_ASSERT("netif_input: invalid pbuf", p != NULL);
233   LWIP_ASSERT("netif_input: invalid netif", inp != NULL);
234 
235 #if LWIP_ETHERNET
236   if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
237     return ethernet_input(p, inp);
238   } else
239 #endif /* LWIP_ETHERNET */
240     return ip_input(p, inp);
241 }
242 
243 /**
244  * @ingroup netif
245  * Add a network interface to the list of lwIP netifs.
246  *
247  * Same as @ref netif_add but without IPv4 addresses
248  */
249 struct netif *
netif_add_noaddr(struct netif * netif,void * state,netif_init_fn init,netif_input_fn input)250 netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input)
251 {
252   return netif_add(netif,
253 #if LWIP_IPV4
254                    NULL, NULL, NULL,
255 #endif /* LWIP_IPV4*/
256                    state, init, input);
257 }
258 
259 /**
260  * @ingroup netif
261  * Add a network interface to the list of lwIP netifs.
262  *
263  * @param netif a pre-allocated netif structure
264  * @param ipaddr IP address for the new netif
265  * @param netmask network mask for the new netif
266  * @param gw default gateway IP address for the new netif
267  * @param state opaque data passed to the new netif
268  * @param init callback function that initializes the interface
269  * @param input callback function that is called to pass
270  * ingress packets up in the protocol layer stack.<br>
271  * It is recommended to use a function that passes the input directly
272  * to the stack (netif_input(), NO_SYS=1 mode) or via sending a
273  * message to TCPIP thread (tcpip_input(), NO_SYS=0 mode).<br>
274  * These functions use netif flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
275  * to decide whether to forward to ethernet_input() or ip_input().
276  * In other words, the functions only work when the netif
277  * driver is implemented correctly!<br>
278  * Most members of struct netif should be be initialized by the
279  * netif init function = netif driver (init parameter of this function).<br>
280  * IPv6: Don't forget to call netif_create_ip6_linklocal_address() after
281  * setting the MAC address in struct netif.hwaddr
282  * (IPv6 requires a link-local address).
283  *
284  * @return netif, or NULL if failed.
285  */
286 struct netif *
netif_add(struct netif * netif,const ip4_addr_t * ipaddr,const ip4_addr_t * netmask,const ip4_addr_t * gw,void * state,netif_init_fn init,netif_input_fn input)287 netif_add(struct netif *netif,
288 #if LWIP_IPV4
289           const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
290 #endif /* LWIP_IPV4 */
291           void *state, netif_init_fn init, netif_input_fn input)
292 {
293 #if LWIP_IPV6
294   s8_t i;
295 #endif
296 
297   LWIP_ASSERT_CORE_LOCKED();
298 
299 #if LWIP_SINGLE_NETIF
300   if (netif_default != NULL) {
301     LWIP_ASSERT("single netif already set", 0);
302     return NULL;
303   }
304 #endif
305 
306   LWIP_ERROR("netif_add: invalid netif", netif != NULL, return NULL);
307   LWIP_ERROR("netif_add: No init function given", init != NULL, return NULL);
308 
309 #if LWIP_IPV4
310   if (ipaddr == NULL) {
311     ipaddr = ip_2_ip4(IP4_ADDR_ANY);
312   }
313   if (netmask == NULL) {
314     netmask = ip_2_ip4(IP4_ADDR_ANY);
315   }
316   if (gw == NULL) {
317     gw = ip_2_ip4(IP4_ADDR_ANY);
318   }
319 
320   /* reset new interface configuration state */
321   ip_addr_set_zero_ip4(&netif->ip_addr);
322   ip_addr_set_zero_ip4(&netif->netmask);
323   ip_addr_set_zero_ip4(&netif->gw);
324   netif->output = netif_null_output_ip4;
325 #endif /* LWIP_IPV4 */
326 #if LWIP_IPV6
327   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
328     ip_addr_set_zero_ip6(&netif->ip6_addr[i]);
329     netif->ip6_addr_state[i] = IP6_ADDR_INVALID;
330 #if LWIP_IPV6_ADDRESS_LIFETIMES
331     netif->ip6_addr_valid_life[i] = IP6_ADDR_LIFE_STATIC;
332     netif->ip6_addr_pref_life[i] = IP6_ADDR_LIFE_STATIC;
333 #endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
334   }
335   netif->output_ip6 = netif_null_output_ip6;
336 #endif /* LWIP_IPV6 */
337   NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);
338   netif->mtu = 0;
339   netif->flags = 0;
340 #ifdef netif_get_client_data
341   memset(netif->client_data, 0, sizeof(netif->client_data));
342 #endif /* LWIP_NUM_NETIF_CLIENT_DATA */
343 #if LWIP_IPV6
344 #if LWIP_IPV6_AUTOCONFIG
345   /* IPv6 address autoconfiguration not enabled by default */
346   netif->ip6_autoconfig_enabled = 0;
347 #endif /* LWIP_IPV6_AUTOCONFIG */
348   nd6_restart_netif(netif);
349 #endif /* LWIP_IPV6 */
350 #if LWIP_NETIF_STATUS_CALLBACK
351   netif->status_callback = NULL;
352 #endif /* LWIP_NETIF_STATUS_CALLBACK */
353 #if LWIP_NETIF_LINK_CALLBACK
354   netif->link_callback = NULL;
355 #endif /* LWIP_NETIF_LINK_CALLBACK */
356 #if LWIP_IGMP
357   netif->igmp_mac_filter = NULL;
358 #endif /* LWIP_IGMP */
359 #if LWIP_IPV6 && LWIP_IPV6_MLD
360   netif->mld_mac_filter = NULL;
361 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
362 #if ENABLE_LOOPBACK
363   netif->loop_first = NULL;
364   netif->loop_last = NULL;
365 #endif /* ENABLE_LOOPBACK */
366 
367   /* remember netif specific state information data */
368   netif->state = state;
369   netif->num = netif_num;
370   netif->input = input;
371 
372   NETIF_RESET_HINTS(netif);
373 #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
374   netif->loop_cnt_current = 0;
375 #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
376 
377 #if LWIP_IPV4
378   netif_set_addr(netif, ipaddr, netmask, gw);
379 #endif /* LWIP_IPV4 */
380 
381   /* call user specified initialization function for netif */
382   if (init(netif) != ERR_OK) {
383     return NULL;
384   }
385 #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
386   /* Initialize the MTU for IPv6 to the one set by the netif driver.
387      This can be updated later by RA. */
388   netif->mtu6 = netif->mtu;
389 #endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */
390 
391 #if !LWIP_SINGLE_NETIF
392   /* Assign a unique netif number in the range [0..254], so that (num+1) can
393      serve as an interface index that fits in a u8_t.
394      We assume that the new netif has not yet been added to the list here.
395      This algorithm is O(n^2), but that should be OK for lwIP.
396      */
397   {
398     struct netif *netif2;
399     int num_netifs;
400     do {
401       if (netif->num == 255) {
402         netif->num = 0;
403       }
404       num_netifs = 0;
405       for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) {
406         LWIP_ASSERT("netif already added", netif2 != netif);
407         num_netifs++;
408         LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255);
409         if (netif2->num == netif->num) {
410           netif->num++;
411           break;
412         }
413       }
414     } while (netif2 != NULL);
415   }
416   if (netif->num == 254) {
417     netif_num = 0;
418   } else {
419     netif_num = (u8_t)(netif->num + 1);
420   }
421 
422   /* add this netif to the list */
423   netif->next = netif_list;
424   netif_list = netif;
425 #endif /* "LWIP_SINGLE_NETIF */
426   mib2_netif_added(netif);
427 
428 #if LWIP_IGMP
429   /* start IGMP processing */
430   if (netif->flags & NETIF_FLAG_IGMP) {
431     igmp_start(netif);
432   }
433 #endif /* LWIP_IGMP */
434 
435   LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP",
436                             netif->name[0], netif->name[1]));
437 #if LWIP_IPV4
438   LWIP_DEBUGF(NETIF_DEBUG, (" addr "));
439   ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
440   LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
441   ip4_addr_debug_print(NETIF_DEBUG, netmask);
442   LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
443   ip4_addr_debug_print(NETIF_DEBUG, gw);
444 #endif /* LWIP_IPV4 */
445   LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
446 
447   netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);
448 
449   return netif;
450 }
451 
452 static void
netif_do_ip_addr_changed(const ip_addr_t * old_addr,const ip_addr_t * new_addr)453 netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr)
454 {
455 #if LWIP_TCP
456   tcp_netif_ip_addr_changed(old_addr, new_addr);
457 #endif /* LWIP_TCP */
458 #if LWIP_UDP
459   udp_netif_ip_addr_changed(old_addr, new_addr);
460 #endif /* LWIP_UDP */
461 #if LWIP_RAW
462   raw_netif_ip_addr_changed(old_addr, new_addr);
463 #endif /* LWIP_RAW */
464 }
465 
466 #if LWIP_IPV4
467 static int
netif_do_set_ipaddr(struct netif * netif,const ip4_addr_t * ipaddr,ip_addr_t * old_addr)468 netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *old_addr)
469 {
470   LWIP_ASSERT("invalid pointer", ipaddr != NULL);
471   LWIP_ASSERT("invalid pointer", old_addr != NULL);
472 
473   /* address is actually being changed? */
474   if (ip4_addr_cmp(ipaddr, netif_ip4_addr(netif)) == 0) {
475     ip_addr_t new_addr;
476     *ip_2_ip4(&new_addr) = *ipaddr;
477     IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4);
478 
479     ip_addr_copy(*old_addr, *netif_ip_addr4(netif));
480 
481     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
482     netif_do_ip_addr_changed(old_addr, &new_addr);
483 
484 #if LWIP_ACD
485     acd_netif_ip_addr_changed(netif, old_addr, &new_addr);
486 #endif /* LWIP_ACD */
487 
488     mib2_remove_ip4(netif);
489     mib2_remove_route_ip4(0, netif);
490     /* set new IP address to netif */
491     ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr);
492     IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4);
493     mib2_add_ip4(netif);
494     mib2_add_route_ip4(0, netif);
495 
496     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4);
497 
498     NETIF_STATUS_CALLBACK(netif);
499     return 1; /* address changed */
500   }
501   return 0; /* address unchanged */
502 }
503 
504 /**
505  * @ingroup netif_ip4
506  * Change the IP address of a network interface
507  *
508  * @param netif the network interface to change
509  * @param ipaddr the new IP address
510  *
511  * @note call netif_set_addr() if you also want to change netmask and
512  * default gateway
513  */
514 void
netif_set_ipaddr(struct netif * netif,const ip4_addr_t * ipaddr)515 netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr)
516 {
517   ip_addr_t old_addr;
518 
519   LWIP_ERROR("netif_set_ipaddr: invalid netif", netif != NULL, return);
520 
521   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
522   if (ipaddr == NULL) {
523     ipaddr = IP4_ADDR_ANY4;
524   }
525 
526   LWIP_ASSERT_CORE_LOCKED();
527 
528   if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
529 #if LWIP_NETIF_EXT_STATUS_CALLBACK
530     netif_ext_callback_args_t args;
531     args.ipv4_changed.old_address = &old_addr;
532     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_ADDRESS_CHANGED, &args);
533 #endif
534   }
535 }
536 
537 static int
netif_do_set_netmask(struct netif * netif,const ip4_addr_t * netmask,ip_addr_t * old_nm)538 netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm)
539 {
540   /* address is actually being changed? */
541   if (ip4_addr_cmp(netmask, netif_ip4_netmask(netif)) == 0) {
542 #if LWIP_NETIF_EXT_STATUS_CALLBACK
543     LWIP_ASSERT("invalid pointer", old_nm != NULL);
544     ip_addr_copy(*old_nm, *netif_ip_netmask4(netif));
545 #else
546     LWIP_UNUSED_ARG(old_nm);
547 #endif
548     mib2_remove_route_ip4(0, netif);
549     /* set new netmask to netif */
550     ip4_addr_set(ip_2_ip4(&netif->netmask), netmask);
551     IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4);
552     mib2_add_route_ip4(0, netif);
553     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
554                 netif->name[0], netif->name[1],
555                 ip4_addr1_16(netif_ip4_netmask(netif)),
556                 ip4_addr2_16(netif_ip4_netmask(netif)),
557                 ip4_addr3_16(netif_ip4_netmask(netif)),
558                 ip4_addr4_16(netif_ip4_netmask(netif))));
559     return 1; /* netmask changed */
560   }
561   return 0; /* netmask unchanged */
562 }
563 
564 /**
565  * @ingroup netif_ip4
566  * Change the netmask of a network interface
567  *
568  * @param netif the network interface to change
569  * @param netmask the new netmask
570  *
571  * @note call netif_set_addr() if you also want to change ip address and
572  * default gateway
573  */
574 void
netif_set_netmask(struct netif * netif,const ip4_addr_t * netmask)575 netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask)
576 {
577 #if LWIP_NETIF_EXT_STATUS_CALLBACK
578   ip_addr_t old_nm_val;
579   ip_addr_t *old_nm = &old_nm_val;
580 #else
581   ip_addr_t *old_nm = NULL;
582 #endif
583   LWIP_ASSERT_CORE_LOCKED();
584 
585   LWIP_ERROR("netif_set_netmask: invalid netif", netif != NULL, return);
586 
587   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
588   if (netmask == NULL) {
589     netmask = IP4_ADDR_ANY4;
590   }
591 
592   if (netif_do_set_netmask(netif, netmask, old_nm)) {
593 #if LWIP_NETIF_EXT_STATUS_CALLBACK
594     netif_ext_callback_args_t args;
595     args.ipv4_changed.old_netmask = old_nm;
596     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_NETMASK_CHANGED, &args);
597 #endif
598   }
599 }
600 
601 static int
netif_do_set_gw(struct netif * netif,const ip4_addr_t * gw,ip_addr_t * old_gw)602 netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw)
603 {
604   /* address is actually being changed? */
605   if (ip4_addr_cmp(gw, netif_ip4_gw(netif)) == 0) {
606 #if LWIP_NETIF_EXT_STATUS_CALLBACK
607     LWIP_ASSERT("invalid pointer", old_gw != NULL);
608     ip_addr_copy(*old_gw, *netif_ip_gw4(netif));
609 #else
610     LWIP_UNUSED_ARG(old_gw);
611 #endif
612 
613     ip4_addr_set(ip_2_ip4(&netif->gw), gw);
614     IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4);
615     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
616                 netif->name[0], netif->name[1],
617                 ip4_addr1_16(netif_ip4_gw(netif)),
618                 ip4_addr2_16(netif_ip4_gw(netif)),
619                 ip4_addr3_16(netif_ip4_gw(netif)),
620                 ip4_addr4_16(netif_ip4_gw(netif))));
621     return 1; /* gateway changed */
622   }
623   return 0; /* gateway unchanged */
624 }
625 
626 /**
627  * @ingroup netif_ip4
628  * Change the default gateway for a network interface
629  *
630  * @param netif the network interface to change
631  * @param gw the new default gateway
632  *
633  * @note call netif_set_addr() if you also want to change ip address and netmask
634  */
635 void
netif_set_gw(struct netif * netif,const ip4_addr_t * gw)636 netif_set_gw(struct netif *netif, const ip4_addr_t *gw)
637 {
638 #if LWIP_NETIF_EXT_STATUS_CALLBACK
639   ip_addr_t old_gw_val;
640   ip_addr_t *old_gw = &old_gw_val;
641 #else
642   ip_addr_t *old_gw = NULL;
643 #endif
644   LWIP_ASSERT_CORE_LOCKED();
645 
646   LWIP_ERROR("netif_set_gw: invalid netif", netif != NULL, return);
647 
648   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
649   if (gw == NULL) {
650     gw = IP4_ADDR_ANY4;
651   }
652 
653   if (netif_do_set_gw(netif, gw, old_gw)) {
654 #if LWIP_NETIF_EXT_STATUS_CALLBACK
655     netif_ext_callback_args_t args;
656     args.ipv4_changed.old_gw = old_gw;
657     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_GATEWAY_CHANGED, &args);
658 #endif
659   }
660 }
661 
662 /**
663  * @ingroup netif_ip4
664  * Change IP address configuration for a network interface (including netmask
665  * and default gateway).
666  *
667  * @param netif the network interface to change
668  * @param ipaddr the new IP address
669  * @param netmask the new netmask
670  * @param gw the new default gateway
671  */
672 void
netif_set_addr(struct netif * netif,const ip4_addr_t * ipaddr,const ip4_addr_t * netmask,const ip4_addr_t * gw)673 netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
674                const ip4_addr_t *gw)
675 {
676 #if LWIP_NETIF_EXT_STATUS_CALLBACK
677   netif_nsc_reason_t change_reason = LWIP_NSC_NONE;
678   netif_ext_callback_args_t cb_args;
679   ip_addr_t old_nm_val;
680   ip_addr_t old_gw_val;
681   ip_addr_t *old_nm = &old_nm_val;
682   ip_addr_t *old_gw = &old_gw_val;
683 #else
684   ip_addr_t *old_nm = NULL;
685   ip_addr_t *old_gw = NULL;
686 #endif
687   ip_addr_t old_addr;
688   int remove;
689 
690   LWIP_ASSERT_CORE_LOCKED();
691 
692   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
693   if (ipaddr == NULL) {
694     ipaddr = IP4_ADDR_ANY4;
695   }
696   if (netmask == NULL) {
697     netmask = IP4_ADDR_ANY4;
698   }
699   if (gw == NULL) {
700     gw = IP4_ADDR_ANY4;
701   }
702 
703   remove = ip4_addr_isany(ipaddr);
704   if (remove) {
705     /* when removing an address, we have to remove it *before* changing netmask/gw
706        to ensure that tcp RST segment can be sent correctly */
707     if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
708 #if LWIP_NETIF_EXT_STATUS_CALLBACK
709       change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED;
710       cb_args.ipv4_changed.old_address = &old_addr;
711 #endif
712     }
713   }
714   if (netif_do_set_netmask(netif, netmask, old_nm)) {
715 #if LWIP_NETIF_EXT_STATUS_CALLBACK
716     change_reason |= LWIP_NSC_IPV4_NETMASK_CHANGED;
717     cb_args.ipv4_changed.old_netmask = old_nm;
718 #endif
719   }
720   if (netif_do_set_gw(netif, gw, old_gw)) {
721 #if LWIP_NETIF_EXT_STATUS_CALLBACK
722     change_reason |= LWIP_NSC_IPV4_GATEWAY_CHANGED;
723     cb_args.ipv4_changed.old_gw = old_gw;
724 #endif
725   }
726   if (!remove) {
727     /* set ipaddr last to ensure netmask/gw have been set when status callback is called */
728     if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
729 #if LWIP_NETIF_EXT_STATUS_CALLBACK
730       change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED;
731       cb_args.ipv4_changed.old_address = &old_addr;
732 #endif
733     }
734   }
735 
736 #if LWIP_NETIF_EXT_STATUS_CALLBACK
737   if (change_reason != LWIP_NSC_NONE) {
738     change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED;
739     netif_invoke_ext_callback(netif, change_reason, &cb_args);
740   }
741 #endif
742 }
743 #endif /* LWIP_IPV4*/
744 
745 /**
746  * @ingroup netif
747  * Remove a network interface from the list of lwIP netifs.
748  *
749  * @param netif the network interface to remove
750  */
751 void
netif_remove(struct netif * netif)752 netif_remove(struct netif *netif)
753 {
754 #if LWIP_IPV6
755   int i;
756 #endif
757 
758   LWIP_ASSERT_CORE_LOCKED();
759 
760   if (netif == NULL) {
761     return;
762   }
763 
764   netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL);
765 
766 #if LWIP_IPV4
767   if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
768     netif_do_ip_addr_changed(netif_ip_addr4(netif), NULL);
769   }
770 
771 #if LWIP_IGMP
772   /* stop IGMP processing */
773   if (netif->flags & NETIF_FLAG_IGMP) {
774     igmp_stop(netif);
775   }
776 #endif /* LWIP_IGMP */
777 #endif /* LWIP_IPV4*/
778 
779 #if LWIP_IPV6
780   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
781     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
782       netif_do_ip_addr_changed(netif_ip_addr6(netif, i), NULL);
783     }
784   }
785 #if LWIP_IPV6_MLD
786   /* stop MLD processing */
787   mld6_stop(netif);
788 #endif /* LWIP_IPV6_MLD */
789 #endif /* LWIP_IPV6 */
790   if (netif_is_up(netif)) {
791     /* set netif down before removing (call callback function) */
792     netif_set_down(netif);
793   }
794 
795   mib2_remove_ip4(netif);
796 
797   /* this netif is default? */
798   if (netif_default == netif) {
799     /* reset default netif */
800     netif_set_default(NULL);
801   }
802 #if !LWIP_SINGLE_NETIF
803   /*  is it the first netif? */
804   if (netif_list == netif) {
805     netif_list = netif->next;
806   } else {
807     /*  look for netif further down the list */
808     struct netif *tmp_netif;
809     NETIF_FOREACH(tmp_netif) {
810       if (tmp_netif->next == netif) {
811         tmp_netif->next = netif->next;
812         break;
813       }
814     }
815     if (tmp_netif == NULL) {
816       return; /* netif is not on the list */
817     }
818   }
819 #endif /* !LWIP_SINGLE_NETIF */
820   mib2_netif_removed(netif);
821 #if LWIP_NETIF_REMOVE_CALLBACK
822   if (netif->remove_callback) {
823     netif->remove_callback(netif);
824   }
825 #endif /* LWIP_NETIF_REMOVE_CALLBACK */
826   LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
827 }
828 
829 /**
830  * @ingroup netif
831  * Set a network interface as the default network interface
832  * (used to output all packets for which no specific route is found)
833  *
834  * @param netif the default network interface
835  */
836 void
netif_set_default(struct netif * netif)837 netif_set_default(struct netif *netif)
838 {
839   LWIP_ASSERT_CORE_LOCKED();
840 
841   if (netif == NULL) {
842     /* remove default route */
843     mib2_remove_route_ip4(1, netif);
844   } else {
845     /* install default route */
846     mib2_add_route_ip4(1, netif);
847   }
848   netif_default = netif;
849   LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
850                             netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
851 }
852 
853 /**
854  * @ingroup netif
855  * Bring an interface up, available for processing
856  * traffic.
857  */
858 void
netif_set_up(struct netif * netif)859 netif_set_up(struct netif *netif)
860 {
861   LWIP_ASSERT_CORE_LOCKED();
862 
863   LWIP_ERROR("netif_set_up: invalid netif", netif != NULL, return);
864 
865   if (!(netif->flags & NETIF_FLAG_UP)) {
866     netif_set_flags(netif, NETIF_FLAG_UP);
867 
868     MIB2_COPY_SYSUPTIME_TO(&netif->ts);
869 
870     NETIF_STATUS_CALLBACK(netif);
871 
872 #if LWIP_NETIF_EXT_STATUS_CALLBACK
873     {
874       netif_ext_callback_args_t args;
875       args.status_changed.state = 1;
876       netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args);
877     }
878 #endif
879 
880     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6);
881 #if LWIP_IPV6
882     nd6_restart_netif(netif);
883 #endif /* LWIP_IPV6 */
884   }
885 }
886 
887 /** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change
888  */
889 static void
netif_issue_reports(struct netif * netif,u8_t report_type)890 netif_issue_reports(struct netif *netif, u8_t report_type)
891 {
892   LWIP_ASSERT("netif_issue_reports: invalid netif", netif != NULL);
893 
894   /* Only send reports when both link and admin states are up */
895   if (!(netif->flags & NETIF_FLAG_LINK_UP) ||
896       !(netif->flags & NETIF_FLAG_UP)) {
897     return;
898   }
899 
900 #if LWIP_IPV4
901   if ((report_type & NETIF_REPORT_TYPE_IPV4) &&
902       !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
903 #if LWIP_ARP && !LWIP_ACD
904     /* For Ethernet network interfaces:
905      * we would like to send a "gratuitous ARP".
906      * Only needs to be done here if ACD isn't configured.
907      */
908     if (netif->flags & (NETIF_FLAG_ETHARP)) {
909       etharp_gratuitous(netif);
910     }
911 #endif /* LWIP_ARP */
912 
913 #if LWIP_IGMP
914     /* resend IGMP memberships */
915     if (netif->flags & NETIF_FLAG_IGMP) {
916       igmp_report_groups(netif);
917     }
918 #endif /* LWIP_IGMP */
919   }
920 #endif /* LWIP_IPV4 */
921 
922 #if LWIP_IPV6
923   if (report_type & NETIF_REPORT_TYPE_IPV6) {
924 #if LWIP_IPV6_MLD
925     /* send mld memberships */
926     mld6_report_groups(netif);
927 #endif /* LWIP_IPV6_MLD */
928   }
929 #endif /* LWIP_IPV6 */
930 }
931 
932 /**
933  * @ingroup netif
934  * Bring an interface down, disabling any traffic processing.
935  */
936 void
netif_set_down(struct netif * netif)937 netif_set_down(struct netif *netif)
938 {
939   LWIP_ASSERT_CORE_LOCKED();
940 
941   LWIP_ERROR("netif_set_down: invalid netif", netif != NULL, return);
942 
943   if (netif->flags & NETIF_FLAG_UP) {
944 #if LWIP_NETIF_EXT_STATUS_CALLBACK
945     {
946       netif_ext_callback_args_t args;
947       args.status_changed.state = 0;
948       netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args);
949     }
950 #endif
951 
952     netif_clear_flags(netif, NETIF_FLAG_UP);
953     MIB2_COPY_SYSUPTIME_TO(&netif->ts);
954 
955 #if LWIP_IPV4 && LWIP_ARP
956     if (netif->flags & NETIF_FLAG_ETHARP) {
957       etharp_cleanup_netif(netif);
958     }
959 #endif /* LWIP_IPV4 && LWIP_ARP */
960 
961 #if LWIP_IPV6
962     nd6_cleanup_netif(netif);
963 #endif /* LWIP_IPV6 */
964 
965     NETIF_STATUS_CALLBACK(netif);
966   }
967 }
968 
969 #if LWIP_NETIF_STATUS_CALLBACK
970 /**
971  * @ingroup netif
972  * Set callback to be called when interface is brought up/down or address is changed while up
973  */
974 void
netif_set_status_callback(struct netif * netif,netif_status_callback_fn status_callback)975 netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
976 {
977   LWIP_ASSERT_CORE_LOCKED();
978 
979   if (netif) {
980     netif->status_callback = status_callback;
981   }
982 }
983 #endif /* LWIP_NETIF_STATUS_CALLBACK */
984 
985 #if LWIP_NETIF_REMOVE_CALLBACK
986 /**
987  * @ingroup netif
988  * Set callback to be called when the interface has been removed
989  */
990 void
netif_set_remove_callback(struct netif * netif,netif_status_callback_fn remove_callback)991 netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback)
992 {
993   LWIP_ASSERT_CORE_LOCKED();
994 
995   if (netif) {
996     netif->remove_callback = remove_callback;
997   }
998 }
999 #endif /* LWIP_NETIF_REMOVE_CALLBACK */
1000 
1001 /**
1002  * @ingroup netif
1003  * Called by a driver when its link goes up
1004  */
1005 void
netif_set_link_up(struct netif * netif)1006 netif_set_link_up(struct netif *netif)
1007 {
1008   LWIP_ASSERT_CORE_LOCKED();
1009 
1010   LWIP_ERROR("netif_set_link_up: invalid netif", netif != NULL, return);
1011 
1012   if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
1013     netif_set_flags(netif, NETIF_FLAG_LINK_UP);
1014 
1015 #if LWIP_DHCP
1016     dhcp_network_changed_link_up(netif);
1017 #endif /* LWIP_DHCP */
1018 
1019 #if LWIP_AUTOIP
1020     autoip_network_changed_link_up(netif);
1021 #endif /* LWIP_AUTOIP */
1022 
1023     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6);
1024 #if LWIP_IPV6
1025     nd6_restart_netif(netif);
1026 #endif /* LWIP_IPV6 */
1027 
1028     NETIF_LINK_CALLBACK(netif);
1029 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1030     {
1031       netif_ext_callback_args_t args;
1032       args.link_changed.state = 1;
1033       netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args);
1034     }
1035 #endif
1036   }
1037 }
1038 
1039 /**
1040  * @ingroup netif
1041  * Called by a driver when its link goes down
1042  */
1043 void
netif_set_link_down(struct netif * netif)1044 netif_set_link_down(struct netif *netif)
1045 {
1046   LWIP_ASSERT_CORE_LOCKED();
1047 
1048   LWIP_ERROR("netif_set_link_down: invalid netif", netif != NULL, return);
1049 
1050   if (netif->flags & NETIF_FLAG_LINK_UP) {
1051     netif_clear_flags(netif, NETIF_FLAG_LINK_UP);
1052 
1053 #if LWIP_AUTOIP
1054     autoip_network_changed_link_down(netif);
1055 #endif /* LWIP_AUTOIP */
1056 
1057 #if LWIP_ACD
1058     acd_network_changed_link_down(netif);
1059 #endif /* LWIP_ACD */
1060 
1061 #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
1062     netif->mtu6 = netif->mtu;
1063 #endif
1064 
1065     NETIF_LINK_CALLBACK(netif);
1066 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1067     {
1068       netif_ext_callback_args_t args;
1069       args.link_changed.state = 0;
1070       netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args);
1071     }
1072 #endif
1073   }
1074 }
1075 
1076 #if LWIP_NETIF_LINK_CALLBACK
1077 /**
1078  * @ingroup netif
1079  * Set callback to be called when link is brought up/down
1080  */
1081 void
netif_set_link_callback(struct netif * netif,netif_status_callback_fn link_callback)1082 netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
1083 {
1084   LWIP_ASSERT_CORE_LOCKED();
1085 
1086   if (netif) {
1087     netif->link_callback = link_callback;
1088   }
1089 }
1090 #endif /* LWIP_NETIF_LINK_CALLBACK */
1091 
1092 #if ENABLE_LOOPBACK
1093 /**
1094  * @ingroup netif
1095  * Send an IP packet to be received on the same netif (loopif-like).
1096  * The pbuf is simply copied and handed back to netif->input.
1097  * In multithreaded mode, this is done directly since netif->input must put
1098  * the packet on a queue.
1099  * In callback mode, the packet is put on an internal queue and is fed to
1100  * netif->input by netif_poll().
1101  *
1102  * @param netif the lwip network interface structure
1103  * @param p the (IP) packet to 'send'
1104  * @return ERR_OK if the packet has been sent
1105  *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
1106  */
1107 err_t
netif_loop_output(struct netif * netif,struct pbuf * p)1108 netif_loop_output(struct netif *netif, struct pbuf *p)
1109 {
1110   struct pbuf *r;
1111   err_t err;
1112   struct pbuf *last;
1113 #if LWIP_LOOPBACK_MAX_PBUFS
1114   u16_t clen = 0;
1115 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1116   /* If we have a loopif, SNMP counters are adjusted for it,
1117    * if not they are adjusted for 'netif'. */
1118 #if MIB2_STATS
1119 #if LWIP_HAVE_LOOPIF
1120   struct netif *stats_if = &loop_netif;
1121 #else /* LWIP_HAVE_LOOPIF */
1122   struct netif *stats_if = netif;
1123 #endif /* LWIP_HAVE_LOOPIF */
1124 #endif /* MIB2_STATS */
1125 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1126   u8_t schedule_poll = 0;
1127 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1128   SYS_ARCH_DECL_PROTECT(lev);
1129 
1130   LWIP_ASSERT("netif_loop_output: invalid netif", netif != NULL);
1131   LWIP_ASSERT("netif_loop_output: invalid pbuf", p != NULL);
1132 
1133   /* Allocate a new pbuf */
1134   r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
1135   if (r == NULL) {
1136     LINK_STATS_INC(link.memerr);
1137     LINK_STATS_INC(link.drop);
1138     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1139     return ERR_MEM;
1140   }
1141 #if LWIP_LOOPBACK_MAX_PBUFS
1142   clen = pbuf_clen(r);
1143   /* check for overflow or too many pbuf on queue */
1144   if (((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
1145       ((netif->loop_cnt_current + clen) > LWIP_MIN(LWIP_LOOPBACK_MAX_PBUFS, 0xFFFF))) {
1146     pbuf_free(r);
1147     LINK_STATS_INC(link.memerr);
1148     LINK_STATS_INC(link.drop);
1149     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1150     return ERR_MEM;
1151   }
1152   netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current + clen);
1153 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1154 
1155   /* Copy the whole pbuf queue p into the single pbuf r */
1156   if ((err = pbuf_copy(r, p)) != ERR_OK) {
1157     pbuf_free(r);
1158     LINK_STATS_INC(link.memerr);
1159     LINK_STATS_INC(link.drop);
1160     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1161     return err;
1162   }
1163 
1164   /* Put the packet on a linked list which gets emptied through calling
1165      netif_poll(). */
1166 
1167   /* let last point to the last pbuf in chain r */
1168   for (last = r; last->next != NULL; last = last->next) {
1169     /* nothing to do here, just get to the last pbuf */
1170   }
1171 
1172   SYS_ARCH_PROTECT(lev);
1173   if (netif->loop_first != NULL) {
1174     LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
1175     netif->loop_last->next = r;
1176     netif->loop_last = last;
1177   } else {
1178     netif->loop_first = r;
1179     netif->loop_last = last;
1180 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1181     /* No existing packets queued, schedule poll */
1182     schedule_poll = 1;
1183 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1184   }
1185   SYS_ARCH_UNPROTECT(lev);
1186 
1187   LINK_STATS_INC(link.xmit);
1188   MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len);
1189   MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts);
1190 
1191 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1192   /* For multithreading environment, schedule a call to netif_poll */
1193   if (schedule_poll) {
1194     tcpip_try_callback((tcpip_callback_fn)netif_poll, netif);
1195   }
1196 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1197 
1198   return ERR_OK;
1199 }
1200 
1201 #if LWIP_HAVE_LOOPIF
1202 #if LWIP_IPV4
1203 static err_t
netif_loop_output_ipv4(struct netif * netif,struct pbuf * p,const ip4_addr_t * addr)1204 netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr)
1205 {
1206   LWIP_UNUSED_ARG(addr);
1207   return netif_loop_output(netif, p);
1208 }
1209 #endif /* LWIP_IPV4 */
1210 
1211 #if LWIP_IPV6
1212 static err_t
netif_loop_output_ipv6(struct netif * netif,struct pbuf * p,const ip6_addr_t * addr)1213 netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr)
1214 {
1215   LWIP_UNUSED_ARG(addr);
1216   return netif_loop_output(netif, p);
1217 }
1218 #endif /* LWIP_IPV6 */
1219 #endif /* LWIP_HAVE_LOOPIF */
1220 
1221 
1222 /**
1223  * Call netif_poll() in the main loop of your application. This is to prevent
1224  * reentering non-reentrant functions like tcp_input(). Packets passed to
1225  * netif_loop_output() are put on a list that is passed to netif->input() by
1226  * netif_poll().
1227  */
1228 void
netif_poll(struct netif * netif)1229 netif_poll(struct netif *netif)
1230 {
1231   /* If we have a loopif, SNMP counters are adjusted for it,
1232    * if not they are adjusted for 'netif'. */
1233 #if MIB2_STATS
1234 #if LWIP_HAVE_LOOPIF
1235   struct netif *stats_if = &loop_netif;
1236 #else /* LWIP_HAVE_LOOPIF */
1237   struct netif *stats_if = netif;
1238 #endif /* LWIP_HAVE_LOOPIF */
1239 #endif /* MIB2_STATS */
1240   SYS_ARCH_DECL_PROTECT(lev);
1241 
1242   LWIP_ASSERT("netif_poll: invalid netif", netif != NULL);
1243 
1244   /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
1245   SYS_ARCH_PROTECT(lev);
1246   while (netif->loop_first != NULL) {
1247     struct pbuf *in, *in_end;
1248 #if LWIP_LOOPBACK_MAX_PBUFS
1249     u8_t clen = 1;
1250 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1251 
1252     in = in_end = netif->loop_first;
1253     while (in_end->len != in_end->tot_len) {
1254       LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
1255       in_end = in_end->next;
1256 #if LWIP_LOOPBACK_MAX_PBUFS
1257       clen++;
1258 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1259     }
1260 #if LWIP_LOOPBACK_MAX_PBUFS
1261     /* adjust the number of pbufs on queue */
1262     LWIP_ASSERT("netif->loop_cnt_current underflow",
1263                 ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
1264     netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current - clen);
1265 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1266 
1267     /* 'in_end' now points to the last pbuf from 'in' */
1268     if (in_end == netif->loop_last) {
1269       /* this was the last pbuf in the list */
1270       netif->loop_first = netif->loop_last = NULL;
1271     } else {
1272       /* pop the pbuf off the list */
1273       netif->loop_first = in_end->next;
1274       LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
1275     }
1276     /* De-queue the pbuf from its successors on the 'loop_' list. */
1277     in_end->next = NULL;
1278     SYS_ARCH_UNPROTECT(lev);
1279 
1280     in->if_idx = netif_get_index(netif);
1281 
1282     LINK_STATS_INC(link.recv);
1283     MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
1284     MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
1285     /* loopback packets are always IP packets! */
1286     if (ip_input(in, netif) != ERR_OK) {
1287       pbuf_free(in);
1288     }
1289     SYS_ARCH_PROTECT(lev);
1290   }
1291   SYS_ARCH_UNPROTECT(lev);
1292 }
1293 
1294 #if !LWIP_NETIF_LOOPBACK_MULTITHREADING
1295 /**
1296  * Calls netif_poll() for every netif on the netif_list.
1297  */
1298 void
netif_poll_all(void)1299 netif_poll_all(void)
1300 {
1301   struct netif *netif;
1302   /* loop through netifs */
1303   NETIF_FOREACH(netif) {
1304     netif_poll(netif);
1305   }
1306 }
1307 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
1308 #endif /* ENABLE_LOOPBACK */
1309 
1310 #if LWIP_NUM_NETIF_CLIENT_DATA > 0
1311 /**
1312  * @ingroup netif_cd
1313  * Allocate an index to store data in client_data member of struct netif.
1314  * Returned value is an index in mentioned array.
1315  * @see LWIP_NUM_NETIF_CLIENT_DATA
1316  */
1317 u8_t
netif_alloc_client_data_id(void)1318 netif_alloc_client_data_id(void)
1319 {
1320   u8_t result = netif_client_id;
1321   netif_client_id++;
1322 
1323   LWIP_ASSERT_CORE_LOCKED();
1324 
1325 #if LWIP_NUM_NETIF_CLIENT_DATA > 256
1326 #error LWIP_NUM_NETIF_CLIENT_DATA must be <= 256
1327 #endif
1328   LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA);
1329   return (u8_t)(result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX);
1330 }
1331 #endif
1332 
1333 #if LWIP_IPV6
1334 /**
1335  * @ingroup netif_ip6
1336  * Change an IPv6 address of a network interface
1337  *
1338  * @param netif the network interface to change
1339  * @param addr_idx index of the IPv6 address
1340  * @param addr6 the new IPv6 address
1341  *
1342  * @note call netif_ip6_addr_set_state() to set the address valid/temptative
1343  */
1344 void
netif_ip6_addr_set(struct netif * netif,s8_t addr_idx,const ip6_addr_t * addr6)1345 netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6)
1346 {
1347   LWIP_ASSERT_CORE_LOCKED();
1348 
1349   LWIP_ASSERT("netif_ip6_addr_set: invalid netif", netif != NULL);
1350   LWIP_ASSERT("netif_ip6_addr_set: invalid addr6", addr6 != NULL);
1351 
1352   netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1],
1353                            addr6->addr[2], addr6->addr[3]);
1354 }
1355 
1356 /*
1357  * Change an IPv6 address of a network interface (internal version taking 4 * u32_t)
1358  *
1359  * @param netif the network interface to change
1360  * @param addr_idx index of the IPv6 address
1361  * @param i0 word0 of the new IPv6 address
1362  * @param i1 word1 of the new IPv6 address
1363  * @param i2 word2 of the new IPv6 address
1364  * @param i3 word3 of the new IPv6 address
1365  */
1366 void
netif_ip6_addr_set_parts(struct netif * netif,s8_t addr_idx,u32_t i0,u32_t i1,u32_t i2,u32_t i3)1367 netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3)
1368 {
1369   ip_addr_t old_addr;
1370   ip_addr_t new_ipaddr;
1371   LWIP_ASSERT_CORE_LOCKED();
1372   LWIP_ASSERT("netif != NULL", netif != NULL);
1373   LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
1374 
1375   ip6_addr_copy(*ip_2_ip6(&old_addr), *netif_ip6_addr(netif, addr_idx));
1376   IP_SET_TYPE_VAL(old_addr, IPADDR_TYPE_V6);
1377 
1378   /* address is actually being changed? */
1379   if ((ip_2_ip6(&old_addr)->addr[0] != i0) || (ip_2_ip6(&old_addr)->addr[1] != i1) ||
1380       (ip_2_ip6(&old_addr)->addr[2] != i2) || (ip_2_ip6(&old_addr)->addr[3] != i3)) {
1381     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n"));
1382 
1383     IP_ADDR6(&new_ipaddr, i0, i1, i2, i3);
1384     ip6_addr_assign_zone(ip_2_ip6(&new_ipaddr), IP6_UNICAST, netif);
1385 
1386     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) {
1387       netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr);
1388     }
1389     /* @todo: remove/readd mib2 ip6 entries? */
1390 
1391     ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr);
1392 
1393     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) {
1394       netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
1395       NETIF_STATUS_CALLBACK(netif);
1396     }
1397 
1398 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1399     {
1400       netif_ext_callback_args_t args;
1401       args.ipv6_set.addr_index  = addr_idx;
1402       args.ipv6_set.old_address = &old_addr;
1403       netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_SET, &args);
1404     }
1405 #endif
1406   }
1407 
1408   LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n",
1409               addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
1410               netif_ip6_addr_state(netif, addr_idx)));
1411 }
1412 
1413 /**
1414  * @ingroup netif_ip6
1415  * Change the state of an IPv6 address of a network interface
1416  * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE
1417  * includes the number of checks done, see ip6_addr.h)
1418  *
1419  * @param netif the network interface to change
1420  * @param addr_idx index of the IPv6 address
1421  * @param state the new IPv6 address state
1422  */
1423 void
netif_ip6_addr_set_state(struct netif * netif,s8_t addr_idx,u8_t state)1424 netif_ip6_addr_set_state(struct netif *netif, s8_t addr_idx, u8_t state)
1425 {
1426   u8_t old_state;
1427   LWIP_ASSERT_CORE_LOCKED();
1428   LWIP_ASSERT("netif != NULL", netif != NULL);
1429   LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
1430 
1431   old_state = netif_ip6_addr_state(netif, addr_idx);
1432   /* state is actually being changed? */
1433   if (old_state != state) {
1434     u8_t old_valid = old_state & IP6_ADDR_VALID;
1435     u8_t new_valid = state & IP6_ADDR_VALID;
1436     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n"));
1437 
1438 #if LWIP_IPV6_MLD
1439     /* Reevaluate solicited-node multicast group membership. */
1440     if (netif->flags & NETIF_FLAG_MLD6) {
1441       nd6_adjust_mld_membership(netif, addr_idx, state);
1442     }
1443 #endif /* LWIP_IPV6_MLD */
1444 
1445     if (old_valid && !new_valid) {
1446       /* address about to be removed by setting invalid */
1447       netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL);
1448       /* @todo: remove mib2 ip6 entries? */
1449     }
1450     netif->ip6_addr_state[addr_idx] = state;
1451 
1452     if (!old_valid && new_valid) {
1453       /* address added by setting valid */
1454       /* This is a good moment to check that the address is properly zoned. */
1455       IP6_ADDR_ZONECHECK_NETIF(netif_ip6_addr(netif, addr_idx), netif);
1456       /* @todo: add mib2 ip6 entries? */
1457       netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
1458     }
1459     if ((old_state & ~IP6_ADDR_TENTATIVE_COUNT_MASK) !=
1460         (state     & ~IP6_ADDR_TENTATIVE_COUNT_MASK)) {
1461       /* address state has changed -> call the callback function */
1462       NETIF_STATUS_CALLBACK(netif);
1463     }
1464 
1465 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1466     {
1467       netif_ext_callback_args_t args;
1468       args.ipv6_addr_state_changed.addr_index = addr_idx;
1469       args.ipv6_addr_state_changed.old_state  = old_state;
1470       args.ipv6_addr_state_changed.address    = netif_ip_addr6(netif, addr_idx);
1471       netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_ADDR_STATE_CHANGED, &args);
1472     }
1473 #endif
1474   }
1475   LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IPv6 address %d of interface %c%c set to %s/0x%"X8_F"\n",
1476               addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
1477               netif_ip6_addr_state(netif, addr_idx)));
1478 }
1479 
1480 /**
1481  * Checks if a specific local address is present on the netif and returns its
1482  * index. Depending on its state, it may or may not be assigned to the
1483  * interface (as per RFC terminology).
1484  *
1485  * The given address may or may not be zoned (i.e., have a zone index other
1486  * than IP6_NO_ZONE). If the address is zoned, it must have the correct zone
1487  * for the given netif, or no match will be found.
1488  *
1489  * @param netif the netif to check
1490  * @param ip6addr the IPv6 address to find
1491  * @return >= 0: address found, this is its index
1492  *         -1: address not found on this netif
1493  */
1494 s8_t
netif_get_ip6_addr_match(struct netif * netif,const ip6_addr_t * ip6addr)1495 netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr)
1496 {
1497   s8_t i;
1498 
1499   LWIP_ASSERT_CORE_LOCKED();
1500 
1501   LWIP_ASSERT("netif_get_ip6_addr_match: invalid netif", netif != NULL);
1502   LWIP_ASSERT("netif_get_ip6_addr_match: invalid ip6addr", ip6addr != NULL);
1503 
1504 #if LWIP_IPV6_SCOPES
1505   if (ip6_addr_has_zone(ip6addr) && !ip6_addr_test_zone(ip6addr, netif)) {
1506     return -1; /* wrong zone, no match */
1507   }
1508 #endif /* LWIP_IPV6_SCOPES */
1509 
1510   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1511     if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) &&
1512         ip6_addr_cmp_zoneless(netif_ip6_addr(netif, i), ip6addr)) {
1513       return i;
1514     }
1515   }
1516   return -1;
1517 }
1518 
1519 /**
1520  * @ingroup netif_ip6
1521  * Create a link-local IPv6 address on a netif (stored in slot 0)
1522  *
1523  * @param netif the netif to create the address on
1524  * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion)
1525  *                       if == 0, use hwaddr directly as interface ID
1526  */
1527 void
netif_create_ip6_linklocal_address(struct netif * netif,u8_t from_mac_48bit)1528 netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
1529 {
1530   u8_t i, addr_index;
1531 
1532   LWIP_ASSERT_CORE_LOCKED();
1533 
1534   LWIP_ASSERT("netif_create_ip6_linklocal_address: invalid netif", netif != NULL);
1535 
1536   /* Link-local prefix. */
1537   ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul);
1538   ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0;
1539 
1540   /* Generate interface ID. */
1541   if (from_mac_48bit) {
1542     /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
1543     ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
1544         ((u32_t)(netif->hwaddr[1]) << 16) |
1545         ((u32_t)(netif->hwaddr[2]) << 8) |
1546         (0xff));
1547     ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((u32_t)(0xfeul << 24) |
1548         ((u32_t)(netif->hwaddr[3]) << 16) |
1549         ((u32_t)(netif->hwaddr[4]) << 8) |
1550         (netif->hwaddr[5]));
1551   } else {
1552     /* Use hwaddr directly as interface ID. */
1553     ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0;
1554     ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0;
1555 
1556     addr_index = 3;
1557     for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) {
1558       if (i == 4) {
1559         addr_index--;
1560       }
1561       ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= lwip_htonl(((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)));
1562     }
1563   }
1564 
1565   /* Set a link-local zone. Even though the zone is implied by the owning
1566    * netif, setting the zone anyway has two important conceptual advantages:
1567    * 1) it avoids the need for a ton of exceptions in internal code, allowing
1568    *    e.g. ip6_addr_cmp() to be used on local addresses;
1569    * 2) the properly zoned address is visible externally, e.g. when any outside
1570    *    code enumerates available addresses or uses one to bind a socket.
1571    * Any external code unaware of address scoping is likely to just ignore the
1572    * zone field, so this should not create any compatibility problems. */
1573   ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[0]), IP6_UNICAST, netif);
1574 
1575   /* Set address state. */
1576 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
1577   /* Will perform duplicate address detection (DAD). */
1578   netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE);
1579 #else
1580   /* Consider address valid. */
1581   netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED);
1582 #endif /* LWIP_IPV6_AUTOCONFIG */
1583 }
1584 
1585 /**
1586  * @ingroup netif_ip6
1587  * This function allows for the easy addition of a new IPv6 address to an interface.
1588  * It takes care of finding an empty slot and then sets the address tentative
1589  * (to make sure that all the subsequent processing happens).
1590  *
1591  * @param netif netif to add the address on
1592  * @param ip6addr address to add
1593  * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here
1594  */
1595 err_t
netif_add_ip6_address(struct netif * netif,const ip6_addr_t * ip6addr,s8_t * chosen_idx)1596 netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx)
1597 {
1598   s8_t i;
1599 
1600   LWIP_ASSERT_CORE_LOCKED();
1601 
1602   LWIP_ASSERT("netif_add_ip6_address: invalid netif", netif != NULL);
1603   LWIP_ASSERT("netif_add_ip6_address: invalid ip6addr", ip6addr != NULL);
1604 
1605   i = netif_get_ip6_addr_match(netif, ip6addr);
1606   if (i >= 0) {
1607     /* Address already added */
1608     if (chosen_idx != NULL) {
1609       *chosen_idx = i;
1610     }
1611     return ERR_OK;
1612   }
1613 
1614   /* Find a free slot. The first one is reserved for link-local addresses. */
1615   for (i = ip6_addr_islinklocal(ip6addr) ? 0 : 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1616     if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
1617       ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr);
1618       ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[i]), IP6_UNICAST, netif);
1619       netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE);
1620       if (chosen_idx != NULL) {
1621         *chosen_idx = i;
1622       }
1623       return ERR_OK;
1624     }
1625   }
1626 
1627   if (chosen_idx != NULL) {
1628     *chosen_idx = -1;
1629   }
1630   return ERR_VAL;
1631 }
1632 
1633 /** Dummy IPv6 output function for netifs not supporting IPv6
1634  */
1635 static err_t
netif_null_output_ip6(struct netif * netif,struct pbuf * p,const ip6_addr_t * ipaddr)1636 netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
1637 {
1638   LWIP_UNUSED_ARG(netif);
1639   LWIP_UNUSED_ARG(p);
1640   LWIP_UNUSED_ARG(ipaddr);
1641 
1642   return ERR_IF;
1643 }
1644 #endif /* LWIP_IPV6 */
1645 
1646 #if LWIP_IPV4
1647 /** Dummy IPv4 output function for netifs not supporting IPv4
1648  */
1649 static err_t
netif_null_output_ip4(struct netif * netif,struct pbuf * p,const ip4_addr_t * ipaddr)1650 netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
1651 {
1652   LWIP_UNUSED_ARG(netif);
1653   LWIP_UNUSED_ARG(p);
1654   LWIP_UNUSED_ARG(ipaddr);
1655 
1656   return ERR_IF;
1657 }
1658 #endif /* LWIP_IPV4 */
1659 
1660 /**
1661 * @ingroup netif
1662 * Return the interface index for the netif with name
1663 * or NETIF_NO_INDEX if not found/on error
1664 *
1665 * @param name the name of the netif
1666 */
1667 u8_t
netif_name_to_index(const char * name)1668 netif_name_to_index(const char *name)
1669 {
1670   struct netif *netif = netif_find(name);
1671   if (netif != NULL) {
1672     return netif_get_index(netif);
1673   }
1674   /* No name found, return invalid index */
1675   return NETIF_NO_INDEX;
1676 }
1677 
1678 /**
1679 * @ingroup netif
1680 * Return the interface name for the netif matching index
1681 * or NULL if not found/on error
1682 *
1683 * @param idx the interface index of the netif
1684 * @param name char buffer of at least NETIF_NAMESIZE bytes
1685 */
1686 char *
netif_index_to_name(u8_t idx,char * name)1687 netif_index_to_name(u8_t idx, char *name)
1688 {
1689   struct netif *netif = netif_get_by_index(idx);
1690 
1691   if (netif != NULL) {
1692     name[0] = netif->name[0];
1693     name[1] = netif->name[1];
1694     lwip_itoa(&name[2], NETIF_NAMESIZE - 2, netif_index_to_num(idx));
1695     return name;
1696   }
1697   return NULL;
1698 }
1699 
1700 /**
1701 * @ingroup netif
1702 * Return the interface for the netif index
1703 *
1704 * @param idx index of netif to find
1705 */
1706 struct netif *
netif_get_by_index(u8_t idx)1707 netif_get_by_index(u8_t idx)
1708 {
1709   struct netif *netif;
1710 
1711   LWIP_ASSERT_CORE_LOCKED();
1712 
1713   if (idx != NETIF_NO_INDEX) {
1714     NETIF_FOREACH(netif) {
1715       if (idx == netif_get_index(netif)) {
1716         return netif; /* found! */
1717       }
1718     }
1719   }
1720 
1721   return NULL;
1722 }
1723 
1724 /**
1725  * @ingroup netif
1726  * Find a network interface by searching for its name
1727  *
1728  * @param name the name of the netif (like netif->name) plus concatenated number
1729  * in ascii representation (e.g. 'en0')
1730  */
1731 struct netif *
netif_find(const char * name)1732 netif_find(const char *name)
1733 {
1734   struct netif *netif;
1735   u8_t num;
1736 
1737   LWIP_ASSERT_CORE_LOCKED();
1738 
1739   if (name == NULL) {
1740     return NULL;
1741   }
1742 
1743   num = (u8_t)atoi(&name[2]);
1744 
1745   NETIF_FOREACH(netif) {
1746     if (num == netif->num &&
1747         name[0] == netif->name[0] &&
1748         name[1] == netif->name[1]) {
1749       LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
1750       return netif;
1751     }
1752   }
1753   LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
1754   return NULL;
1755 }
1756 
1757 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1758 /**
1759  * @ingroup netif
1760  * Add extended netif events listener
1761  * @param callback pointer to listener structure
1762  * @param fn callback function
1763  */
1764 void
netif_add_ext_callback(netif_ext_callback_t * callback,netif_ext_callback_fn fn)1765 netif_add_ext_callback(netif_ext_callback_t *callback, netif_ext_callback_fn fn)
1766 {
1767   LWIP_ASSERT_CORE_LOCKED();
1768   LWIP_ASSERT("callback must be != NULL", callback != NULL);
1769   LWIP_ASSERT("fn must be != NULL", fn != NULL);
1770 
1771   callback->callback_fn = fn;
1772   callback->next        = ext_callback;
1773   ext_callback          = callback;
1774 }
1775 
1776 /**
1777  * @ingroup netif
1778  * Remove extended netif events listener
1779  * @param callback pointer to listener structure
1780  */
1781 void
netif_remove_ext_callback(netif_ext_callback_t * callback)1782 netif_remove_ext_callback(netif_ext_callback_t* callback)
1783 {
1784   netif_ext_callback_t *last, *iter;
1785 
1786   LWIP_ASSERT_CORE_LOCKED();
1787   LWIP_ASSERT("callback must be != NULL", callback != NULL);
1788 
1789   if (ext_callback == NULL) {
1790     return;
1791   }
1792 
1793   if (callback == ext_callback) {
1794     ext_callback = ext_callback->next;
1795   } else {
1796     last = ext_callback;
1797     for (iter = ext_callback->next; iter != NULL; last = iter, iter = iter->next) {
1798       if (iter == callback) {
1799         LWIP_ASSERT("last != NULL", last != NULL);
1800         last->next = callback->next;
1801         callback->next = NULL;
1802         return;
1803       }
1804     }
1805   }
1806 }
1807 
1808 /**
1809  * Invoke extended netif status event
1810  * @param netif netif that is affected by change
1811  * @param reason change reason
1812  * @param args depends on reason, see reason description
1813  */
1814 void
netif_invoke_ext_callback(struct netif * netif,netif_nsc_reason_t reason,const netif_ext_callback_args_t * args)1815 netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args)
1816 {
1817   netif_ext_callback_t *callback = ext_callback;
1818 
1819   LWIP_ASSERT("netif must be != NULL", netif != NULL);
1820 
1821   while (callback != NULL) {
1822     callback->callback_fn(netif, reason, args);
1823     callback = callback->next;
1824   }
1825 }
1826 #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */
1827