![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.
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 /* TODO: Handling of obsolete pcbs */ 00322 /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ 00323 #if LWIP_TCP 00324 struct tcp_pcb *pcb; 00325 struct tcp_pcb_listen *lpcb; 00326 00327 /* address is actually being changed? */ 00328 if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { 00329 /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ 00330 LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); 00331 pcb = tcp_active_pcbs; 00332 while (pcb != NULL) { 00333 /* PCB bound to current local interface address? */ 00334 if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) 00335 #if LWIP_AUTOIP 00336 /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ 00337 && !ip_addr_islinklocal(&(pcb->local_ip)) 00338 #endif /* LWIP_AUTOIP */ 00339 ) { 00340 /* this connection must be aborted */ 00341 struct tcp_pcb *next = pcb->next; 00342 LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); 00343 tcp_abort(pcb); 00344 pcb = next; 00345 } else { 00346 pcb = pcb->next; 00347 } 00348 } 00349 for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { 00350 /* PCB bound to current local interface address? */ 00351 if ((!(ip_addr_isany(&(lpcb->local_ip)))) && 00352 (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { 00353 /* The PCB is listening to the old ipaddr and 00354 * is set to listen to the new one instead */ 00355 ip_addr_set(&(lpcb->local_ip), ipaddr); 00356 } 00357 } 00358 } 00359 #endif 00360 snmp_delete_ipaddridx_tree(netif); 00361 snmp_delete_iprteidx_tree(0,netif); 00362 /* set new IP address to netif */ 00363 ip_addr_set(&(netif->ip_addr), ipaddr); 00364 snmp_insert_ipaddridx_tree(netif); 00365 snmp_insert_iprteidx_tree(0,netif); 00366 00367 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", 00368 netif->name[0], netif->name[1], 00369 ip4_addr1_16(&netif->ip_addr), 00370 ip4_addr2_16(&netif->ip_addr), 00371 ip4_addr3_16(&netif->ip_addr), 00372 ip4_addr4_16(&netif->ip_addr))); 00373 } 00374 00375 /** 00376 * Change the default gateway for a network interface 00377 * 00378 * @param netif the network interface to change 00379 * @param gw the new default gateway 00380 * 00381 * @note call netif_set_addr() if you also want to change ip address and netmask 00382 */ 00383 void 00384 netif_set_gw(struct netif *netif, ip_addr_t *gw) 00385 { 00386 ip_addr_set(&(netif->gw), gw); 00387 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", 00388 netif->name[0], netif->name[1], 00389 ip4_addr1_16(&netif->gw), 00390 ip4_addr2_16(&netif->gw), 00391 ip4_addr3_16(&netif->gw), 00392 ip4_addr4_16(&netif->gw))); 00393 } 00394 00395 /** 00396 * Change the netmask of a network interface 00397 * 00398 * @param netif the network interface to change 00399 * @param netmask the new netmask 00400 * 00401 * @note call netif_set_addr() if you also want to change ip address and 00402 * default gateway 00403 */ 00404 void 00405 netif_set_netmask(struct netif *netif, ip_addr_t *netmask) 00406 { 00407 snmp_delete_iprteidx_tree(0, netif); 00408 /* set new netmask to netif */ 00409 ip_addr_set(&(netif->netmask), netmask); 00410 snmp_insert_iprteidx_tree(0, netif); 00411 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", 00412 netif->name[0], netif->name[1], 00413 ip4_addr1_16(&netif->netmask), 00414 ip4_addr2_16(&netif->netmask), 00415 ip4_addr3_16(&netif->netmask), 00416 ip4_addr4_16(&netif->netmask))); 00417 } 00418 00419 /** 00420 * Set a network interface as the default network interface 00421 * (used to output all packets for which no specific route is found) 00422 * 00423 * @param netif the default network interface 00424 */ 00425 void 00426 netif_set_default(struct netif *netif) 00427 { 00428 if (netif == NULL) { 00429 /* remove default route */ 00430 snmp_delete_iprteidx_tree(1, netif); 00431 } else { 00432 /* install default route */ 00433 snmp_insert_iprteidx_tree(1, netif); 00434 } 00435 netif_default = netif; 00436 LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", 00437 netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); 00438 } 00439 00440 /** 00441 * Bring an interface up, available for processing 00442 * traffic. 00443 * 00444 * @note: Enabling DHCP on a down interface will make it come 00445 * up once configured. 00446 * 00447 * @see dhcp_start() 00448 */ 00449 void netif_set_up(struct netif *netif) 00450 { 00451 if (!(netif->flags & NETIF_FLAG_UP)) { 00452 netif->flags |= NETIF_FLAG_UP; 00453 00454 #if LWIP_SNMP 00455 snmp_get_sysuptime(&netif->ts); 00456 #endif /* LWIP_SNMP */ 00457 00458 NETIF_STATUS_CALLBACK(netif); 00459 00460 if (netif->flags & NETIF_FLAG_LINK_UP) { 00461 #if LWIP_ARP 00462 /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 00463 if (netif->flags & (NETIF_FLAG_ETHARP)) { 00464 etharp_gratuitous(netif); 00465 } 00466 #endif /* LWIP_ARP */ 00467 00468 #if LWIP_IGMP 00469 /* resend IGMP memberships */ 00470 if (netif->flags & NETIF_FLAG_IGMP) { 00471 igmp_report_groups( netif); 00472 } 00473 #endif /* LWIP_IGMP */ 00474 } 00475 } 00476 } 00477 00478 /** 00479 * Bring an interface down, disabling any traffic processing. 00480 * 00481 * @note: Enabling DHCP on a down interface will make it come 00482 * up once configured. 00483 * 00484 * @see dhcp_start() 00485 */ 00486 void netif_set_down(struct netif *netif) 00487 { 00488 if (netif->flags & NETIF_FLAG_UP) { 00489 netif->flags &= ~NETIF_FLAG_UP; 00490 #if LWIP_SNMP 00491 snmp_get_sysuptime(&netif->ts); 00492 #endif 00493 00494 NETIF_STATUS_CALLBACK(netif); 00495 } 00496 } 00497 00498 #if LWIP_NETIF_STATUS_CALLBACK 00499 /** 00500 * Set callback to be called when interface is brought up/down 00501 */ 00502 void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) 00503 { 00504 if (netif) { 00505 netif->status_callback = status_callback; 00506 } 00507 } 00508 #endif /* LWIP_NETIF_STATUS_CALLBACK */ 00509 00510 /** 00511 * Called by a driver when its link goes up 00512 */ 00513 void netif_set_link_up(struct netif *netif ) 00514 { 00515 if (!(netif->flags & NETIF_FLAG_LINK_UP)) { 00516 netif->flags |= NETIF_FLAG_LINK_UP; 00517 00518 #if LWIP_DHCP 00519 if (netif->dhcp) { 00520 dhcp_network_changed(netif); 00521 } 00522 #endif /* LWIP_DHCP */ 00523 00524 #if LWIP_AUTOIP 00525 if (netif->autoip) { 00526 autoip_network_changed(netif); 00527 } 00528 #endif /* LWIP_AUTOIP */ 00529 00530 if (netif->flags & NETIF_FLAG_UP) { 00531 #if LWIP_ARP 00532 /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 00533 if (netif->flags & NETIF_FLAG_ETHARP) { 00534 etharp_gratuitous(netif); 00535 } 00536 #endif /* LWIP_ARP */ 00537 00538 #if LWIP_IGMP 00539 /* resend IGMP memberships */ 00540 if (netif->flags & NETIF_FLAG_IGMP) { 00541 igmp_report_groups( netif); 00542 } 00543 #endif /* LWIP_IGMP */ 00544 } 00545 NETIF_LINK_CALLBACK(netif); 00546 } 00547 } 00548 00549 /** 00550 * Called by a driver when its link goes down 00551 */ 00552 void netif_set_link_down(struct netif *netif ) 00553 { 00554 if (netif->flags & NETIF_FLAG_LINK_UP) { 00555 netif->flags &= ~NETIF_FLAG_LINK_UP; 00556 NETIF_LINK_CALLBACK(netif); 00557 } 00558 } 00559 00560 #if LWIP_NETIF_LINK_CALLBACK 00561 /** 00562 * Set callback to be called when link is brought up/down 00563 */ 00564 void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) 00565 { 00566 if (netif) { 00567 netif->link_callback = link_callback; 00568 } 00569 } 00570 #endif /* LWIP_NETIF_LINK_CALLBACK */ 00571 00572 #if ENABLE_LOOPBACK 00573 /** 00574 * Send an IP packet to be received on the same netif (loopif-like). 00575 * The pbuf is simply copied and handed back to netif->input. 00576 * In multithreaded mode, this is done directly since netif->input must put 00577 * the packet on a queue. 00578 * In callback mode, the packet is put on an internal queue and is fed to 00579 * netif->input by netif_poll(). 00580 * 00581 * @param netif the lwip network interface structure 00582 * @param p the (IP) packet to 'send' 00583 * @param ipaddr the ip address to send the packet to (not used) 00584 * @return ERR_OK if the packet has been sent 00585 * ERR_MEM if the pbuf used to copy the packet couldn't be allocated 00586 */ 00587 err_t 00588 netif_loop_output(struct netif *netif, struct pbuf *p, 00589 ip_addr_t *ipaddr) 00590 { 00591 struct pbuf *r; 00592 err_t err; 00593 struct pbuf *last; 00594 #if LWIP_LOOPBACK_MAX_PBUFS 00595 u8_t clen = 0; 00596 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00597 /* If we have a loopif, SNMP counters are adjusted for it, 00598 * if not they are adjusted for 'netif'. */ 00599 #if LWIP_SNMP 00600 #if LWIP_HAVE_LOOPIF 00601 struct netif *stats_if = &loop_netif; 00602 #else /* LWIP_HAVE_LOOPIF */ 00603 struct netif *stats_if = netif; 00604 #endif /* LWIP_HAVE_LOOPIF */ 00605 #endif /* LWIP_SNMP */ 00606 SYS_ARCH_DECL_PROTECT(lev); 00607 LWIP_UNUSED_ARG(ipaddr); 00608 00609 /* Allocate a new pbuf */ 00610 r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00611 if (r == NULL) { 00612 LINK_STATS_INC(link.memerr); 00613 LINK_STATS_INC(link.drop); 00614 snmp_inc_ifoutdiscards(stats_if); 00615 return ERR_MEM; 00616 } 00617 #if LWIP_LOOPBACK_MAX_PBUFS 00618 clen = pbuf_clen(r); 00619 /* check for overflow or too many pbuf on queue */ 00620 if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || 00621 ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { 00622 pbuf_free(r); 00623 LINK_STATS_INC(link.memerr); 00624 LINK_STATS_INC(link.drop); 00625 snmp_inc_ifoutdiscards(stats_if); 00626 return ERR_MEM; 00627 } 00628 netif->loop_cnt_current += clen; 00629 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00630 00631 /* Copy the whole pbuf queue p into the single pbuf r */ 00632 if ((err = pbuf_copy(r, p)) != ERR_OK) { 00633 pbuf_free(r); 00634 LINK_STATS_INC(link.memerr); 00635 LINK_STATS_INC(link.drop); 00636 snmp_inc_ifoutdiscards(stats_if); 00637 return err; 00638 } 00639 00640 /* Put the packet on a linked list which gets emptied through calling 00641 netif_poll(). */ 00642 00643 /* let last point to the last pbuf in chain r */ 00644 for (last = r; last->next != NULL; last = last->next); 00645 00646 SYS_ARCH_PROTECT(lev); 00647 if(netif->loop_first != NULL) { 00648 LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); 00649 netif->loop_last->next = r; 00650 netif->loop_last = last; 00651 } else { 00652 netif->loop_first = r; 00653 netif->loop_last = last; 00654 } 00655 SYS_ARCH_UNPROTECT(lev); 00656 00657 LINK_STATS_INC(link.xmit); 00658 snmp_add_ifoutoctets(stats_if, p->tot_len); 00659 snmp_inc_ifoutucastpkts(stats_if); 00660 00661 #if LWIP_NETIF_LOOPBACK_MULTITHREADING 00662 /* For multithreading environment, schedule a call to netif_poll */ 00663 tcpip_callback((tcpip_callback_fn)netif_poll, netif); 00664 #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ 00665 00666 return ERR_OK; 00667 } 00668 00669 /** 00670 * Call netif_poll() in the main loop of your application. This is to prevent 00671 * reentering non-reentrant functions like tcp_input(). Packets passed to 00672 * netif_loop_output() are put on a list that is passed to netif->input() by 00673 * netif_poll(). 00674 */ 00675 void 00676 netif_poll(struct netif *netif) 00677 { 00678 struct pbuf *in; 00679 /* If we have a loopif, SNMP counters are adjusted for it, 00680 * if not they are adjusted for 'netif'. */ 00681 #if LWIP_SNMP 00682 #if LWIP_HAVE_LOOPIF 00683 struct netif *stats_if = &loop_netif; 00684 #else /* LWIP_HAVE_LOOPIF */ 00685 struct netif *stats_if = netif; 00686 #endif /* LWIP_HAVE_LOOPIF */ 00687 #endif /* LWIP_SNMP */ 00688 SYS_ARCH_DECL_PROTECT(lev); 00689 00690 do { 00691 /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ 00692 SYS_ARCH_PROTECT(lev); 00693 in = netif->loop_first; 00694 if (in != NULL) { 00695 struct pbuf *in_end = in; 00696 #if LWIP_LOOPBACK_MAX_PBUFS 00697 u8_t clen = pbuf_clen(in); 00698 /* adjust the number of pbufs on queue */ 00699 LWIP_ASSERT("netif->loop_cnt_current underflow", 00700 ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); 00701 netif->loop_cnt_current -= clen; 00702 #endif /* LWIP_LOOPBACK_MAX_PBUFS */ 00703 while (in_end->len != in_end->tot_len) { 00704 LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); 00705 in_end = in_end->next; 00706 } 00707 /* 'in_end' now points to the last pbuf from 'in' */ 00708 if (in_end == netif->loop_last) { 00709 /* this was the last pbuf in the list */ 00710 netif->loop_first = netif->loop_last = NULL; 00711 } else { 00712 /* pop the pbuf off the list */ 00713 netif->loop_first = in_end->next; 00714 LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); 00715 } 00716 /* De-queue the pbuf from its successors on the 'loop_' list. */ 00717 in_end->next = NULL; 00718 } 00719 SYS_ARCH_UNPROTECT(lev); 00720 00721 if (in != NULL) { 00722 LINK_STATS_INC(link.recv); 00723 snmp_add_ifinoctets(stats_if, in->tot_len); 00724 snmp_inc_ifinucastpkts(stats_if); 00725 /* loopback packets are always IP packets! */ 00726 if (ip_input(in, netif) != ERR_OK) { 00727 pbuf_free(in); 00728 } 00729 /* Don't reference the packet any more! */ 00730 in = NULL; 00731 } 00732 /* go on while there is a packet on the list */ 00733 } while (netif->loop_first != NULL); 00734 } 00735 00736 #if !LWIP_NETIF_LOOPBACK_MULTITHREADING 00737 /** 00738 * Calls netif_poll() for every netif on the netif_list. 00739 */ 00740 void 00741 netif_poll_all(void) 00742 { 00743 struct netif *netif = netif_list; 00744 /* loop through netifs */ 00745 while (netif != NULL) { 00746 netif_poll(netif); 00747 /* proceed to next network interface */ 00748 netif = netif->next; 00749 } 00750 } 00751 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ 00752 #endif /* ENABLE_LOOPBACK */
Generated on Tue Jul 12 2022 21:10:25 by
![doxygen](doxygen.png)