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