diff options
Diffstat (limited to 'nuttx/net')
-rw-r--r-- | nuttx/net/Makefile | 86 | ||||
-rw-r--r-- | nuttx/net/uip/.psock.h.swo | bin | 0 -> 16398 bytes | |||
-rw-r--r-- | nuttx/net/uip/Make.defs | 38 | ||||
-rw-r--r-- | nuttx/net/uip/psock.c | 377 | ||||
-rw-r--r-- | nuttx/net/uip/uip-arp.c | 405 | ||||
-rw-r--r-- | nuttx/net/uip/uip-fw.c | 513 | ||||
-rw-r--r-- | nuttx/net/uip/uip-fw.h | 176 | ||||
-rw-r--r-- | nuttx/net/uip/uip-neighbor.c | 158 | ||||
-rw-r--r-- | nuttx/net/uip/uip-neighbor.h | 54 | ||||
-rw-r--r-- | nuttx/net/uip/uip-split.c | 132 | ||||
-rw-r--r-- | nuttx/net/uip/uip-split.h | 96 | ||||
-rw-r--r-- | nuttx/net/uip/uip-wait.c | 180 | ||||
-rw-r--r-- | nuttx/net/uip/uip.c | 2091 |
13 files changed, 4306 insertions, 0 deletions
diff --git a/nuttx/net/Makefile b/nuttx/net/Makefile new file mode 100644 index 000000000..5aeacc213 --- /dev/null +++ b/nuttx/net/Makefile @@ -0,0 +1,86 @@ +############################################################ +# Makefile +# +# Copyright (C) 2007 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# 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. Neither the name Gregory Nutt nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "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 +# COPYRIGHT OWNER OR CONTRIBUTORS 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. +# +############################################################ + +-include $(TOPDIR)/Make.defs + +MKDEP = $(TOPDIR)/tools/mkdeps.sh + +ifeq ($(CONFIG_NET_UIP),y) +include uip/Make.defs +endif + +ASRCS = $(UIP_ASRCS) +AOBJS = $(ASRCS:.S=$(OBJEXT)) + +CSRCS = $(UIP_CSRCS) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +BIN = libnet$(LIBEXT) + +VPATH = uip + +all: $(BIN) + +$(AOBJS): %$(OBJEXT): %.S + $(CC) -c $(CFLAGS) -D__ASSEMBLY__ $< -o $@ + +$(COBJS): %$(OBJEXT): %.c + $(CC) -c $(CFLAGS) $< -o $@ + +$(BIN): $(OBJS) + ( for obj in $(OBJS) ; do \ + $(AR) $@ $${obj} || \ + { echo "$(AR) $@ $obj FAILED!" ; exit 1 ; } ; \ + done ; ) + +.depend: Makefile $(SRCS) +ifeq ($(CONFIG_NET_UIP),y) + $(MKDEP) --dep-path uip $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep +endif + touch $@ + +depend: .depend + +clean: + rm -f $(BIN) *.o *.rel *.asm *.lst *.sym *.adb *~ + if [ ! -z "$(OBJEXT)" ]; then rm -f *$(OBJEXT); fi + +distclean: clean + rm -f Make.dep .depend + +-include Make.dep diff --git a/nuttx/net/uip/.psock.h.swo b/nuttx/net/uip/.psock.h.swo Binary files differnew file mode 100644 index 000000000..9daa59748 --- /dev/null +++ b/nuttx/net/uip/.psock.h.swo diff --git a/nuttx/net/uip/Make.defs b/nuttx/net/uip/Make.defs new file mode 100644 index 000000000..85d61d0d9 --- /dev/null +++ b/nuttx/net/uip/Make.defs @@ -0,0 +1,38 @@ +############################################################################ +# Make.defs +# +# Copyright (C) 2007 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt <spudmonkey@racsa.co.cr> +# +# 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. Neither the name Gregory Nutt nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "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 +# COPYRIGHT OWNER OR CONTRIBUTORS 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. +# +############################################################################ + +UIP_ASRCS = +UIP_CSRCS = psock.c uip-arp.c uip.c uip-fw.c uip-neighbor.c uip-split.c uip-wait.c + diff --git a/nuttx/net/uip/psock.c b/nuttx/net/uip/psock.c new file mode 100644 index 000000000..892c97602 --- /dev/null +++ b/nuttx/net/uip/psock.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 uIP TCP/IP stack + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: psock.c,v 1.1.1.1 2007-08-26 23:04:11 patacongo Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <debug.h> + +#include <net/uip/uip.h> +#include <net/uip/uipopt.h> +#include <net/uip/psock.h> + +#define STATE_NONE 0 +#define STATE_ACKED 1 +#define STATE_READ 2 +#define STATE_BLOCKED_NEWDATA 3 +#define STATE_BLOCKED_CLOSE 4 +#define STATE_BLOCKED_SEND 5 +#define STATE_DATA_SENT 6 + +/* + * Return value of the buffering functions that indicates that a + * buffer was not filled by incoming data. + * + */ +#define BUF_NOT_FULL 0 +#define BUF_NOT_FOUND 0 + +/* + * Return value of the buffering functions that indicates that a + * buffer was completely filled by incoming data. + * + */ +#define BUF_FULL 1 + +/* + * Return value of the buffering functions that indicates that an + * end-marker byte was found. + * + */ +#define BUF_FOUND 2 + +static void buf_setup(struct psock_buf *buf, uint8 *bufptr, uint16 bufsize) +{ + buf->ptr = bufptr; + buf->left = bufsize; +} + +static uint8 buf_bufdata(struct psock_buf *buf, uint16 len, uint8 **dataptr, uint16 *datalen) +{ + if (*datalen < buf->left) + { + memcpy(buf->ptr, *dataptr, *datalen); + buf->ptr += *datalen; + buf->left -= *datalen; + *dataptr += *datalen; + *datalen = 0; + return BUF_NOT_FULL; + } + else if (*datalen == buf->left) + { + memcpy(buf->ptr, *dataptr, *datalen); + buf->ptr += *datalen; + buf->left = 0; + *dataptr += *datalen; + *datalen = 0; + return BUF_FULL; + } + else + { + memcpy(buf->ptr, *dataptr, buf->left); + buf->ptr += buf->left; + *datalen -= buf->left; + *dataptr += buf->left; + buf->left = 0; + return BUF_FULL; + } +} + +static uint8 buf_bufto(struct psock_buf *buf, uint8 endmarker, uint8 **dataptr, uint16 *datalen) +{ + uint8 c; + while(buf->left > 0 && *datalen > 0) + { + c = *buf->ptr = **dataptr; + ++*dataptr; + ++buf->ptr; + --*datalen; + --buf->left; + + if (c == endmarker) + { + return BUF_FOUND; + } + } + + if (*datalen == 0) + { + return BUF_NOT_FOUND; + } + + while(*datalen > 0) + { + c = **dataptr; + --*datalen; + ++*dataptr; + + if (c == endmarker) + { + return BUF_FOUND | BUF_FULL; + } + } + + return BUF_FULL; +} + +static boolean send_data(register struct psock *s) +{ + /* Inidicate that we are blocked waiting for the send to complete */ + + s->state = STATE_BLOCKED_SEND; + + /* Loop until we successfully send the data */ + + for (;;) + { + /* If the data has not been sent OR if it needs to be retransmitted, + * then send it now. + */ + + if (s->state != STATE_DATA_SENT || uip_rexmit()) + { + if (s->sendlen > uip_mss()) + { + uip_send(s->sendptr, uip_mss()); + } + else + { + uip_send(s->sendptr, s->sendlen); + } + + s->state = STATE_DATA_SENT; + } + + /* Check if all data has been sent and acknowledged */ + + if (s->state == STATE_DATA_SENT && uip_acked()) + { + /* Yes.. the data has been sent AND acknowledge */ + + if (s->sendlen > uip_mss()) + { + s->sendlen -= uip_mss(); + s->sendptr += uip_mss(); + } + else + { + s->sendptr += s->sendlen; + s->sendlen = 0; + } + + s->state = STATE_ACKED; + return TRUE; + } + + /* No.. then wait on the retransmit or acked events */ + + (void)uip_event_wait(UIP_ACKDATA|UIP_REXMIT); + } + + return FALSE; /* We never get here */ +} + +void psock_send(struct psock *s, const char *buf, unsigned int len) +{ + /* If there is no data to send, we exit immediately. */ + + if (len > 0) + { + /* Save the length of and a pointer to the data that is to be sent. */ + + s->sendptr = (const uint8*)buf; + s->sendlen = len; + s->state = STATE_NONE; + + /* Loop here until all data is sent. The s->sendlen variable is updated + * by the data_sent() function. + */ + + while(s->sendlen > 0) { + + /* Wait until the data has been sent and acknowledged */ + + send_data(s); + } + + /* Done */ + + s->state = STATE_NONE; + } +} + +void psock_generator_send(register struct psock *s, unsigned short (*generate)(void *), void *arg) +{ + /* Ensure that there is a generator function to call. */ + + if (generate != NULL) + { + /* Call the generator function to generate the data in the uip_appdata + * buffer. + */ + + s->sendlen = generate(arg); + s->sendptr = uip_appdata; + s->state = STATE_NONE; + + do + { + /* Call the generator function again if we are called to perform a + * retransmission. + */ + + if (uip_rexmit()) + { + generate(arg); + } + + /* Wait until all data is sent and acknowledged. */ + + send_data(s); + } + while(s->sendlen > 0); + + /* Done */ + + s->state = STATE_NONE; + } +} + +uint16 psock_datalen(struct psock *psock) +{ + return psock->bufsize - psock->buf.left; +} + +boolean psock_checknewdata(struct psock *s) +{ + if (s->readlen > 0) + { + /* There is data in the uip_appdata buffer that has not yet been read + * with the PSOCK_READ functions. + */ + return TRUE; + } + else if (s->state == STATE_READ) + { + /* All data in uip_appdata buffer already consumed. */ + + s->state = STATE_BLOCKED_NEWDATA; + return FALSE; + } + else if (uip_newdata()) + { + /* There is new data that has not been consumed. */ + + return TRUE; + } + else + { + /* There is no new data. */ + + return FALSE; + } +} + +void psock_waitnewdata(struct psock *s) +{ + while (!psock_checknewdata(s)) + { + uip_event_wait(UIP_NEWDATA); + } +} + +void psock_readto(register struct psock *psock, unsigned char c) +{ +restart: + buf_setup(&psock->buf, psock->bufptr, psock->bufsize); + + /* XXX: Should add buf_checkmarker() before do{} loop, if + incoming data has been handled while waiting for a write. */ + + do + { + if (psock->readlen == 0) + { + psock_waitnewdata(psock); + psock->state = STATE_READ; + psock->readptr = (uint8 *)uip_appdata; + psock->readlen = uip_datalen(); + } + } + while((buf_bufto(&psock->buf, c, &psock->readptr, &psock->readlen) & BUF_FOUND) == 0); + + if (psock_datalen(psock) == 0) + { + psock->state = STATE_NONE; + goto restart; + } +} + +void psock_readbuf(register struct psock *psock) +{ +restart: + buf_setup(&psock->buf, psock->bufptr, psock->bufsize); + + /* XXX: Should add buf_checkmarker() before do{} loop, if + incoming data has been handled while waiting for a write. */ + + do + { + if (psock->readlen == 0) + { + psock_waitnewdata(psock); + dbg("Waited for newdata\n"); + psock->state = STATE_READ; + psock->readptr = (uint8 *)uip_appdata; + psock->readlen = uip_datalen(); + } + } + while(buf_bufdata(&psock->buf, psock->bufsize, &psock->readptr, &psock->readlen) != BUF_FULL); + + if (psock_datalen(psock) == 0) + { + psock->state = STATE_NONE; + goto restart; + } +} + +void psock_init(register struct psock *psock, char *buffer, unsigned int buffersize) +{ + psock->state = STATE_NONE; + psock->readlen = 0; + psock->bufptr = (uint8*)buffer; + psock->bufsize = buffersize; + buf_setup(&psock->buf, (uint8*)buffer, buffersize); +} diff --git a/nuttx/net/uip/uip-arp.c b/nuttx/net/uip/uip-arp.c new file mode 100644 index 000000000..f27f5bb2e --- /dev/null +++ b/nuttx/net/uip/uip-arp.c @@ -0,0 +1,405 @@ +/* uip-arp.c + * Implementation of the ARP Address Resolution Protocol. + * Author: Adam Dunkels <adam@dunkels.com> + * + * The Address Resolution Protocol ARP is used for mapping between IP + * addresses and link level addresses such as the Ethernet MAC + * addresses. ARP uses broadcast queries to ask for the link level + * address of a known IP address and the host which is configured with + * the IP address for which the query was meant, will respond with its + * link level address. + * + * Note: This ARP implementation only supports Ethernet. + * + * Copyright (c) 2001-2003, Adam Dunkels. + * 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. + */ + +#include <sys/types.h> +#include <string.h> +#include <net/uip/uip-arp.h> + +struct arp_hdr +{ + struct uip_eth_hdr ethhdr; + uint16 hwtype; + uint16 protocol; + uint8 hwlen; + uint8 protolen; + uint16 opcode; + struct uip_eth_addr shwaddr; + uint16 sipaddr[2]; + struct uip_eth_addr dhwaddr; + uint16 dipaddr[2]; +}; + +struct ethip_hdr { + struct uip_eth_hdr ethhdr; + /* IP header. */ + uint8 vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16 ipchksum; + uint16 srcipaddr[2], + destipaddr[2]; +}; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +struct arp_entry { + uint16 ipaddr[2]; + struct uip_eth_addr ethaddr; + uint8 time; +}; + +static const struct uip_eth_addr broadcast_ethaddr = + {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const uint16 broadcast_ipaddr[2] = {0xffff,0xffff}; + +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; +static uint16 ipaddr[2]; +static uint8 i, c; + +static uint8 arptime; +static uint8 tmpage; + +#define BUF ((struct arp_hdr *)&uip_buf[0]) +#define IPBUF ((struct ethip_hdr *)&uip_buf[0]) +/*-----------------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_init(void) +{ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + memset(arp_table[i].ipaddr, 0, 4); + } +} +/*-----------------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_timer(void) +{ + struct arp_entry *tabptr; + + ++arptime; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && + arptime - tabptr->time >= UIP_ARP_MAXAGE) { + memset(tabptr->ipaddr, 0, 4); + } + } + +} + +/*-----------------------------------------------------------------------------------*/ +static void +uip_arp_update(uint16 *pipaddr, struct uip_eth_addr *ethaddr) +{ + register struct arp_entry *tabptr; + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + + tabptr = &arp_table[i]; + /* Only check those entries that are actually in use. */ + if(tabptr->ipaddr[0] != 0 && + tabptr->ipaddr[1] != 0) { + + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(pipaddr[0] == tabptr->ipaddr[0] && + pipaddr[1] == tabptr->ipaddr[1]) { + + /* An old entry found, update this and return. */ + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; + + return; + } + } + } + + /* If we get here, no existing ARP table entry was found, so we + create one. */ + + /* First, we try to find an unused entry in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(tabptr->ipaddr[0] == 0 && + tabptr->ipaddr[1] == 0) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == UIP_ARPTAB_SIZE) { + tmpage = 0; + c = 0; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(arptime - tabptr->time > tmpage) { + tmpage = arptime - tabptr->time; + c = i; + } + } + i = c; + tabptr = &arp_table[i]; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + memcpy(tabptr->ipaddr, pipaddr, 4); + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; +} +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming IP packets + * + * This function should be called by the device driver when an IP + * packet has been received. The function will check if the address is + * in the ARP cache, and if so the ARP cache entry will be + * refreshed. If no ARP cache entry was found, a new one is created. + * + * This function expects an IP packet with a prepended Ethernet header + * in the uip_buf[] buffer, and the length of the packet in the global + * variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +#if 0 +void +uip_arp_ipin(void) +{ + uip_len -= sizeof(struct uip_eth_hdr); + + /* Only insert/update an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + if((IPBUF->srcipaddr[0] & uip_netmask[0]) != + (uip_hostaddr[0] & uip_netmask[0])) { + return; + } + if((IPBUF->srcipaddr[1] & uip_netmask[1]) != + (uip_hostaddr[1] & uip_netmask[1])) { + return; + } + uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); + + return; +} +#endif /* 0 */ +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming ARP packets. + * + * This function should be called by the device driver when an ARP + * packet has been received. The function will act differently + * depending on the ARP packet type: if it is a reply for a request + * that we previously sent out, the ARP cache will be filled in with + * the values from the ARP reply. If the incoming ARP packet is an ARP + * request for our IP address, an ARP reply packet is created and put + * into the uip_buf[] buffer. + * + * When the function returns, the value of the global variable uip_len + * indicates whether the device driver should send out a packet or + * not. If uip_len is zero, no packet should be sent. If uip_len is + * non-zero, it contains the length of the outbound packet that is + * present in the uip_buf[] buffer. + * + * This function expects an ARP packet with a prepended Ethernet + * header in the uip_buf[] buffer, and the length of the packet in the + * global variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_arpin(void) +{ + + if(uip_len < sizeof(struct arp_hdr)) { + uip_len = 0; + return; + } + uip_len = 0; + + switch(BUF->opcode) { + case HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + reply. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + /* First, we register the one who made the request in our ARP + table, since it is likely that we will do more communication + with this host in the future. */ + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + + /* The reply opcode is 2. */ + BUF->opcode = HTONS(2); + + memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); + + BUF->dipaddr[0] = BUF->sipaddr[0]; + BUF->dipaddr[1] = BUF->sipaddr[1]; + BUF->sipaddr[0] = uip_hostaddr[0]; + BUF->sipaddr[1] = uip_hostaddr[1]; + + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + uip_len = sizeof(struct arp_hdr); + } + break; + case HTONS(ARP_REPLY): + /* ARP reply. We insert or update the ARP table if it was meant + for us. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + } + break; + } + + return; +} +/*-----------------------------------------------------------------------------------*/ +/** + * Prepend Ethernet header to an outbound IP packet and see if we need + * to send out an ARP request. + * + * This function should be called before sending out an IP packet. The + * function checks the destination IP address of the IP packet to see + * what Ethernet MAC address that should be used as a destination MAC + * address on the Ethernet. + * + * If the destination IP address is in the local network (determined + * by logical ANDing of netmask and our IP address), the function + * checks the ARP cache to see if an entry for the destination IP + * address is found. If so, an Ethernet header is prepended and the + * function returns. If no ARP cache entry is found for the + * destination IP address, the packet in the uip_buf[] is replaced by + * an ARP request packet for the IP address. The IP packet is dropped + * and it is assumed that they higher level protocols (e.g., TCP) + * eventually will retransmit the dropped packet. + * + * If the destination IP address is not on the local network, the IP + * address of the default router is used instead. + * + * When the function returns, a packet is present in the uip_buf[] + * buffer, and the length of the packet is in the global variable + * uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_out(void) +{ + struct arp_entry *tabptr; + + /* Find the destination IP address in the ARP table and construct + the Ethernet header. If the destination IP addres isn't on the + local network, we use the default router's IP address instead. + + If not ARP table entry is found, we overwrite the original IP + packet with an ARP request for the IP address. */ + + /* First check if destination is a local broadcast. */ + if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { + memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); + } else { + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ipaddr_copy(ipaddr, uip_draddr); + } else { + /* Else, we use the destination IP address. */ + uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); + } + + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { + break; + } + } + + if(i == UIP_ARPTAB_SIZE) { + /* The destination address was not in our ARP table, so we + overwrite the IP packet with an ARP request. */ + + memset(BUF->ethhdr.dest.addr, 0xff, 6); + memset(BUF->dhwaddr.addr, 0x00, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + + uip_ipaddr_copy(BUF->dipaddr, ipaddr); + uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); + BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ + BUF->hwtype = HTONS(ARP_HWTYPE_ETH); + BUF->protocol = HTONS(UIP_ETHTYPE_IP); + BUF->hwlen = 6; + BUF->protolen = 4; + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + + uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; + + uip_len = sizeof(struct arp_hdr); + return; + } + + /* Build an ethernet header. */ + memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); + } + memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + + IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); + + uip_len += sizeof(struct uip_eth_hdr); +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/nuttx/net/uip/uip-fw.c b/nuttx/net/uip/uip-fw.c new file mode 100644 index 000000000..7e5356f56 --- /dev/null +++ b/nuttx/net/uip/uip-fw.c @@ -0,0 +1,513 @@ +/* uip-fw.c + * uIP packet forwarding. + * Author: Adam Dunkels <adam@sics.se> + * + * This file implements a number of simple functions which do packet + * forwarding over multiple network interfaces with uIP. + * + * Copyright (c) 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +#include <net/uip/uip.h> +#include <net/uip/uip-arch.h> + +#include "uip-fw.h" + +#include <string.h> /* for memcpy() */ + +/* + * The list of registered network interfaces. + */ +static struct uip_fw_netif *netifs = NULL; + +/* + * A pointer to the default network interface. + */ +static struct uip_fw_netif *defaultnetif = NULL; + +struct tcpip_hdr { + /* IP header. */ + uint8 vhl, + tos; + uint16 len, + ipid, + ipoffset; + uint8 ttl, + proto; + uint16 ipchksum; + uint16 srcipaddr[2], + destipaddr[2]; + + /* TCP header. */ + uint16 srcport, + destport; + uint8 seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + uint16 tcpchksum; + uint8 urgp[2]; + uint8 optdata[4]; +}; + +struct icmpip_hdr { + /* IP header. */ + uint8 vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16 ipchksum; + uint16 srcipaddr[2], + destipaddr[2]; + /* ICMP (echo) header. */ + uint8 type, icode; + uint16 icmpchksum; + uint16 id, seqno; + uint8 payload[1]; +}; + +/* ICMP ECHO. */ +#define ICMP_ECHO 8 + +/* ICMP TIME-EXCEEDED. */ +#define ICMP_TE 11 + +/* + * Pointer to the TCP/IP headers of the packet in the uip_buf buffer. + */ +#define BUF ((struct tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/* + * Pointer to the ICMP/IP headers of the packet in the uip_buf buffer. + */ +#define ICMPBUF ((struct icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/* + * Certain fields of an IP packet that are used for identifying + * duplicate packets. + */ +struct fwcache_entry { + uint16 timer; + + uint16 srcipaddr[2]; + uint16 destipaddr[2]; + uint16 ipid; + uint8 proto; + uint8 unused; + +#if notdef + uint16 payload[2]; +#endif + +#if UIP_REASSEMBLY > 0 + uint16 len, offset; +#endif +}; + +/* + * The number of packets to remember when looking for duplicates. + */ +#ifdef CONFIG_UIP_FWCACHE_SIZE +# define FWCACHE_SIZE CONFIG_UIP_FWCACHE_SIZE +#else +# define FWCACHE_SIZE 2 +#endif + + +/* + * A cache of packet header fields which are used for + * identifying duplicate packets. + */ +static struct fwcache_entry fwcache[FWCACHE_SIZE]; + +/** + * \internal + * The time that a packet cache is active. + */ +#define FW_TIME 20 + +/*------------------------------------------------------------------------------*/ +/** + * Initialize the uIP packet forwarding module. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_init(void) +{ + struct uip_fw_netif *t; + defaultnetif = NULL; + while(netifs != NULL) { + t = netifs; + netifs = netifs->next; + t->next = NULL; + } +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Check if an IP address is within the network defined by an IP + * address and a netmask. + * + * \param ipaddr The IP address to be checked. + * \param netipaddr The IP address of the network. + * \param netmask The netmask of the network. + * + * \return Non-zero if IP address is in network, zero otherwise. + */ +/*------------------------------------------------------------------------------*/ +static unsigned char +ipaddr_maskcmp(uint16 *ipaddr, uint16 *netipaddr, uint16 *netmask) +{ + return (ipaddr[0] & netmask [0]) == (netipaddr[0] & netmask[0]) && + (ipaddr[1] & netmask[1]) == (netipaddr[1] & netmask[1]); +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Send out an ICMP TIME-EXCEEDED message. + * + * This function replaces the packet in the uip_buf buffer with the + * ICMP packet. + */ +/*------------------------------------------------------------------------------*/ +static void +time_exceeded(void) +{ + uint16 tmp16; + + /* We don't send out ICMP errors for ICMP messages. */ + if(ICMPBUF->proto == UIP_PROTO_ICMP) { + uip_len = 0; + return; + } + /* Copy fields from packet header into payload of this ICMP packet. */ + memcpy(&(ICMPBUF->payload[0]), ICMPBUF, 28); + + /* Set the ICMP type and code. */ + ICMPBUF->type = ICMP_TE; + ICMPBUF->icode = 0; + + /* Calculate the ICMP checksum. */ + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_chksum((uint16 *)&(ICMPBUF->type), 36); + + /* Set the IP destination address to be the source address of the + original packet. */ + tmp16= BUF->destipaddr[0]; + BUF->destipaddr[0] = BUF->srcipaddr[0]; + BUF->srcipaddr[0] = tmp16; + tmp16 = BUF->destipaddr[1]; + BUF->destipaddr[1] = BUF->srcipaddr[1]; + BUF->srcipaddr[1] = tmp16; + + /* Set our IP address as the source address. */ + BUF->srcipaddr[0] = uip_hostaddr[0]; + BUF->srcipaddr[1] = uip_hostaddr[1]; + + /* The size of the ICMP time exceeded packet is 36 + the size of the + IP header (20) = 56. */ + uip_len = 56; + ICMPBUF->len[0] = 0; + ICMPBUF->len[1] = uip_len; + + /* Fill in the other fields in the IP header. */ + ICMPBUF->vhl = 0x45; + ICMPBUF->tos = 0; + ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0; + ICMPBUF->ttl = UIP_TTL; + ICMPBUF->proto = UIP_PROTO_ICMP; + + /* Calculate IP checksum. */ + ICMPBUF->ipchksum = 0; + ICMPBUF->ipchksum = ~(uip_ipchksum()); + + +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Register a packet in the forwarding cache so that it won't be + * forwarded again. + */ +/*------------------------------------------------------------------------------*/ +static void +fwcache_register(void) +{ + struct fwcache_entry *fw; + int i, oldest; + + oldest = FW_TIME; + fw = NULL; + + /* Find the oldest entry in the cache. */ + for(i = 0; i < FWCACHE_SIZE; ++i) { + if(fwcache[i].timer == 0) { + fw = &fwcache[i]; + break; + } else if(fwcache[i].timer <= oldest) { + fw = &fwcache[i]; + oldest = fwcache[i].timer; + } + } + + fw->timer = FW_TIME; + fw->ipid = BUF->ipid; + fw->srcipaddr[0] = BUF->srcipaddr[0]; + fw->srcipaddr[1] = BUF->srcipaddr[1]; + fw->destipaddr[0] = BUF->destipaddr[0]; + fw->destipaddr[1] = BUF->destipaddr[1]; + fw->proto = BUF->proto; +#if notdef + fw->payload[0] = BUF->srcport; + fw->payload[1] = BUF->destport; +#endif +#if UIP_REASSEMBLY > 0 + fw->len = BUF->len; + fw->offset = BUF->ipoffset; +#endif +} +/*------------------------------------------------------------------------------*/ +/** + * \internal + * Find a network interface for the IP packet in uip_buf. + */ +/*------------------------------------------------------------------------------*/ +static struct uip_fw_netif * +find_netif(void) +{ + struct uip_fw_netif *netif; + + /* Walk through every network interface to check for a match. */ + for(netif = netifs; netif != NULL; netif = netif->next) { + if(ipaddr_maskcmp(BUF->destipaddr, netif->ipaddr, + netif->netmask)) { + /* If there was a match, we break the loop. */ + return netif; + } + } + + /* If no matching netif was found, we use default netif. */ + return defaultnetif; +} +/*------------------------------------------------------------------------------*/ +/** + * Output an IP packet on the correct network interface. + * + * The IP packet should be present in the uip_buf buffer and its + * length in the global uip_len variable. + * + * \retval UIP_FW_ZEROLEN Indicates that a zero-length packet + * transmission was attempted and that no packet was sent. + * + * \retval UIP_FW_NOROUTE No suitable network interface could be found + * for the outbound packet, and the packet was not sent. + * + * \return The return value from the actual network interface output + * function is passed unmodified as a return value. + */ +/*------------------------------------------------------------------------------*/ +uint8 +uip_fw_output(void) +{ + struct uip_fw_netif *netif; + + if(uip_len == 0) { + return UIP_FW_ZEROLEN; + } + + fwcache_register(); + +#if UIP_BROADCAST + /* Link local broadcasts go out on all interfaces. */ + if(/*BUF->proto == UIP_PROTO_UDP &&*/ + BUF->destipaddr[0] == 0xffff && + BUF->destipaddr[1] == 0xffff) { + if(defaultnetif != NULL) { + defaultnetif->output(); + } + for(netif = netifs; netif != NULL; netif = netif->next) { + netif->output(); + } + return UIP_FW_OK; + } +#endif /* UIP_BROADCAST */ + + netif = find_netif(); + /* printf("uip_fw_output: netif %p ->output %p len %d\n", netif, + netif->output, + uip_len);*/ + + if(netif == NULL) { + return UIP_FW_NOROUTE; + } + /* If we now have found a suitable network interface, we call its + output function to send out the packet. */ + return netif->output(); +} +/*------------------------------------------------------------------------------*/ +/** + * Forward an IP packet in the uip_buf buffer. + * + * + * + * \return UIP_FW_FORWARDED if the packet was forwarded, UIP_FW_LOCAL if + * the packet should be processed locally. + */ +/*------------------------------------------------------------------------------*/ +uint8 +uip_fw_forward(void) +{ + struct fwcache_entry *fw; + + /* First check if the packet is destined for ourselves and return 0 + to indicate that the packet should be processed locally. */ + if(BUF->destipaddr[0] == uip_hostaddr[0] && + BUF->destipaddr[1] == uip_hostaddr[1]) { + return UIP_FW_LOCAL; + } + + /* If we use ping IP address configuration, and our IP address is + not yet configured, we should intercept all ICMP echo packets. */ +#if UIP_PINGADDRCONF + if((uip_hostaddr[0] | uip_hostaddr[1]) == 0 && + BUF->proto == UIP_PROTO_ICMP && + ICMPBUF->type == ICMP_ECHO) { + return UIP_FW_LOCAL; + } +#endif /* UIP_PINGADDRCONF */ + + /* Check if the packet is in the forwarding cache already, and if so + we drop it. */ + + for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { + if(fw->timer != 0 && +#if UIP_REASSEMBLY > 0 + fw->len == BUF->len && + fw->offset == BUF->ipoffset && +#endif + fw->ipid == BUF->ipid && + fw->srcipaddr[0] == BUF->srcipaddr[0] && + fw->srcipaddr[1] == BUF->srcipaddr[1] && + fw->destipaddr[0] == BUF->destipaddr[0] && + fw->destipaddr[1] == BUF->destipaddr[1] && +#if notdef + fw->payload[0] == BUF->srcport && + fw->payload[1] == BUF->destport && +#endif + fw->proto == BUF->proto) { + /* Drop packet. */ + return UIP_FW_FORWARDED; + } + } + + /* If the TTL reaches zero we produce an ICMP time exceeded message + in the uip_buf buffer and forward that packet back to the sender + of the packet. */ + if(BUF->ttl <= 1) { + /* No time exceeded for broadcasts and multicasts! */ + if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) { + return UIP_FW_LOCAL; + } + time_exceeded(); + } + + /* Decrement the TTL (time-to-live) value in the IP header */ + BUF->ttl = BUF->ttl - 1; + + /* Update the IP checksum. */ + if(BUF->ipchksum >= HTONS(0xffff - 0x0100)) { + BUF->ipchksum = BUF->ipchksum + HTONS(0x0100) + 1; + } else { + BUF->ipchksum = BUF->ipchksum + HTONS(0x0100); + } + + if(uip_len > 0) { + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]; + uip_fw_output(); + } + +#if UIP_BROADCAST + if(BUF->destipaddr[0] == 0xffff && BUF->destipaddr[1] == 0xffff) { + return UIP_FW_LOCAL; + } +#endif /* UIP_BROADCAST */ + + /* Return non-zero to indicate that the packet was forwarded and that no + other processing should be made. */ + return UIP_FW_FORWARDED; +} +/*------------------------------------------------------------------------------*/ +/** + * Register a network interface with the forwarding module. + * + * \param netif A pointer to the network interface that is to be + * registered. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_register(struct uip_fw_netif *netif) +{ + netif->next = netifs; + netifs = netif; +} +/*------------------------------------------------------------------------------*/ +/** + * Register a default network interface. + * + * All packets that don't go out on any of the other interfaces will + * be routed to the default interface. + * + * \param netif A pointer to the network interface that is to be + * registered. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_default(struct uip_fw_netif *netif) +{ + defaultnetif = netif; +} +/*------------------------------------------------------------------------------*/ +/** + * Perform periodic processing. + */ +/*------------------------------------------------------------------------------*/ +void +uip_fw_periodic(void) +{ + struct fwcache_entry *fw; + for(fw = fwcache; fw < &fwcache[FWCACHE_SIZE]; ++fw) { + if(fw->timer > 0) { + --fw->timer; + } + } +} +/*------------------------------------------------------------------------------*/ diff --git a/nuttx/net/uip/uip-fw.h b/nuttx/net/uip/uip-fw.h new file mode 100644 index 000000000..cba0bea13 --- /dev/null +++ b/nuttx/net/uip/uip-fw.h @@ -0,0 +1,176 @@ +/** + * \addtogroup uipfw + * @{ + */ + +/** + * \file + * uIP packet forwarding header file. + * \author Adam Dunkels <adam@sics.se> + */ + +/* + * Copyright (c) 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 uIP TCP/IP stack + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: uip-fw.h,v 1.1.1.1 2007-08-26 23:04:07 patacongo Exp $ + */ +#ifndef __UIP_FW_H__ +#define __UIP_FW_H__ + +#include <net/uip/uip.h> + +/** + * Representation of a uIP network interface. + */ +struct uip_fw_netif { + struct uip_fw_netif *next; /**< Pointer to the next interface when + linked in a list. */ + uint16 ipaddr[2]; /**< The IP address of this interface. */ + uint16 netmask[2]; /**< The netmask of the interface. */ + uint8 (* output)(void); + /**< A pointer to the function that + sends a packet. */ +}; + +/** + * Intantiating macro for a uIP network interface. + * + * Example: + \code + struct uip_fw_netif slipnetif = + {UIP_FW_NETIF(192,168,76,1, 255,255,255,0, slip_output)}; + \endcode + * \param ip1,ip2,ip3,ip4 The IP address of the network interface. + * + * \param nm1,nm2,nm3,nm4 The netmask of the network interface. + * + * \param outputfunc A pointer to the output function of the network interface. + * + * \hideinitializer + */ +#define UIP_FW_NETIF(ip1,ip2,ip3,ip4, nm1,nm2,nm3,nm4, outputfunc) \ + NULL, \ + {HTONS((ip1 << 8) | ip2), HTONS((ip3 << 8) | ip4)}, \ + {HTONS((nm1 << 8) | nm2), HTONS((nm3 << 8) | nm4)}, \ + outputfunc + +/** + * Set the IP address of a network interface. + * + * \param netif A pointer to the uip_fw_netif structure for the network interface. + * + * \param addr A pointer to an IP address. + * + * \hideinitializer + */ +#define uip_fw_setipaddr(netif, addr) \ + do { (netif)->ipaddr[0] = ((uint16 *)(addr))[0]; \ + (netif)->ipaddr[1] = ((uint16 *)(addr))[1]; } while(0) +/** + * Set the netmask of a network interface. + * + * \param netif A pointer to the uip_fw_netif structure for the network interface. + * + * \param addr A pointer to an IP address representing the netmask. + * + * \hideinitializer + */ +#define uip_fw_setnetmask(netif, addr) \ + do { (netif)->netmask[0] = ((uint16 *)(addr))[0]; \ + (netif)->netmask[1] = ((uint16 *)(addr))[1]; } while(0) + +void uip_fw_init(void); +uint8 uip_fw_forward(void); +uint8 uip_fw_output(void); +void uip_fw_register(struct uip_fw_netif *netif); +void uip_fw_default(struct uip_fw_netif *netif); +void uip_fw_periodic(void); + + +/** + * A non-error message that indicates that a packet should be + * processed locally. + * + * \hideinitializer + */ +#define UIP_FW_LOCAL 0 + +/** + * A non-error message that indicates that something went OK. + * + * \hideinitializer + */ +#define UIP_FW_OK 0 + +/** + * A non-error message that indicates that a packet was forwarded. + * + * \hideinitializer + */ +#define UIP_FW_FORWARDED 1 + +/** + * A non-error message that indicates that a zero-length packet + * transmission was attempted, and that no packet was sent. + * + * \hideinitializer + */ +#define UIP_FW_ZEROLEN 2 + +/** + * An error message that indicates that a packet that was too large + * for the outbound network interface was detected. + * + * \hideinitializer + */ +#define UIP_FW_TOOLARGE 3 + +/** + * An error message that indicates that no suitable interface could be + * found for an outbound packet. + * + * \hideinitializer + */ +#define UIP_FW_NOROUTE 4 + +/** + * An error message that indicates that a packet that should be + * forwarded or output was dropped. + * + * \hideinitializer + */ +#define UIP_FW_DROPPED 5 + + +#endif /* __UIP_FW_H__ */ + +/** @} */ diff --git a/nuttx/net/uip/uip-neighbor.c b/nuttx/net/uip/uip-neighbor.c new file mode 100644 index 000000000..6da1a891d --- /dev/null +++ b/nuttx/net/uip/uip-neighbor.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006, 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 uIP TCP/IP stack + * + * $Id: uip-neighbor.c,v 1.1.1.1 2007-08-26 23:04:08 patacongo Exp $ + */ + +/** + * \file + * Database of link-local neighbors, used by IPv6 code and + * to be used by a future ARP code rewrite. + * \author + * Adam Dunkels <adam@sics.se> + */ + +#include "uip-neighbor.h" + +#include <string.h> + +#define MAX_TIME 128 + +#ifdef UIP_NEIGHBOR_CONF_ENTRIES +#define ENTRIES UIP_NEIGHBOR_CONF_ENTRIES +#else /* UIP_NEIGHBOR_CONF_ENTRIES */ +#define ENTRIES 8 +#endif /* UIP_NEIGHBOR_CONF_ENTRIES */ + +struct neighbor_entry { + uip_ipaddr_t ipaddr; + struct uip_neighbor_addr addr; + uint8 time; +}; +static struct neighbor_entry entries[ENTRIES]; + +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_init(void) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + entries[i].time = MAX_TIME; + } +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_periodic(void) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + if(entries[i].time < MAX_TIME) { + entries[i].time++; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr) +{ + int i, oldest; + uint8 oldest_time; + + printf("Adding neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n", + addr->addr.addr[0], addr->addr.addr[1], addr->addr.addr[2], addr->addr.addr[3], + addr->addr.addr[4], addr->addr.addr[5]); + + /* Find the first unused entry or the oldest used entry. */ + oldest_time = 0; + oldest = 0; + for(i = 0; i < ENTRIES; ++i) { + if(entries[i].time == MAX_TIME) { + oldest = i; + break; + } + if(uip_ipaddr_cmp(entries[i].ipaddr, addr)) { + oldest = i; + break; + } + if(entries[i].time > oldest_time) { + oldest = i; + oldest_time = entries[i].time; + } + } + + /* Use the oldest or first free entry (either pointed to by the + "oldest" variable). */ + entries[oldest].time = 0; + uip_ipaddr_copy(entries[oldest].ipaddr, ipaddr); + memcpy(&entries[oldest].addr, addr, sizeof(struct uip_neighbor_addr)); +} +/*---------------------------------------------------------------------------*/ +static struct neighbor_entry * +find_entry(uip_ipaddr_t ipaddr) +{ + int i; + + for(i = 0; i < ENTRIES; ++i) { + if(uip_ipaddr_cmp(entries[i].ipaddr, ipaddr)) { + return &entries[i]; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +uip_neighbor_update(uip_ipaddr_t ipaddr) +{ + struct neighbor_entry *e; + + e = find_entry(ipaddr); + if(e != NULL) { + e->time = 0; + } +} +/*---------------------------------------------------------------------------*/ +struct uip_neighbor_addr * +uip_neighbor_lookup(uip_ipaddr_t ipaddr) +{ + struct neighbor_entry *e; + + e = find_entry(ipaddr); + if(e != NULL) { + /* printf("Lookup neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n", + e->addr.addr.addr[0], e->addr.addr.addr[1], e->addr.addr.addr[2], e->addr.addr.addr[3], + e->addr.addr.addr[4], e->addr.addr.addr[5]);*/ + + return &e->addr; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ diff --git a/nuttx/net/uip/uip-neighbor.h b/nuttx/net/uip/uip-neighbor.h new file mode 100644 index 000000000..277b5f848 --- /dev/null +++ b/nuttx/net/uip/uip-neighbor.h @@ -0,0 +1,54 @@ +/* uip-neighbor.h + * Header file for database of link-local neighbors, used by IPv6 code and + * to be used by future ARP code. + * Author: Adam Dunkels <adam@sics.se> + * + * Copyright (c) 2006, 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +#ifndef __UIP_NEIGHBOR_H__ +#define __UIP_NEIGHBOR_H__ + +#include <net/uip/uip.h> + +struct uip_neighbor_addr +{ +#if UIP_NEIGHBOR_CONF_ADDRTYPE + UIP_NEIGHBOR_CONF_ADDRTYPE addr; +#else + struct uip_eth_addr addr; +#endif +}; + +void uip_neighbor_init(void); +void uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr); +void uip_neighbor_update(uip_ipaddr_t ipaddr); +struct uip_neighbor_addr *uip_neighbor_lookup(uip_ipaddr_t ipaddr); +void uip_neighbor_periodic(void); + +#endif /* __UIP-NEIGHBOR_H__ */ diff --git a/nuttx/net/uip/uip-split.c b/nuttx/net/uip/uip-split.c new file mode 100644 index 000000000..155418a9c --- /dev/null +++ b/nuttx/net/uip/uip-split.c @@ -0,0 +1,132 @@ +/* uip-split.c + * Author: Adam Dunkels <adam@sics.se> + * + * Copyright (c) 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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. + */ + +#include <nuttx/config.h> +#include <string.h> + +#include <net/uip/uip.h> +#include <net/uip/uip-arch.h> + +#include "uip-split.h" +#include "uip-fw.h" + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/*-----------------------------------------------------------------------------*/ +void +uip_split_output(void) +{ + uint16 tcplen, len1, len2; + + /* We only try to split maximum sized TCP segments. */ + if(BUF->proto == UIP_PROTO_TCP && + uip_len == UIP_BUFSIZE - UIP_LLH_LEN) { + + tcplen = uip_len - UIP_TCPIP_HLEN; + /* Split the segment in two. If the original packet length was + odd, we make the second packet one byte larger. */ + len1 = len2 = tcplen / 2; + if(len1 + len2 < tcplen) { + ++len2; + } + + /* Create the first packet. This is done by altering the length + field of the IP header and updating the checksums. */ + uip_len = len1 + UIP_TCPIP_HLEN; +#ifdef CONFIG_NET_UIP_IPv6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* CONFIG_NET_UIP_IPv6 */ + BUF->len[0] = uip_len >> 8; + BUF->len[1] = uip_len & 0xff; +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* Recalculate the TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + +#ifndef CONFIG_NET_UIP_IPv6 + /* Recalculate the IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* Transmit the first packet. */ + /* uip_fw_output();*/ + tcpip_output(); + + /* Now, create the second packet. To do this, it is not enough to + just alter the length field, but we must also update the TCP + sequence number and point the uip_appdata to a new place in + memory. This place is detemined by the length of the first + packet (len1). */ + uip_len = len2 + UIP_TCPIP_HLEN; +#ifdef CONFIG_NET_UIP_IPv6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* CONFIG_NET_UIP_IPv6 */ + BUF->len[0] = uip_len >> 8; + BUF->len[1] = uip_len & 0xff; +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* uip_appdata += len1;*/ + memcpy(uip_appdata, (uint8 *)uip_appdata + len1, len2); + + uip_add32(BUF->seqno, len1); + BUF->seqno[0] = uip_acc32[0]; + BUF->seqno[1] = uip_acc32[1]; + BUF->seqno[2] = uip_acc32[2]; + BUF->seqno[3] = uip_acc32[3]; + + /* Recalculate the TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + +#ifndef CONFIG_NET_UIP_IPv6 + /* Recalculate the IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* Transmit the second packet. */ + /* uip_fw_output();*/ + tcpip_output(); + } else { + /* uip_fw_output();*/ + tcpip_output(); + } + +} +/*-----------------------------------------------------------------------------*/ diff --git a/nuttx/net/uip/uip-split.h b/nuttx/net/uip/uip-split.h new file mode 100644 index 000000000..99f36ccdb --- /dev/null +++ b/nuttx/net/uip/uip-split.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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 uIP TCP/IP stack + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: uip-split.h,v 1.1.1.1 2007-08-26 23:04:08 patacongo Exp $ + */ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uipsplit uIP TCP throughput booster hack + * @{ + * + * The basic uIP TCP implementation only allows each TCP connection to + * have a single TCP segment in flight at any given time. Because of + * the delayed ACK algorithm employed by most TCP receivers, uIP's + * limit on the amount of in-flight TCP segments seriously reduces the + * maximum achievable throughput for sending data from uIP. + * + * The uip-split module is a hack which tries to remedy this + * situation. By splitting maximum sized outgoing TCP segments into + * two, the delayed ACK algorithm is not invoked at TCP + * receivers. This improves the throughput when sending data from uIP + * by orders of magnitude. + * + * The uip-split module uses the uip-fw module (uIP IP packet + * forwarding) for sending packets. Therefore, the uip-fw module must + * be set up with the appropriate network interfaces for this module + * to work. + */ + + +/** + * \file + * Module for splitting outbound TCP segments in two to avoid the + * delayed ACK throughput degradation. + * \author + * Adam Dunkels <adam@sics.se> + * + */ + +#ifndef __UIP_SPLIT_H__ +#define __UIP_SPLIT_H__ + +/** + * Handle outgoing packets. + * + * This function inspects an outgoing packet in the uip_buf buffer and + * sends it out using the uip_fw_output() function. If the packet is a + * full-sized TCP segment it will be split into two segments and + * transmitted separately. This function should be called instead of + * the actual device driver output function, or the uip_fw_output() + * function. + * + * The headers of the outgoing packet is assumed to be in the uip_buf + * buffer and the payload is assumed to be wherever uip_appdata + * points. The length of the outgoing packet is assumed to be in the + * uip_len variable. + * + */ +void uip_split_output(void); + +#endif /* __UIP_SPLIT_H__ */ + +/** @} */ +/** @} */ diff --git a/nuttx/net/uip/uip-wait.c b/nuttx/net/uip/uip-wait.c new file mode 100644 index 000000000..c7bf0a1bb --- /dev/null +++ b/nuttx/net/uip/uip-wait.c @@ -0,0 +1,180 @@ +/************************************************************ + * uip-wait.c + * + * Copyright (C) 2007 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + * + ************************************************************/ + +/************************************************************ + * Included Files + ************************************************************/ + +#include <nuttx/config.h> +#include <semaphore.h> +#include <wdog.h> +#include <arch/irq.h> +#include <net/uip/uip.h> + +/************************************************************ + * Definitions + ************************************************************/ + +/************************************************************ + * Private Data + ************************************************************/ + +/* Threads and tasks can both wait a semaphore. This + * initializer uses internal, non-portable knowledge of the\ + * structure of sem_t to initialize it to the value 0. + */ + +static sem_t uip_waitsem = { 0 }; /* Semaphore to wait on */ +static uint16 uip_waitflags = 0; /* UIP flags to wait for */ + +/************************************************************ + * Private Functions + ************************************************************/ + +/* Called from the timer interrupt handler when a event wait + * watchdog expires. + */ + +static void uip_event_timeout(int argc, uint32 itcb, ...) +{ + irqstate_t save = irqsave(); /* Should not be necessary */ + uip_flags |= UIP_APPTIMEOUT; /* Set software timeout event */ + uip_event_signal(); /* Signal the waiting thread/task */ + irqrestore(save); /* Restore interrupts */ +} + +/************************************************************ + * Global Functions + ************************************************************/ + +/* This function is called user code to set up the wait */ + +int uip_event_timedwait(uint16 waitflags, int timeout) +{ + /* Prevent conflicts with the interrupt level operation of + * uip_event_signal(). + */ + irqstate_t save = irqsave(); + WDOG_ID wdog; + + /* At present, we support only a single waiter. If uip_waitflags + * is non-zero on entry, then there is a problem. + */ + + if ( uip_waitflags == 0) + { + /* If the requested event bits are not set in the uip_flags, + * then wait. We will be awakened as soon as an interrupt is + * received that sets these bits. + */ + + goto errout_with_irqdisabled; + } + + /* Loop until the requested bits are set in the flags */ + + while ((waitflags & uip_flags) != 0) + { + /* Set the event flags that the caller is waiting on */ + + uip_waitflags = waitflags; + + /* Was a timeut requested as well? */ + + if (timeout) + { + /* Yes, then set the application timeout event as well */ + + uip_waitflags |= UIP_APPTIMEOUT; + + /* Create a watchdog */ + + wdog = wd_create(); + if (!wdog) + { + goto errout_with_irqdisabled; + } + + /* Start the watchdog */ + + wd_start(wdog, timeout, (wdentry_t)uip_event_timeout, 0); + } + + /* Wait for the event (or timeout) to occur */ + + if (sem_wait(&uip_waitsem) != 0) + { + goto errout_with_watchdog; + } + + /* We no longer need the watchdog */ + + if (wdog) + { + wd_delete(wdog); + wdog = NULL; + } + } + + irqrestore(save); + return OK; + +errout_with_watchdog: + if (wdog) + { + wd_delete(wdog); + } + +errout_with_irqdisabled: + irqrestore(save); + return ERROR; +} + +/* This function is called from uip_interrupt() to wake up any + * waiting threads/tasks. + */ + +void uip_event_signal(void) +{ + /* If any bits in uip_waitflags match bits set in uip_flags, then + * there must be a thread/task waiting for this event to occur. + */ + + if ((uip_waitflags & uip_flags) != 0) + { + sem_post(&uip_waitsem); /* Post the event */ + uip_waitflags = 0; /* Prohibit posting the event multiple times */ + } +} diff --git a/nuttx/net/uip/uip.c b/nuttx/net/uip/uip.c new file mode 100644 index 000000000..b81c85cd9 --- /dev/null +++ b/nuttx/net/uip/uip.c @@ -0,0 +1,2091 @@ +/**************************************************************************** + * uip.c + * The uIP TCP/IP stack code. + * author Adam Dunkels <adam@dunkels.com> + * + * uIP is an implementation of the TCP/IP protocol stack intended for + * small 8-bit and 16-bit microcontrollers. + * + * uIP provides the necessary protocols for Internet communication, + * with a very small code footprint and RAM requirements - the uIP + * code size is on the order of a few kilobytes and RAM usage is on + * the order of a few hundred bytes. + * + * Copyright (c) 2001-2003, Adam Dunkels. + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * uIP is a small implementation of the IP, UDP and TCP protocols (as + * well as some basic ICMP stuff). The implementation couples the IP, + * UDP, TCP and the application layers very tightly. To keep the size + * of the compiled code down, this code frequently uses the goto + * statement. While it would be possible to break the uip_interrupt() + * function into many smaller functions, this would increase the code + * size because of the overhead of parameter passing and the fact that + * the optimier would not be as efficient. + * + * The principle is that we have a small buffer, called the uip_buf, + * in which the device driver puts an incoming packet. The TCP/IP + * stack parses the headers in the packet, and calls the + * application. If the remote host has sent data to the application, + * this data is present in the uip_buf and the application read the + * data from there. It is up to the application to put this data into + * a byte stream if needed. The application will not be fed with data + * that is out of sequence. + * + * If the application whishes to send data to the peer, it should put + * its data into the uip_buf. The uip_appdata pointer points to the + * first available byte. The TCP/IP stack will calculate the + * checksums, and fill in the necessary header fields and finally send + * the packet back to the peer. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <sys/types.h> +#include <debug.h> + +#include <net/uip/uipopt.h> +#include <net/uip/uip.h> +#include <net/uip/uip-arch.h> + +#ifdef CONFIG_NET_UIP_IPv6 +# include "uip-neighbor.h" +#endif /* CONFIG_NET_UIP_IPv6 */ + +#include <string.h> + +#if UIP_LOGGING == 1 +#include <stdio.h> +extern void uip_log(char *msg); +# define UIP_LOG(m) uip_log(m) +#else +# define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_CTL 0x3f + +#define TCP_OPT_END 0 /* End of TCP options list */ +#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */ +#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */ + +#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */ + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 + +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 +#define ICMP6_NEIGHBOR_SOLICITATION 135 +#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 + +#define ICMP6_FLAG_S (1 << 6) + +#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 +#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 + +/* Macros. */ +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) +#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/* The IP address of this host. If it is defined to be fixed (by + setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set + here. Otherwise, the address */ +#if UIP_FIXEDADDR > 0 +const uip_ipaddr_t uip_hostaddr = + {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1), + HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)}; + +const uip_ipaddr_t uip_draddr = + {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1), + HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)}; + +const uip_ipaddr_t uip_netmask = + {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1), + HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)}; +#else +uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask; +#endif /* UIP_FIXEDADDR */ + +#ifndef CONFIG_UIP_EXTERNAL_BUFFER +uint8 uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains incoming packets. */ +#endif /* CONFIG_UIP_EXTERNAL_BUFFER */ + +void *uip_appdata; /* The uip_appdata pointer points to application data. */ +void *uip_sappdata; /* The uip_appdata pointer points to the application + * data which is to be sent. */ +#if UIP_URGDATA > 0 +void *uip_urgdata; /* The uip_urgdata pointer points to urgent data + * (out-of-band data), if present. */ +uint16 uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + +uint16 uip_len, uip_slen; /* The uip_len is either 8 or 16 bits, depending + * on the maximum packet size. */ + +uint16 uip_flags; /* The uip_flags variable is used for communication + * between the TCP/IP stack and the application + * program. */ +struct uip_conn *uip_conn; /* uip_conn always points to the current connection. */ + +struct uip_conn uip_conns[UIP_CONNS]; + /* The uip_conns array holds all TCP connections. */ +uint16 uip_listenports[UIP_LISTENPORTS]; + /* The uip_listenports list all currently listning ports. */ +#if UIP_UDP +struct uip_udp_conn *uip_udp_conn; +struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +/* Temporary variables. */ +uint8 uip_acc32[4]; + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +# define UIP_STAT(s) s +#else +# define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +static const uip_ipaddr_t all_ones_addr = +#ifdef CONFIG_NET_UIP_IPv6 + {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; +#else /* CONFIG_NET_UIP_IPv6 */ + {0xffff,0xffff}; +#endif /* CONFIG_NET_UIP_IPv6 */ + +static const uip_ipaddr_t all_zeroes_addr = +#ifdef CONFIG_NET_UIP_IPv6 + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; +#else /* CONFIG_NET_UIP_IPv6 */ + {0x0000,0x0000}; +#endif /* CONFIG_NET_UIP_IPv6 */ + +#if UIP_FIXEDETHADDR +const struct uip_eth_addr uip_ethaddr = +{{ UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 }}; +#else +struct uip_eth_addr uip_ethaddr = {{ 0,0,0,0,0,0 }}; +#endif + +static uint16 ipid; /* Ths ipid variable is an increasing number that is + * used for the IP ID field. */ + +static uint8 iss[4]; /* The iss variable is used for the TCP initial + * sequence number. */ + +#if UIP_ACTIVE_OPEN +static uint16 lastport; /* Keeps track of the last port used for a new + * connection. */ +#endif /* UIP_ACTIVE_OPEN */ + +/* Temporary variables. */ +static uint8 c, opt; +static uint16 tmp16; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if !UIP_ARCH_ADD32 +static void uip_add32(uint8 *op32, uint16 op16) +{ + uip_acc32[3] = op32[3] + (op16 & 0xff); + uip_acc32[2] = op32[2] + (op16 >> 8); + uip_acc32[1] = op32[1]; + uip_acc32[0] = op32[0]; + + if (uip_acc32[2] < (op16 >> 8)) { + ++uip_acc32[1]; + if (uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + + if (uip_acc32[3] < (op16 & 0xff)) { + ++uip_acc32[2]; + if (uip_acc32[2] == 0) { + ++uip_acc32[1]; + if (uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + } +} +#endif /* UIP_ARCH_ADD32 */ + +#if !UIP_ARCH_CHKSUM +static uint16 chksum(uint16 sum, const uint8 *data, uint16 len) +{ + uint16 t; + const uint8 *dataptr; + const uint8 *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { + /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if (sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if (dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if (sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +static uint16 upper_layer_chksum(uint8 proto) +{ + uint16 upper_layer_len; + uint16 sum; + +#ifdef CONFIG_NET_UIP_IPv6 + upper_layer_len = (((uint16)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* CONFIG_NET_UIP_IPv6 */ + upper_layer_len = (((uint16)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (uint8 *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + /* Sum TCP header and data. */ + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_len); + + return (sum == 0) ? 0xffff : htons(sum); +} + +#ifdef CONFIG_NET_UIP_IPv6 +static uint16 uip_icmp6chksum(void) +{ + return upper_layer_chksum(UIP_PROTO_ICMP6); +} +#endif /* CONFIG_NET_UIP_IPv6 */ + +#endif /* UIP_ARCH_CHKSUM */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* This function may be used at boot time to set the initial ip_id.*/ + +void uip_setipid(uint16 id) +{ + ipid = id; +} + +/* Calculate the Internet checksum over a buffer. */ + +#if !UIP_ARCH_CHKSUM +uint16 uip_chksum(uint16 *data, uint16 len) +{ + return htons(chksum(0, (uint8 *)data, len)); +} + +/* Calculate the IP header checksum of the packet header in uip_buf. */ + +#ifndef UIP_ARCH_IPCHKSUM +uint16 uip_ipchksum(void) +{ + uint16 sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + dbg("uip_ipchksum: sum 0x%04x\n", sum); + return (sum == 0) ? 0xffff : htons(sum); +} +#endif + +/* Calculate the TCP checksum of the packet in uip_buf and uip_appdata. */ + +uint16 uip_tcpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_TCP); +} + +/* Calculate the UDP checksum of the packet in uip_buf and uip_appdata. */ + +#if UIP_UDP_CHECKSUMS +uint16 uip_udpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_UDP); +} +#endif /* UIP_UDP_CHECKSUMS */ +#endif /* UIP_ARCH_CHKSUM */ + +void uip_init(void) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + uip_listenports[c] = 0; + } + for(c = 0; c < UIP_CONNS; ++c) { + uip_conns[c].tcpstateflags = UIP_CLOSED; + } +#if UIP_ACTIVE_OPEN + lastport = 1024; +#endif /* UIP_ACTIVE_OPEN */ + +#if UIP_UDP + for(c = 0; c < UIP_UDP_CONNS; ++c) { + uip_udp_conns[c].lport = 0; + } +#endif /* UIP_UDP */ + + /* IPv4 initialization. */ +#if UIP_FIXEDADDR == 0 + /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/ +#endif /* UIP_FIXEDADDR */ + +} + +#if UIP_ACTIVE_OPEN +struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, uint16 rport) +{ + register struct uip_conn *conn, *cconn; + + /* Find an unused local port. */ + again: + ++lastport; + + if (lastport >= 32000) { + lastport = 4096; + } + + /* Check if this port is already in use, and if so try to find + another one. */ + for(c = 0; c < UIP_CONNS; ++c) { + conn = &uip_conns[c]; + if (conn->tcpstateflags != UIP_CLOSED && + conn->lport == htons(lastport)) { + goto again; + } + } + + conn = 0; + for(c = 0; c < UIP_CONNS; ++c) { + cconn = &uip_conns[c]; + if (cconn->tcpstateflags == UIP_CLOSED) { + conn = cconn; + break; + } + if (cconn->tcpstateflags == UIP_TIME_WAIT) { + if (conn == 0 || cconn->timer > conn->timer) { + conn = cconn; + } + } + } + + if (conn == 0) { + return 0; + } + + conn->tcpstateflags = UIP_SYN_SENT; + + conn->snd_nxt[0] = iss[0]; + conn->snd_nxt[1] = iss[1]; + conn->snd_nxt[2] = iss[2]; + conn->snd_nxt[3] = iss[3]; + + conn->initialmss = conn->mss = UIP_TCP_MSS; + + conn->len = 1; /* TCP length of the SYN is one. */ + conn->nrtx = 0; + conn->timer = 1; /* Send the SYN next time around. */ + conn->rto = UIP_RTO; + conn->sa = 0; + conn->sv = 16; /* Initial value of the RTT variance. */ + conn->lport = htons(lastport); + conn->rport = rport; + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + + return conn; +} +#endif /* UIP_ACTIVE_OPEN */ + +#if UIP_UDP +struct uip_udp_conn * +uip_udp_new(uip_ipaddr_t *ripaddr, uint16 rport) +{ + register struct uip_udp_conn *conn; + + /* Find an unused local port. */ + again: + ++lastport; + + if (lastport >= 32000) { + lastport = 4096; + } + + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if (uip_udp_conns[c].lport == htons(lastport)) { + goto again; + } + } + + + conn = 0; + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if (uip_udp_conns[c].lport == 0) { + conn = &uip_udp_conns[c]; + break; + } + } + + if (conn == 0) { + return 0; + } + + conn->lport = HTONS(lastport); + conn->rport = rport; + if (ripaddr == NULL) { + memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + } else { + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + } + conn->ttl = UIP_TTL; + + return conn; +} +#endif /* UIP_UDP */ + +void uip_unlisten(uint16 port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if (uip_listenports[c] == port) { + uip_listenports[c] = 0; + return; + } + } +} + +void uip_listen(uint16 port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if (uip_listenports[c] == 0) { + uip_listenports[c] = port; + return; + } + } +} + +/* XXX: IP fragment reassembly: not well-tested. */ + +#if UIP_REASSEMBLY && !defined(CONFIG_NET_UIP_IPv6) +#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) +static uint8 uip_reassbuf[UIP_REASS_BUFSIZE]; +static uint8 uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const uint8 bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; +static uint16 uip_reasslen; +static uint8 uip_reassflags; +#define UIP_REASS_FLAG_LASTFRAG 0x01 +static uint8 uip_reasstmr; + +#define IP_MF 0x20 + +static uint8 uip_reass(void) +{ + uint16 offset, len; + uint16 i; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if (uip_reasstmr == 0) { + memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + /* Clear the bitmap. */ + memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if (BUF->srcipaddr[0] == FBUF->srcipaddr[0] && + BUF->srcipaddr[1] == FBUF->srcipaddr[1] && + BUF->destipaddr[0] == FBUF->destipaddr[0] && + BUF->destipaddr[1] == FBUF->destipaddr[1] && + BUF->ipid[0] == FBUF->ipid[0] && + BUF->ipid[1] == FBUF->ipid[1]) { + + len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; + offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if (offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], + (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), + len); + + /* Update the bitmap. */ + if (offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if ((BUF->ipoffset[0] & IP_MF) == 0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if (uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if (uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if (uip_reassbitmap[uip_reasslen / (8 * 8)] != + (uint8)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + memcpy(BUF, FBUF, uip_reasslen); + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + BUF->len[0] = uip_reasslen >> 8; + BUF->len[1] = uip_reasslen & 0xff; + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + + return uip_reasslen; + } + } + + nullreturn: + return 0; +} +#endif /* UIP_REASSEMBLY */ + +static void uip_add_rcv_nxt(uint16 n) +{ + uip_add32(uip_conn->rcv_nxt, n); + uip_conn->rcv_nxt[0] = uip_acc32[0]; + uip_conn->rcv_nxt[1] = uip_acc32[1]; + uip_conn->rcv_nxt[2] = uip_acc32[2]; + uip_conn->rcv_nxt[3] = uip_acc32[3]; +} + +void uip_interrupt(uint8 flag) +{ + register struct uip_conn *uip_connr = uip_conn; + +#if UIP_UDP + if (flag == UIP_UDP_SEND_CONN) + { + goto udp_send; + } +#endif /* UIP_UDP */ + + uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; + + /* Check if we were invoked because of a poll request for a + * particular connection. + */ + + if (flag == UIP_POLL_REQUEST) + { + if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && + !uip_outstanding(uip_connr)) + { + uip_flags = UIP_POLL; + uip_event_signal(); + uip_interrupt_event(); + goto appsend; + } + goto drop; + } + + /* Check if we were invoked because of the perodic timer fireing. */ + + else if (flag == UIP_TIMER) + { +#if UIP_REASSEMBLY + if (uip_reasstmr != 0) + { + --uip_reasstmr; + } +#endif /* UIP_REASSEMBLY */ + + /* Increase the initial sequence number */ + + if (++iss[3] == 0) + { + if (++iss[2] == 0) + { + if (++iss[1] == 0) + { + ++iss[0]; + } + } + } + + /* Reset the length variables. */ + + uip_len = 0; + uip_slen = 0; + + /* Check if the connection is in a state in which we simply wait + * for the connection to time out. If so, we increase the + * connection's timer and remove the connection if it times + * out. + */ + + if (uip_connr->tcpstateflags == UIP_TIME_WAIT || + uip_connr->tcpstateflags == UIP_FIN_WAIT_2) + { + ++(uip_connr->timer); + if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) + { + uip_connr->tcpstateflags = UIP_CLOSED; + } + } + else if (uip_connr->tcpstateflags != UIP_CLOSED) + { + /* If the connection has outstanding data, we increase the + * connection's timer and see if it has reached the RTO value + * in which case we retransmit. + */ + + if (uip_outstanding(uip_connr)) + { + if (uip_connr->timer-- == 0) + { + if (uip_connr->nrtx == UIP_MAXRTX || + ((uip_connr->tcpstateflags == UIP_SYN_SENT || + uip_connr->tcpstateflags == UIP_SYN_RCVD) && + uip_connr->nrtx == UIP_MAXSYNRTX)) + { + uip_connr->tcpstateflags = UIP_CLOSED; + + /* We call uip_interrupt_event() with uip_flags set to + * UIP_TIMEDOUT to inform the application that the + * connection has timed out. + */ + + uip_flags = UIP_TIMEDOUT; + uip_event_signal(); + uip_interrupt_event(); + + /* We also send a reset packet to the remote host. */ + + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + /* Exponential backoff. */ + + uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4 ? 4: uip_connr->nrtx); + ++(uip_connr->nrtx); + + /* Ok, so we need to retransmit. We do this differently + * depending on which state we are in. In ESTABLISHED, we + * call upon the application so that it may prepare the + * data for the retransmit. In SYN_RCVD, we resend the + * SYNACK that we sent earlier and in LAST_ACK we have to + * retransmit our FINACK. + */ + + UIP_STAT(++uip_stat.tcp.rexmit); + switch(uip_connr->tcpstateflags & UIP_TS_MASK) + { + case UIP_SYN_RCVD: + /* In the SYN_RCVD state, we should retransmit our + * SYNACK. + */ + + goto tcp_send_synack; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application + * to do the actual retransmit after which we jump into + * the code for sending out the packet (the apprexmit + * label). + */ + + uip_flags = UIP_REXMIT; + uip_event_signal(); + uip_interrupt_event(); + goto apprexmit; + + case UIP_FIN_WAIT_1: + case UIP_CLOSING: + case UIP_LAST_ACK: + /* In all these states we should retransmit a FINACK. */ + goto tcp_send_finack; + + } + } + } + else if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) + { + /* If there was no need for a retransmission, we poll the + * application for new data. + */ + + uip_flags = UIP_POLL; + uip_event_signal(); + uip_interrupt_event(); + goto appsend; + } + } + goto drop; + } + +#if UIP_UDP + if (flag == UIP_UDP_TIMER) + { + if (uip_udp_conn->lport != 0) + { + uip_conn = NULL; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_slen = 0; + uip_flags = UIP_POLL; + uip_event_signal(); + uip_interrupt_udp_event(); + goto udp_send; + } + else + { + goto drop; + } + } +#endif + + /* This is where the input processing starts. */ + UIP_STAT(++uip_stat.ip.recv); + + /* Start of IP input header processing code. */ + +#ifdef CONFIG_NET_UIP_IPv6 + /* Check validity of the IP header. */ + if ((BUF->vtc & 0xf0) != 0x60) + { + /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ipv6: invalid version."); + goto drop; + } +#else /* CONFIG_NET_UIP_IPv6 */ + /* Check validity of the IP header. */ + if (BUF->vhl != 0x45) + { + /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ip: invalid version or header length."); + goto drop; + } +#endif /* CONFIG_NET_UIP_IPv6 */ + + /* Check the size of the packet. If the size reported to us in + uip_len is smaller the size reported in the IP header, we assume + that the packet has been corrupted in transit. If the size of + uip_len is larger than the size reported in the IP packet header, + the packet has been padded and we set uip_len to the correct + value.. */ + + if ((BUF->len[0] << 8) + BUF->len[1] <= uip_len) + { + uip_len = (BUF->len[0] << 8) + BUF->len[1]; +#ifdef CONFIG_NET_UIP_IPv6 + uip_len += 40; /* The length reported in the IPv6 header is the + length of the payload that follows the + header. However, uIP uses the uip_len variable + for holding the size of the entire packet, + including the IP header. For IPv4 this is not a + problem as the length field in the IPv4 header + contains the length of the entire packet. But + for IPv6 we need to add the size of the IPv6 + header (40 bytes). */ +#endif /* CONFIG_NET_UIP_IPv6 */ + } + else + { + UIP_LOG("ip: packet shorter than reported in IP header."); + goto drop; + } + +#ifndef CONFIG_NET_UIP_IPv6 + /* Check the fragment flag. */ + + if ((BUF->ipoffset[0] & 0x3f) != 0 || + BUF->ipoffset[1] != 0) + { +#if UIP_REASSEMBLY + uip_len = uip_reass(); + if (uip_len == 0) + { + goto drop; + } +#else /* UIP_REASSEMBLY */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.fragerr); + UIP_LOG("ip: fragment dropped."); + goto drop; +#endif /* UIP_REASSEMBLY */ + } +#endif /* CONFIG_NET_UIP_IPv6 */ + + if (uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) + { + /* If we are configured to use ping IP address configuration and + hasn't been assigned an IP address yet, we accept all ICMP + packets. */ +#if UIP_PINGADDRCONF && !CONFIG_NET_UIP_IPv6 + if (BUF->proto == UIP_PROTO_ICMP) + { + UIP_LOG("ip: possible ping config packet received."); + goto icmp_input; + } + else + { + UIP_LOG("ip: packet dropped since no address assigned."); + goto drop; + } +#endif /* UIP_PINGADDRCONF */ + + } + else + { + /* If IP broadcast support is configured, we check for a broadcast + UDP packet, which may be destined to us. */ +#if UIP_BROADCAST + dbg("UDP IP checksum 0x%04x\n", uip_ipchksum()); + if (BUF->proto == UIP_PROTO_UDP && + uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) + /*&& uip_ipchksum() == 0xffff*/) + { + goto udp_input; + } +#endif /* UIP_BROADCAST */ + + /* Check if the packet is destined for our IP address. */ +#ifndef CONFIG_NET_UIP_IPv6 + if (!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) + { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#else /* CONFIG_NET_UIP_IPv6 */ + /* For IPv6, packet reception is a little trickier as we need to + make sure that we listen to certain multicast addresses (all + hosts multicast address, and the solicited-node multicast + address) as well. However, we will cheat here and accept all + multicast packets that are sent to the ff02::/16 addresses. */ + if (!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && + BUF->destipaddr[0] != HTONS(0xff02)) + { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#endif /* CONFIG_NET_UIP_IPv6 */ + } + +#ifndef CONFIG_NET_UIP_IPv6 + if (uip_ipchksum() != 0xffff) + { + /* Compute and check the IP header checksum. */ + + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_LOG("ip: bad checksum."); + goto drop; + } +#endif /* CONFIG_NET_UIP_IPv6 */ + + if (BUF->proto == UIP_PROTO_TCP) + { + /* Check for TCP packet. If so, proceed with TCP input processing. */ + + goto tcp_input; + } + +#if UIP_UDP + if (BUF->proto == UIP_PROTO_UDP) + { + goto udp_input; + } +#endif /* UIP_UDP */ + +#ifndef CONFIG_NET_UIP_IPv6 + /* ICMPv4 processing code follows. */ + if (BUF->proto != UIP_PROTO_ICMP) + { + /* We only allow ICMP packets from here. */ + + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp."); + goto drop; + } + +#if UIP_PINGADDRCONF + icmp_input: +#endif /* UIP_PINGADDRCONF */ + UIP_STAT(++uip_stat.icmp.recv); + + /* ICMP echo (i.e., ping) processing. This is simple, we only change + the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP + checksum before we return the packet. */ + if (ICMPBUF->type != ICMP_ECHO) + { + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: not icmp echo."); + goto drop; + } + + /* If we are configured to use ping IP address assignment, we use + the destination IP address of this ping packet and assign it to + ourself. */ +#if UIP_PINGADDRCONF + if ((uip_hostaddr[0] | uip_hostaddr[1]) == 0) + { + uip_hostaddr[0] = BUF->destipaddr[0]; + uip_hostaddr[1] = BUF->destipaddr[1]; + } +#endif /* UIP_PINGADDRCONF */ + + ICMPBUF->type = ICMP_ECHO_REPLY; + + if (ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) + { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1; + } + else + { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8); + } + + /* Swap IP addresses. */ + + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + + /* End of IPv4 input header processing code. */ +#else /* !CONFIG_NET_UIP_IPv6 */ + + /* This is IPv6 ICMPv6 processing code. */ + dbg("icmp6_input: length %d\n", uip_len); + + if (BUF->proto != UIP_PROTO_ICMP6) + { + /* We only allow ICMPv6 packets from here. */ + + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp6."); + goto drop; + } + + UIP_STAT(++uip_stat.icmp.recv); + + /* If we get a neighbor solicitation for our address we should send + a neighbor advertisement message back. */ + if (ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) + { + if (uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) + { + if (ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) + { + /* Save the sender's address in our neighbor list. */ + uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2])); + } + + /* We should now send a neighbor advertisement back to where the + neighbor solicication came from. */ + ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT; + ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */ + + ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0; + + uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr); + uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr); + ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; + ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ + memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + goto send; + } + goto drop; + } + else if (ICMPBUF->type == ICMP6_ECHO) + { + /* ICMP echo (i.e., ping) processing. This is simple, we only + change the ICMP type from ECHO to ECHO_REPLY and update the + ICMP checksum before we return the packet. */ + + ICMPBUF->type = ICMP6_ECHO_REPLY; + + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + } + else + { + dbg("Unknown icmp6 message type %d\n", ICMPBUF->type); + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: unknown ICMP message."); + goto drop; + } + + /* End of IPv6 ICMP processing. */ + +#endif /* !CONFIG_NET_UIP_IPv6 */ + +#if UIP_UDP + /* UDP input processing. */ + udp_input: + /* UDP processing is really just a hack. We don't do anything to the + UDP/IP headers, but let the UDP application do all the hard + work. If the application sets uip_slen, it has a packet to + send. */ +#if UIP_UDP_CHECKSUMS + uip_len = uip_len - UIP_IPUDPH_LEN; + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if (UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) + { + UIP_STAT(++uip_stat.udp.drop); + UIP_STAT(++uip_stat.udp.chkerr); + UIP_LOG("udp: bad checksum."); + goto drop; + } +#else /* UIP_UDP_CHECKSUMS */ + uip_len = uip_len - UIP_IPUDPH_LEN; +#endif /* UIP_UDP_CHECKSUMS */ + + /* Demultiplex this UDP packet between the UDP "connections". */ + for (uip_udp_conn = &uip_udp_conns[0]; + uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; + ++uip_udp_conn) + { + /* If the local UDP port is non-zero, the connection is considered + to be used. If so, the local port number is checked against the + destination port number in the received packet. If the two port + numbers match, the remote port number is checked if the + connection is bound to a remote port. Finally, if the + connection is bound to a remote IP address, the source IP + address of the packet is checked. */ + if (uip_udp_conn->lport != 0 && + UDPBUF->destport == uip_udp_conn->lport && + (uip_udp_conn->rport == 0 || + UDPBUF->srcport == uip_udp_conn->rport) && + (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) || + uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || + uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) + { + goto udp_found; + } + } + UIP_LOG("udp: no matching connection found"); + goto drop; + + udp_found: + uip_conn = NULL; + uip_flags = UIP_NEWDATA; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_slen = 0; + uip_event_signal(); + uip_interrupt_udp_event(); + + udp_send: + if (uip_slen == 0) + { + goto drop; + } + uip_len = uip_slen + UIP_IPUDPH_LEN; + +#ifdef CONFIG_NET_UIP_IPv6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* CONFIG_NET_UIP_IPv6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* CONFIG_NET_UIP_IPv6 */ + + BUF->ttl = uip_udp_conn->ttl; + BUF->proto = UIP_PROTO_UDP; + + UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN); + UDPBUF->udpchksum = 0; + + BUF->srcport = uip_udp_conn->lport; + BUF->destport = uip_udp_conn->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr); + + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; + +#if UIP_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + UDPBUF->udpchksum = ~(uip_udpchksum()); + if (UDPBUF->udpchksum == 0) + { + UDPBUF->udpchksum = 0xffff; + } +#endif /* UIP_UDP_CHECKSUMS */ + + goto ip_send_nolen; +#endif /* UIP_UDP */ + + /* TCP input processing. */ + tcp_input: + UIP_STAT(++uip_stat.tcp.recv); + + /* Start of TCP input header processing code. */ + + if (uip_tcpchksum() != 0xffff) + { + /* Compute and check the TCP checksum. */ + UIP_STAT(++uip_stat.tcp.drop); + UIP_STAT(++uip_stat.tcp.chkerr); + UIP_LOG("tcp: bad checksum."); + goto drop; + } + + /* Demultiplex this segment. */ + /* First check any active connections. */ + for (uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; + ++uip_connr) + { + if (uip_connr->tcpstateflags != UIP_CLOSED && + BUF->destport == uip_connr->lport && + BUF->srcport == uip_connr->rport && + uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) + { + goto found; + } + } + + /* If we didn't find and active connection that expected the packet, + either this packet is an old duplicate, or this is a SYN packet + destined for a connection in LISTEN. If the SYN flag isn't set, + it is an old packet and we send a RST. */ + if ((BUF->flags & TCP_CTL) != TCP_SYN) + { + goto reset; + } + + tmp16 = BUF->destport; + + /* Next, check listening connections. */ + for(c = 0; c < UIP_LISTENPORTS; ++c) + { + if (tmp16 == uip_listenports[c]) + goto found_listen; + } + + /* No matching connection found, so we send a RST packet. */ + UIP_STAT(++uip_stat.tcp.synrst); + reset: + + /* We do not send resets in response to resets. */ + if (BUF->flags & TCP_RST) + { + goto drop; + } + + UIP_STAT(++uip_stat.tcp.rst); + + BUF->flags = TCP_RST | TCP_ACK; + uip_len = UIP_IPTCPH_LEN; + BUF->tcpoffset = 5 << 4; + + /* Flip the seqno and ackno fields in the TCP header. */ + c = BUF->seqno[3]; + BUF->seqno[3] = BUF->ackno[3]; + BUF->ackno[3] = c; + + c = BUF->seqno[2]; + BUF->seqno[2] = BUF->ackno[2]; + BUF->ackno[2] = c; + + c = BUF->seqno[1]; + BUF->seqno[1] = BUF->ackno[1]; + BUF->ackno[1] = c; + + c = BUF->seqno[0]; + BUF->seqno[0] = BUF->ackno[0]; + BUF->ackno[0] = c; + + /* We also have to increase the sequence number we are + acknowledging. If the least significant byte overflowed, we need + to propagate the carry to the other bytes as well. */ + if (++BUF->ackno[3] == 0) + { + if (++BUF->ackno[2] == 0) + { + if (++BUF->ackno[1] == 0) + { + ++BUF->ackno[0]; + } + } + } + + /* Swap port numbers. */ + tmp16 = BUF->srcport; + BUF->srcport = BUF->destport; + BUF->destport = tmp16; + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + /* And send out the RST packet! */ + goto tcp_send_noconn; + + /* This label will be jumped to if we matched the incoming packet + with a connection in LISTEN. In that case, we should create a new + connection and send a SYNACK in return. */ + found_listen: + /* First we check if there are any connections avaliable. Unused + connections are kept in the same table as used connections, but + unused ones have the tcpstate set to CLOSED. Also, connections in + TIME_WAIT are kept track of and we'll use the oldest one if no + CLOSED connections are found. Thanks to Eddie C. Dost for a very + nice algorithm for the TIME_WAIT search. */ + uip_connr = 0; + for(c = 0; c < UIP_CONNS; ++c) + { + if (uip_conns[c].tcpstateflags == UIP_CLOSED) + { + uip_connr = &uip_conns[c]; + break; + } + if (uip_conns[c].tcpstateflags == UIP_TIME_WAIT) + { + if (uip_connr == 0 || uip_conns[c].timer > uip_connr->timer) + { + uip_connr = &uip_conns[c]; + } + } + } + + if (uip_connr == 0) + { + /* All connections are used already, we drop packet and hope that + the remote end will retransmit the packet at a time when we + have more spare connections. */ + UIP_STAT(++uip_stat.tcp.syndrop); + UIP_LOG("tcp: found no unused connections."); + goto drop; + } + uip_conn = uip_connr; + + /* Fill in the necessary fields for the new connection. */ + uip_connr->rto = uip_connr->timer = UIP_RTO; + uip_connr->sa = 0; + uip_connr->sv = 4; + uip_connr->nrtx = 0; + uip_connr->lport = BUF->destport; + uip_connr->rport = BUF->srcport; + uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); + uip_connr->tcpstateflags = UIP_SYN_RCVD; + + uip_connr->snd_nxt[0] = iss[0]; + uip_connr->snd_nxt[1] = iss[1]; + uip_connr->snd_nxt[2] = iss[2]; + uip_connr->snd_nxt[3] = iss[3]; + uip_connr->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_add_rcv_nxt(1); + + /* Parse the TCP MSS option, if present. */ + if ((BUF->tcpoffset & 0xf0) > 0x50) + { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) + { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + if (opt == TCP_OPT_END) + { + /* End of options. */ + break; + } + else if (opt == TCP_OPT_NOOP) + { + ++c; + /* NOP option. */ + } + else if (opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) + { + /* An MSS option with the right option length. */ + tmp16 = ((uint16)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + (uint16)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = uip_connr->mss = + tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } + else + { + /* All other options have a length field, so that we easily + can skip past them. */ + if (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) + { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + + /* Our response will be a SYNACK. */ +#if UIP_ACTIVE_OPEN + tcp_send_synack: + BUF->flags = TCP_ACK; + + tcp_send_syn: + BUF->flags |= TCP_SYN; +#else /* UIP_ACTIVE_OPEN */ + tcp_send_synack: + BUF->flags = TCP_SYN | TCP_ACK; +#endif /* UIP_ACTIVE_OPEN */ + + /* We send out the TCP Maximum Segment Size option with our + SYNACK. */ + BUF->optdata[0] = TCP_OPT_MSS; + BUF->optdata[1] = TCP_OPT_MSS_LEN; + BUF->optdata[2] = (UIP_TCP_MSS) / 256; + BUF->optdata[3] = (UIP_TCP_MSS) & 255; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; + goto tcp_send; + + /* This label will be jumped to if we found an active connection. */ + found: + uip_conn = uip_connr; + uip_flags = 0; + + /* We do a very naive form of TCP reset processing; we just accept + * any RST and kill our connection. We should in fact check if the + * sequence number of this reset is wihtin our advertised window + * before we accept the reset. + */ + + if (BUF->flags & TCP_RST) + { + uip_connr->tcpstateflags = UIP_CLOSED; + UIP_LOG("tcp: got reset, aborting connection."); + uip_flags = UIP_ABORT; + uip_event_signal(); + uip_interrupt_event(); + goto drop; + } + + /* Calculated the length of the data, if the application has sent + * any data to us. + */ + + c = (BUF->tcpoffset >> 4) << 2; + + /* uip_len will contain the length of the actual TCP data. This is + * calculated by subtracing the length of the TCP header (in + * c) and the length of the IP header (20 bytes). + */ + + uip_len = uip_len - c - UIP_IPH_LEN; + + /* First, check if the sequence number of the incoming packet is + * what we're expecting next. If not, we send out an ACK with the + * correct numbers in. + */ + + if (!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && + ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) + { + if ((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && + (BUF->seqno[0] != uip_connr->rcv_nxt[0] || + BUF->seqno[1] != uip_connr->rcv_nxt[1] || + BUF->seqno[2] != uip_connr->rcv_nxt[2] || + BUF->seqno[3] != uip_connr->rcv_nxt[3])) + { + goto tcp_send_ack; + } + } + + /* Next, check if the incoming segment acknowledges any outstanding + data. If so, we update the sequence number, reset the length of + the outstanding data, calculate RTT estimations, and reset the + retransmission timer. */ + if ((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) + { + uip_add32(uip_connr->snd_nxt, uip_connr->len); + + if (BUF->ackno[0] == uip_acc32[0] && + BUF->ackno[1] == uip_acc32[1] && + BUF->ackno[2] == uip_acc32[2] && + BUF->ackno[3] == uip_acc32[3]) + { + /* Update sequence number. */ + uip_connr->snd_nxt[0] = uip_acc32[0]; + uip_connr->snd_nxt[1] = uip_acc32[1]; + uip_connr->snd_nxt[2] = uip_acc32[2]; + uip_connr->snd_nxt[3] = uip_acc32[3]; + + /* Do RTT estimation, unless we have done retransmissions. */ + if (uip_connr->nrtx == 0) + { + signed char m; + m = uip_connr->rto - uip_connr->timer; + + /* This is taken directly from VJs original code in his paper */ + m = m - (uip_connr->sa >> 3); + uip_connr->sa += m; + if (m < 0) + { + m = -m; + } + m = m - (uip_connr->sv >> 2); + uip_connr->sv += m; + uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; + } + + /* Set the acknowledged flag. */ + uip_flags = UIP_ACKDATA; + + /* Reset the retransmission timer. */ + uip_connr->timer = uip_connr->rto; + + /* Reset length of outstanding data. */ + uip_connr->len = 0; + } + } + + /* Do different things depending on in what state the connection is. */ + switch(uip_connr->tcpstateflags & UIP_TS_MASK) + { + /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not + implemented, since we force the application to close when the + peer sends a FIN (hence the application goes directly from + ESTABLISHED to LAST_ACK). */ + case UIP_SYN_RCVD: + /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and + * we are waiting for an ACK that acknowledges the data we sent + * out the last time. Therefore, we want to have the UIP_ACKDATA + * flag set. If so, we enter the ESTABLISHED state. + */ + + if (uip_flags & UIP_ACKDATA) + { + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_flags = UIP_CONNECTED; + uip_connr->len = 0; + if (uip_len > 0) + { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + uip_slen = 0; + uip_event_signal(); + uip_interrupt_event(); + goto appsend; + } + goto drop; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In SYN_SENT, we wait for a SYNACK that is sent in response to + our SYN. The rcv_nxt is set to sequence number in the SYNACK + plus one, and we send an ACK. We move into the ESTABLISHED + state. */ + if ((uip_flags & UIP_ACKDATA) && + (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) + { + /* Parse the TCP MSS option, if present. */ + if ((BUF->tcpoffset & 0xf0) > 0x50) + { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) + { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + if (opt == TCP_OPT_END) + { + /* End of options. */ + break; + } + else if (opt == TCP_OPT_NOOP) + { + ++c; + /* NOP option. */ + } + else if (opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) + { + /* An MSS option with the right option length. */ + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = + uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } + else + { + /* All other options have a length field, so that we easily + can skip past them. */ + if (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) + { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_add_rcv_nxt(1); + uip_flags = UIP_CONNECTED | UIP_NEWDATA; + uip_connr->len = 0; + uip_len = 0; + uip_slen = 0; + uip_event_signal(); + uip_interrupt_event(); + goto appsend; + } + + /* Inform the application that the connection failed */ + uip_flags = UIP_ABORT; + uip_event_signal(); + uip_interrupt_event(); + + /* The connection is closed after we send the RST */ + uip_conn->tcpstateflags = UIP_CLOSED; + goto reset; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application to feed + data into the uip_buf. If the UIP_ACKDATA flag is set, the + application should put new data into the buffer, otherwise we are + retransmitting an old segment, and the application should put that + data into the buffer. + + If the incoming packet is a FIN, we should close the connection on + this side as well, and we send out a FIN and enter the LAST_ACK + state. We require that there is no outstanding data; otherwise the + sequence numbers will be screwed up. */ + + if (BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) + { + if (uip_outstanding(uip_connr)) + { + goto drop; + } + uip_add_rcv_nxt(1 + uip_len); + uip_flags |= UIP_CLOSE; + if (uip_len > 0) + { + uip_flags |= UIP_NEWDATA; + } + uip_event_signal(); + uip_interrupt_event(); + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_LAST_ACK; + uip_connr->nrtx = 0; + + tcp_send_finack: + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* Check the URG flag. If this is set, the segment carries urgent + data that we must pass to the application. */ + if ((BUF->flags & TCP_URG) != 0) + { +#if UIP_URGDATA > 0 + uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1]; + if (uip_urglen > uip_len) + { + /* There is more urgent data in the next segment to come. */ + uip_urglen = uip_len; + } + uip_add_rcv_nxt(uip_urglen); + uip_len -= uip_urglen; + uip_urgdata = uip_appdata; + uip_appdata += uip_urglen; + } + else + { + uip_urglen = 0; +#else /* UIP_URGDATA > 0 */ + uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); + uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +#endif /* UIP_URGDATA > 0 */ + } + + /* If uip_len > 0 we have TCP data in the packet, and we flag this + by setting the UIP_NEWDATA flag and update the sequence number + we acknowledge. If the application has stopped the dataflow + using uip_stop(), we must not accept any data packets from the + remote host. */ + if (uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) + { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + + /* Check if the available buffer space advertised by the other end + is smaller than the initial MSS for this connection. If so, we + set the current MSS to the window size to ensure that the + application does not send more data than the other end can + handle. + + If the remote host advertises a zero window, we set the MSS to + the initial MSS so that the application will send an entire MSS + of data. This data will not be acknowledged by the receiver, + and the application will retransmit it. This is called the + "persistent timer" and uses the retransmission mechanim. + */ + tmp16 = ((uint16)BUF->wnd[0] << 8) + (uint16)BUF->wnd[1]; + if (tmp16 > uip_connr->initialmss || tmp16 == 0) + { + tmp16 = uip_connr->initialmss; + } + uip_connr->mss = tmp16; + + /* If this packet constitutes an ACK for outstanding data (flagged + by the UIP_ACKDATA flag, we should call the application since it + might want to send more data. If the incoming packet had data + from the peer (as flagged by the UIP_NEWDATA flag), the + application must also be notified. + + When the application is called, the global variable uip_len + contains the length of the incoming data. The application can + access the incoming data through the global pointer + uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN + bytes into the uip_buf array. + + If the application wishes to send any data, this data should be + put into the uip_appdata and the length of the data should be + put into uip_len. If the application don't have any data to + send, uip_len must be set to 0. */ + if (uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) + { + uip_slen = 0; + uip_event_signal(); + uip_interrupt_event(); + + appsend: + if (uip_flags & UIP_ABORT) + { + uip_slen = 0; + uip_connr->tcpstateflags = UIP_CLOSED; + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + if (uip_flags & UIP_CLOSE) + { + uip_slen = 0; + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_FIN_WAIT_1; + uip_connr->nrtx = 0; + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* If uip_slen > 0, the application has data to be sent. */ + if (uip_slen > 0) + { + /* If the connection has acknowledged data, the contents of + the ->len variable should be discarded. */ + if ((uip_flags & UIP_ACKDATA) != 0) + { + uip_connr->len = 0; + } + + /* If the ->len variable is non-zero the connection has + already data in transit and cannot send anymore right + now. */ + if (uip_connr->len == 0) + { + /* The application cannot send more than what is allowed by + the mss (the minumum of the MSS and the available + window). */ + if (uip_slen > uip_connr->mss) + { + uip_slen = uip_connr->mss; + } + + /* Remember how much data we send out now so that we know + when everything has been acknowledged. */ + uip_connr->len = uip_slen; + } + else + { + /* If the application already had unacknowledged data, we + make sure that the application does not send (i.e., + retransmit) out more than it previously sent out. */ + uip_slen = uip_connr->len; + } + } + uip_connr->nrtx = 0; + apprexmit: + uip_appdata = uip_sappdata; + + /* If the application has data to be sent, or if the incoming + packet had new data in it, we must send out a packet. */ + if (uip_slen > 0 && uip_connr->len > 0) + { + /* Add the length of the IP and TCP headers. */ + uip_len = uip_connr->len + UIP_TCPIP_HLEN; + + /* We always set the ACK flag in response packets. */ + BUF->flags = TCP_ACK | TCP_PSH; + + /* Send the packet. */ + goto tcp_send_noopts; + } + + /* If there is no data to send, just send out a pure ACK if + there is newdata. */ + if (uip_flags & UIP_NEWDATA) + { + uip_len = UIP_TCPIP_HLEN; + BUF->flags = TCP_ACK; + goto tcp_send_noopts; + } + } + goto drop; + + case UIP_LAST_ACK: + /* We can close this connection if the peer has acknowledged our + FIN. This is indicated by the UIP_ACKDATA flag. */ + if (uip_flags & UIP_ACKDATA) + { + uip_connr->tcpstateflags = UIP_CLOSED; + uip_flags = UIP_CLOSE; + uip_event_signal(); + uip_interrupt_event(); + } + break; + + case UIP_FIN_WAIT_1: + /* The application has closed the connection, but the remote host + hasn't closed its end yet. Thus we do nothing but wait for a + FIN from the other side. */ + if (uip_len > 0) + { + uip_add_rcv_nxt(uip_len); + } + if (BUF->flags & TCP_FIN) + { + if (uip_flags & UIP_ACKDATA) + { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_connr->len = 0; + } + else + { + uip_connr->tcpstateflags = UIP_CLOSING; + } + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + uip_event_signal(); + uip_interrupt_event(); + goto tcp_send_ack; + } + else if (uip_flags & UIP_ACKDATA) + { + uip_connr->tcpstateflags = UIP_FIN_WAIT_2; + uip_connr->len = 0; + goto drop; + } + if (uip_len > 0) + { + goto tcp_send_ack; + } + goto drop; + + case UIP_FIN_WAIT_2: + if (uip_len > 0) + { + uip_add_rcv_nxt(uip_len); + } + if (BUF->flags & TCP_FIN) + { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + uip_event_signal(); + uip_interrupt_event(); + goto tcp_send_ack; + } + if (uip_len > 0) + { + goto tcp_send_ack; + } + goto drop; + + case UIP_TIME_WAIT: + goto tcp_send_ack; + + case UIP_CLOSING: + if (uip_flags & UIP_ACKDATA) + { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + } + } + goto drop; + + /* We jump here when we are ready to send the packet, and just want + to set the appropriate TCP sequence numbers in the TCP header. */ + tcp_send_ack: + BUF->flags = TCP_ACK; + tcp_send_nodata: + uip_len = UIP_IPTCPH_LEN; + tcp_send_noopts: + BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; + tcp_send: + /* We're done with the input processing. We are now ready to send a + reply. Our job is to fill in all the fields of the TCP and IP + headers before calculating the checksum and finally send the + packet. */ + BUF->ackno[0] = uip_connr->rcv_nxt[0]; + BUF->ackno[1] = uip_connr->rcv_nxt[1]; + BUF->ackno[2] = uip_connr->rcv_nxt[2]; + BUF->ackno[3] = uip_connr->rcv_nxt[3]; + + BUF->seqno[0] = uip_connr->snd_nxt[0]; + BUF->seqno[1] = uip_connr->snd_nxt[1]; + BUF->seqno[2] = uip_connr->snd_nxt[2]; + BUF->seqno[3] = uip_connr->snd_nxt[3]; + + BUF->proto = UIP_PROTO_TCP; + + BUF->srcport = uip_connr->lport; + BUF->destport = uip_connr->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr); + + if (uip_connr->tcpstateflags & UIP_STOPPED) + { + /* If the connection has issued uip_stop(), we advertise a zero + window so that the remote host will stop sending data. */ + BUF->wnd[0] = BUF->wnd[1] = 0; + } + else + { + BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); + BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); + } + + tcp_send_noconn: + BUF->ttl = UIP_TTL; +#ifdef CONFIG_NET_UIP_IPv6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* CONFIG_NET_UIP_IPv6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* CONFIG_NET_UIP_IPv6 */ + + BUF->urgp[0] = BUF->urgp[1] = 0; + + /* Calculate TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + +#if UIP_UDP + ip_send_nolen: +#endif /* UIP_UDP */ + +#ifdef CONFIG_NET_UIP_IPv6 + BUF->vtc = 0x60; + BUF->tcflow = 0x00; + BUF->flow = 0x00; +#else /* CONFIG_NET_UIP_IPv6 */ + BUF->vhl = 0x45; + BUF->tos = 0; + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + ++ipid; + BUF->ipid[0] = ipid >> 8; + BUF->ipid[1] = ipid & 0xff; + + /* Calculate IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + dbg("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum()); +#endif /* CONFIG_NET_UIP_IPv6 */ + + UIP_STAT(++uip_stat.tcp.sent); + send: + dbg("Sending packet with length %d (%d)\n", uip_len, + (BUF->len[0] << 8) | BUF->len[1]); + + UIP_STAT(++uip_stat.ip.sent); + + /* Return and let the caller do the actual transmission. */ + uip_flags = 0; + return; + drop: + uip_len = 0; + uip_flags = 0; + return; +} + +uint16 htons(uint16 val) +{ + return HTONS(val); +} + +void uip_send(const void *data, int len) +{ + if (len > 0) + { + uip_slen = len; + if (data != uip_sappdata) + { + memcpy(uip_sappdata, (data), uip_slen); + } + } +} |