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.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers netif.c Source File

netif.c

Go to the documentation of this file.
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 */