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