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