mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-07-04 20:08:57 +00:00
fix bug #2595: "loopif results
in NULL reference for incoming TCP packets". Loopif has to be configured (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() (multithreading environments, e.g. netif->input() = tcpip_input()) or putting packets on a list that is fed to the stack by calling loopif_poll() (single-thread / NO_SYS / polling environment where e.g. netif->input() = ip_input).
This commit is contained in:
parent
82e579a29d
commit
02e194b15f
|
@ -117,6 +117,15 @@ HISTORY
|
||||||
|
|
||||||
++ Bug fixes:
|
++ Bug fixes:
|
||||||
|
|
||||||
|
2007-04-23 Simon Goldschmidt
|
||||||
|
* loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results
|
||||||
|
in NULL reference for incoming TCP packets". Loopif has to be configured
|
||||||
|
(using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input()
|
||||||
|
(multithreading environments, e.g. netif->input() = tcpip_input()) or
|
||||||
|
putting packets on a list that is fed to the stack by calling loopif_poll()
|
||||||
|
(single-thread / NO_SYS / polling environment where e.g.
|
||||||
|
netif->input() = ip_input).
|
||||||
|
|
||||||
2007-04-17 Jonathan Larmour
|
2007-04-17 Jonathan Larmour
|
||||||
* pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold
|
* pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold
|
||||||
the difference between two u16_t's.
|
the difference between two u16_t's.
|
||||||
|
|
|
@ -408,6 +408,17 @@ a lot of data that needs to be copied, this should be set high. */
|
||||||
#define LWIP_HAVE_LOOPIF 0
|
#define LWIP_HAVE_LOOPIF 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This switches between directly calling netif->input() (=1 for multithreading
|
||||||
|
* environments like tcpip.c) or putting the packets on a list and calling
|
||||||
|
* loopif_poll() in the main application loop (=0 for polling / NO_SYS
|
||||||
|
* environments).
|
||||||
|
* Setting this is needed to avoid reentering non-reentrant functions like
|
||||||
|
* tcp_input().
|
||||||
|
*/
|
||||||
|
#ifndef LWIP_LOOPIF_MULTITHREADING
|
||||||
|
#define LWIP_LOOPIF_MULTITHREADING 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef LWIP_EVENT_API
|
#ifndef LWIP_EVENT_API
|
||||||
#define LWIP_EVENT_API 0
|
#define LWIP_EVENT_API 0
|
||||||
#define LWIP_CALLBACK_API 1
|
#define LWIP_CALLBACK_API 1
|
||||||
|
|
|
@ -34,6 +34,10 @@
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
|
#if !LWIP_LOOPIF_MULTITHREADING
|
||||||
|
void loopif_poll(struct netif *netif);
|
||||||
|
#endif
|
||||||
|
|
||||||
err_t loopif_init(struct netif *netif);
|
err_t loopif_init(struct netif *netif);
|
||||||
|
|
||||||
#endif /* __NETIF_LOOPIF_H__ */
|
#endif /* __NETIF_LOOPIF_H__ */
|
||||||
|
|
|
@ -15,10 +15,8 @@ ethernetif.c
|
||||||
network device drivers. It uses the etharp.c ARP code.
|
network device drivers. It uses the etharp.c ARP code.
|
||||||
|
|
||||||
loopif.c
|
loopif.c
|
||||||
An example network interface that shows how a "loopback"
|
A "loopback" network interface driver. It requires configuration
|
||||||
interface would work. This is not really intended for actual
|
through the define LWIP_LOOPIF_MULTITHREADING (see opt.h).
|
||||||
use, but as a very basic example of how initialization and
|
|
||||||
output functions work.
|
|
||||||
|
|
||||||
slipif.c
|
slipif.c
|
||||||
A generic implementation of the SLIP (Serial Line IP)
|
A generic implementation of the SLIP (Serial Line IP)
|
||||||
|
|
|
@ -36,75 +36,121 @@
|
||||||
#include "netif/loopif.h"
|
#include "netif/loopif.h"
|
||||||
#include "lwip/mem.h"
|
#include "lwip/mem.h"
|
||||||
|
|
||||||
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
|
#if !LWIP_LOOPIF_MULTITHREADING
|
||||||
#include "netif/tcpdump.h"
|
|
||||||
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
|
|
||||||
|
|
||||||
#include "lwip/tcp.h"
|
#include "lwip/sys.h"
|
||||||
#include "lwip/ip.h"
|
|
||||||
|
|
||||||
static void
|
/* helper struct for the linked list of pbufs */
|
||||||
loopif_input( void * arg )
|
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().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
loopif_poll(struct netif *netif)
|
||||||
{
|
{
|
||||||
struct netif *netif = (struct netif *)( ((void **)arg)[ 0 ] );
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
struct pbuf *r = (struct pbuf *)( ((void **)arg)[ 1 ] );
|
struct pbuf *in = NULL;
|
||||||
|
struct loopif_private *priv = (struct loopif_private*)netif->state;
|
||||||
|
|
||||||
mem_free( arg );
|
do {
|
||||||
netif -> input( r, netif );
|
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
|
||||||
|
SYS_ARCH_PROTECT(lev);
|
||||||
|
in = priv->first;
|
||||||
|
if(priv->first) {
|
||||||
|
if(priv->first == priv->last) {
|
||||||
|
/* this was the last pbuf in the list */
|
||||||
|
priv->first = priv->last = NULL;
|
||||||
|
} else {
|
||||||
|
/* pop the pbuf off the list */
|
||||||
|
priv->first = priv->first->next;
|
||||||
|
LWIP_ASSERT("should not be null since first != last!", priv->first != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
|
||||||
|
if(in != NULL) {
|
||||||
|
if(in->next != NULL) {
|
||||||
|
in->next = NULL;
|
||||||
|
LWIP_ASSERT("packet must not consist of multiple pbufs!", in->len == in->tot_len);
|
||||||
|
}
|
||||||
|
netif->input(in, netif);
|
||||||
|
}
|
||||||
|
/* go on while there is a packet on the list */
|
||||||
|
} while(in != NULL);
|
||||||
}
|
}
|
||||||
|
#endif /* LWIP_LOOPIF_MULTITHREADING */
|
||||||
|
|
||||||
static err_t
|
static err_t
|
||||||
loopif_output(struct netif *netif, struct pbuf *p,
|
loopif_output(struct netif *netif, struct pbuf *p,
|
||||||
struct ip_addr *ipaddr)
|
struct ip_addr *ipaddr)
|
||||||
{
|
{
|
||||||
|
#if !LWIP_LOOPIF_MULTITHREADING
|
||||||
|
SYS_ARCH_DECL_PROTECT(lev);
|
||||||
|
struct loopif_private *priv;
|
||||||
|
#endif /* LWIP_LOOPIF_MULTITHREADING */
|
||||||
struct pbuf *q, *r;
|
struct pbuf *q, *r;
|
||||||
u8_t *ptr;
|
u8_t *ptr;
|
||||||
void **arg;
|
|
||||||
|
|
||||||
#if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP)
|
LWIP_UNUSED_ARG(ipaddr);
|
||||||
tcpdump(p);
|
|
||||||
#endif /* LWIP_DEBUG && LWIP_TCPDUMP */
|
|
||||||
|
|
||||||
|
/* Allocate a new pbuf */
|
||||||
r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||||
if (r != NULL) {
|
if (r == NULL) {
|
||||||
ptr = r->payload;
|
return ERR_MEM;
|
||||||
|
|
||||||
for(q = p; q != NULL; q = q->next) {
|
|
||||||
memcpy(ptr, q->payload, q->len);
|
|
||||||
ptr += q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg = mem_malloc( sizeof( void *[2]));
|
|
||||||
if( NULL == arg ) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg[0] = netif;
|
|
||||||
arg[1] = r;
|
|
||||||
/**
|
|
||||||
* workaround (patch #1779) to try to prevent bug #2595:
|
|
||||||
* When connecting to "localhost" with the loopif interface,
|
|
||||||
* tcp_output doesn't get the opportunity to finnish sending the
|
|
||||||
* segment before tcp_process gets it, resulting in tcp_process
|
|
||||||
* referencing pcb->unacked-> which still is NULL.
|
|
||||||
*
|
|
||||||
* TODO: Is there still a race condition here? Leon
|
|
||||||
*/
|
|
||||||
sys_timeout( 1, loopif_input, arg );
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
}
|
||||||
return ERR_MEM;
|
|
||||||
|
/* Copy the whole pbuf queue p into the single pbuf r */
|
||||||
|
ptr = r->payload;
|
||||||
|
for(q = p; q != NULL; q = q->next) {
|
||||||
|
memcpy(ptr, q->payload, q->len);
|
||||||
|
ptr += q->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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!!!) */
|
||||||
|
netif->input(r, netif);
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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 = r;
|
||||||
|
} else {
|
||||||
|
priv->first = priv->last = r;
|
||||||
|
}
|
||||||
|
SYS_ARCH_UNPROTECT(lev);
|
||||||
|
#endif /* LWIP_LOOPIF_MULTITHREADING */
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_t
|
err_t
|
||||||
loopif_init(struct netif *netif)
|
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 */
|
||||||
|
|
||||||
netif->name[0] = 'l';
|
netif->name[0] = 'l';
|
||||||
netif->name[1] = 'o';
|
netif->name[1] = 'o';
|
||||||
#if 0 /** TODO: I think this should be enabled, or not? Leon */
|
|
||||||
netif->input = loopif_input;
|
|
||||||
#endif
|
|
||||||
netif->output = loopif_output;
|
netif->output = loopif_output;
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user