/** | |
* @file | |
* Loop Interface | |
* | |
*/ | |
/* | |
* Copyright (c) 2001-2004 Swedish Institute of Computer Science. | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright notice, | |
* this list of conditions and the following disclaimer in the documentation | |
* and/or other materials provided with the distribution. | |
* 3. The name of the author may not be used to endorse or promote products | |
* derived from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT | |
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | |
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | |
* OF SUCH DAMAGE. | |
* | |
* This file is part of the lwIP TCP/IP stack. | |
* | |
* Author: Adam Dunkels <adam@sics.se> | |
* | |
*/ | |
#include "lwip/opt.h" | |
#if LWIP_HAVE_LOOPIF | |
#include "netif/loopif.h" | |
#include "lwip/pbuf.h" | |
#include "lwip/snmp.h" | |
#include <string.h> | |
#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 | |
* | |
* @param netif the lwip network interface structure for this loopif | |
* @return ERR_OK if the loopif is initialized | |
* ERR_MEM if private data couldn't be allocated | |
*/ | |
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! | |
*/ | |
NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); | |
netif->name[0] = 'l'; | |
netif->name[1] = 'o'; | |
netif->output = loopif_output; | |
return ERR_OK; | |
} | |
#endif /* LWIP_HAVE_LOOPIF */ |