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