Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested
Dependents: STM32F746_iothub_client_sample_mqtt DISCO-F746NG_Ethernet Nucleo_F746ZG_Ethernet thethingsiO-DISCO_F746NG-mqtt ... more
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 Tue Jul 12 2022 18:14:54 by 1.7.2