diff --git a/CHANGELOG b/CHANGELOG index 87f5d337..da1ce943 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,6 +53,11 @@ HISTORY ++ New features: + 2008-03-10 Simon Goldschmidt (patch by Luca Ceresoli) + * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly + modified version of patch # 6370: Moved loopif code to netif.c so that + loopback traffic is supported on all netifs (all local IPs). + 2008-03-10 Jonathan Larmour * inet_chksum.c: Allow choice of one of the sample algorithms to be made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index fbcef5dc..696217b0 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -531,9 +531,19 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip_debug_print(p); - LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); +#if (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) && !LWIP_NETIF_LOOPBACK_MULTITHREADING + if (ip_addr_cmp(dest, &netif->ip_addr)) { + /* Packet to self, enqueue it for loopback */ + LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); - return netif->output(netif, p, dest); + return netif_loop_output(netif, p, dest); + } else +#endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ + { + LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); + + return netif->output(netif, p, dest); + } } /** diff --git a/src/core/netif.c b/src/core/netif.c index aae68b45..4ab1f8a6 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -45,6 +45,9 @@ #include "lwip/snmp.h" #include "lwip/igmp.h" #include "netif/etharp.h" +#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING +#include "lwip/sys.h" +#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #if LWIP_NETIF_STATUS_CALLBACK #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } @@ -106,6 +109,10 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ +#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING + netif->loop_first = NULL; + netif->loop_last = NULL; +#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ /* remember netif specific state information data */ netif->state = state; @@ -497,3 +504,138 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif->link_callback = link_callback; } #endif /* LWIP_NETIF_LINK_CALLBACK */ + +#if ENABLE_LOOPBACK +/** + * Send an IP packet to be received on the same netif (loopif-like). + * The pbuf is simply copied and handed back to netif->input. + * In multithreaded mode, this is done directly since netif->input must put + * the packet on a queue. + * In callback mode, the packet is put on an internal queue and is fed to + * netif->input by netif_poll(). + * + * @param netif the lwip network interface structure + * @param p the (IP) packet to 'send' + * @param ipaddr the ip address to send the packet to (not used) + * @return ERR_OK if the packet has been sent + * ERR_MEM if the pbuf used to copy the packet couldn't be allocated + */ +err_t +netif_loop_output(struct netif *netif, struct pbuf *p, + struct ip_addr *ipaddr) +{ + struct pbuf *r; + err_t err; +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING + struct pbuf *last; + SYS_ARCH_DECL_PROTECT(lev); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + LWIP_UNUSED_ARG(ipaddr); + + /* Allocate a new pbuf */ + r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + if (r == NULL) { + return ERR_MEM; + } + + /* Copy the whole pbuf queue p into the single pbuf r */ + if ((err = pbuf_copy(r, p)) != ERR_OK) { + pbuf_free(r); + r = NULL; + return err; + } + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING + /* Multithreading environment, netif->input() is supposed to put the packet + into a mailbox, so we can safely call it here without risking to re-enter + functions that are not reentrant (TCP!!!) */ + LWIP_ASSERT(netif->input != ip_input, "Don't use ip_input as netif->input with LWIP_NETIF_LOOPBACK_MULTITHREADING = 1!"); + if(netif->input(r, netif) != ERR_OK) { + pbuf_free(r); + r = NULL; + } +#else /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + /* Raw API without threads: put the packet on a linked list which gets emptied + through calling netif_poll(). */ + + /* let last point to the last pbuf in chain r */ + for (last = r; last->next != NULL; last = last->next); + SYS_ARCH_PROTECT(lev); + if(netif->loop_first != NULL) { + LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); + netif->loop_last->next = r; + netif->loop_last = last; + } else { + netif->loop_first = r; + netif->loop_last = last; + } + SYS_ARCH_UNPROTECT(lev); +#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ + + return ERR_OK; +} + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +/** + * Calls netif_poll() for every netif on the netif_list. + */ +void +netif_poll_all(void) +{ + struct netif *netif = netif_list; + /* loop through netifs */ + while (netif != NULL) { + netif_poll(netif); + /* proceed to next network interface */ + netif = netif->next; + } +} + +/** + * Call netif_poll() in the main loop of your application. This is to prevent + * reentering non-reentrant functions like tcp_input(). Packets passed to + * netif_loop_output() are put on a list that is passed to netif->input() by + * netif_poll(). + */ +void +netif_poll(struct netif *netif) +{ + struct pbuf *in; + SYS_ARCH_DECL_PROTECT(lev); + + do { + /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ + SYS_ARCH_PROTECT(lev); + in = netif->loop_first; + if(in != NULL) { + struct pbuf *in_end = in; + while(in_end->len != in_end->tot_len) { + LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); + in_end = in_end->next; + } + /* 'in_end' now points to the last pbuf from 'in' */ + if(in_end == netif->loop_last) { + /* this was the last pbuf in the list */ + netif->loop_first = netif->loop_last = NULL; + } else { + /* pop the pbuf off the list */ + netif->loop_first = in_end->next; + LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); + } + /* De-queue the pbuf from its successors on the 'loop_' list. */ + in_end->next = NULL; + } + SYS_ARCH_UNPROTECT(lev); + + if(in != NULL) { + if(netif->input(in, netif) != ERR_OK) { + pbuf_free(in); + } + /* Don't reference the packet any more! */ + in = NULL; + } + /* go on while there is a packet on the list */ + } while(netif->loop_first != NULL); +} +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 19c38087..b8dbfcde 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -34,6 +34,8 @@ #include "lwip/opt.h" +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + #include "lwip/err.h" #include "lwip/ip_addr.h" @@ -165,6 +167,11 @@ struct netif { #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING + /* List of packets to be queued for ourselves. */ + struct pbuf *loop_first; + struct pbuf *loop_last; +#endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ }; #if LWIP_SNMP @@ -242,4 +249,12 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct } #endif +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +void netif_poll(struct netif *netif); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + #endif /* __LWIP_NETIF_H__ */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 1f7b6ab5..7f45eabd 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -832,6 +832,31 @@ #define LWIP_NETIF_HWADDRHINT 0 #endif +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK 0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + * multithreaded environment like tcpip.c. In this case, netif->input() + * is called directly. + * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + * The packets are put on a list and netif_poll() must be called in + * the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) +#endif + /* ------------------------------------ ---------- LOOPIF options ---------- @@ -844,22 +869,6 @@ #define LWIP_HAVE_LOOPIF 0 #endif -/** - * LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in - * the system, as LOOPIF must change how it behaves depending on this setting. - * Setting this is needed to avoid reentering non-reentrant functions like - * tcp_input(). - * LWIP_LOOPIF_MULTITHREADING==1: Indicates that the user is using a - * multithreaded environment like tcpip.c. In this case, netif->input() - * is called directly. - * LWIP_LOOPIF_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. - * The packets are put on a list and loopif_poll() must be called in - * the main application loop. - */ -#ifndef LWIP_LOOPIF_MULTITHREADING -#define LWIP_LOOPIF_MULTITHREADING 1 -#endif - /* ------------------------------------ ---------- Thread options ---------- diff --git a/src/include/netif/loopif.h b/src/include/netif/loopif.h index 68fc7b39..0232fc55 100644 --- a/src/include/netif/loopif.h +++ b/src/include/netif/loopif.h @@ -39,8 +39,8 @@ extern "C" { #endif -#if !LWIP_LOOPIF_MULTITHREADING -void loopif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +#define loopif_poll(netif) netif_poll() #endif err_t loopif_init(struct netif *netif); diff --git a/src/netif/loopif.c b/src/netif/loopif.c index adffdcf3..1e1f28cf 100644 --- a/src/netif/loopif.c +++ b/src/netif/loopif.c @@ -40,149 +40,8 @@ #if LWIP_HAVE_LOOPIF #include "netif/loopif.h" -#include "lwip/pbuf.h" #include "lwip/snmp.h" -#include - -#if !LWIP_LOOPIF_MULTITHREADING - -#include "lwip/sys.h" -#include "lwip/mem.h" - -/* helper struct for the linked list of pbufs */ -struct loopif_private { - struct pbuf *first; - struct pbuf *last; -}; - -/** - * Call loopif_poll() in the main loop of your application. This is to prevent - * reentering non-reentrant functions like tcp_input(). Packets passed to - * loopif_output() are put on a list that is passed to netif->input() by - * loopif_poll(). - * - * @param netif the lwip network interface structure for this loopif - */ -void -loopif_poll(struct netif *netif) -{ - SYS_ARCH_DECL_PROTECT(lev); - struct pbuf *in, *in_end; - struct loopif_private *priv = (struct loopif_private*)netif->state; - - LWIP_ERROR("priv != NULL", (priv != NULL), return;); - - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = priv->first; - if(in) { - in_end = in; - while(in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; - } - /* 'in_end' now points to the last pbuf from 'in' */ - if(in_end == priv->last) { - /* this was the last pbuf in the list */ - priv->first = priv->last = NULL; - } else { - /* pop the pbuf off the list */ - priv->first = in_end->next; - LWIP_ASSERT("should not be null since first != last!", priv->first != NULL); - } - } - SYS_ARCH_UNPROTECT(lev); - - if(in != NULL) { - if(in_end->next != NULL) { - /* De-queue the pbuf from its successors on the 'priv' list. */ - in_end->next = NULL; - } - if(netif->input(in, netif) != ERR_OK) { - pbuf_free(in); - } - /* Don't reference the packet any more! */ - in = NULL; - in_end = NULL; - } - /* go on while there is a packet on the list */ - } while(priv->first != NULL); -} -#endif /* LWIP_LOOPIF_MULTITHREADING */ - -/** - * Send an IP packet over the loopback interface. - * The pbuf is simply copied and handed back to netif->input. - * In multithreaded mode, this is done directly since netif->input must put - * the packet on a queue. - * In callback mode, the packet is put on an internal queue and is fed to - * netif->input by loopif_poll(). - * - * @param netif the lwip network interface structure for this loopif - * @param p the (IP) packet to 'send' - * @param ipaddr the ip address to send the packet to (not used for loopif) - * @return ERR_OK if the packet has been sent - * ERR_MEM if the pbuf used to copy the packet couldn't be allocated - */ -static err_t -loopif_output(struct netif *netif, struct pbuf *p, - struct ip_addr *ipaddr) -{ -#if !LWIP_LOOPIF_MULTITHREADING - SYS_ARCH_DECL_PROTECT(lev); - struct loopif_private *priv; - struct pbuf *last; -#endif /* LWIP_LOOPIF_MULTITHREADING */ - struct pbuf *r; - err_t err; - - LWIP_UNUSED_ARG(ipaddr); - - /* Allocate a new pbuf */ - r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (r == NULL) { - return ERR_MEM; - } - - /* Copy the whole pbuf queue p into the single pbuf r */ - if ((err = pbuf_copy(r, p)) != ERR_OK) { - pbuf_free(r); - r = NULL; - return err; - } - -#if LWIP_LOOPIF_MULTITHREADING - /* Multithreading environment, netif->input() is supposed to put the packet - into a mailbox, so we can safely call it here without risking to re-enter - functions that are not reentrant (TCP!!!) */ - if(netif->input(r, netif) != ERR_OK) { - pbuf_free(r); - r = NULL; - } -#else /* LWIP_LOOPIF_MULTITHREADING */ - /* Raw API without threads: put the packet on a linked list which gets emptied - through calling loopif_poll(). */ - priv = (struct loopif_private*)netif->state; - - /* let last point to the last pbuf in chain r */ - for (last = r; last->next != NULL; last = last->next); - SYS_ARCH_PROTECT(lev); - if(priv->first != NULL) { - LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL); - priv->last->next = r; - priv->last = last; - } else { - priv->first = r; - priv->last = last; - } - SYS_ARCH_UNPROTECT(lev); -#endif /* LWIP_LOOPIF_MULTITHREADING */ - - return ERR_OK; -} - /** * Initialize a lwip network interface structure for a loopback interface * @@ -193,16 +52,6 @@ loopif_output(struct netif *netif, struct pbuf *p, err_t loopif_init(struct netif *netif) { -#if !LWIP_LOOPIF_MULTITHREADING - struct loopif_private *priv; - - priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private)); - if(priv == NULL) - return ERR_MEM; - priv->first = priv->last = NULL; - netif->state = priv; -#endif /* LWIP_LOOPIF_MULTITHREADING */ - /* initialize the snmp variables and counters inside the struct netif * ifSpeed: no assumption can be made! */ @@ -210,7 +59,7 @@ loopif_init(struct netif *netif) netif->name[0] = 'l'; netif->name[1] = 'o'; - netif->output = loopif_output; + netif->output = netif_loop_output; return ERR_OK; }