xref: /reactos/drivers/network/tcpip/lwip/src/core/netif.c (revision d6eebaa4)
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 <adam@sics.se>
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 should be enabled by default */
346   netif->ip6_autoconfig_enabled = 1;
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 
363   /* remember netif specific state information data */
364   netif->state = state;
365   netif->num = netif_num;
366   netif->input = input;
367 
368 #if LWIP_ACD
369   netif->acd_list = NULL;
370 #endif /* LWIP_ACD */
371   NETIF_RESET_HINTS(netif);
372 #if ENABLE_LOOPBACK
373   netif->loop_first = NULL;
374   netif->loop_last = NULL;
375 #if LWIP_LOOPBACK_MAX_PBUFS
376   netif->loop_cnt_current = 0;
377 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
378 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
379   netif->reschedule_poll = 0;
380 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
381 #endif /* ENABLE_LOOPBACK */
382 
383 #if LWIP_IPV4
384   netif_set_addr(netif, ipaddr, netmask, gw);
385 #endif /* LWIP_IPV4 */
386 
387   /* call user specified initialization function for netif */
388   if (init(netif) != ERR_OK) {
389     return NULL;
390   }
391 #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
392   /* Initialize the MTU for IPv6 to the one set by the netif driver.
393      This can be updated later by RA. */
394   netif->mtu6 = netif->mtu;
395 #endif /* LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES */
396 
397 #if !LWIP_SINGLE_NETIF
398   /* Assign a unique netif number in the range [0..254], so that (num+1) can
399      serve as an interface index that fits in a u8_t.
400      We assume that the new netif has not yet been added to the list here.
401      This algorithm is O(n^2), but that should be OK for lwIP.
402      */
403   {
404     struct netif *netif2;
405     int num_netifs;
406     do {
407       if (netif->num == 255) {
408         netif->num = 0;
409       }
410       num_netifs = 0;
411       for (netif2 = netif_list; netif2 != NULL; netif2 = netif2->next) {
412         LWIP_ASSERT("netif already added", netif2 != netif);
413         num_netifs++;
414         LWIP_ASSERT("too many netifs, max. supported number is 255", num_netifs <= 255);
415         if (netif2->num == netif->num) {
416           netif->num++;
417           break;
418         }
419       }
420     } while (netif2 != NULL);
421   }
422   if (netif->num == 254) {
423     netif_num = 0;
424   } else {
425     netif_num = (u8_t)(netif->num + 1);
426   }
427 
428   /* add this netif to the list */
429   netif->next = netif_list;
430   netif_list = netif;
431 #endif /* "LWIP_SINGLE_NETIF */
432   mib2_netif_added(netif);
433 
434 #if LWIP_IGMP
435   /* start IGMP processing */
436   if (netif->flags & NETIF_FLAG_IGMP) {
437     igmp_start(netif);
438   }
439 #endif /* LWIP_IGMP */
440 
441   LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP",
442                             netif->name[0], netif->name[1]));
443 #if LWIP_IPV4
444   LWIP_DEBUGF(NETIF_DEBUG, (" addr "));
445   ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
446   LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
447   ip4_addr_debug_print(NETIF_DEBUG, netmask);
448   LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
449   ip4_addr_debug_print(NETIF_DEBUG, gw);
450 #endif /* LWIP_IPV4 */
451   LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
452 
453   netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_ADDED, NULL);
454 
455   return netif;
456 }
457 
458 static void
netif_do_ip_addr_changed(const ip_addr_t * old_addr,const ip_addr_t * new_addr)459 netif_do_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr)
460 {
461 #if LWIP_TCP
462   tcp_netif_ip_addr_changed(old_addr, new_addr);
463 #endif /* LWIP_TCP */
464 #if LWIP_UDP
465   udp_netif_ip_addr_changed(old_addr, new_addr);
466 #endif /* LWIP_UDP */
467 #if LWIP_RAW
468   raw_netif_ip_addr_changed(old_addr, new_addr);
469 #endif /* LWIP_RAW */
470 }
471 
472 #if LWIP_IPV4
473 static int
netif_do_set_ipaddr(struct netif * netif,const ip4_addr_t * ipaddr,ip_addr_t * old_addr)474 netif_do_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr, ip_addr_t *old_addr)
475 {
476   LWIP_ASSERT("invalid pointer", ipaddr != NULL);
477   LWIP_ASSERT("invalid pointer", old_addr != NULL);
478 
479   /* address is actually being changed? */
480   if (ip4_addr_eq(ipaddr, netif_ip4_addr(netif)) == 0) {
481     ip_addr_t new_addr;
482     *ip_2_ip4(&new_addr) = *ipaddr;
483     IP_SET_TYPE_VAL(new_addr, IPADDR_TYPE_V4);
484 
485     ip_addr_copy(*old_addr, *netif_ip_addr4(netif));
486 
487     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
488     netif_do_ip_addr_changed(old_addr, &new_addr);
489 
490 #if LWIP_ACD
491     acd_netif_ip_addr_changed(netif, old_addr, &new_addr);
492 #endif /* LWIP_ACD */
493 
494     mib2_remove_ip4(netif);
495     mib2_remove_route_ip4(0, netif);
496     /* set new IP address to netif */
497     ip4_addr_set(ip_2_ip4(&netif->ip_addr), ipaddr);
498     IP_SET_TYPE_VAL(netif->ip_addr, IPADDR_TYPE_V4);
499     mib2_add_ip4(netif);
500     mib2_add_route_ip4(0, netif);
501 
502     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4);
503 
504     NETIF_STATUS_CALLBACK(netif);
505     return 1; /* address changed */
506   }
507   return 0; /* address unchanged */
508 }
509 
510 /**
511  * @ingroup netif_ip4
512  * Change the IP address of a network interface
513  *
514  * @param netif the network interface to change
515  * @param ipaddr the new IP address
516  *
517  * @note call netif_set_addr() if you also want to change netmask and
518  * default gateway
519  */
520 void
netif_set_ipaddr(struct netif * netif,const ip4_addr_t * ipaddr)521 netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr)
522 {
523   ip_addr_t old_addr;
524 
525   LWIP_ERROR("netif_set_ipaddr: invalid netif", netif != NULL, return);
526 
527   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
528   if (ipaddr == NULL) {
529     ipaddr = IP4_ADDR_ANY4;
530   }
531 
532   LWIP_ASSERT_CORE_LOCKED();
533 
534   if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
535 #if LWIP_NETIF_EXT_STATUS_CALLBACK
536     netif_ext_callback_args_t args;
537     args.ipv4_changed.old_address = &old_addr;
538     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_ADDRESS_CHANGED, &args);
539 #endif
540   }
541 }
542 
543 static int
netif_do_set_netmask(struct netif * netif,const ip4_addr_t * netmask,ip_addr_t * old_nm)544 netif_do_set_netmask(struct netif *netif, const ip4_addr_t *netmask, ip_addr_t *old_nm)
545 {
546   /* address is actually being changed? */
547   if (ip4_addr_eq(netmask, netif_ip4_netmask(netif)) == 0) {
548 #if LWIP_NETIF_EXT_STATUS_CALLBACK
549     LWIP_ASSERT("invalid pointer", old_nm != NULL);
550     ip_addr_copy(*old_nm, *netif_ip_netmask4(netif));
551 #else
552     LWIP_UNUSED_ARG(old_nm);
553 #endif
554     mib2_remove_route_ip4(0, netif);
555     /* set new netmask to netif */
556     ip4_addr_set(ip_2_ip4(&netif->netmask), netmask);
557     IP_SET_TYPE_VAL(netif->netmask, IPADDR_TYPE_V4);
558     mib2_add_route_ip4(0, netif);
559     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",
560                 netif->name[0], netif->name[1],
561                 ip4_addr1_16(netif_ip4_netmask(netif)),
562                 ip4_addr2_16(netif_ip4_netmask(netif)),
563                 ip4_addr3_16(netif_ip4_netmask(netif)),
564                 ip4_addr4_16(netif_ip4_netmask(netif))));
565     return 1; /* netmask changed */
566   }
567   return 0; /* netmask unchanged */
568 }
569 
570 /**
571  * @ingroup netif_ip4
572  * Change the netmask of a network interface
573  *
574  * @param netif the network interface to change
575  * @param netmask the new netmask
576  *
577  * @note call netif_set_addr() if you also want to change ip address and
578  * default gateway
579  */
580 void
netif_set_netmask(struct netif * netif,const ip4_addr_t * netmask)581 netif_set_netmask(struct netif *netif, const ip4_addr_t *netmask)
582 {
583 #if LWIP_NETIF_EXT_STATUS_CALLBACK
584   ip_addr_t old_nm_val;
585   ip_addr_t *old_nm = &old_nm_val;
586 #else
587   ip_addr_t *old_nm = NULL;
588 #endif
589   LWIP_ASSERT_CORE_LOCKED();
590 
591   LWIP_ERROR("netif_set_netmask: invalid netif", netif != NULL, return);
592 
593   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
594   if (netmask == NULL) {
595     netmask = IP4_ADDR_ANY4;
596   }
597 
598   if (netif_do_set_netmask(netif, netmask, old_nm)) {
599 #if LWIP_NETIF_EXT_STATUS_CALLBACK
600     netif_ext_callback_args_t args;
601     args.ipv4_changed.old_netmask = old_nm;
602     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_NETMASK_CHANGED, &args);
603 #endif
604   }
605 }
606 
607 static int
netif_do_set_gw(struct netif * netif,const ip4_addr_t * gw,ip_addr_t * old_gw)608 netif_do_set_gw(struct netif *netif, const ip4_addr_t *gw, ip_addr_t *old_gw)
609 {
610   /* address is actually being changed? */
611   if (ip4_addr_eq(gw, netif_ip4_gw(netif)) == 0) {
612 #if LWIP_NETIF_EXT_STATUS_CALLBACK
613     LWIP_ASSERT("invalid pointer", old_gw != NULL);
614     ip_addr_copy(*old_gw, *netif_ip_gw4(netif));
615 #else
616     LWIP_UNUSED_ARG(old_gw);
617 #endif
618 
619     ip4_addr_set(ip_2_ip4(&netif->gw), gw);
620     IP_SET_TYPE_VAL(netif->gw, IPADDR_TYPE_V4);
621     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",
622                 netif->name[0], netif->name[1],
623                 ip4_addr1_16(netif_ip4_gw(netif)),
624                 ip4_addr2_16(netif_ip4_gw(netif)),
625                 ip4_addr3_16(netif_ip4_gw(netif)),
626                 ip4_addr4_16(netif_ip4_gw(netif))));
627     return 1; /* gateway changed */
628   }
629   return 0; /* gateway unchanged */
630 }
631 
632 /**
633  * @ingroup netif_ip4
634  * Change the default gateway for a network interface
635  *
636  * @param netif the network interface to change
637  * @param gw the new default gateway
638  *
639  * @note call netif_set_addr() if you also want to change ip address and netmask
640  */
641 void
netif_set_gw(struct netif * netif,const ip4_addr_t * gw)642 netif_set_gw(struct netif *netif, const ip4_addr_t *gw)
643 {
644 #if LWIP_NETIF_EXT_STATUS_CALLBACK
645   ip_addr_t old_gw_val;
646   ip_addr_t *old_gw = &old_gw_val;
647 #else
648   ip_addr_t *old_gw = NULL;
649 #endif
650   LWIP_ASSERT_CORE_LOCKED();
651 
652   LWIP_ERROR("netif_set_gw: invalid netif", netif != NULL, return);
653 
654   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
655   if (gw == NULL) {
656     gw = IP4_ADDR_ANY4;
657   }
658 
659   if (netif_do_set_gw(netif, gw, old_gw)) {
660 #if LWIP_NETIF_EXT_STATUS_CALLBACK
661     netif_ext_callback_args_t args;
662     args.ipv4_changed.old_gw = old_gw;
663     netif_invoke_ext_callback(netif, LWIP_NSC_IPV4_GATEWAY_CHANGED, &args);
664 #endif
665   }
666 }
667 
668 /**
669  * @ingroup netif_ip4
670  * Change IP address configuration for a network interface (including netmask
671  * and default gateway).
672  *
673  * @param netif the network interface to change
674  * @param ipaddr the new IP address
675  * @param netmask the new netmask
676  * @param gw the new default gateway
677  */
678 void
netif_set_addr(struct netif * netif,const ip4_addr_t * ipaddr,const ip4_addr_t * netmask,const ip4_addr_t * gw)679 netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
680                const ip4_addr_t *gw)
681 {
682 #if LWIP_NETIF_EXT_STATUS_CALLBACK
683   netif_nsc_reason_t change_reason = LWIP_NSC_NONE;
684   netif_ext_callback_args_t cb_args;
685   ip_addr_t old_nm_val;
686   ip_addr_t old_gw_val;
687   ip_addr_t *old_nm = &old_nm_val;
688   ip_addr_t *old_gw = &old_gw_val;
689 #else
690   ip_addr_t *old_nm = NULL;
691   ip_addr_t *old_gw = NULL;
692 #endif
693   ip_addr_t old_addr;
694   int remove;
695 
696   LWIP_ASSERT_CORE_LOCKED();
697 
698   /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */
699   if (ipaddr == NULL) {
700     ipaddr = IP4_ADDR_ANY4;
701   }
702   if (netmask == NULL) {
703     netmask = IP4_ADDR_ANY4;
704   }
705   if (gw == NULL) {
706     gw = IP4_ADDR_ANY4;
707   }
708 
709   remove = ip4_addr_isany(ipaddr);
710   if (remove) {
711     /* when removing an address, we have to remove it *before* changing netmask/gw
712        to ensure that tcp RST segment can be sent correctly */
713     if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
714 #if LWIP_NETIF_EXT_STATUS_CALLBACK
715       change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED;
716       cb_args.ipv4_changed.old_address = &old_addr;
717 #endif
718     }
719   }
720   if (netif_do_set_netmask(netif, netmask, old_nm)) {
721 #if LWIP_NETIF_EXT_STATUS_CALLBACK
722     change_reason |= LWIP_NSC_IPV4_NETMASK_CHANGED;
723     cb_args.ipv4_changed.old_netmask = old_nm;
724 #endif
725   }
726   if (netif_do_set_gw(netif, gw, old_gw)) {
727 #if LWIP_NETIF_EXT_STATUS_CALLBACK
728     change_reason |= LWIP_NSC_IPV4_GATEWAY_CHANGED;
729     cb_args.ipv4_changed.old_gw = old_gw;
730 #endif
731   }
732   if (!remove) {
733     /* set ipaddr last to ensure netmask/gw have been set when status callback is called */
734     if (netif_do_set_ipaddr(netif, ipaddr, &old_addr)) {
735 #if LWIP_NETIF_EXT_STATUS_CALLBACK
736       change_reason |= LWIP_NSC_IPV4_ADDRESS_CHANGED;
737       cb_args.ipv4_changed.old_address = &old_addr;
738 #endif
739     }
740   }
741 
742 #if LWIP_NETIF_EXT_STATUS_CALLBACK
743   if (change_reason != LWIP_NSC_NONE) {
744     change_reason |= LWIP_NSC_IPV4_SETTINGS_CHANGED;
745   }
746   if (!remove) {
747     /* Issue a callback even if the address hasn't changed, eg. DHCP reboot */
748     change_reason |= LWIP_NSC_IPV4_ADDR_VALID;
749   }
750   if (change_reason != LWIP_NSC_NONE) {
751     netif_invoke_ext_callback(netif, change_reason, &cb_args);
752   }
753 #endif
754 }
755 #endif /* LWIP_IPV4*/
756 
757 /**
758  * @ingroup netif
759  * Remove a network interface from the list of lwIP netifs.
760  *
761  * @param netif the network interface to remove
762  */
763 void
netif_remove(struct netif * netif)764 netif_remove(struct netif *netif)
765 {
766 #if LWIP_IPV6
767   int i;
768 #endif
769 
770   LWIP_ASSERT_CORE_LOCKED();
771 
772   if (netif == NULL) {
773     return;
774   }
775 
776   netif_invoke_ext_callback(netif, LWIP_NSC_NETIF_REMOVED, NULL);
777 
778 #if LWIP_IPV4
779   if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
780     netif_do_ip_addr_changed(netif_ip_addr4(netif), NULL);
781   }
782 
783 #if LWIP_IGMP
784   /* stop IGMP processing */
785   if (netif->flags & NETIF_FLAG_IGMP) {
786     igmp_stop(netif);
787   }
788 #endif /* LWIP_IGMP */
789 #endif /* LWIP_IPV4*/
790 
791 #if LWIP_IPV6
792   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
793     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
794       netif_do_ip_addr_changed(netif_ip_addr6(netif, i), NULL);
795     }
796   }
797 #if LWIP_IPV6_MLD
798   /* stop MLD processing */
799   mld6_stop(netif);
800 #endif /* LWIP_IPV6_MLD */
801 #endif /* LWIP_IPV6 */
802   if (netif_is_up(netif)) {
803     /* set netif down before removing (call callback function) */
804     netif_set_down(netif);
805   }
806 
807   mib2_remove_ip4(netif);
808 
809   /* this netif is default? */
810   if (netif_default == netif) {
811     /* reset default netif */
812     netif_set_default(NULL);
813   }
814 #if !LWIP_SINGLE_NETIF
815   /*  is it the first netif? */
816   if (netif_list == netif) {
817     netif_list = netif->next;
818   } else {
819     /*  look for netif further down the list */
820     struct netif *tmp_netif;
821     NETIF_FOREACH(tmp_netif) {
822       if (tmp_netif->next == netif) {
823         tmp_netif->next = netif->next;
824         break;
825       }
826     }
827     if (tmp_netif == NULL) {
828       return; /* netif is not on the list */
829     }
830   }
831 #endif /* !LWIP_SINGLE_NETIF */
832   mib2_netif_removed(netif);
833 #if LWIP_NETIF_REMOVE_CALLBACK
834   if (netif->remove_callback) {
835     netif->remove_callback(netif);
836   }
837 #endif /* LWIP_NETIF_REMOVE_CALLBACK */
838   LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
839 }
840 
841 /**
842  * @ingroup netif
843  * Set a network interface as the default network interface
844  * (used to output all packets for which no specific route is found)
845  *
846  * @param netif the default network interface
847  */
848 void
netif_set_default(struct netif * netif)849 netif_set_default(struct netif *netif)
850 {
851   LWIP_ASSERT_CORE_LOCKED();
852 
853   if (netif == NULL) {
854     /* remove default route */
855     mib2_remove_route_ip4(1, netif);
856   } else {
857     /* install default route */
858     mib2_add_route_ip4(1, netif);
859   }
860   netif_default = netif;
861   LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
862                             netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
863 }
864 
865 /**
866  * @ingroup netif
867  * Bring an interface up, available for processing
868  * traffic.
869  */
870 void
netif_set_up(struct netif * netif)871 netif_set_up(struct netif *netif)
872 {
873   LWIP_ASSERT_CORE_LOCKED();
874 
875   LWIP_ERROR("netif_set_up: invalid netif", netif != NULL, return);
876 
877   if (!(netif->flags & NETIF_FLAG_UP)) {
878     netif_set_flags(netif, NETIF_FLAG_UP);
879 
880     MIB2_COPY_SYSUPTIME_TO(&netif->ts);
881 
882     NETIF_STATUS_CALLBACK(netif);
883 
884 #if LWIP_NETIF_EXT_STATUS_CALLBACK
885     {
886       netif_ext_callback_args_t args;
887       args.status_changed.state = 1;
888       netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args);
889     }
890 #endif
891 
892     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6);
893 #if LWIP_IPV6
894     nd6_restart_netif(netif);
895 #endif /* LWIP_IPV6 */
896   }
897 }
898 
899 /** Send ARP/IGMP/MLD/RS events, e.g. on link-up/netif-up or addr-change
900  */
901 static void
netif_issue_reports(struct netif * netif,u8_t report_type)902 netif_issue_reports(struct netif *netif, u8_t report_type)
903 {
904   LWIP_ASSERT("netif_issue_reports: invalid netif", netif != NULL);
905 
906   /* Only send reports when both link and admin states are up */
907   if (!(netif->flags & NETIF_FLAG_LINK_UP) ||
908       !(netif->flags & NETIF_FLAG_UP)) {
909     return;
910   }
911 
912 #if LWIP_IPV4
913   if ((report_type & NETIF_REPORT_TYPE_IPV4) &&
914       !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
915 #if LWIP_ARP && !LWIP_ACD
916     /* For Ethernet network interfaces:
917      * we would like to send a "gratuitous ARP".
918      * Only needs to be done here if ACD isn't configured.
919      */
920     if (netif->flags & (NETIF_FLAG_ETHARP)) {
921       etharp_gratuitous(netif);
922     }
923 #endif /* LWIP_ARP */
924 
925 #if LWIP_IGMP
926     /* resend IGMP memberships */
927     if (netif->flags & NETIF_FLAG_IGMP) {
928       igmp_report_groups(netif);
929     }
930 #endif /* LWIP_IGMP */
931   }
932 #endif /* LWIP_IPV4 */
933 
934 #if LWIP_IPV6
935   if (report_type & NETIF_REPORT_TYPE_IPV6) {
936 #if LWIP_IPV6_MLD
937     /* send mld memberships */
938     mld6_report_groups(netif);
939 #endif /* LWIP_IPV6_MLD */
940   }
941 #endif /* LWIP_IPV6 */
942 }
943 
944 /**
945  * @ingroup netif
946  * Bring an interface down, disabling any traffic processing.
947  */
948 void
netif_set_down(struct netif * netif)949 netif_set_down(struct netif *netif)
950 {
951   LWIP_ASSERT_CORE_LOCKED();
952 
953   LWIP_ERROR("netif_set_down: invalid netif", netif != NULL, return);
954 
955   if (netif->flags & NETIF_FLAG_UP) {
956 #if LWIP_NETIF_EXT_STATUS_CALLBACK
957     {
958       netif_ext_callback_args_t args;
959       args.status_changed.state = 0;
960       netif_invoke_ext_callback(netif, LWIP_NSC_STATUS_CHANGED, &args);
961     }
962 #endif
963 
964     netif_clear_flags(netif, NETIF_FLAG_UP);
965     MIB2_COPY_SYSUPTIME_TO(&netif->ts);
966 
967 #if LWIP_IPV4 && LWIP_ARP
968     if (netif->flags & NETIF_FLAG_ETHARP) {
969       etharp_cleanup_netif(netif);
970     }
971 #endif /* LWIP_IPV4 && LWIP_ARP */
972 
973 #if LWIP_IPV6
974     nd6_cleanup_netif(netif);
975 #endif /* LWIP_IPV6 */
976 
977     NETIF_STATUS_CALLBACK(netif);
978   }
979 }
980 
981 #if LWIP_NETIF_STATUS_CALLBACK
982 /**
983  * @ingroup netif
984  * Set callback to be called when interface is brought up/down or address is changed while up
985  */
986 void
netif_set_status_callback(struct netif * netif,netif_status_callback_fn status_callback)987 netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
988 {
989   LWIP_ASSERT_CORE_LOCKED();
990 
991   if (netif) {
992     netif->status_callback = status_callback;
993   }
994 }
995 #endif /* LWIP_NETIF_STATUS_CALLBACK */
996 
997 #if LWIP_NETIF_REMOVE_CALLBACK
998 /**
999  * @ingroup netif
1000  * Set callback to be called when the interface has been removed
1001  */
1002 void
netif_set_remove_callback(struct netif * netif,netif_status_callback_fn remove_callback)1003 netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback)
1004 {
1005   LWIP_ASSERT_CORE_LOCKED();
1006 
1007   if (netif) {
1008     netif->remove_callback = remove_callback;
1009   }
1010 }
1011 #endif /* LWIP_NETIF_REMOVE_CALLBACK */
1012 
1013 /**
1014  * @ingroup netif
1015  * Called by a driver when its link goes up
1016  */
1017 void
netif_set_link_up(struct netif * netif)1018 netif_set_link_up(struct netif *netif)
1019 {
1020   LWIP_ASSERT_CORE_LOCKED();
1021 
1022   LWIP_ERROR("netif_set_link_up: invalid netif", netif != NULL, return);
1023 
1024   if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
1025     netif_set_flags(netif, NETIF_FLAG_LINK_UP);
1026 
1027 #if LWIP_DHCP
1028     dhcp_network_changed_link_up(netif);
1029 #endif /* LWIP_DHCP */
1030 
1031 #if LWIP_AUTOIP
1032     autoip_network_changed_link_up(netif);
1033 #endif /* LWIP_AUTOIP */
1034 
1035     netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV4 | NETIF_REPORT_TYPE_IPV6);
1036 #if LWIP_IPV6
1037     nd6_restart_netif(netif);
1038 #endif /* LWIP_IPV6 */
1039 
1040     NETIF_LINK_CALLBACK(netif);
1041 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1042     {
1043       netif_ext_callback_args_t args;
1044       args.link_changed.state = 1;
1045       netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args);
1046     }
1047 #endif
1048   }
1049 }
1050 
1051 /**
1052  * @ingroup netif
1053  * Called by a driver when its link goes down
1054  */
1055 void
netif_set_link_down(struct netif * netif)1056 netif_set_link_down(struct netif *netif)
1057 {
1058   LWIP_ASSERT_CORE_LOCKED();
1059 
1060   LWIP_ERROR("netif_set_link_down: invalid netif", netif != NULL, return);
1061 
1062   if (netif->flags & NETIF_FLAG_LINK_UP) {
1063     netif_clear_flags(netif, NETIF_FLAG_LINK_UP);
1064 
1065 #if LWIP_AUTOIP
1066     autoip_network_changed_link_down(netif);
1067 #endif /* LWIP_AUTOIP */
1068 
1069 #if LWIP_ACD
1070     acd_network_changed_link_down(netif);
1071 #endif /* LWIP_ACD */
1072 
1073 #if LWIP_IPV6 && LWIP_ND6_ALLOW_RA_UPDATES
1074     netif->mtu6 = netif->mtu;
1075 #endif
1076 
1077     NETIF_LINK_CALLBACK(netif);
1078 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1079     {
1080       netif_ext_callback_args_t args;
1081       args.link_changed.state = 0;
1082       netif_invoke_ext_callback(netif, LWIP_NSC_LINK_CHANGED, &args);
1083     }
1084 #endif
1085   }
1086 }
1087 
1088 #if LWIP_NETIF_LINK_CALLBACK
1089 /**
1090  * @ingroup netif
1091  * Set callback to be called when link is brought up/down
1092  */
1093 void
netif_set_link_callback(struct netif * netif,netif_status_callback_fn link_callback)1094 netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
1095 {
1096   LWIP_ASSERT_CORE_LOCKED();
1097 
1098   if (netif) {
1099     netif->link_callback = link_callback;
1100   }
1101 }
1102 #endif /* LWIP_NETIF_LINK_CALLBACK */
1103 
1104 #if ENABLE_LOOPBACK
1105 /**
1106  * @ingroup netif
1107  * Send an IP packet to be received on the same netif (loopif-like).
1108  * The pbuf is copied and added to an internal queue which is fed to
1109  * netif->input by netif_poll().
1110  * In multithreaded mode, the call to netif_poll() is queued to be done on the
1111  * TCP/IP thread.
1112  * In callback mode, the user has the responsibility to call netif_poll() in
1113  * the main loop of their application.
1114  *
1115  * @param netif the lwip network interface structure
1116  * @param p the (IP) packet to 'send'
1117  * @return ERR_OK if the packet has been sent
1118  *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
1119  */
1120 err_t
netif_loop_output(struct netif * netif,struct pbuf * p)1121 netif_loop_output(struct netif *netif, struct pbuf *p)
1122 {
1123   struct pbuf *r;
1124   err_t err;
1125   struct pbuf *last;
1126 #if LWIP_LOOPBACK_MAX_PBUFS
1127   u16_t clen = 0;
1128 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1129   /* If we have a loopif, SNMP counters are adjusted for it,
1130    * if not they are adjusted for 'netif'. */
1131 #if MIB2_STATS
1132 #if LWIP_HAVE_LOOPIF
1133   struct netif *stats_if = &loop_netif;
1134 #else /* LWIP_HAVE_LOOPIF */
1135   struct netif *stats_if = netif;
1136 #endif /* LWIP_HAVE_LOOPIF */
1137 #endif /* MIB2_STATS */
1138 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1139   u8_t schedule_poll = 0;
1140 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1141   SYS_ARCH_DECL_PROTECT(lev);
1142 
1143   LWIP_ASSERT("netif_loop_output: invalid netif", netif != NULL);
1144   LWIP_ASSERT("netif_loop_output: invalid pbuf", p != NULL);
1145 
1146   /* Allocate a new pbuf */
1147   r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
1148   if (r == NULL) {
1149     LINK_STATS_INC(link.memerr);
1150     LINK_STATS_INC(link.drop);
1151     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1152     return ERR_MEM;
1153   }
1154 #if LWIP_LOOPBACK_MAX_PBUFS
1155   clen = pbuf_clen(r);
1156   /* check for overflow or too many pbuf on queue */
1157   if (((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
1158       ((netif->loop_cnt_current + clen) > LWIP_MIN(LWIP_LOOPBACK_MAX_PBUFS, 0xFFFF))) {
1159     pbuf_free(r);
1160     LINK_STATS_INC(link.memerr);
1161     LINK_STATS_INC(link.drop);
1162     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1163     return ERR_MEM;
1164   }
1165   netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current + clen);
1166 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1167 
1168   /* Copy the whole pbuf queue p into the single pbuf r */
1169   if ((err = pbuf_copy(r, p)) != ERR_OK) {
1170     pbuf_free(r);
1171     LINK_STATS_INC(link.memerr);
1172     LINK_STATS_INC(link.drop);
1173     MIB2_STATS_NETIF_INC(stats_if, ifoutdiscards);
1174     return err;
1175   }
1176 
1177   /* Put the packet on a linked list which gets emptied through calling
1178      netif_poll(). */
1179 
1180   /* let last point to the last pbuf in chain r */
1181   for (last = r; last->next != NULL; last = last->next) {
1182     /* nothing to do here, just get to the last pbuf */
1183   }
1184 
1185   SYS_ARCH_PROTECT(lev);
1186   if (netif->loop_first != NULL) {
1187     LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
1188     netif->loop_last->next = r;
1189     netif->loop_last = last;
1190 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1191     if (netif->reschedule_poll) {
1192       schedule_poll = 1;
1193       netif->reschedule_poll = 0;
1194     }
1195 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1196   } else {
1197     netif->loop_first = r;
1198     netif->loop_last = last;
1199 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1200     /* No existing packets queued, schedule poll */
1201     schedule_poll = 1;
1202 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1203   }
1204   SYS_ARCH_UNPROTECT(lev);
1205 
1206   LINK_STATS_INC(link.xmit);
1207   MIB2_STATS_NETIF_ADD(stats_if, ifoutoctets, p->tot_len);
1208   MIB2_STATS_NETIF_INC(stats_if, ifoutucastpkts);
1209 
1210 #if LWIP_NETIF_LOOPBACK_MULTITHREADING
1211   /* For multithreading environment, schedule a call to netif_poll */
1212   if (schedule_poll) {
1213     if (tcpip_try_callback((tcpip_callback_fn)netif_poll, netif) != ERR_OK) {
1214       SYS_ARCH_PROTECT(lev);
1215       netif->reschedule_poll = 1;
1216       SYS_ARCH_UNPROTECT(lev);
1217     }
1218   }
1219 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
1220 
1221   return ERR_OK;
1222 }
1223 
1224 #if LWIP_HAVE_LOOPIF
1225 #if LWIP_IPV4
1226 static err_t
netif_loop_output_ipv4(struct netif * netif,struct pbuf * p,const ip4_addr_t * addr)1227 netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *addr)
1228 {
1229   LWIP_UNUSED_ARG(addr);
1230   return netif_loop_output(netif, p);
1231 }
1232 #endif /* LWIP_IPV4 */
1233 
1234 #if LWIP_IPV6
1235 static err_t
netif_loop_output_ipv6(struct netif * netif,struct pbuf * p,const ip6_addr_t * addr)1236 netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *addr)
1237 {
1238   LWIP_UNUSED_ARG(addr);
1239   return netif_loop_output(netif, p);
1240 }
1241 #endif /* LWIP_IPV6 */
1242 #endif /* LWIP_HAVE_LOOPIF */
1243 
1244 
1245 /**
1246  * Call netif_poll() in the main loop of your application. This is to prevent
1247  * reentering non-reentrant functions like tcp_input(). Packets passed to
1248  * netif_loop_output() are put on a list that is passed to netif->input() by
1249  * netif_poll().
1250  */
1251 void
netif_poll(struct netif * netif)1252 netif_poll(struct netif *netif)
1253 {
1254   /* If we have a loopif, SNMP counters are adjusted for it,
1255    * if not they are adjusted for 'netif'. */
1256 #if MIB2_STATS
1257 #if LWIP_HAVE_LOOPIF
1258   struct netif *stats_if = &loop_netif;
1259 #else /* LWIP_HAVE_LOOPIF */
1260   struct netif *stats_if = netif;
1261 #endif /* LWIP_HAVE_LOOPIF */
1262 #endif /* MIB2_STATS */
1263   SYS_ARCH_DECL_PROTECT(lev);
1264 
1265   LWIP_ASSERT("netif_poll: invalid netif", netif != NULL);
1266 
1267   /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
1268   SYS_ARCH_PROTECT(lev);
1269   while (netif->loop_first != NULL) {
1270     struct pbuf *in, *in_end;
1271 #if LWIP_LOOPBACK_MAX_PBUFS
1272     u8_t clen = 1;
1273 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1274 
1275     in = in_end = netif->loop_first;
1276     while (in_end->len != in_end->tot_len) {
1277       LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
1278       in_end = in_end->next;
1279 #if LWIP_LOOPBACK_MAX_PBUFS
1280       clen++;
1281 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1282     }
1283 #if LWIP_LOOPBACK_MAX_PBUFS
1284     /* adjust the number of pbufs on queue */
1285     LWIP_ASSERT("netif->loop_cnt_current underflow",
1286                 ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
1287     netif->loop_cnt_current = (u16_t)(netif->loop_cnt_current - clen);
1288 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
1289 
1290     /* 'in_end' now points to the last pbuf from 'in' */
1291     if (in_end == netif->loop_last) {
1292       /* this was the last pbuf in the list */
1293       netif->loop_first = netif->loop_last = NULL;
1294     } else {
1295       /* pop the pbuf off the list */
1296       netif->loop_first = in_end->next;
1297       LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
1298     }
1299     /* De-queue the pbuf from its successors on the 'loop_' list. */
1300     in_end->next = NULL;
1301     SYS_ARCH_UNPROTECT(lev);
1302 
1303     in->if_idx = netif_get_index(netif);
1304 
1305     LINK_STATS_INC(link.recv);
1306     MIB2_STATS_NETIF_ADD(stats_if, ifinoctets, in->tot_len);
1307     MIB2_STATS_NETIF_INC(stats_if, ifinucastpkts);
1308     /* loopback packets are always IP packets! */
1309     if (ip_input(in, netif) != ERR_OK) {
1310       pbuf_free(in);
1311     }
1312     SYS_ARCH_PROTECT(lev);
1313   }
1314   SYS_ARCH_UNPROTECT(lev);
1315 }
1316 
1317 #if !LWIP_NETIF_LOOPBACK_MULTITHREADING
1318 /**
1319  * Calls netif_poll() for every netif on the netif_list.
1320  */
1321 void
netif_poll_all(void)1322 netif_poll_all(void)
1323 {
1324   struct netif *netif;
1325   /* loop through netifs */
1326   NETIF_FOREACH(netif) {
1327     netif_poll(netif);
1328   }
1329 }
1330 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
1331 #endif /* ENABLE_LOOPBACK */
1332 
1333 #if LWIP_NUM_NETIF_CLIENT_DATA > 0
1334 /**
1335  * @ingroup netif_cd
1336  * Allocate an index to store data in client_data member of struct netif.
1337  * Returned value is an index in mentioned array.
1338  * @see LWIP_NUM_NETIF_CLIENT_DATA
1339  */
1340 u8_t
netif_alloc_client_data_id(void)1341 netif_alloc_client_data_id(void)
1342 {
1343   u8_t result = netif_client_id;
1344   netif_client_id++;
1345 
1346   LWIP_ASSERT_CORE_LOCKED();
1347 
1348 #if LWIP_NUM_NETIF_CLIENT_DATA > 256
1349 #error LWIP_NUM_NETIF_CLIENT_DATA must be <= 256
1350 #endif
1351   LWIP_ASSERT("Increase LWIP_NUM_NETIF_CLIENT_DATA in lwipopts.h", result < LWIP_NUM_NETIF_CLIENT_DATA);
1352   return (u8_t)(result + LWIP_NETIF_CLIENT_DATA_INDEX_MAX);
1353 }
1354 #endif
1355 
1356 #if LWIP_IPV6
1357 /**
1358  * @ingroup netif_ip6
1359  * Change an IPv6 address of a network interface
1360  *
1361  * @param netif the network interface to change
1362  * @param addr_idx index of the IPv6 address
1363  * @param addr6 the new IPv6 address
1364  *
1365  * @note call netif_ip6_addr_set_state() to set the address valid/temptative
1366  */
1367 void
netif_ip6_addr_set(struct netif * netif,s8_t addr_idx,const ip6_addr_t * addr6)1368 netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6)
1369 {
1370   LWIP_ASSERT_CORE_LOCKED();
1371 
1372   LWIP_ASSERT("netif_ip6_addr_set: invalid netif", netif != NULL);
1373   LWIP_ASSERT("netif_ip6_addr_set: invalid addr6", addr6 != NULL);
1374 
1375   netif_ip6_addr_set_parts(netif, addr_idx, addr6->addr[0], addr6->addr[1],
1376                            addr6->addr[2], addr6->addr[3]);
1377 }
1378 
1379 /*
1380  * Change an IPv6 address of a network interface (internal version taking 4 * u32_t)
1381  *
1382  * @param netif the network interface to change
1383  * @param addr_idx index of the IPv6 address
1384  * @param i0 word0 of the new IPv6 address
1385  * @param i1 word1 of the new IPv6 address
1386  * @param i2 word2 of the new IPv6 address
1387  * @param i3 word3 of the new IPv6 address
1388  */
1389 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)1390 netif_ip6_addr_set_parts(struct netif *netif, s8_t addr_idx, u32_t i0, u32_t i1, u32_t i2, u32_t i3)
1391 {
1392   ip_addr_t old_addr;
1393   ip_addr_t new_ipaddr;
1394   LWIP_ASSERT_CORE_LOCKED();
1395   LWIP_ASSERT("netif != NULL", netif != NULL);
1396   LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
1397 
1398   ip6_addr_copy(*ip_2_ip6(&old_addr), *netif_ip6_addr(netif, addr_idx));
1399   IP_SET_TYPE_VAL(old_addr, IPADDR_TYPE_V6);
1400 
1401   /* address is actually being changed? */
1402   if ((ip_2_ip6(&old_addr)->addr[0] != i0) || (ip_2_ip6(&old_addr)->addr[1] != i1) ||
1403       (ip_2_ip6(&old_addr)->addr[2] != i2) || (ip_2_ip6(&old_addr)->addr[3] != i3)) {
1404     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set: netif address being changed\n"));
1405 
1406     IP_ADDR6(&new_ipaddr, i0, i1, i2, i3);
1407     ip6_addr_assign_zone(ip_2_ip6(&new_ipaddr), IP6_UNICAST, netif);
1408 
1409     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) {
1410       netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), &new_ipaddr);
1411     }
1412     /* @todo: remove/readd mib2 ip6 entries? */
1413 
1414     ip_addr_copy(netif->ip6_addr[addr_idx], new_ipaddr);
1415 
1416     if (ip6_addr_isvalid(netif_ip6_addr_state(netif, addr_idx))) {
1417       netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
1418       NETIF_STATUS_CALLBACK(netif);
1419     }
1420 
1421 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1422     {
1423       netif_ext_callback_args_t args;
1424       args.ipv6_set.addr_index  = addr_idx;
1425       args.ipv6_set.old_address = &old_addr;
1426       netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_SET, &args);
1427     }
1428 #endif
1429   }
1430 
1431   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",
1432               addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
1433               netif_ip6_addr_state(netif, addr_idx)));
1434 }
1435 
1436 /**
1437  * @ingroup netif_ip6
1438  * Change the state of an IPv6 address of a network interface
1439  * (INVALID, TEMPTATIVE, PREFERRED, DEPRECATED, where TEMPTATIVE
1440  * includes the number of checks done, see ip6_addr.h)
1441  *
1442  * @param netif the network interface to change
1443  * @param addr_idx index of the IPv6 address
1444  * @param state the new IPv6 address state
1445  */
1446 void
netif_ip6_addr_set_state(struct netif * netif,s8_t addr_idx,u8_t state)1447 netif_ip6_addr_set_state(struct netif *netif, s8_t addr_idx, u8_t state)
1448 {
1449   u8_t old_state;
1450   LWIP_ASSERT_CORE_LOCKED();
1451   LWIP_ASSERT("netif != NULL", netif != NULL);
1452   LWIP_ASSERT("invalid index", addr_idx < LWIP_IPV6_NUM_ADDRESSES);
1453 
1454   old_state = netif_ip6_addr_state(netif, addr_idx);
1455   /* state is actually being changed? */
1456   if (old_state != state) {
1457     u8_t old_valid = old_state & IP6_ADDR_VALID;
1458     u8_t new_valid = state & IP6_ADDR_VALID;
1459     LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_ip6_addr_set_state: netif address state being changed\n"));
1460 
1461 #if LWIP_IPV6_MLD
1462     /* Reevaluate solicited-node multicast group membership. */
1463     if (netif->flags & NETIF_FLAG_MLD6) {
1464       nd6_adjust_mld_membership(netif, addr_idx, state);
1465     }
1466 #endif /* LWIP_IPV6_MLD */
1467 
1468     if (old_valid && !new_valid) {
1469       /* address about to be removed by setting invalid */
1470       netif_do_ip_addr_changed(netif_ip_addr6(netif, addr_idx), NULL);
1471       /* @todo: remove mib2 ip6 entries? */
1472     }
1473     netif->ip6_addr_state[addr_idx] = state;
1474 
1475     if (!old_valid && new_valid) {
1476       /* address added by setting valid */
1477       /* This is a good moment to check that the address is properly zoned. */
1478       IP6_ADDR_ZONECHECK_NETIF(netif_ip6_addr(netif, addr_idx), netif);
1479       /* @todo: add mib2 ip6 entries? */
1480       netif_issue_reports(netif, NETIF_REPORT_TYPE_IPV6);
1481     }
1482     if ((old_state & ~IP6_ADDR_TENTATIVE_COUNT_MASK) !=
1483         (state     & ~IP6_ADDR_TENTATIVE_COUNT_MASK)) {
1484       /* address state has changed -> call the callback function */
1485       NETIF_STATUS_CALLBACK(netif);
1486     }
1487 
1488 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1489     {
1490       netif_ext_callback_args_t args;
1491       args.ipv6_addr_state_changed.addr_index = addr_idx;
1492       args.ipv6_addr_state_changed.old_state  = old_state;
1493       args.ipv6_addr_state_changed.address    = netif_ip_addr6(netif, addr_idx);
1494       netif_invoke_ext_callback(netif, LWIP_NSC_IPV6_ADDR_STATE_CHANGED, &args);
1495     }
1496 #endif
1497   }
1498   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",
1499               addr_idx, netif->name[0], netif->name[1], ip6addr_ntoa(netif_ip6_addr(netif, addr_idx)),
1500               netif_ip6_addr_state(netif, addr_idx)));
1501 }
1502 
1503 /**
1504  * Checks if a specific local address is present on the netif and returns its
1505  * index. Depending on its state, it may or may not be assigned to the
1506  * interface (as per RFC terminology).
1507  *
1508  * The given address may or may not be zoned (i.e., have a zone index other
1509  * than IP6_NO_ZONE). If the address is zoned, it must have the correct zone
1510  * for the given netif, or no match will be found.
1511  *
1512  * @param netif the netif to check
1513  * @param ip6addr the IPv6 address to find
1514  * @return >= 0: address found, this is its index
1515  *         -1: address not found on this netif
1516  */
1517 s8_t
netif_get_ip6_addr_match(struct netif * netif,const ip6_addr_t * ip6addr)1518 netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr)
1519 {
1520   s8_t i;
1521 
1522   LWIP_ASSERT_CORE_LOCKED();
1523 
1524   LWIP_ASSERT("netif_get_ip6_addr_match: invalid netif", netif != NULL);
1525   LWIP_ASSERT("netif_get_ip6_addr_match: invalid ip6addr", ip6addr != NULL);
1526 
1527 #if LWIP_IPV6_SCOPES
1528   if (ip6_addr_has_zone(ip6addr) && !ip6_addr_test_zone(ip6addr, netif)) {
1529     return -1; /* wrong zone, no match */
1530   }
1531 #endif /* LWIP_IPV6_SCOPES */
1532 
1533   for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1534     if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) &&
1535         ip6_addr_zoneless_eq(netif_ip6_addr(netif, i), ip6addr)) {
1536       return i;
1537     }
1538   }
1539   return -1;
1540 }
1541 
1542 /**
1543  * @ingroup netif_ip6
1544  * Create a link-local IPv6 address on a netif (stored in slot 0)
1545  *
1546  * @param netif the netif to create the address on
1547  * @param from_mac_48bit if != 0, assume hwadr is a 48-bit MAC address (std conversion)
1548  *                       if == 0, use hwaddr directly as interface ID
1549  */
1550 void
netif_create_ip6_linklocal_address(struct netif * netif,u8_t from_mac_48bit)1551 netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
1552 {
1553   u8_t i, addr_index;
1554 
1555   LWIP_ASSERT_CORE_LOCKED();
1556 
1557   LWIP_ASSERT("netif_create_ip6_linklocal_address: invalid netif", netif != NULL);
1558 
1559   /* Link-local prefix. */
1560   ip_2_ip6(&netif->ip6_addr[0])->addr[0] = PP_HTONL(0xfe800000ul);
1561   ip_2_ip6(&netif->ip6_addr[0])->addr[1] = 0;
1562 
1563   /* Generate interface ID. */
1564   if (from_mac_48bit) {
1565     /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
1566     ip_2_ip6(&netif->ip6_addr[0])->addr[2] = lwip_htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
1567         ((u32_t)(netif->hwaddr[1]) << 16) |
1568         ((u32_t)(netif->hwaddr[2]) << 8) |
1569         (0xff));
1570     ip_2_ip6(&netif->ip6_addr[0])->addr[3] = lwip_htonl((u32_t)(0xfeul << 24) |
1571         ((u32_t)(netif->hwaddr[3]) << 16) |
1572         ((u32_t)(netif->hwaddr[4]) << 8) |
1573         (netif->hwaddr[5]));
1574   } else {
1575     /* Use hwaddr directly as interface ID. */
1576     ip_2_ip6(&netif->ip6_addr[0])->addr[2] = 0;
1577     ip_2_ip6(&netif->ip6_addr[0])->addr[3] = 0;
1578 
1579     addr_index = 3;
1580     for (i = 0; (i < 8) && (i < netif->hwaddr_len); i++) {
1581       if (i == 4) {
1582         addr_index--;
1583       }
1584       ip_2_ip6(&netif->ip6_addr[0])->addr[addr_index] |= lwip_htonl(((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)));
1585     }
1586   }
1587 
1588   /* Set a link-local zone. Even though the zone is implied by the owning
1589    * netif, setting the zone anyway has two important conceptual advantages:
1590    * 1) it avoids the need for a ton of exceptions in internal code, allowing
1591    *    e.g. ip6_addr_eq() to be used on local addresses;
1592    * 2) the properly zoned address is visible externally, e.g. when any outside
1593    *    code enumerates available addresses or uses one to bind a socket.
1594    * Any external code unaware of address scoping is likely to just ignore the
1595    * zone field, so this should not create any compatibility problems. */
1596   ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[0]), IP6_UNICAST, netif);
1597 
1598   /* Set address state. */
1599 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
1600   /* Will perform duplicate address detection (DAD). */
1601   netif_ip6_addr_set_state(netif, 0, IP6_ADDR_TENTATIVE);
1602 #else
1603   /* Consider address valid. */
1604   netif_ip6_addr_set_state(netif, 0, IP6_ADDR_PREFERRED);
1605 #endif /* LWIP_IPV6_AUTOCONFIG */
1606 }
1607 
1608 /**
1609  * @ingroup netif_ip6
1610  * This function allows for the easy addition of a new IPv6 address to an interface.
1611  * It takes care of finding an empty slot and then sets the address tentative
1612  * (to make sure that all the subsequent processing happens).
1613  *
1614  * @param netif netif to add the address on
1615  * @param ip6addr address to add
1616  * @param chosen_idx if != NULL, the chosen IPv6 address index will be stored here
1617  */
1618 err_t
netif_add_ip6_address(struct netif * netif,const ip6_addr_t * ip6addr,s8_t * chosen_idx)1619 netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx)
1620 {
1621   s8_t i;
1622 
1623   LWIP_ASSERT_CORE_LOCKED();
1624 
1625   LWIP_ASSERT("netif_add_ip6_address: invalid netif", netif != NULL);
1626   LWIP_ASSERT("netif_add_ip6_address: invalid ip6addr", ip6addr != NULL);
1627 
1628   i = netif_get_ip6_addr_match(netif, ip6addr);
1629   if (i >= 0) {
1630     /* Address already added */
1631     if (chosen_idx != NULL) {
1632       *chosen_idx = i;
1633     }
1634     return ERR_OK;
1635   }
1636 
1637   /* Find a free slot. The first one is reserved for link-local addresses. */
1638   for (i = ip6_addr_islinklocal(ip6addr) ? 0 : 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
1639     if (ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) {
1640       ip_addr_copy_from_ip6(netif->ip6_addr[i], *ip6addr);
1641       ip6_addr_assign_zone(ip_2_ip6(&netif->ip6_addr[i]), IP6_UNICAST, netif);
1642       netif_ip6_addr_set_state(netif, i, IP6_ADDR_TENTATIVE);
1643       if (chosen_idx != NULL) {
1644         *chosen_idx = i;
1645       }
1646       return ERR_OK;
1647     }
1648   }
1649 
1650   if (chosen_idx != NULL) {
1651     *chosen_idx = -1;
1652   }
1653   return ERR_VAL;
1654 }
1655 
1656 /** Dummy IPv6 output function for netifs not supporting IPv6
1657  */
1658 static err_t
netif_null_output_ip6(struct netif * netif,struct pbuf * p,const ip6_addr_t * ipaddr)1659 netif_null_output_ip6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
1660 {
1661   LWIP_UNUSED_ARG(netif);
1662   LWIP_UNUSED_ARG(p);
1663   LWIP_UNUSED_ARG(ipaddr);
1664 
1665   return ERR_IF;
1666 }
1667 #endif /* LWIP_IPV6 */
1668 
1669 #if LWIP_IPV4
1670 /** Dummy IPv4 output function for netifs not supporting IPv4
1671  */
1672 static err_t
netif_null_output_ip4(struct netif * netif,struct pbuf * p,const ip4_addr_t * ipaddr)1673 netif_null_output_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
1674 {
1675   LWIP_UNUSED_ARG(netif);
1676   LWIP_UNUSED_ARG(p);
1677   LWIP_UNUSED_ARG(ipaddr);
1678 
1679   return ERR_IF;
1680 }
1681 #endif /* LWIP_IPV4 */
1682 
1683 /**
1684 * @ingroup netif
1685 * Return the interface index for the netif with name
1686 * or NETIF_NO_INDEX if not found/on error
1687 *
1688 * @param name the name of the netif
1689 */
1690 u8_t
netif_name_to_index(const char * name)1691 netif_name_to_index(const char *name)
1692 {
1693   struct netif *netif = netif_find(name);
1694   if (netif != NULL) {
1695     return netif_get_index(netif);
1696   }
1697   /* No name found, return invalid index */
1698   return NETIF_NO_INDEX;
1699 }
1700 
1701 /**
1702 * @ingroup netif
1703 * Return the interface name for the netif matching index
1704 * or NULL if not found/on error
1705 *
1706 * @param idx the interface index of the netif
1707 * @param name char buffer of at least NETIF_NAMESIZE bytes
1708 */
1709 char *
netif_index_to_name(u8_t idx,char * name)1710 netif_index_to_name(u8_t idx, char *name)
1711 {
1712   struct netif *netif = netif_get_by_index(idx);
1713 
1714   if (netif != NULL) {
1715     name[0] = netif->name[0];
1716     name[1] = netif->name[1];
1717     lwip_itoa(&name[2], NETIF_NAMESIZE - 2, netif_index_to_num(idx));
1718     return name;
1719   }
1720   return NULL;
1721 }
1722 
1723 /**
1724 * @ingroup netif
1725 * Return the interface for the netif index
1726 *
1727 * @param idx index of netif to find
1728 */
1729 struct netif *
netif_get_by_index(u8_t idx)1730 netif_get_by_index(u8_t idx)
1731 {
1732   struct netif *netif;
1733 
1734   LWIP_ASSERT_CORE_LOCKED();
1735 
1736   if (idx != NETIF_NO_INDEX) {
1737     NETIF_FOREACH(netif) {
1738       if (idx == netif_get_index(netif)) {
1739         return netif; /* found! */
1740       }
1741     }
1742   }
1743 
1744   return NULL;
1745 }
1746 
1747 /**
1748  * @ingroup netif
1749  * Find a network interface by searching for its name
1750  *
1751  * @param name the name of the netif (like netif->name) plus concatenated number
1752  * in ascii representation (e.g. 'en0')
1753  */
1754 struct netif *
netif_find(const char * name)1755 netif_find(const char *name)
1756 {
1757   struct netif *netif;
1758   u8_t num;
1759 
1760   LWIP_ASSERT_CORE_LOCKED();
1761 
1762   if (name == NULL) {
1763     return NULL;
1764   }
1765 
1766   num = (u8_t)atoi(&name[2]);
1767   if (!num && (name[2] != '0')) {
1768     /* this means atoi has failed */
1769     return NULL;
1770   }
1771 
1772   NETIF_FOREACH(netif) {
1773     if (num == netif->num &&
1774         name[0] == netif->name[0] &&
1775         name[1] == netif->name[1]) {
1776       LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
1777       return netif;
1778     }
1779   }
1780   LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
1781   return NULL;
1782 }
1783 
1784 #if LWIP_NETIF_EXT_STATUS_CALLBACK
1785 /**
1786  * @ingroup netif
1787  * Add extended netif events listener
1788  * @param callback pointer to listener structure
1789  * @param fn callback function
1790  */
1791 void
netif_add_ext_callback(netif_ext_callback_t * callback,netif_ext_callback_fn fn)1792 netif_add_ext_callback(netif_ext_callback_t *callback, netif_ext_callback_fn fn)
1793 {
1794   LWIP_ASSERT_CORE_LOCKED();
1795   LWIP_ASSERT("callback must be != NULL", callback != NULL);
1796   LWIP_ASSERT("fn must be != NULL", fn != NULL);
1797 
1798   callback->callback_fn = fn;
1799   callback->next        = ext_callback;
1800   ext_callback          = callback;
1801 }
1802 
1803 /**
1804  * @ingroup netif
1805  * Remove extended netif events listener
1806  * @param callback pointer to listener structure
1807  */
1808 void
netif_remove_ext_callback(netif_ext_callback_t * callback)1809 netif_remove_ext_callback(netif_ext_callback_t* callback)
1810 {
1811   netif_ext_callback_t *last, *iter;
1812 
1813   LWIP_ASSERT_CORE_LOCKED();
1814   LWIP_ASSERT("callback must be != NULL", callback != NULL);
1815 
1816   if (ext_callback == NULL) {
1817     return;
1818   }
1819 
1820   if (callback == ext_callback) {
1821     ext_callback = ext_callback->next;
1822   } else {
1823     last = ext_callback;
1824     for (iter = ext_callback->next; iter != NULL; last = iter, iter = iter->next) {
1825       if (iter == callback) {
1826         LWIP_ASSERT("last != NULL", last != NULL);
1827         last->next = callback->next;
1828         break;
1829       }
1830     }
1831   }
1832   callback->next = NULL;
1833 }
1834 
1835 /**
1836  * Invoke extended netif status event
1837  * @param netif netif that is affected by change
1838  * @param reason change reason
1839  * @param args depends on reason, see reason description
1840  */
1841 void
netif_invoke_ext_callback(struct netif * netif,netif_nsc_reason_t reason,const netif_ext_callback_args_t * args)1842 netif_invoke_ext_callback(struct netif *netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t *args)
1843 {
1844   netif_ext_callback_t *callback = ext_callback;
1845 
1846   LWIP_ASSERT("netif must be != NULL", netif != NULL);
1847 
1848   while (callback != NULL) {
1849     /* cache next pointer: the callback might unregister itself */
1850     netif_ext_callback_t *next = callback->next;
1851     callback->callback_fn(netif, reason, args);
1852     callback = next;
1853   }
1854 }
1855 #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */
1856