Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
netif.c
00001 /** 00002 * @file 00003 * lwIP network interface abstraction 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 */ 00038 00039 #include "lwip/opt.h" 00040 00041 #include "lwip/def.h" 00042 #include "lwip/ip_addr.h" 00043 #include "lwip/netif.h" 00044 #include "lwip/tcp_impl.h" 00045 #include "lwip/snmp.h" 00046 #include "lwip/igmp.h" 00047 #include "netif/etharp.h" 00048 #include "lwip/stats.h" 00049 #if ENABLE_LOOPBACK 00050 #include "lwip/sys.h" 00051 #if LWIP_NETIF_LOOPBACK_MULTITHREADING 00052 #include "lwip/tcpip.h" 00053 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ 00054 #endif /* ENABLE_LOOPBACK */ 00055 00056 #if LWIP_AUTOIP 00057 #include "lwip/autoip.h" 00058 #endif /* LWIP_AUTOIP */ 00059 #if LWIP_DHCP 00060 #include "lwip/dhcp.h " 00061 #endif /* LWIP_DHCP */ 00062 00063 #if LWIP_NETIF_STATUS_CALLBACK 00064 #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) 00065 #else 00066 #define NETIF_STATUS_CALLBACK(n) 00067 #endif /* LWIP_NETIF_STATUS_CALLBACK */ 00068 00069 #if LWIP_NETIF_LINK_CALLBACK 00070 #define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) 00071 #else 00072 #define NETIF_LINK_CALLBACK(n) 00073 #endif /* LWIP_NETIF_LINK_CALLBACK */ 00074 00075 struct netif *netif_list; 00076 struct netif *netif_default; 00077 00078 #if LWIP_HAVE_LOOPIF 00079 static struct netif loop_netif; 00080 00081 /** 00082 * Initialize a lwip network interface structure for a loopback interface 00083 * 00084 * @param netif the lwip network interface structure for this loopif 00085 * @return ERR_OK if the loopif is initialized 00086 * ERR_MEM if private data couldn't be allocated 00087 */ 00088 static err_t 00089 netif_loopif_init(struct netif *netif) 00090 { 00091 /* initialize the snmp variables and counters inside the struct netif 00092 * ifSpeed: no assumption can be made! 00093 */ 00094 NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); 00095 00096 netif->name[0] = 'l'; 00097 netif->name[1] = 'o'; 00098 netif->output = netif_loop_output; 00099 return ERR_OK; 00100 } 00101 #endif /* LWIP_HAVE_LOOPIF */ 00102 00103 void 00104 netif_init(void) 00105 { 00106 #if LWIP_HAVE_LOOPIF 00107 ip_addr_t loop_ipaddr, loop_netmask, loop_gw; 00108 IP4_ADDR(&loop_gw, 127,0,0,1); 00109 IP4_ADDR(&loop_ipaddr, 127,0,0,1); 00110 IP4_ADDR(&loop_netmask, 255,0,0,0); 00111 00112 #if NO_SYS 00113 netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); 00114 #else /* NO_SYS */ 00115 netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); 00116 #endif /* NO_SYS */ 00117 netif_set_up(&loop_netif); 00118 00119 #endif /* LWIP_HAVE_LOOPIF */ 00120 } 00121 00122 /** 00123 * Add a network interface to the list of lwIP netifs. 00124 * 00125 * @param netif a pre-allocated netif structure 00126 * @param ipaddr IP address for the new netif 00127 * @param netmask network mask for the new netif 00128 * @param gw default gateway IP address for the new netif 00129 * @param state opaque data passed to the new netif 00130 * @param init callback function that initializes the interface 00131 * @param input callback function that is called to pass 00132 * ingress packets up in the protocol layer stack. 00133 * 00134 * @return netif, or NULL if failed. 00135 */ 00136 struct netif * 00137 netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, 00138 ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) 00139 { 00140 static u8_t netifnum = 0; 00141 00142 LWIP_ASSERT("No init function given", init != NULL); 00143 00144 /* reset new interface configuration state */ 00145 ip_addr_set_zero(&netif->ip_addr); 00146 ip_addr_set_zero(&netif->netmask); 00147 ip_addr_set_zero(&netif->gw); 00148 netif->flags = 0; 00149 #if LWIP_DHCP 00150 /* netif not under DHCP control by default */ 00151 netif->dhcp = NULL; 00152 #endif /* LWIP_DHCP */ 00153 #if LWIP_AUTOIP 00154 /* netif not under AutoIP control by default */ 00155 netif->autoip = NULL; 00156 #endif /* LWIP_AUTOIP */ 00157 #if LWIP_NETIF_STATUS_CALLBACK 00158 netif->status_callback = NULL; 00159 #endif /* LWIP_NETIF_STATUS_CALLBACK */ 00160 #if LWIP_NETIF_LINK_CALLBACK 00161 netif->link_callback = NULL; 00162 #endif /* LWIP_NETIF_LINK_CALLBACK */ 00163 #if LWIP_IGMP 00164 netif->igmp_mac_filter = NULL; 00165 #endif /* LWIP_IGMP */ 00166 #if ENABLE_LOOPBACK 00167 netif->loop_first = NULL; 00168 netif->loop_last = NULL; 00169 #endif /* ENABLE_LOOPBACK */ 00170 00171 /* remember netif specific state information data */ 00172 netif->state = state; 00173 netif->num = netifnum++; 00174 netif->input = input; 00175 #if LWIP_NETIF_HWADDRHINT 00176 netif->addr_hint = NULL; 00177 #endif /* LWIP_NETIF_HWADDRHINT*/ 00178 #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS 00179 netif->loop_cnt_current = 0; 00180 #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ 00181 00182 netif_set_addr(netif, ipaddr, netmask, gw); 00183 00184 /* call user specified initialization function for netif */ 00185 if (init(netif) != ERR_OK) { 00186 return NULL; 00187 } 00188 00189 /* add this netif to the list */ 00190 netif->next = netif_list; 00191 netif_list = netif; 00192 snmp_inc_iflist(); 00193 00194 #if LWIP_IGMP 00195 /* start IGMP processing */ 00196 if (netif->flags & NETIF_FLAG_IGMP) { 00197 igmp_start(netif); 00198 } 00199 #endif /* LWIP_IGMP */ 00200 00201 LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", 00202 netif->name[0], netif->name[1])); 00203 ip_addr_debug_print(NETIF_DEBUG, ipaddr); 00204 LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); 00205 ip_addr_debug_print(NETIF_DEBUG, netmask); 00206 LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); 00207 ip_addr_debug_print(NETIF_DEBUG, gw); 00208 LWIP_DEBUGF(NETIF_DEBUG, ("\n")); 00209 return netif; 00210 } 00211 00212 /** 00213 * Change IP address configuration for a network interface (including netmask 00214 * and default gateway). 00215 * 00216 * @param netif the network interface to change 00217 * @param ipaddr the new IP address 00218 * @param netmask the new netmask 00219 * @param gw the new default gateway 00220 */ 00221 void 00222 netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, 00223 ip_addr_t *gw) 00224 { 00225 netif_set_ipaddr(netif, ipaddr); 00226 netif_set_netmask(netif, netmask); 00227 netif_set_gw(netif, gw); 00228 } 00229 00230 /** 00231 * Remove a network interface from the list of lwIP netifs. 00232 * 00233 * @param netif the network interface to remove 00234 */ 00235 void 00236 netif_remove(struct netif *netif) 00237 { 00238 if (netif == NULL) { 00239 return; 00240 } 00241 00242 #if LWIP_IGMP 00243 /* stop IGMP processing */ 00244 if (netif->flags & NETIF_FLAG_IGMP) { 00245 igmp_stop(netif); 00246 } 00247 #endif /* LWIP_IGMP */ 00248 if (netif_is_up(netif)) { 00249 /* set netif down before removing (call callback function) */ 00250 netif_set_down(netif); 00251 } 00252 00253 snmp_delete_ipaddridx_tree(netif); 00254 00255 /* is it the first netif? */ 00256 if (netif_list == netif) { 00257 netif_list = netif->next; 00258 } else { 00259 /* look for netif further down the list */ 00260 struct netif * tmpNetif; 00261 for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { 00262 if (tmpNetif->next == netif) { 00263 tmpNetif->next = netif->next; 00264 break; 00265 } 00266 } 00267 if (tmpNetif == NULL) 00268 return; /* we didn't find any netif today */ 00269 } 00270 snmp_dec_iflist(); 00271 /* this netif is default? */ 00272 if (netif_default == netif) { 00273 /* reset default netif */ 00274 netif_set_default(NULL); 00275 } 00276 LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); 00277 } 00278 00279 /** 00280 * Find a network interface by searching for its name 00281 * 00282 * @param name the name of the netif (like netif->name) plus concatenated number 00283 * in ascii representation (e.g. 'en0') 00284 */ 00285 struct netif * 00286 netif_find(char *name) 00287 { 00288 struct netif *netif; 00289 u8_t num; 00290 00291 if (name == NULL) { 00292 return NULL; 00293 } 00294 00295 num = name[2] - '0'; 00296 00297 for(netif = netif_list; netif != NULL; netif = netif->next) { 00298 if (num == netif->num && 00299 name[0] == netif->name[0] && 00300 name[1] == netif->name[1]) { 00301 LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); 00302 return netif; 00303 } 00304 } 00305 LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); 00306 return NULL; 00307 } 00308 00309 /** 00310 * Change the IP address of a network interface 00311 * 00312 * @param netif the network interface to change 00313 * @param ipaddr the new IP address 00314 * 00315 * @note call netif_set_addr() if you also want to change netmask and 00316 * default gateway 00317 */ 00318 void 00319 netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) 00320 { 00321 /* Protect against dereferencing NULL pointers by 00322 treating like ANY, as does ip_addr_set() */ 00323 if (!ipaddr) { 00324 ipaddr = IP_ADDR_ANY; 00325 } 00326 00327 /* TODO: Handling of obsolete pcbs */ 00328 /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ 00329 #if LWIP_TCP 00330 struct tcp_pcb *pcb; 00331 struct tcp_pcb_listen *lpcb; 00332 00333 /* address is actually being changed? */ 00334 if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { 00335 /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ 00336 LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); 00337 pcb = tcp_active_pcbs; 00338 while (pcb != NULL) { 00339 /* PCB bound to current local interface address? */ 00340 if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) 00341 #if LWIP_AUTOIP 00342 /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ 00343 && !ip_addr_islinklocal(&(pcb->local_ip)) 00344 #endif /* LWIP_AUTOIP */ 00345 ) { 00346 /* this connection must be aborted */ 00347 struct tcp_pcb *next = pcb->next; 00348 LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); 00349 tcp_abort(pcb); 00350 pcb = next; 00351 } else { 00352 pcb = pcb->next; 00353 } 00354 } 00355 for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 00356 /* PCB bound to current local interface address? */ 00357 if ((!(ip_addr_isany(&(lpcb->local_ip)))) && 00358 (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { 00359 /* The PCB is listening to the old ipaddr and 00360 * is set to listen to the new one instead */ 00361 ip_addr_set(&(lpcb->local_ip), ipaddr); 00362 } 00363 } 00364 } 00365 #endif 00366 snmp_delete_ipaddridx_tree(netif); 00367 snmp_delete_iprteidx_tree(0,netif); 00368 /* set new IP address to netif */ 00369 ip_addr_set(&(netif->ip_addr), ipaddr); 00370 snmp_insert_ipaddridx_tree(netif); 00371 snmp_insert_iprteidx_tree(0,netif); 00372 00373 LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00374 netif->name[0], netif->name[1], 00375 ip4_addr1_16(&netif->ip_addr), 00376 ip4_addr2_16(&netif->ip_addr), 00377 ip4_addr3_16(&netif->ip_addr), 00378 ip4_addr4_16(&netif->ip_addr))); 00379 } 00380 00381 /** 00382 * Change the default gateway for a network interface 00383 * 00384 * @param netif the network interface to change 00385 * @param gw the new default gateway 00386 * 00387 * @note call netif_set_addr() if you also want to change ip address and netmask 00388 */ 00389 void 00390 netif_set_gw(struct netif *netif, ip_addr_t *gw) 00391 { 00392 ip_addr_set(&(netif->gw), gw); 00393 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", 00394 netif->name[0], netif->name[1], 00395 ip4_addr1_16(&netif->gw), 00396 ip4_addr2_16(&netif->gw), 00397 ip4_addr3_16(&netif->gw), 00398 ip4_addr4_16(&netif->gw))); 00399 } 00400 00401 /** 00402 * Change the netmask of a network interface 00403 * 00404 * @param netif the network interface to change 00405 * @param netmask the new netmask 00406 * 00407 * @note call netif_set_addr() if you also want to change ip address and 00408 * default gateway 00409 */ 00410 void 00411 netif_set_netmask(struct netif *netif, ip_addr_t *netmask) 00412 { 00413 snmp_delete_iprteidx_tree(0, netif); 00414 /* set new netmask to netif */ 00415 ip_addr_set(&(netif->netmask), netmask); 00416 snmp_insert_iprteidx_tree(0, netif); 00417 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", 00418 netif->name[0], netif->name[1], 00419 ip4_addr1_16(&netif->netmask), 00420 ip4_addr2_16(&netif->netmask), 00421 ip4_addr3_16(&netif->netmask), 00422 ip4_addr4_16(&netif->netmask))); 00423 } 00424 00425 /** 00426 * Set a network interface as the default network interface 00427 * (used to output all packets for which no specific route is found) 00428 * 00429 * @param netif the default network interface 00430 */ 00431 void 00432 netif_set_default(struct netif *netif) 00433 { 00434 if (netif == NULL) { 00435 /* remove default route */ 00436 snmp_delete_iprteidx_tree(1, netif); 00437 } else { 00438 /* install default route */ 00439 snmp_insert_iprteidx_tree(1, netif); 00440 } 00441 netif_default = netif; 00442 LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", 00443 netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); 00444 } 00445 00446 /** 00447 * Bring an interface up, available for processing 00448 * traffic. 00449 * 00450 * @note: Enabling DHCP on a down interface will make it come 00451 * up once configured. 00452 * 00453 * @see dhcp_start() 00454 */ 00455 void netif_set_up(struct netif *netif) 00456 { 00457 if (!(netif->flags & NETIF_FLAG_UP)) { 00458 netif->flags |= NETIF_FLAG_UP; 00459 00460 #if LWIP_SNMP 00461 snmp_get_sysuptime(&netif->ts); 00462 #endif /* LWIP_SNMP */ 00463 00464 NETIF_STATUS_CALLBACK(netif); 00465 00466 if (netif->flags & NETIF_FLAG_LINK_UP) { 00467 #if LWIP_ARP 00468 /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 00469 if (netif->flags & (NETIF_FLAG_ETHARP)) { 00470 etharp_gratuitous(netif); 00471 } 00472 #endif /* LWIP_ARP */ 00473 00474 #if LWIP_IGMP 00475 /* resend IGMP memberships */ 00476 if (netif->flags & NETIF_FLAG_IGMP) { 00477 igmp_report_groups( netif); 00478 } 00479 #endif /* LWIP_IGMP */ 00480 } 00481 } 00482 } 00483 00484 /** 00485 * Bring an interface down, disabling any traffic processing. 00486 * 00487 * @note: Enabling DHCP on a down interface will make it come 00488 * up once configured. 00489 * 00490 * @see dhcp_start() 00491 */ 00492 void netif_set_down(struct netif *netif) 00493 { 00494 if (netif->flags & NETIF_FLAG_UP) { 00495 netif->flags &= ~NETIF_FLAG_UP; 00496 #if LWIP_SNMP 00497 snmp_get_sysuptime(&netif->ts); 00498 #endif 00499 00500 NETIF_STATUS_CALLBACK(netif); 00501 } 00502 } 00503 00504 #if LWIP_NETIF_STATUS_CALLBACK 00505 /** 00506 * Set callback to be called when interface is brought up/down 00507 */ 00508 void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) 00509 { 00510 if (netif) { 00511 netif->status_callback = status_callback; 00512 } 00513 } 00514 #endif /* LWIP_NETIF_STATUS_CALLBACK */ 00515 00516 /** 00517 * Called by a driver when its link goes up 00518 */ 00519 void netif_set_link_up(struct netif *netif ) 00520 { 00521 if (!(netif->flags & NETIF_FLAG_LINK_UP)) { 00522 netif->flags |= NETIF_FLAG_LINK_UP; 00523 00524 #if LWIP_DHCP 00525 if (netif->dhcp) { 00526 dhcp_network_changed(netif); 00527 } 00528 #endif /* LWIP_DHCP */ 00529 00530 #if LWIP_AUTOIP 00531 if (netif->autoip) { 00532 autoip_network_changed(netif); 00533 } 00534 #endif /* LWIP_AUTOIP */ 00535 00536 if (netif->flags & NETIF_FLAG_UP) { 00537 #if LWIP_ARP 00538 /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 00539 if (netif->flags & NETIF_FLAG_ETHARP) { 00540 etharp_gratuitous(netif); 00541 } 00542 #endif /* LWIP_ARP */ 00543 00544 #if LWIP_IGMP 00545 /* resend IGMP memberships */ 00546 if (netif->flags & NETIF_FLAG_IGMP) { 00547 igmp_report_groups( netif); 00548 } 00549 #endif /* LWIP_IGMP */ 00550 } 00551 NETIF_LINK_CALLBACK(netif); 00552 } 00553 } 00554 00555 /** 00556 * Called by a driver when its link goes down 00557 */ 00558 void netif_set_link_down(struct netif *netif ) 00559 { 00560 if (netif->flags & NETIF_FLAG_LINK_UP) { 00561 netif->flags &= ~NETIF_FLAG_LINK_UP; 00562 NETIF_LINK_CALLBACK(netif); 00563 } 00564 } 00565 00566 #if LWIP_NETIF_LINK_CALLBACK 00567 /** 00568 * Set callback to be called when link is brought up/down 00569 */ 00570 void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) 00571 { 00572 if (netif) { 00573 netif->link_callback = link_callback; 00574 } 00575 } 00576 #endif /* LWIP_NETIF_LINK_CALLBACK */ 00577 00578 #if ENABLE_LOOPBACK 00579 /** 00580 * Send an IP packet to be received on the same netif (loopif-like). 00581 * The pbuf is simply copied and handed back to netif->input. 00582 * In multithreaded mode, this is done directly since netif->input must put 00583 * the packet on a queue. 00584 * In callback mode, the packet is put on an internal queue and is fed to 00585 * netif->input by netif_poll(). 00586 * 00587 * @param netif the lwip network interface structure 00588 * @param p the (IP) packet to 'send' 00589 * @param ipaddr the ip address to send the packet to (not used) 00590 * @return ERR_OK if the packet has been sent 00591 * ERR_MEM if the pbuf used to copy the packet couldn't be allocated 00592 */ 00593 err_t 00594 netif_loop_output(struct netif *netif, struct pbuf *p, 00595 ip_addr_t *ipaddr) 00596 { 00597 struct pbuf *r; 00598 err_t err; 00599 struct pbuf *last; 00600 #if LWIP_LOOPBACK_MAX_PBUFS 00601 u8_t clen = 0; 00602 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00603 /* If we have a loopif, SNMP counters are adjusted for it, 00604 * if not they are adjusted for 'netif'. */ 00605 #if LWIP_SNMP 00606 #if LWIP_HAVE_LOOPIF 00607 struct netif *stats_if = &loop_netif; 00608 #else /* LWIP_HAVE_LOOPIF */ 00609 struct netif *stats_if = netif; 00610 #endif /* LWIP_HAVE_LOOPIF */ 00611 #endif /* LWIP_SNMP */ 00612 SYS_ARCH_DECL_PROTECT(lev); 00613 LWIP_UNUSED_ARG(ipaddr); 00614 00615 /* Allocate a new pbuf */ 00616 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00617 if (r == NULL) { 00618 LINK_STATS_INC(link.memerr); 00619 LINK_STATS_INC(link.drop); 00620 snmp_inc_ifoutdiscards(stats_if); 00621 return ERR_MEM; 00622 } 00623 #if LWIP_LOOPBACK_MAX_PBUFS 00624 clen = pbuf_clen(r); 00625 /* check for overflow or too many pbuf on queue */ 00626 if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || 00627 ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { 00628 pbuf_free(r); 00629 LINK_STATS_INC(link.memerr); 00630 LINK_STATS_INC(link.drop); 00631 snmp_inc_ifoutdiscards(stats_if); 00632 return ERR_MEM; 00633 } 00634 netif->loop_cnt_current += clen; 00635 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00636 00637 /* Copy the whole pbuf queue p into the single pbuf r */ 00638 if ((err = pbuf_copy(r, p)) != ERR_OK) { 00639 pbuf_free(r); 00640 LINK_STATS_INC(link.memerr); 00641 LINK_STATS_INC(link.drop); 00642 snmp_inc_ifoutdiscards(stats_if); 00643 return err; 00644 } 00645 00646 /* Put the packet on a linked list which gets emptied through calling 00647 netif_poll(). */ 00648 00649 /* let last point to the last pbuf in chain r */ 00650 for (last = r; last->next != NULL; last = last->next); 00651 00652 SYS_ARCH_PROTECT(lev); 00653 if(netif->loop_first != NULL) { 00654 LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); 00655 netif->loop_last->next = r; 00656 netif->loop_last = last; 00657 } else { 00658 netif->loop_first = r; 00659 netif->loop_last = last; 00660 } 00661 SYS_ARCH_UNPROTECT(lev); 00662 00663 LINK_STATS_INC(link.xmit); 00664 snmp_add_ifoutoctets(stats_if, p->tot_len); 00665 snmp_inc_ifoutucastpkts(stats_if); 00666 00667 #if LWIP_NETIF_LOOPBACK_MULTITHREADING 00668 /* For multithreading environment, schedule a call to netif_poll */ 00669 tcpip_callback((tcpip_callback_fn)netif_poll, netif); 00670 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ 00671 00672 return ERR_OK; 00673 } 00674 00675 /** 00676 * Call netif_poll() in the main loop of your application. This is to prevent 00677 * reentering non-reentrant functions like tcp_input(). Packets passed to 00678 * netif_loop_output() are put on a list that is passed to netif->input() by 00679 * netif_poll(). 00680 */ 00681 void 00682 netif_poll(struct netif *netif) 00683 { 00684 struct pbuf *in; 00685 /* If we have a loopif, SNMP counters are adjusted for it, 00686 * if not they are adjusted for 'netif'. */ 00687 #if LWIP_SNMP 00688 #if LWIP_HAVE_LOOPIF 00689 struct netif *stats_if = &loop_netif; 00690 #else /* LWIP_HAVE_LOOPIF */ 00691 struct netif *stats_if = netif; 00692 #endif /* LWIP_HAVE_LOOPIF */ 00693 #endif /* LWIP_SNMP */ 00694 SYS_ARCH_DECL_PROTECT(lev); 00695 00696 do { 00697 /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ 00698 SYS_ARCH_PROTECT(lev); 00699 in = netif->loop_first; 00700 if (in != NULL) { 00701 struct pbuf *in_end = in; 00702 #if LWIP_LOOPBACK_MAX_PBUFS 00703 u8_t clen = pbuf_clen(in); 00704 /* adjust the number of pbufs on queue */ 00705 LWIP_ASSERT("netif->loop_cnt_current underflow", 00706 ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); 00707 netif->loop_cnt_current -= clen; 00708 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00709 while (in_end->len != in_end->tot_len) { 00710 LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); 00711 in_end = in_end->next; 00712 } 00713 /* 'in_end' now points to the last pbuf from 'in' */ 00714 if (in_end == netif->loop_last) { 00715 /* this was the last pbuf in the list */ 00716 netif->loop_first = netif->loop_last = NULL; 00717 } else { 00718 /* pop the pbuf off the list */ 00719 netif->loop_first = in_end->next; 00720 LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); 00721 } 00722 /* De-queue the pbuf from its successors on the 'loop_' list. */ 00723 in_end->next = NULL; 00724 } 00725 SYS_ARCH_UNPROTECT(lev); 00726 00727 if (in != NULL) { 00728 LINK_STATS_INC(link.recv); 00729 snmp_add_ifinoctets(stats_if, in->tot_len); 00730 snmp_inc_ifinucastpkts(stats_if); 00731 /* loopback packets are always IP packets! */ 00732 if (ip_input(in, netif) != ERR_OK) { 00733 pbuf_free(in); 00734 } 00735 /* Don't reference the packet any more! */ 00736 in = NULL; 00737 } 00738 /* go on while there is a packet on the list */ 00739 } while (netif->loop_first != NULL); 00740 } 00741 00742 #if !LWIP_NETIF_LOOPBACK_MULTITHREADING 00743 /** 00744 * Calls netif_poll() for every netif on the netif_list. 00745 */ 00746 void 00747 netif_poll_all(void) 00748 { 00749 struct netif *netif = netif_list; 00750 /* loop through netifs */ 00751 while (netif != NULL) { 00752 netif_poll(netif); 00753 /* proceed to next network interface */ 00754 netif = netif->next; 00755 } 00756 } 00757 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ 00758 #endif /* ENABLE_LOOPBACK */
Generated on Tue Jul 12 2022 13:44:41 by
