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