mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-08-08 00:23:39 +08:00
Initial revision
This commit is contained in:
162
src/core/inet.c
Normal file
162
src/core/inet.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet.c
|
||||
*
|
||||
* Functions common to all TCP/IP modules, such as the Internet checksum and the
|
||||
* byte order functions.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/arch.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static u16_t
|
||||
lwip_chksum(void *dataptr, int len)
|
||||
{
|
||||
u32_t acc;
|
||||
|
||||
for(acc = 0; len > 1; len -= 2) {
|
||||
acc += *((u16_t *)dataptr)++;
|
||||
}
|
||||
|
||||
/* add up any odd byte */
|
||||
if(len == 1) {
|
||||
acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8);
|
||||
DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", *(u8_t *)dataptr));
|
||||
}
|
||||
acc = (acc >> 16) + (acc & 0xffffUL);
|
||||
|
||||
if(acc & 0xffff0000 != 0) {
|
||||
acc = (acc >> 16) + (acc & 0xffffUL);
|
||||
}
|
||||
|
||||
return (u16_t)acc;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum_pseudo(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += lwip_chksum(q->payload, q->len);
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
if(q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
acc += (dest->addr & 0xffffUL);
|
||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
return ~(acc & 0xffffUL);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
|
||||
* and ICMP.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc;
|
||||
|
||||
acc = lwip_chksum(dataptr, len);
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum_pbuf(struct pbuf *p)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += lwip_chksum(q->payload, q->len);
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if(q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
168
src/core/inet6.c
Normal file
168
src/core/inet6.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet6.c
|
||||
*
|
||||
* Functions common to all TCP/IP modules, such as the Internet checksum and the
|
||||
* byte order functions.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* chksum:
|
||||
*
|
||||
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
|
||||
* This function is used by the other checksum functions.
|
||||
*
|
||||
* For now, this is not optimized. Must be optimized for the particular processor
|
||||
* arcitecture on which it is to run. Preferebly coded in assembler.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static u32_t
|
||||
chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u16_t *sdataptr = dataptr;
|
||||
u32_t acc;
|
||||
|
||||
|
||||
for(acc = 0; len > 1; len -= 2) {
|
||||
acc += *sdataptr++;
|
||||
}
|
||||
|
||||
/* add up any odd byte */
|
||||
if(len == 1) {
|
||||
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum_pseudo(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u32_t proto_len)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped, i;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += chksum(q->payload, q->len);
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if(q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
acc += ((u16_t *)src->addr)[i] & 0xffff;
|
||||
acc += ((u16_t *)dest->addr)[i] & 0xffff;
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
}
|
||||
acc += (u16_t)htons((u16_t)proto);
|
||||
acc += ((u16_t *)&proto_len)[0] & 0xffff;
|
||||
acc += ((u16_t *)&proto_len)[1] & 0xffff;
|
||||
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
|
||||
* and ICMP.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc, sum;
|
||||
|
||||
acc = chksum(dataptr, len);
|
||||
sum = (acc & 0xffff) + (acc >> 16);
|
||||
sum += (sum >> 16);
|
||||
return ~(sum & 0xffff);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u16_t
|
||||
inet_chksum_pbuf(struct pbuf *p)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += chksum(q->payload, q->len);
|
||||
while(acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if(q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if(swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
199
src/core/ipv4/icmp.c
Normal file
199
src/core/ipv4/icmp.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/* Some ICMP messages should be passed to the transport protocols. This
|
||||
is not implemented. */
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
icmp_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
unsigned char type;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
struct ip_addr tmpaddr;
|
||||
u16_t hlen;
|
||||
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.recv;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
|
||||
iphdr = p->payload;
|
||||
hlen = IPH_HL(iphdr) * 4/sizeof(u8_t);
|
||||
pbuf_header(p, -hlen);
|
||||
|
||||
type = *((u8_t *)p->payload);
|
||||
|
||||
switch(type) {
|
||||
case ICMP_ECHO:
|
||||
if(ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) ||
|
||||
ip_addr_ismulticast(&iphdr->dest)) {
|
||||
DEBUGF(ICMP_DEBUG, ("Smurf.\n"));
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.err;
|
||||
#endif /* ICMP_STATS */
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||
DEBUGF(DEMO_DEBUG, ("Pong!\n"));
|
||||
if(p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||
pbuf_free(p);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.lenerr;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
return;
|
||||
}
|
||||
iecho = p->payload;
|
||||
if(inet_chksum_pbuf(p) != 0) {
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
|
||||
pbuf_free(p);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.chkerr;
|
||||
#endif /* ICMP_STATS */
|
||||
return;
|
||||
}
|
||||
tmpaddr.addr = iphdr->src.addr;
|
||||
iphdr->src.addr = iphdr->dest.addr;
|
||||
iphdr->dest.addr = tmpaddr.addr;
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
||||
/* adjust the checksum */
|
||||
if(iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
|
||||
iecho->chksum += htons(ICMP_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += htons(ICMP_ECHO << 8);
|
||||
}
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
pbuf_header(p, hlen);
|
||||
ip_output_if(p, &(iphdr->src), IP_HDRINCL,
|
||||
IPH_TTL(iphdr), IP_PROTO_ICMP, inp);
|
||||
break;
|
||||
default:
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type not supported.\n"));
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.proterr;
|
||||
++stats.icmp.drop;
|
||||
#endif /* ICMP_STATS */
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
ICMPH_TYPE_SET(idur, ICMP_DUR);
|
||||
ICMPH_CODE_SET(idur, t);
|
||||
|
||||
bcopy(p->payload, (char *)q->payload + 8, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, q->len);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
ip_output(q, NULL, &(iphdr->src),
|
||||
ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if IP_FORWARD
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
|
||||
iphdr = p->payload;
|
||||
#if ICMP_DEBUG
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
||||
ip_addr_debug_print(&(iphdr->src));
|
||||
DEBUGF(ICMP_DEBUG, (" to "));
|
||||
ip_addr_debug_print(&(iphdr->dest));
|
||||
DEBUGF(ICMP_DEBUG, ("\n"));
|
||||
#endif /* ICMP_DEBNUG */
|
||||
|
||||
tehdr = q->payload;
|
||||
ICMPH_TYPE_SET(tehdr, ICMP_TE);
|
||||
ICMPH_CODE_SET(tehdr, t);
|
||||
|
||||
/* copy fields from original packet */
|
||||
bcopy((char *)p->payload, (char *)q->payload + 8, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
ip_output(q, NULL, &(iphdr->src),
|
||||
ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* IP_FORWARDING > 0 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
700
src/core/ipv4/ip.c
Normal file
700
src/core/ipv4/ip.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip.c
|
||||
*
|
||||
* This is the code for the IP layer.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include "arch/perf.h"
|
||||
|
||||
#if LWIP_DHCP
|
||||
#include "lwip/dhcp.h"
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_init:
|
||||
*
|
||||
* Initializes the IP layer.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
ip_init(void)
|
||||
{
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_lookup:
|
||||
*
|
||||
* An experimental feature that will be changed in future versions. Do
|
||||
* not depend on it yet...
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#ifdef LWIP_DEBUG
|
||||
u8_t
|
||||
ip_lookup(void *header, struct netif *inp)
|
||||
{
|
||||
struct ip_hdr *iphdr;
|
||||
|
||||
iphdr = header;
|
||||
|
||||
/* Refuse anything that isn't IPv4. */
|
||||
if(IPH_V(iphdr) != 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Immediately accept/decline packets that are fragments or has
|
||||
options. */
|
||||
#if IP_REASSEMBLY == 0
|
||||
/* if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
return 0;
|
||||
}*/
|
||||
#endif /* IP_REASSEMBLY == 0 */
|
||||
|
||||
#if IP_OPTIONS == 0
|
||||
if(IPH_HL(iphdr) != 5) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* IP_OPTIONS == 0 */
|
||||
|
||||
switch(IPH_PROTO(iphdr)) {
|
||||
#if LWIP_UDP > 0
|
||||
case IP_PROTO_UDP:
|
||||
return udp_lookup(iphdr, inp);
|
||||
break;
|
||||
#endif /* LWIP_UDP */
|
||||
#if LWIP_TCP > 0
|
||||
case IP_PROTO_TCP:
|
||||
return 1;
|
||||
#endif /* LWIP_TCP */
|
||||
case IP_PROTO_ICMP:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_route:
|
||||
*
|
||||
* Finds the appropriate network interface for a given IP address. It
|
||||
* searches the list of network interfaces linearly. A match is found
|
||||
* if the masked IP address of the network interface equals the masked
|
||||
* IP address given to the function.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct netif *
|
||||
ip_route(struct ip_addr *dest)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if(ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
|
||||
return netif_default;
|
||||
}
|
||||
#if IP_FORWARD
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_forward:
|
||||
*
|
||||
* Forwards an IP packet. It finds an appropriate route for the
|
||||
* packet, decrements the TTL value of the packet, adjusts the
|
||||
* checksum and outputs the packet on the appropriate interface.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
{
|
||||
static struct netif *netif;
|
||||
|
||||
PERF_START;
|
||||
|
||||
if((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%lx found\n",
|
||||
iphdr->dest.addr));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't forward packets onto the same network interface on which
|
||||
they arrived. */
|
||||
if(netif == inp) {
|
||||
DEBUGF(IP_DEBUG, ("ip_forward: not forward packets back on incoming interface.\n"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decrement TTL and send ICMP if ttl == 0. */
|
||||
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
|
||||
if(IPH_TTL(iphdr) == 0) {
|
||||
/* Don't send ICMP messages in response to ICMP messages */
|
||||
if(IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
|
||||
icmp_time_exceeded(p, ICMP_TE_TTL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Incremental update of the IP checksum. */
|
||||
if(IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
|
||||
} else {
|
||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
|
||||
}
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%lx\n",
|
||||
iphdr->dest.addr));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.fw;
|
||||
++stats.ip.xmit;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
PERF_STOP("ip_forward");
|
||||
|
||||
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
|
||||
}
|
||||
#endif /* IP_FORWARD */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_reass:
|
||||
*
|
||||
* Tries to reassemble a fragmented IP packet.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#define IP_REASSEMBLY 1
|
||||
#define IP_REASS_BUFSIZE 5760
|
||||
#define IP_REASS_MAXAGE 10
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE];
|
||||
static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8)];
|
||||
static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
|
||||
0x0f, 0x07, 0x03, 0x01};
|
||||
static u16_t ip_reasslen;
|
||||
static u8_t ip_reassflags;
|
||||
#define IP_REASS_FLAG_LASTFRAG 0x01
|
||||
static u8_t ip_reasstmr;
|
||||
|
||||
static struct pbuf *
|
||||
ip_reass(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *fraghdr, *iphdr;
|
||||
u16_t offset, len;
|
||||
u16_t i;
|
||||
|
||||
iphdr = (struct ip_hdr *)ip_reassbuf;
|
||||
fraghdr = (struct ip_hdr *)p->payload;
|
||||
|
||||
/* 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(ip_reasstmr == 0) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
|
||||
bcopy(fraghdr, iphdr, IP_HLEN);
|
||||
ip_reasstmr = IP_REASS_MAXAGE;
|
||||
ip_reassflags = 0;
|
||||
/* Clear the bitmap. */
|
||||
bzero(ip_reassbitmap, sizeof(ip_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(ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
|
||||
ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
|
||||
IPH_ID(iphdr) == IPH_ID(fraghdr)) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n"));
|
||||
/* Find out the offset in the reassembly buffer where we should
|
||||
copy the fragment. */
|
||||
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
||||
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
||||
|
||||
/* If the offset or the offset + fragment length overflows the
|
||||
reassembly buffer, we discard the entire packet. */
|
||||
if(offset > IP_REASS_BUFSIZE ||
|
||||
offset + len > IP_REASS_BUFSIZE) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%d:%d/%d).\n",
|
||||
offset, offset + len, IP_REASS_BUFSIZE));
|
||||
ip_reasstmr = 0;
|
||||
goto nullreturn;
|
||||
}
|
||||
|
||||
/* Copy the fragment into the reassembly buffer, at the right
|
||||
offset. */
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %d into %d:%d\n",
|
||||
offset, IP_HLEN + offset, IP_HLEN + offset + len));
|
||||
bcopy((u8_t *)fraghdr + IPH_HL(fraghdr) * 4,
|
||||
&ip_reassbuf[IP_HLEN + offset], len);
|
||||
|
||||
/* Update the bitmap. */
|
||||
if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating single byte in bitmap.\n"));
|
||||
/* If the two endpoints are in the same byte, we only update
|
||||
that byte. */
|
||||
ip_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. */
|
||||
ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7];
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating many bytes in bitmap (%d:%d).\n",
|
||||
1 + offset / (8 * 8), (offset + len) / (8 * 8)));
|
||||
for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
|
||||
ip_reassbitmap[i] = 0xff;
|
||||
}
|
||||
ip_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((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
|
||||
ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
|
||||
ip_reasslen = offset + len;
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %d\n", ip_reasslen));
|
||||
}
|
||||
|
||||
/* 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(ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
|
||||
/* Check all bytes up to and including all but the last byte in
|
||||
the bitmap. */
|
||||
for(i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
|
||||
if(ip_reassbitmap[i] != 0xff) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
|
||||
goto nullreturn;
|
||||
}
|
||||
}
|
||||
/* Check the last byte in the bitmap. It should contain just the
|
||||
right amount of bits. */
|
||||
if(ip_reassbitmap[ip_reasslen / (8 * 8)] !=
|
||||
(u8_t)~bitmap_bits[ip_reasslen / 8 & 7]) {
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n",
|
||||
ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
|
||||
ip_reassbitmap[ip_reasslen / (8 * 8)]));
|
||||
goto nullreturn;
|
||||
}
|
||||
|
||||
/* Pretend to be a "normal" (i.e., not fragmented) IP packet
|
||||
from now on. */
|
||||
IPH_OFFSET_SET(iphdr, 0);
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
/* 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. */
|
||||
ip_reasstmr = 0;
|
||||
pbuf_free(p);
|
||||
p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
|
||||
if(p != NULL) {
|
||||
i = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
/* Copy enough bytes to fill this pbuf in the chain. The
|
||||
avaliable data in the pbuf is given by the q->len
|
||||
variable. */
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: bcopy from %p (%d) to %p, %d bytes\n",
|
||||
&ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i? ip_reasslen - i: q->len));
|
||||
bcopy(&ip_reassbuf[i], q->payload,
|
||||
q->len > ip_reasslen - i? ip_reasslen - i: q->len);
|
||||
i += q->len;
|
||||
}
|
||||
}
|
||||
DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", p));
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
nullreturn:
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_input:
|
||||
*
|
||||
* This function is called by the network interface device driver when
|
||||
* an IP packet is received. The function does the basic checks of the
|
||||
* IP header such as packet size being at least larger than the header
|
||||
* size etc. If the packet was not destined for us, the packet is
|
||||
* forwarded (using ip_forward). The IP checksum is always checked.
|
||||
*
|
||||
* Finally, the packet is sent to the upper layer protocol input function.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
ip_input(struct pbuf *p, struct netif *inp) {
|
||||
static struct ip_hdr *iphdr;
|
||||
static struct netif *netif;
|
||||
static u8_t hl;
|
||||
|
||||
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.recv;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
/* identify the IP header */
|
||||
iphdr = p->payload;
|
||||
if(IPH_V(iphdr) != 4) {
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr)));
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
pbuf_free(p);
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.err;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
hl = IPH_HL(iphdr);
|
||||
|
||||
if(hl * 4 > p->len) {
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped due to too short packet %d\n", p->len));
|
||||
|
||||
pbuf_free(p);
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.lenerr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* verify checksum */
|
||||
if(inet_chksum(iphdr, hl * 4) != 0) {
|
||||
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped due to failing checksum 0x%x\n", inet_chksum(iphdr, hl * 4)));
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
pbuf_free(p);
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.chkerr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/* Trim pbuf. This should have been done at the netif layer,
|
||||
but we'll do it anyway just to be sure that its done. */
|
||||
pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));
|
||||
|
||||
/* is this packet for us? */
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx)\n",
|
||||
iphdr->dest.addr, netif->ip_addr.addr,
|
||||
iphdr->dest.addr & netif->netmask.addr,
|
||||
netif->ip_addr.addr & netif->netmask.addr,
|
||||
iphdr->dest.addr & ~(netif->netmask.addr)));
|
||||
|
||||
if(ip_addr_isany(&(netif->ip_addr)) ||
|
||||
ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
|
||||
(ip_addr_isbroadcast(&(iphdr->dest), &(netif->netmask)) &&
|
||||
ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
|
||||
ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_DHCP
|
||||
/* If a DHCP packet has arrived on the interface, we pass it up the
|
||||
stack regardless of destination IP address. The reason is that
|
||||
DHCP replies are sent to the IP adress that will be given to this
|
||||
node (as recommended by RFC 1542 section 3.1.1, referred by RFC
|
||||
2131). */
|
||||
if(IPH_PROTO(iphdr) == IP_PROTO_UDP &&
|
||||
((struct udp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t)))->src ==
|
||||
DHCP_SERVER_PORT) {
|
||||
netif = inp;
|
||||
}
|
||||
#endif /* LWIP_DHCP */
|
||||
|
||||
if(netif == NULL) {
|
||||
/* packet not for us, route or discard */
|
||||
DEBUGF(IP_DEBUG, ("ip_input: packet not for us.\n"));
|
||||
#if IP_FORWARD
|
||||
if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) {
|
||||
ip_forward(p, iphdr, inp);
|
||||
}
|
||||
#endif /* IP_FORWARD */
|
||||
pbuf_free(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if IP_REASSEMBLY
|
||||
if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
p = ip_reass(p);
|
||||
if(p == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
iphdr = p->payload;
|
||||
}
|
||||
#else /* IP_REASSEMBLY */
|
||||
if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
||||
pbuf_free(p);
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped since it was fragmented (0x%x).\n",
|
||||
ntohs(IPH_OFFSET(iphdr))));
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.opterr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* IP_REASSEMBLY */
|
||||
|
||||
#if IP_OPTIONS == 0
|
||||
if(hl * 4 > IP_HLEN) {
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped since there were IP options.\n"));
|
||||
|
||||
pbuf_free(p);
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.opterr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* IP_OPTIONS == 0 */
|
||||
|
||||
|
||||
/* send to upper layers */
|
||||
#if IP_DEBUG
|
||||
DEBUGF(IP_DEBUG, ("ip_input: \n"));
|
||||
ip_debug_print(p);
|
||||
DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len));
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
switch(IPH_PROTO(iphdr)) {
|
||||
#if LWIP_UDP > 0
|
||||
case IP_PROTO_UDP:
|
||||
udp_input(p, inp);
|
||||
break;
|
||||
#endif /* LWIP_UDP */
|
||||
#if LWIP_TCP > 0
|
||||
case IP_PROTO_TCP:
|
||||
tcp_input(p, inp);
|
||||
break;
|
||||
#endif /* LWIP_TCP */
|
||||
case IP_PROTO_ICMP:
|
||||
icmp_input(p, inp);
|
||||
break;
|
||||
default:
|
||||
/* send ICMP destination protocol unreachable unless is was a broadcast */
|
||||
if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
|
||||
!ip_addr_ismulticast(&(iphdr->dest))) {
|
||||
p->payload = iphdr;
|
||||
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", IPH_PROTO(iphdr)));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.proterr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_output_if:
|
||||
*
|
||||
* Sends an IP packet on a network interface. This function constructs
|
||||
* the IP header and calculates the IP header checksum. If the source
|
||||
* IP address is NULL, the IP address of the outgoing network
|
||||
* interface is filled in as source address.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl,
|
||||
u8_t proto, struct netif *netif)
|
||||
{
|
||||
static struct ip_hdr *iphdr;
|
||||
static u16_t ip_id = 0;
|
||||
|
||||
|
||||
|
||||
if(dest != IP_HDRINCL) {
|
||||
if(pbuf_header(p, IP_HLEN)) {
|
||||
DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.err;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
IPH_TTL_SET(iphdr, ttl);
|
||||
IPH_PROTO_SET(iphdr, proto);
|
||||
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
|
||||
IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
IPH_OFFSET_SET(iphdr, htons(IP_DF));
|
||||
IPH_ID_SET(iphdr, htons(ip_id));
|
||||
++ip_id;
|
||||
|
||||
if(ip_addr_isany(src)) {
|
||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
||||
} else {
|
||||
ip_addr_set(&(iphdr->src), src);
|
||||
}
|
||||
|
||||
IPH_CHKSUM_SET(iphdr, 0);
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
} else {
|
||||
iphdr = p->payload;
|
||||
dest = &(iphdr->dest);
|
||||
}
|
||||
|
||||
#ifdef IP_STATS
|
||||
stats.ip.xmit++;
|
||||
#endif /* IP_STATS */
|
||||
DEBUGF(IP_DEBUG, ("ip_output_if: %c%c ", netif->name[0], netif->name[1]));
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
|
||||
return netif->output(netif, p, dest);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_output:
|
||||
*
|
||||
* Simple interface to ip_output_if. It finds the outgoing network
|
||||
* interface and calls upon ip_output_if to do the actual work.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto)
|
||||
{
|
||||
static struct netif *netif;
|
||||
|
||||
|
||||
if((netif = ip_route(dest)) == NULL) {
|
||||
DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.rterr;
|
||||
#endif /* IP_STATS */
|
||||
pbuf_free(p);
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
return ip_output_if(p, src, dest, ttl, proto, netif);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if IP_DEBUG
|
||||
void
|
||||
ip_debug_print(struct pbuf *p)
|
||||
{
|
||||
struct ip_hdr *iphdr = p->payload;
|
||||
u8_t *payload;
|
||||
|
||||
payload = (u8_t *)iphdr + IP_HLEN/sizeof(u8_t);
|
||||
|
||||
DEBUGF(IP_DEBUG, ("IP header:\n"));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("|%2d |%2d | %2d | %4d | (v, hl, tos, len)\n",
|
||||
IPH_V(iphdr),
|
||||
IPH_HL(iphdr),
|
||||
IPH_TOS(iphdr),
|
||||
ntohs(IPH_LEN(iphdr))));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %5d |%d%d%d| %4d | (id, flags, offset)\n",
|
||||
ntohs(IPH_ID(iphdr)),
|
||||
ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
|
||||
ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
|
||||
ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
|
||||
ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %2d | %2d | 0x%04x | (ttl, proto, chksum)\n",
|
||||
IPH_TTL(iphdr),
|
||||
IPH_PROTO(iphdr),
|
||||
ntohs(IPH_CHKSUM(iphdr))));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (src)\n",
|
||||
ntohl(iphdr->src.addr) >> 24 & 0xff,
|
||||
ntohl(iphdr->src.addr) >> 16 & 0xff,
|
||||
ntohl(iphdr->src.addr) >> 8 & 0xff,
|
||||
ntohl(iphdr->src.addr) & 0xff));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (dest)\n",
|
||||
ntohl(iphdr->dest.addr) >> 24 & 0xff,
|
||||
ntohl(iphdr->dest.addr) >> 16 & 0xff,
|
||||
ntohl(iphdr->dest.addr) >> 8 & 0xff,
|
||||
ntohl(iphdr->dest.addr) & 0xff));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
}
|
||||
#endif /* IP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
41
src/core/ipv4/ip_addr.c
Normal file
41
src/core/ipv4/ip_addr.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
struct ip_addr ip_addr_broadcast = {0xffffffff};
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
1
src/core/ipv6/README
Normal file
1
src/core/ipv6/README
Normal file
@@ -0,0 +1 @@
|
||||
IPv6 support in lwIP is very experimental.
|
||||
184
src/core/ipv6/icmp6.c
Normal file
184
src/core/ipv6/icmp6.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/* Some ICMP messages should be passed to the transport protocols. This
|
||||
is not implemented. */
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
icmp_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
unsigned char type;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
struct ip_addr tmpaddr;
|
||||
|
||||
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.recv;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
type = ((char *)p->payload)[0];
|
||||
|
||||
switch(type) {
|
||||
case ICMP6_ECHO:
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
||||
|
||||
if(p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
||||
|
||||
pbuf_free(p);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.lenerr;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
return;
|
||||
}
|
||||
iecho = p->payload;
|
||||
iphdr = (struct ip_hdr *)((char *)p->payload - IP_HLEN);
|
||||
if(inet_chksum_pbuf(p) != 0) {
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%x)\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.chkerr;
|
||||
#endif /* ICMP_STATS */
|
||||
/* return;*/
|
||||
}
|
||||
DEBUGF(ICMP_DEBUG, ("icmp: p->len %d p->tot_len %d\n", p->len, p->tot_len));
|
||||
ip_addr_set(&tmpaddr, &(iphdr->src));
|
||||
ip_addr_set(&(iphdr->src), &(iphdr->dest));
|
||||
ip_addr_set(&(iphdr->dest), &tmpaddr);
|
||||
iecho->type = ICMP6_ER;
|
||||
/* adjust the checksum */
|
||||
if(iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8);
|
||||
}
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%x)\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
/* DEBUGF("icmp: p->len %d p->tot_len %d\n", p->len, p->tot_len);*/
|
||||
ip_output_if(p, &(iphdr->src), IP_HDRINCL,
|
||||
iphdr->hoplim, IP_PROTO_ICMP, inp);
|
||||
break;
|
||||
default:
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type not supported.\n"));
|
||||
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.proterr;
|
||||
++stats.icmp.drop;
|
||||
#endif /* ICMP_STATS */
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
idur->type = (char)ICMP6_DUR;
|
||||
idur->icode = (char)t;
|
||||
|
||||
bcopy(p->payload, (char *)q->payload + 8, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, q->len);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
|
||||
DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
|
||||
|
||||
q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
tehdr = q->payload;
|
||||
tehdr->type = (char)ICMP6_TE;
|
||||
tehdr->icode = (char)t;
|
||||
|
||||
/* copy fields from original packet */
|
||||
bcopy((char *)p->payload, (char *)q->payload + 8, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
#ifdef ICMP_STATS
|
||||
++stats.icmp.xmit;
|
||||
#endif /* ICMP_STATS */
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
386
src/core/ipv6/ip6.c
Normal file
386
src/core/ipv6/ip6.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip.c
|
||||
*
|
||||
* This is the code for the IP layer for IPv6.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include "arch/perf.h"
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_init:
|
||||
*
|
||||
* Initializes the IP layer.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
ip_init(void)
|
||||
{
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_route:
|
||||
*
|
||||
* Finds the appropriate network interface for a given IP address. It searches the
|
||||
* list of network interfaces linearly. A match is found if the masked IP address of
|
||||
* the network interface equals the masked IP address given to the function.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct netif *
|
||||
ip_route(struct ip_addr *dest)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if(ip_addr_maskcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
|
||||
return netif_default;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_forward:
|
||||
*
|
||||
* Forwards an IP packet. It finds an appropriate route for the packet, decrements
|
||||
* the TTL value of the packet, adjusts the checksum and outputs the packet on the
|
||||
* appropriate interface.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
ip_forward(struct pbuf *p, struct ip_hdr *iphdr)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
PERF_START;
|
||||
|
||||
if((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));
|
||||
#if IP_DEBUG
|
||||
ip_addr_debug_print(&(iphdr->dest));
|
||||
#endif /* IP_DEBUG */
|
||||
DEBUGF(IP_DEBUG, ("\n"));
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
/* Decrement TTL and send ICMP if ttl == 0. */
|
||||
if(--iphdr->hoplim == 0) {
|
||||
/* Don't send ICMP messages in response to ICMP messages */
|
||||
if(iphdr->nexthdr != IP_PROTO_ICMP) {
|
||||
icmp_time_exceeded(p, ICMP_TE_TTL);
|
||||
}
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Incremental update of the IP checksum. */
|
||||
/* if (iphdr->chksum >= htons(0xffff - 0x100)) {
|
||||
iphdr->chksum += htons(0x100) + 1;
|
||||
} else {
|
||||
iphdr->chksum += htons(0x100);
|
||||
}*/
|
||||
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));
|
||||
#if IP_DEBUG
|
||||
ip_addr_debug_print(&(iphdr->dest));
|
||||
#endif /* IP_DEBUG */
|
||||
DEBUGF(IP_DEBUG, ("\n"));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.fw;
|
||||
++stats.ip.xmit;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
PERF_STOP("ip_forward");
|
||||
|
||||
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_input:
|
||||
*
|
||||
* This function is called by the network interface device driver when an IP packet is
|
||||
* received. The function does the basic checks of the IP header such as packet size
|
||||
* being at least larger than the header size etc. If the packet was not destined for
|
||||
* us, the packet is forwarded (using ip_forward). The IP checksum is always checked.
|
||||
*
|
||||
* Finally, the packet is sent to the upper layer protocol input function.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
ip_input(struct pbuf *p, struct netif *inp) {
|
||||
struct ip_hdr *iphdr;
|
||||
struct netif *netif;
|
||||
|
||||
|
||||
PERF_START;
|
||||
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.recv;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
/* identify the IP header */
|
||||
iphdr = p->payload;
|
||||
|
||||
|
||||
if(iphdr->v != 6) {
|
||||
DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
pbuf_free(p);
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.err;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
return;
|
||||
}
|
||||
|
||||
/* is this packet for us? */
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
#if IP_DEBUG
|
||||
DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
|
||||
ip_addr_debug_print(&(iphdr->dest));
|
||||
DEBUGF(IP_DEBUG, ("netif->ip_addr "));
|
||||
ip_addr_debug_print(&(netif->ip_addr));
|
||||
DEBUGF(IP_DEBUG, ("\n"));
|
||||
#endif /* IP_DEBUG */
|
||||
if(ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(netif == NULL) {
|
||||
/* packet not for us, route or discard */
|
||||
#ifdef IP_FORWARD
|
||||
ip_forward(p, iphdr);
|
||||
#endif
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));
|
||||
|
||||
/* send to upper layers */
|
||||
#if IP_DEBUG
|
||||
/* DEBUGF("ip_input: \n");
|
||||
ip_debug_print(p);
|
||||
DEBUGF("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len);*/
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
|
||||
pbuf_header(p, -IP_HLEN);
|
||||
|
||||
switch(iphdr->nexthdr) {
|
||||
case IP_PROTO_UDP:
|
||||
udp_input(p);
|
||||
break;
|
||||
case IP_PROTO_TCP:
|
||||
tcp_input(p);
|
||||
break;
|
||||
case IP_PROTO_ICMP:
|
||||
icmp_input(p, inp);
|
||||
break;
|
||||
default:
|
||||
/* send ICMP destination protocol unreachable */
|
||||
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
||||
pbuf_free(p);
|
||||
DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n",
|
||||
iphdr->nexthdr));
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.proterr;
|
||||
++stats.ip.drop;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
}
|
||||
PERF_STOP("ip_input");
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_output_if:
|
||||
*
|
||||
* Sends an IP packet on a network interface. This function constructs the IP header
|
||||
* and calculates the IP header checksum. If the source IP address is NULL,
|
||||
* the IP address of the outgoing network interface is filled in as source address.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl,
|
||||
u8_t proto, struct netif *netif)
|
||||
{
|
||||
struct ip_hdr *iphdr;
|
||||
|
||||
PERF_START;
|
||||
|
||||
printf("len %d tot_len %d\n", p->len, p->tot_len);
|
||||
if(pbuf_header(p, IP_HLEN)) {
|
||||
DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.err;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
return ERR_BUF;
|
||||
}
|
||||
printf("len %d tot_len %d\n", p->len, p->tot_len);
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
|
||||
if(dest != IP_HDRINCL) {
|
||||
printf("!IP_HDRLINCL\n");
|
||||
iphdr->hoplim = ttl;
|
||||
iphdr->nexthdr = proto;
|
||||
iphdr->len = htons(p->tot_len - IP_HLEN);
|
||||
ip_addr_set(&(iphdr->dest), dest);
|
||||
|
||||
iphdr->v = 6;
|
||||
|
||||
if(ip_addr_isany(src)) {
|
||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
||||
} else {
|
||||
ip_addr_set(&(iphdr->src), src);
|
||||
}
|
||||
|
||||
} else {
|
||||
dest = &(iphdr->dest);
|
||||
}
|
||||
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.xmit;
|
||||
#endif /* IP_STATS */
|
||||
|
||||
DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %d)\n", netif->name[0], netif->name[1], p->tot_len));
|
||||
#if IP_DEBUG
|
||||
ip_debug_print(p);
|
||||
#endif /* IP_DEBUG */
|
||||
|
||||
PERF_STOP("ip_output_if");
|
||||
return netif->output(netif, p, dest);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* ip_output:
|
||||
*
|
||||
* Simple interface to ip_output_if. It finds the outgoing network interface and
|
||||
* calls upon ip_output_if to do the actual work.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t ttl, u8_t proto)
|
||||
{
|
||||
struct netif *netif;
|
||||
if((netif = ip_route(dest)) == NULL) {
|
||||
DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%lx\n", dest->addr));
|
||||
#ifdef IP_STATS
|
||||
++stats.ip.rterr;
|
||||
#endif /* IP_STATS */
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
return ip_output_if(p, src, dest, ttl, proto, netif);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if IP_DEBUG
|
||||
void
|
||||
ip_debug_print(struct pbuf *p)
|
||||
{
|
||||
struct ip_hdr *iphdr = p->payload;
|
||||
char *payload;
|
||||
|
||||
payload = (char *)iphdr + IP_HLEN;
|
||||
|
||||
DEBUGF(IP_DEBUG, ("IP header:\n"));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("|%2d | %x%x | %x%x | (v, traffic class, flow label)\n",
|
||||
iphdr->v,
|
||||
iphdr->tclass1, iphdr->tclass2,
|
||||
iphdr->flow1, iphdr->flow2));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %5d | %2d | %2d | (len, nexthdr, hoplim)\n",
|
||||
ntohs(iphdr->len),
|
||||
iphdr->nexthdr,
|
||||
iphdr->hoplim));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
|
||||
ntohl(iphdr->src.addr[0]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->src.addr[0]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
|
||||
ntohl(iphdr->src.addr[1]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->src.addr[1]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
|
||||
ntohl(iphdr->src.addr[2]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->src.addr[2]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (src)\n",
|
||||
ntohl(iphdr->src.addr[3]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->src.addr[3]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
|
||||
ntohl(iphdr->dest.addr[0]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->dest.addr[0]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
|
||||
ntohl(iphdr->dest.addr[1]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->dest.addr[1]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
|
||||
ntohl(iphdr->dest.addr[2]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->dest.addr[2]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("| %4lx | %4lx | (dest)\n",
|
||||
ntohl(iphdr->dest.addr[3]) >> 16 & 0xffff,
|
||||
ntohl(iphdr->dest.addr[3]) & 0xffff));
|
||||
DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
||||
}
|
||||
#endif /* IP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
91
src/core/ipv6/ip6_addr.c
Normal file
91
src/core/ipv6/ip6_addr.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
ip_addr_maskcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask)
|
||||
{
|
||||
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
|
||||
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
|
||||
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
|
||||
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
|
||||
{
|
||||
return(addr1->addr[0] == addr2->addr[0] &&
|
||||
addr1->addr[1] == addr2->addr[1] &&
|
||||
addr1->addr[2] == addr2->addr[2] &&
|
||||
addr1->addr[3] == addr2->addr[3]);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
|
||||
{
|
||||
bcopy(src, dest, sizeof(struct ip_addr));
|
||||
/* dest->addr[0] = src->addr[0];
|
||||
dest->addr[1] = src->addr[1];
|
||||
dest->addr[2] = src->addr[2];
|
||||
dest->addr[3] = src->addr[3];*/
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
int
|
||||
ip_addr_isany(struct ip_addr *addr)
|
||||
{
|
||||
if(addr == NULL) return 1;
|
||||
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/*#if IP_DEBUG*/
|
||||
void
|
||||
ip_addr_debug_print(struct ip_addr *addr)
|
||||
{
|
||||
printf("%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx",
|
||||
ntohl(addr->addr[0]) >> 16 & 0xffff,
|
||||
ntohl(addr->addr[0]) & 0xffff,
|
||||
ntohl(addr->addr[1]) >> 16 & 0xffff,
|
||||
ntohl(addr->addr[1]) & 0xffff,
|
||||
ntohl(addr->addr[2]) >> 16 & 0xffff,
|
||||
ntohl(addr->addr[2]) & 0xffff,
|
||||
ntohl(addr->addr[3]) >> 16 & 0xffff,
|
||||
ntohl(addr->addr[3]) & 0xffff);
|
||||
}
|
||||
/*#endif*/ /* IP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
297
src/core/mem.c
Normal file
297
src/core/mem.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* mem.c
|
||||
*
|
||||
* Memory manager.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
struct mem {
|
||||
mem_size_t next, prev;
|
||||
u8_t used;
|
||||
#if MEM_ALIGNMENT == 2
|
||||
u8_t dummy;
|
||||
#endif /* MEM_ALIGNEMNT == 2 */
|
||||
};
|
||||
|
||||
static struct mem *ram_end;
|
||||
static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];
|
||||
|
||||
#define MIN_SIZE 12
|
||||
#define SIZEOF_STRUCT_MEM MEM_ALIGN_SIZE(sizeof(struct mem))
|
||||
/*#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \
|
||||
(((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \
|
||||
(4 - (sizeof(struct mem) % MEM_ALIGNMENT))))*/
|
||||
|
||||
|
||||
static struct mem *lfree; /* pointer to the lowest free block */
|
||||
|
||||
static sys_sem_t mem_sem;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
plug_holes(struct mem *mem)
|
||||
{
|
||||
struct mem *nmem;
|
||||
struct mem *pmem;
|
||||
|
||||
ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
|
||||
ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
|
||||
ASSERT("plug_holes: mem->used == 0", mem->used == 0);
|
||||
|
||||
/* plug hole forward */
|
||||
ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);
|
||||
|
||||
nmem = (struct mem *)&ram[mem->next];
|
||||
if(mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
|
||||
if(lfree == nmem) {
|
||||
lfree = mem;
|
||||
}
|
||||
mem->next = nmem->next;
|
||||
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
|
||||
}
|
||||
|
||||
/* plug hole backward */
|
||||
pmem = (struct mem *)&ram[mem->prev];
|
||||
if(pmem != mem && pmem->used == 0) {
|
||||
if(lfree == mem) {
|
||||
lfree = pmem;
|
||||
}
|
||||
pmem->next = mem->next;
|
||||
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
|
||||
}
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
mem_init(void)
|
||||
{
|
||||
struct mem *mem;
|
||||
|
||||
bzero(ram, MEM_SIZE);
|
||||
mem = (struct mem *)ram;
|
||||
mem->next = MEM_SIZE;
|
||||
mem->prev = 0;
|
||||
mem->used = 0;
|
||||
ram_end = (struct mem *)&ram[MEM_SIZE];
|
||||
ram_end->used = 1;
|
||||
ram_end->next = MEM_SIZE;
|
||||
ram_end->prev = MEM_SIZE;
|
||||
|
||||
mem_sem = sys_sem_new(1);
|
||||
|
||||
lfree = (struct mem *)ram;
|
||||
|
||||
#ifdef MEM_STATS
|
||||
stats.mem.avail = MEM_SIZE;
|
||||
#endif /* MEM_STATS */
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void *
|
||||
mem_malloc(mem_size_t size)
|
||||
{
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
|
||||
if(size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Expand the size of the allocated memory region so that we can
|
||||
adjust for alignment. */
|
||||
if((size % MEM_ALIGNMENT) != 0) {
|
||||
size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
|
||||
}
|
||||
|
||||
if(size > MEM_SIZE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sys_sem_wait(mem_sem);
|
||||
|
||||
for(ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {
|
||||
mem = (struct mem *)&ram[ptr];
|
||||
if(!mem->used &&
|
||||
mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
|
||||
mem2->prev = ptr;
|
||||
mem2->next = mem->next;
|
||||
mem->next = ptr2;
|
||||
if(mem2->next != MEM_SIZE) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
|
||||
mem2->used = 0;
|
||||
mem->used = 1;
|
||||
#ifdef MEM_STATS
|
||||
stats.mem.used += size;
|
||||
/* if(stats.mem.max < stats.mem.used) {
|
||||
stats.mem.max = stats.mem.used;
|
||||
} */
|
||||
if(stats.mem.max < ptr2) {
|
||||
stats.mem.max = ptr2;
|
||||
}
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
if(mem == lfree) {
|
||||
/* Find next free block after mem */
|
||||
while(lfree->used && lfree != ram_end) {
|
||||
lfree = (struct mem *)&ram[lfree->next];
|
||||
}
|
||||
ASSERT("mem_malloc: !lfree->used", !lfree->used);
|
||||
}
|
||||
sys_sem_signal(mem_sem);
|
||||
ASSERT("mem_malloc: allocated memory not above ram_end.",
|
||||
(u32_t)mem + SIZEOF_STRUCT_MEM + size <= (u32_t)ram_end);
|
||||
ASSERT("mem_malloc: allocated memory properly aligned.",
|
||||
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
||||
}
|
||||
}
|
||||
DEBUGF(MEM_DEBUG, ("mem_malloc: could not allocate %d bytes\n", (int)size));
|
||||
#ifdef MEM_STATS
|
||||
++stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
sys_sem_signal(mem_sem);
|
||||
return NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
mem_free(void *rmem)
|
||||
{
|
||||
struct mem *mem;
|
||||
|
||||
if(rmem == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
sys_sem_wait(mem_sem);
|
||||
|
||||
ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
|
||||
if((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
DEBUGF(MEM_DEBUG, ("mem_free: illegal memory\n"));
|
||||
#ifdef MEM_STATS
|
||||
++stats.mem.err;
|
||||
#endif /* MEM_STATS */
|
||||
return;
|
||||
}
|
||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
|
||||
ASSERT("mem_free: mem->used", mem->used);
|
||||
|
||||
mem->used = 0;
|
||||
|
||||
if(mem < lfree) {
|
||||
lfree = mem;
|
||||
}
|
||||
|
||||
#ifdef MEM_STATS
|
||||
stats.mem.used -= mem->next - ((u8_t *)mem - ram) - SIZEOF_STRUCT_MEM;
|
||||
|
||||
#endif /* MEM_STATS */
|
||||
plug_holes(mem);
|
||||
sys_sem_signal(mem_sem);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void *
|
||||
mem_reallocm(void *rmem, mem_size_t newsize)
|
||||
{
|
||||
void *nmem;
|
||||
nmem = mem_malloc(newsize);
|
||||
if(nmem == NULL) {
|
||||
return mem_realloc(rmem, newsize);
|
||||
}
|
||||
bcopy(rmem, nmem, newsize);
|
||||
mem_free(rmem);
|
||||
return nmem;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void *
|
||||
mem_realloc(void *rmem, mem_size_t newsize)
|
||||
{
|
||||
mem_size_t size;
|
||||
mem_size_t ptr, ptr2;
|
||||
struct mem *mem, *mem2;
|
||||
|
||||
sys_sem_wait(mem_sem);
|
||||
|
||||
ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
||||
(u8_t *)rmem < (u8_t *)ram_end);
|
||||
|
||||
if((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
||||
DEBUGF(MEM_DEBUG, ("mem_free: illegal memory\n"));
|
||||
return rmem;
|
||||
}
|
||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
||||
|
||||
ptr = (u8_t *)mem - ram;
|
||||
|
||||
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
|
||||
#ifdef MEM_STATS
|
||||
stats.mem.used -= (size - newsize);
|
||||
#endif /* MEM_STATS */
|
||||
|
||||
if(newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {
|
||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
||||
mem2 = (struct mem *)&ram[ptr2];
|
||||
mem2->used = 0;
|
||||
mem2->next = mem->next;
|
||||
mem2->prev = ptr;
|
||||
mem->next = ptr2;
|
||||
if(mem2->next != MEM_SIZE) {
|
||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
||||
}
|
||||
|
||||
plug_holes(mem2);
|
||||
}
|
||||
sys_sem_signal(mem_sem);
|
||||
return rmem;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
271
src/core/memp.c
Normal file
271
src/core/memp.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwipopts.h"
|
||||
|
||||
#include "lwip/memp.h"
|
||||
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/api_msg.h"
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
struct memp {
|
||||
struct memp *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct memp *memp_tab[MEMP_MAX];
|
||||
|
||||
static const u16_t memp_sizes[MEMP_MAX] = {
|
||||
sizeof(struct pbuf),
|
||||
sizeof(struct udp_pcb),
|
||||
sizeof(struct tcp_pcb),
|
||||
sizeof(struct tcp_pcb_listen),
|
||||
sizeof(struct tcp_seg),
|
||||
sizeof(struct netbuf),
|
||||
sizeof(struct netconn),
|
||||
sizeof(struct api_msg),
|
||||
sizeof(struct tcpip_msg),
|
||||
sizeof(struct sys_timeout)
|
||||
};
|
||||
|
||||
static const u16_t memp_num[MEMP_MAX] = {
|
||||
MEMP_NUM_PBUF,
|
||||
MEMP_NUM_UDP_PCB,
|
||||
MEMP_NUM_TCP_PCB,
|
||||
MEMP_NUM_TCP_PCB_LISTEN,
|
||||
MEMP_NUM_TCP_SEG,
|
||||
MEMP_NUM_NETBUF,
|
||||
MEMP_NUM_NETCONN,
|
||||
MEMP_NUM_API_MSG,
|
||||
MEMP_NUM_TCPIP_MSG,
|
||||
MEMP_NUM_SYS_TIMEOUT
|
||||
};
|
||||
|
||||
static u8_t memp_memory[(MEMP_NUM_PBUF *
|
||||
MEM_ALIGN_SIZE(sizeof(struct pbuf) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_UDP_PCB *
|
||||
MEM_ALIGN_SIZE(sizeof(struct udp_pcb) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_TCP_PCB *
|
||||
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_TCP_PCB_LISTEN *
|
||||
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_TCP_SEG *
|
||||
MEM_ALIGN_SIZE(sizeof(struct tcp_seg) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_NETBUF *
|
||||
MEM_ALIGN_SIZE(sizeof(struct netbuf) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_NETCONN *
|
||||
MEM_ALIGN_SIZE(sizeof(struct netconn) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_API_MSG *
|
||||
MEM_ALIGN_SIZE(sizeof(struct api_msg) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_TCPIP_MSG *
|
||||
MEM_ALIGN_SIZE(sizeof(struct tcpip_msg) +
|
||||
sizeof(struct memp)) +
|
||||
MEMP_NUM_SYS_TIMEOUT *
|
||||
MEM_ALIGN_SIZE(sizeof(struct sys_timeout) +
|
||||
sizeof(struct memp)))];
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static sys_sem_t mutex;
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#ifdef LWIP_DEBUG
|
||||
static int
|
||||
memp_sanity(void)
|
||||
{
|
||||
int i, c;
|
||||
struct memp *m, *n;
|
||||
|
||||
for(i = 0; i < MEMP_MAX; i++) {
|
||||
for(m = memp_tab[i]; m != NULL; m = m->next) {
|
||||
c = 1;
|
||||
for(n = memp_tab[i]; n != NULL; n = n->next) {
|
||||
if(n == m) {
|
||||
--c;
|
||||
}
|
||||
if(c < 0)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
memp_init(void)
|
||||
{
|
||||
struct memp *m, *memp;
|
||||
u16_t i, j;
|
||||
u16_t size;
|
||||
|
||||
#ifdef MEMP_STATS
|
||||
for(i = 0; i < MEMP_MAX; ++i) {
|
||||
stats.memp[i].used = stats.memp[i].max =
|
||||
stats.memp[i].err = stats.memp[i].reclaimed = 0;
|
||||
stats.memp[i].avail = memp_num[i];
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
|
||||
memp = (struct memp *)&memp_memory[0];
|
||||
for(i = 0; i < MEMP_MAX; ++i) {
|
||||
size = MEM_ALIGN_SIZE(memp_sizes[i] + sizeof(struct memp));
|
||||
if(memp_num[i] > 0) {
|
||||
memp_tab[i] = memp;
|
||||
m = memp;
|
||||
|
||||
for(j = 0; j < memp_num[i]; ++j) {
|
||||
m->next = (struct memp *)MEM_ALIGN((u8_t *)m + size);
|
||||
memp = m;
|
||||
m = m->next;
|
||||
}
|
||||
memp->next = NULL;
|
||||
memp = m;
|
||||
} else {
|
||||
memp_tab[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex = sys_sem_new(1);
|
||||
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void *
|
||||
memp_malloc(memp_t type)
|
||||
{
|
||||
struct memp *memp;
|
||||
|
||||
ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);
|
||||
|
||||
memp = memp_tab[type];
|
||||
|
||||
if(memp != NULL) {
|
||||
memp_tab[type] = memp->next;
|
||||
memp->next = NULL;
|
||||
#ifdef MEMP_STATS
|
||||
++stats.memp[type].used;
|
||||
if(stats.memp[type].used > stats.memp[type].max) {
|
||||
stats.memp[type].max = stats.memp[type].used;
|
||||
}
|
||||
#endif /* MEMP_STATS */
|
||||
ASSERT("memp_malloc: memp properly aligned",
|
||||
((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % MEM_ALIGNMENT) == 0);
|
||||
|
||||
return MEM_ALIGN((u8_t *)memp + sizeof(struct memp));
|
||||
} else {
|
||||
DEBUGF(MEMP_DEBUG, ("memp_malloc: out of memory in pool %d\n", type));
|
||||
#ifdef MEMP_STATS
|
||||
++stats.memp[type].err;
|
||||
#endif /* MEMP_STATS */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void *
|
||||
memp_mallocp(memp_t type)
|
||||
{
|
||||
void *mem;
|
||||
sys_sem_wait(mutex);
|
||||
mem = memp_malloc(type);
|
||||
sys_sem_signal(mutex);
|
||||
return mem;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if 0
|
||||
void *
|
||||
memp_realloc(memp_t fromtype, memp_t totype, void *mem)
|
||||
{
|
||||
void *rmem;
|
||||
u16_t size;
|
||||
|
||||
if(mem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rmem = memp_malloc(totype);
|
||||
if(rmem != NULL) {
|
||||
size = memp_sizes[totype];
|
||||
if(memp_sizes[fromtype] < size) {
|
||||
size = memp_sizes[fromtype];
|
||||
}
|
||||
bcopy(mem, rmem, size);
|
||||
memp_free(fromtype, mem);
|
||||
}
|
||||
return rmem;
|
||||
}
|
||||
#endif /* 0 */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
memp_free(memp_t type, void *mem)
|
||||
{
|
||||
struct memp *memp;
|
||||
|
||||
if(mem == NULL) {
|
||||
return;
|
||||
}
|
||||
memp = (struct memp *)((u8_t *)mem - sizeof(struct memp));
|
||||
|
||||
#ifdef MEMP_STATS
|
||||
stats.memp[type].used--;
|
||||
#endif /* MEMP_STATS */
|
||||
|
||||
memp->next = memp_tab[type];
|
||||
memp_tab[type] = memp;
|
||||
|
||||
ASSERT("memp sanity", memp_sanity());
|
||||
|
||||
return;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
memp_freep(memp_t type, void *mem)
|
||||
{
|
||||
sys_sem_wait(mutex);
|
||||
memp_free(type, mem);
|
||||
sys_sem_signal(mutex);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
142
src/core/netif.c
Normal file
142
src/core/netif.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
struct netif *netif_list = NULL;
|
||||
struct netif *netif_default = NULL;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct netif *
|
||||
netif_add(struct ip_addr *ipaddr, struct ip_addr *netmask,
|
||||
struct ip_addr *gw,
|
||||
void (* init)(struct netif *netif),
|
||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
||||
{
|
||||
struct netif *netif;
|
||||
static int netifnum = 0;
|
||||
|
||||
netif = mem_malloc(sizeof(struct netif));
|
||||
|
||||
if(netif == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
netif->num = netifnum++;
|
||||
netif->input = input;
|
||||
ip_addr_set(&(netif->ip_addr), ipaddr);
|
||||
ip_addr_set(&(netif->netmask), netmask);
|
||||
ip_addr_set(&(netif->gw), gw);
|
||||
|
||||
init(netif);
|
||||
|
||||
netif->next = netif_list;
|
||||
netif_list = netif;
|
||||
#if NETIF_DEBUG
|
||||
DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
|
||||
netif->name[0], netif->name[1]));
|
||||
ip_addr_debug_print(ipaddr);
|
||||
DEBUGF(NETIF_DEBUG, (" netmask "));
|
||||
ip_addr_debug_print(netmask);
|
||||
DEBUGF(NETIF_DEBUG, (" gw "));
|
||||
ip_addr_debug_print(gw);
|
||||
DEBUGF(NETIF_DEBUG, ("\n"));
|
||||
#endif /* NETIF_DEBUG */
|
||||
return netif;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct netif *
|
||||
netif_find(char *name)
|
||||
{
|
||||
struct netif *netif;
|
||||
u8_t num;
|
||||
|
||||
if(name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
num = name[2] - '0';
|
||||
|
||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if(num == netif->num &&
|
||||
name[0] == netif->name[0] &&
|
||||
name[1] == netif->name[1]) {
|
||||
DEBUGF(NETIF_DEBUG, ("netif_find: found %s\n", name));
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %s\n", name));
|
||||
return NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
||||
{
|
||||
ip_addr_set(&(netif->ip_addr), ipaddr);
|
||||
DEBUGF(NETIF_DEBUG, ("netif: setting IP address of interface %c%c to %d.%d.%d.%d\n",
|
||||
netif->name[0], netif->name[1],
|
||||
(u8_t)(ntohl(ipaddr->addr) >> 24 & 0xff),
|
||||
(u8_t)(ntohl(ipaddr->addr) >> 16 & 0xff),
|
||||
(u8_t)(ntohl(ipaddr->addr) >> 8 & 0xff),
|
||||
(u8_t)(ntohl(ipaddr->addr) & 0xff)));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
netif_set_gw(struct netif *netif, struct ip_addr *gw)
|
||||
{
|
||||
ip_addr_set(&(netif->gw), gw);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
|
||||
{
|
||||
ip_addr_set(&(netif->netmask), netmask);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
netif_set_default(struct netif *netif)
|
||||
{
|
||||
netif_default = netif;
|
||||
DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
|
||||
netif->name[0], netif->name[1]));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
netif_init(void)
|
||||
{
|
||||
netif_list = netif_default = NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
597
src/core/pbuf.c
Normal file
597
src/core/pbuf.c
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf.c
|
||||
*
|
||||
* Functions for the manipulation of pbufs. The pbufs holds all packets in the
|
||||
* system.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "arch/perf.h"
|
||||
|
||||
static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];
|
||||
static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
|
||||
static sys_sem_t pbuf_pool_free_sem;
|
||||
static struct pbuf *pbuf_pool = NULL;
|
||||
static struct pbuf *pbuf_pool_alloc_cache = NULL;
|
||||
static struct pbuf *pbuf_pool_free_cache = NULL;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_init():
|
||||
*
|
||||
* Initializes the pbuf module. A large part of memory is allocated
|
||||
* for holding the pool of pbufs. The size of the individual pbufs in
|
||||
* the pool is given by the size parameter, and the number of pbufs in
|
||||
* the pool by the num parameter.
|
||||
*
|
||||
* After the memory has been allocated, the pbufs are set up. The
|
||||
* ->next pointer in each pbuf is set up to point to the next pbuf in
|
||||
* the pool.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
pbuf_init(void)
|
||||
{
|
||||
struct pbuf *p, *q;
|
||||
u16_t i;
|
||||
|
||||
pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
|
||||
ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT == 0);
|
||||
|
||||
#ifdef PBUF_STATS
|
||||
stats.pbuf.avail = PBUF_POOL_SIZE;
|
||||
#endif /* PBUF_STATS */
|
||||
|
||||
/* Set up ->next pointers to link the pbufs of the pool together. */
|
||||
p = pbuf_pool;
|
||||
|
||||
for(i = 0; i < PBUF_POOL_SIZE; ++i) {
|
||||
p->next = (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + sizeof(struct pbuf));
|
||||
p->len = p->tot_len = PBUF_POOL_BUFSIZE;
|
||||
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
|
||||
q = p;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
/* The ->next pointer of last pbuf is NULL to indicate that there
|
||||
are no more pbufs in the pool. */
|
||||
q->next = NULL;
|
||||
|
||||
pbuf_pool_alloc_lock = 0;
|
||||
pbuf_pool_free_lock = 0;
|
||||
pbuf_pool_free_sem = sys_sem_new(1);
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* The following two functions are only called from pbuf_alloc(). */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static struct pbuf *
|
||||
pbuf_pool_alloc(void)
|
||||
{
|
||||
struct pbuf *p = NULL;
|
||||
|
||||
/* First, see if there are pbufs in the cache. */
|
||||
if(pbuf_pool_alloc_cache) {
|
||||
p = pbuf_pool_alloc_cache;
|
||||
if(p) {
|
||||
pbuf_pool_alloc_cache = p->next;
|
||||
}
|
||||
} else {
|
||||
/* Next, check the actual pbuf pool, but if the pool is locked, we
|
||||
pretend to be out of buffers and return NULL. */
|
||||
if(pbuf_pool_free_lock) {
|
||||
#ifdef PBUF_STATS
|
||||
++stats.pbuf.alloc_locked;
|
||||
#endif /* PBUF_STATS */
|
||||
return NULL;
|
||||
}
|
||||
pbuf_pool_alloc_lock = 1;
|
||||
if(!pbuf_pool_free_lock) {
|
||||
p = pbuf_pool;
|
||||
if(p) {
|
||||
pbuf_pool = p->next;
|
||||
}
|
||||
#ifdef PBUF_STATS
|
||||
} else {
|
||||
++stats.pbuf.alloc_locked;
|
||||
#endif /* PBUF_STATS */
|
||||
}
|
||||
pbuf_pool_alloc_lock = 0;
|
||||
}
|
||||
|
||||
#ifdef PBUF_STATS
|
||||
if(p != NULL) {
|
||||
++stats.pbuf.used;
|
||||
if(stats.pbuf.used > stats.pbuf.max) {
|
||||
stats.pbuf.max = stats.pbuf.used;
|
||||
}
|
||||
}
|
||||
#endif /* PBUF_STATS */
|
||||
|
||||
return p;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
pbuf_pool_free(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
|
||||
#ifdef PBUF_STATS
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
--stats.pbuf.used;
|
||||
}
|
||||
#endif /* PBUF_STATS */
|
||||
|
||||
if(pbuf_pool_alloc_cache == NULL) {
|
||||
pbuf_pool_alloc_cache = p;
|
||||
} else {
|
||||
for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next);
|
||||
q->next = p;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_alloc():
|
||||
*
|
||||
* Allocates a pbuf at protocol layer l. The actual memory allocated
|
||||
* for the pbuf is determined by the layer at which the pbuf is
|
||||
* allocated and the requested size (from the size parameter). The
|
||||
* flag parameter decides how and where the pbuf should be allocated
|
||||
* as follows:
|
||||
*
|
||||
* * PBUF_RAM: buffer memory for pbuf is allocated as one large
|
||||
* chunk. This includes protocol headers as well.
|
||||
* * RBUF_ROM: no buffer memory is allocated for the pbuf, even for
|
||||
* protocol headers. Additional headers must be prepended
|
||||
* by allocating another pbuf and chain in to the front of
|
||||
* the ROM pbuf.
|
||||
* * PBUF_ROOL: the pbuf is allocated as a pbuf chain, with pbufs from
|
||||
* the pbuf pool that is allocated during pbuf_init().
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct pbuf *
|
||||
pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
|
||||
{
|
||||
struct pbuf *p, *q, *r;
|
||||
u16_t offset;
|
||||
s32_t rsize;
|
||||
|
||||
offset = 0;
|
||||
switch(l) {
|
||||
case PBUF_TRANSPORT:
|
||||
offset += PBUF_TRANSPORT_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
case PBUF_IP:
|
||||
offset += PBUF_IP_HLEN;
|
||||
offset += PBUF_LINK_HLEN;
|
||||
/* FALLTHROUGH */
|
||||
case PBUF_LINK:
|
||||
break;
|
||||
case PBUF_RAW:
|
||||
break;
|
||||
default:
|
||||
ASSERT("pbuf_alloc: bad pbuf layer", 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(flag) {
|
||||
case PBUF_POOL:
|
||||
/* Allocate head of pbuf chain into p. */
|
||||
p = pbuf_pool_alloc();
|
||||
if(p == NULL) {
|
||||
#ifdef PBUF_STATS
|
||||
++stats.pbuf.err;
|
||||
#endif /* PBUF_STATS */
|
||||
return NULL;
|
||||
}
|
||||
p->next = NULL;
|
||||
|
||||
/* Set the payload pointer so that it points offset bytes into
|
||||
pbuf data memory. */
|
||||
p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
|
||||
|
||||
/* The total length of the pbuf is the requested size. */
|
||||
p->tot_len = size;
|
||||
|
||||
/* Set the length of the first pbuf is the chain. */
|
||||
p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size;
|
||||
|
||||
p->flags = PBUF_FLAG_POOL;
|
||||
|
||||
/* Allocate the tail of the pbuf chain. */
|
||||
r = p;
|
||||
rsize = size - p->len;
|
||||
while(rsize > 0) {
|
||||
q = pbuf_pool_alloc();
|
||||
if(q == NULL) {
|
||||
DEBUGF(PBUF_DEBUG, ("pbuf_alloc: Out of pbufs in pool,\n"));
|
||||
#ifdef PBUF_STATS
|
||||
++stats.pbuf.err;
|
||||
#endif /* PBUF_STATS */
|
||||
pbuf_pool_free(p);
|
||||
return NULL;
|
||||
}
|
||||
q->next = NULL;
|
||||
r->next = q;
|
||||
q->len = rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize;
|
||||
q->flags = PBUF_FLAG_POOL;
|
||||
q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
|
||||
r = q;
|
||||
q->ref = 1;
|
||||
q = q->next;
|
||||
rsize -= PBUF_POOL_BUFSIZE;
|
||||
}
|
||||
r->next = NULL;
|
||||
|
||||
ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
break;
|
||||
case PBUF_RAM:
|
||||
/* If pbuf is to be allocated in RAM, allocate memory for it. */
|
||||
p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset));
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* Set up internal structure of the pbuf. */
|
||||
p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset));
|
||||
p->len = p->tot_len = size;
|
||||
p->next = NULL;
|
||||
p->flags = PBUF_FLAG_RAM;
|
||||
|
||||
ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
||||
((u32_t)p->payload % MEM_ALIGNMENT) == 0);
|
||||
break;
|
||||
case PBUF_ROM:
|
||||
/* If the pbuf should point to ROM, we only need to allocate
|
||||
memory for the pbuf structure. */
|
||||
p = memp_mallocp(MEMP_PBUF);
|
||||
if(p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
p->payload = NULL;
|
||||
p->len = p->tot_len = size;
|
||||
p->next = NULL;
|
||||
p->flags = PBUF_FLAG_ROM;
|
||||
break;
|
||||
default:
|
||||
ASSERT("pbuf_alloc: erroneous flag", 0);
|
||||
return NULL;
|
||||
}
|
||||
p->ref = 1;
|
||||
return p;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_refresh():
|
||||
*
|
||||
* Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool
|
||||
* list (if possible).
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
pbuf_refresh(void)
|
||||
{
|
||||
struct pbuf *p;
|
||||
|
||||
sys_sem_wait(pbuf_pool_free_sem);
|
||||
|
||||
if(pbuf_pool_free_cache != NULL) {
|
||||
pbuf_pool_free_lock = 1;
|
||||
if(!pbuf_pool_alloc_lock) {
|
||||
if(pbuf_pool == NULL) {
|
||||
pbuf_pool = pbuf_pool_free_cache;
|
||||
} else {
|
||||
for(p = pbuf_pool; p->next != NULL; p = p->next);
|
||||
p->next = pbuf_pool_free_cache;
|
||||
}
|
||||
pbuf_pool_free_cache = NULL;
|
||||
#ifdef PBUF_STATS
|
||||
} else {
|
||||
++stats.pbuf.refresh_locked;
|
||||
#endif /* PBUF_STATS */
|
||||
}
|
||||
|
||||
pbuf_pool_free_lock = 0;
|
||||
}
|
||||
|
||||
sys_sem_signal(pbuf_pool_free_sem);
|
||||
}
|
||||
#define PBUF_POOL_FREE(p) do { \
|
||||
sys_sem_wait(pbuf_pool_free_sem); \
|
||||
p->next = pbuf_pool_free_cache; \
|
||||
pbuf_pool_free_cache = p; \
|
||||
sys_sem_signal(pbuf_pool_free_sem); \
|
||||
} while(0)
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_realloc:
|
||||
*
|
||||
* Reallocates the memory for a pbuf. If the pbuf is in ROM, this as
|
||||
* simple as to adjust the ->tot_len and ->len fields. If the pbuf is
|
||||
* a pbuf chain, as it might be with both pbufs in dynamically
|
||||
* allocated RAM and for pbufs from the pbuf pool, we have to step
|
||||
* through the chain until we find the new endpoint in the pbuf chain.
|
||||
* Then the pbuf that is right on the endpoint is resized and any
|
||||
* further pbufs on the chain are deallocated.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
pbuf_realloc(struct pbuf *p, u16_t size)
|
||||
{
|
||||
struct pbuf *q, *r;
|
||||
u16_t rsize;
|
||||
|
||||
ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||
|
||||
p->flags == PBUF_FLAG_ROM ||
|
||||
p->flags == PBUF_FLAG_RAM);
|
||||
|
||||
|
||||
if(p->tot_len <= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(p->flags) {
|
||||
case PBUF_FLAG_POOL:
|
||||
/* First, step over any pbufs that should still be in the chain. */
|
||||
rsize = size;
|
||||
q = p;
|
||||
while(rsize > q->len) {
|
||||
rsize -= q->len;
|
||||
q = q->next;
|
||||
}
|
||||
/* Adjust the length of the pbuf that will be halved. */
|
||||
q->len = rsize;
|
||||
|
||||
/* And deallocate any left over pbufs. */
|
||||
r = q->next;
|
||||
q->next = NULL;
|
||||
q = r;
|
||||
while(q != NULL) {
|
||||
r = q->next;
|
||||
PBUF_POOL_FREE(q);
|
||||
#ifdef PBUF_STATS
|
||||
--stats.pbuf.used;
|
||||
#endif /* PBUF_STATS */
|
||||
q = r;
|
||||
}
|
||||
break;
|
||||
case PBUF_FLAG_ROM:
|
||||
p->len = size;
|
||||
break;
|
||||
case PBUF_FLAG_RAM:
|
||||
/* First, step over the pbufs that should still be in the chain. */
|
||||
rsize = size;
|
||||
q = p;
|
||||
while(rsize > q->len) {
|
||||
rsize -= q->len;
|
||||
q = q->next;
|
||||
}
|
||||
if(q->flags == PBUF_FLAG_RAM) {
|
||||
/* Reallocate and adjust the length of the pbuf that will be halved. */
|
||||
mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rsize);
|
||||
}
|
||||
|
||||
q->len = rsize;
|
||||
|
||||
/* And deallocate any left over pbufs. */
|
||||
r = q->next;
|
||||
q->next = NULL;
|
||||
q = r;
|
||||
while(q != NULL) {
|
||||
r = q->next;
|
||||
pbuf_free(q);
|
||||
q = r;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p->tot_len = size;
|
||||
|
||||
pbuf_refresh();
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_header():
|
||||
*
|
||||
* Adjusts the ->payload pointer so that space for a header appears in
|
||||
* the pbuf. Also, the ->tot_len and ->len fields are adjusted.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u8_t
|
||||
pbuf_header(struct pbuf *p, s16_t header_size)
|
||||
{
|
||||
void *payload;
|
||||
|
||||
if(p->flags & PBUF_FLAG_ROM) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
payload = p->payload;
|
||||
p->payload = (u8_t *)p->payload - header_size/sizeof(u8_t);
|
||||
|
||||
DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, p->payload, header_size));
|
||||
|
||||
if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
|
||||
DEBUGF(PBUF_DEBUG, ("pbuf_header: failed %p %p\n",
|
||||
(u8_t *)p->payload,
|
||||
(u8_t *)p + sizeof(struct pbuf)));
|
||||
p->payload = payload;
|
||||
return 1;
|
||||
}
|
||||
p->len += header_size;
|
||||
p->tot_len += header_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_free():
|
||||
*
|
||||
* Decrements the reference count and deallocates the pbuf if the
|
||||
* reference count is zero. If the pbuf is a chain all pbufs in the
|
||||
* chain are deallocated.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u8_t
|
||||
pbuf_free(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
u8_t count = 0;
|
||||
|
||||
if(p == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PERF_START;
|
||||
|
||||
ASSERT("pbuf_free: sane flags", p->flags == PBUF_FLAG_POOL ||
|
||||
p->flags == PBUF_FLAG_ROM ||
|
||||
p->flags == PBUF_FLAG_RAM);
|
||||
|
||||
ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
|
||||
|
||||
/* Decrement reference count. */
|
||||
p->ref--;
|
||||
|
||||
q = NULL;
|
||||
/* If reference count == 0, actually deallocate pbuf. */
|
||||
if(p->ref == 0) {
|
||||
|
||||
while(p != NULL) {
|
||||
/* Check if this is a pbuf from the pool. */
|
||||
if(p->flags == PBUF_FLAG_POOL) {
|
||||
p->len = p->tot_len = PBUF_POOL_BUFSIZE;
|
||||
p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
|
||||
q = p->next;
|
||||
PBUF_POOL_FREE(p);
|
||||
#ifdef PBUF_STATS
|
||||
--stats.pbuf.used;
|
||||
#endif /* PBUF_STATS */
|
||||
} else if(p->flags == PBUF_FLAG_ROM) {
|
||||
q = p->next;
|
||||
memp_freep(MEMP_PBUF, p);
|
||||
} else {
|
||||
q = p->next;
|
||||
mem_free(p);
|
||||
}
|
||||
p = q;
|
||||
++count;
|
||||
}
|
||||
pbuf_refresh();
|
||||
}
|
||||
|
||||
PERF_STOP("pbuf_free");
|
||||
|
||||
return count;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_clen():
|
||||
*
|
||||
* Returns the length of the pbuf chain.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
u8_t
|
||||
pbuf_clen(struct pbuf *p)
|
||||
{
|
||||
u8_t len;
|
||||
|
||||
if(p == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(len = 0; p != NULL; p = p->next) {
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_ref():
|
||||
*
|
||||
* Increments the reference count of the pbuf.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
pbuf_ref(struct pbuf *p)
|
||||
{
|
||||
if(p == NULL) {
|
||||
return;
|
||||
}
|
||||
++(p->ref);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_chain():
|
||||
*
|
||||
* Chains the two pbufs h and t together. The ->tot_len field of the
|
||||
* first pbuf (h) is adjusted.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
pbuf_chain(struct pbuf *h, struct pbuf *t)
|
||||
{
|
||||
struct pbuf *p;
|
||||
|
||||
if(t == NULL) {
|
||||
return;
|
||||
}
|
||||
for(p = h; p->next != NULL; p = p->next);
|
||||
p->next = t;
|
||||
h->tot_len += t->tot_len;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* pbuf_dechain():
|
||||
*
|
||||
* Adjusts the ->tot_len field of the pbuf and returns the tail (if
|
||||
* any) of the pbuf chain.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct pbuf *
|
||||
pbuf_dechain(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
|
||||
q = p->next;
|
||||
if (q != NULL) {
|
||||
q->tot_len = p->tot_len - p->len;
|
||||
}
|
||||
p->tot_len = p->len;
|
||||
p->next = NULL;
|
||||
return q;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
54
src/core/stats.c
Normal file
54
src/core/stats.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/mem.h"
|
||||
|
||||
|
||||
#ifdef STATS
|
||||
struct stats_ stats;
|
||||
#endif /* STATS */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
stats_init(void)
|
||||
{
|
||||
#ifdef STATS
|
||||
bzero(&stats, sizeof(struct stats_));
|
||||
#endif /* STATS */
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
187
src/core/sys.c
Normal file
187
src/core/sys.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
|
||||
#ifndef NO_SYS
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
||||
{
|
||||
u16_t time;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeout *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
void *arg;
|
||||
|
||||
|
||||
again:
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if(timeouts->next == NULL) {
|
||||
sys_arch_mbox_fetch(mbox, msg, 0);
|
||||
} else {
|
||||
if(timeouts->next->time > 0) {
|
||||
time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
|
||||
} else {
|
||||
time = 0;
|
||||
}
|
||||
|
||||
if(time == 0) {
|
||||
/* If time == 0, a timeout occured before a message could be
|
||||
fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = timeouts->next;
|
||||
timeouts->next = tmptimeout->next;
|
||||
h = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
h(arg);
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time > 0, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
microseconds we waited for the message. */
|
||||
if(time <= timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
sys_sem_wait(sys_sem_t sem)
|
||||
{
|
||||
u16_t time;
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeout *tmptimeout;
|
||||
sys_timeout_handler h;
|
||||
void *arg;
|
||||
|
||||
/* while(sys_arch_sem_wait(sem, 1000) == 0);
|
||||
return;*/
|
||||
|
||||
again:
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if(timeouts->next == NULL) {
|
||||
sys_arch_sem_wait(sem, 0);
|
||||
} else {
|
||||
if(timeouts->next->time > 0) {
|
||||
time = sys_arch_sem_wait(sem, timeouts->next->time);
|
||||
} else {
|
||||
time = 0;
|
||||
}
|
||||
|
||||
if(time == 0) {
|
||||
/* If time == 0, a timeout occured before a message could be
|
||||
fetched. We should now call the timeout handler and
|
||||
deallocate the memory allocated for the timeout. */
|
||||
tmptimeout = timeouts->next;
|
||||
timeouts->next = tmptimeout->next;
|
||||
h = tmptimeout->h;
|
||||
arg = tmptimeout->arg;
|
||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
||||
h(arg);
|
||||
|
||||
|
||||
/* We try again to fetch a message from the mbox. */
|
||||
goto again;
|
||||
} else {
|
||||
/* If time > 0, a message was received before the timeout
|
||||
occured. The time variable is set to the number of
|
||||
microseconds we waited for the message. */
|
||||
if(time <= timeouts->next->time) {
|
||||
timeouts->next->time -= time;
|
||||
} else {
|
||||
timeouts->next->time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
sys_timeout(u16_t msecs, sys_timeout_handler h, void *arg)
|
||||
{
|
||||
struct sys_timeouts *timeouts;
|
||||
struct sys_timeout *timeout, *t;
|
||||
|
||||
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
|
||||
if(timeout == NULL) {
|
||||
return;
|
||||
}
|
||||
timeout->next = NULL;
|
||||
timeout->h = h;
|
||||
timeout->arg = arg;
|
||||
timeout->time = msecs;
|
||||
|
||||
timeouts = sys_arch_timeouts();
|
||||
|
||||
if(timeouts->next == NULL) {
|
||||
timeouts->next = timeout;
|
||||
return;
|
||||
}
|
||||
|
||||
if(timeouts->next->time > msecs) {
|
||||
timeouts->next->time -= msecs;
|
||||
timeout->next = timeouts->next;
|
||||
timeouts->next = timeout;
|
||||
} else {
|
||||
for(t = timeouts->next; t != NULL; t = t->next) {
|
||||
timeout->time -= t->time;
|
||||
if(t->next == NULL ||
|
||||
t->next->time > timeout->time) {
|
||||
if(t->next != NULL) {
|
||||
t->next->time -= timeout->time;
|
||||
}
|
||||
timeout->next = t->next;
|
||||
t->next = timeout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#endif /* NO_SYS */
|
||||
1158
src/core/tcp.c
Normal file
1158
src/core/tcp.c
Normal file
File diff suppressed because it is too large
Load Diff
1122
src/core/tcp_input.c
Normal file
1122
src/core/tcp_input.c
Normal file
File diff suppressed because it is too large
Load Diff
589
src/core/tcp_output.c
Normal file
589
src/core/tcp_output.c
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* tcp_output.c
|
||||
*
|
||||
* The output functions of TCP.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "arch/lib.h"
|
||||
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
|
||||
#define MIN(x,y) (x) < (y)? (x): (y)
|
||||
|
||||
|
||||
|
||||
/* Forward declarations.*/
|
||||
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
|
||||
{
|
||||
return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
|
||||
{
|
||||
if(pcb->state == SYN_SENT ||
|
||||
pcb->state == SYN_RCVD ||
|
||||
pcb->state == ESTABLISHED ||
|
||||
pcb->state == CLOSE_WAIT) {
|
||||
if(len > 0) {
|
||||
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
|
||||
}
|
||||
return ERR_OK;
|
||||
} else {
|
||||
return ERR_CONN;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
|
||||
u8_t flags, u8_t copy,
|
||||
u8_t *optdata, u8_t optlen)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_seg *seg, *useg, *queue;
|
||||
u32_t left, seqno;
|
||||
u16_t seglen;
|
||||
void *ptr;
|
||||
u8_t queuelen;
|
||||
|
||||
left = len;
|
||||
ptr = arg;
|
||||
|
||||
if(len > pcb->snd_buf) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too much data %d\n", len));
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
seqno = pcb->snd_lbb;
|
||||
|
||||
queue = NULL;
|
||||
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d\n", pcb->snd_queuelen));
|
||||
queuelen = pcb->snd_queuelen;
|
||||
if(queuelen >= TCP_SND_QUEUELEN) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
if(pcb->snd_queuelen != 0) {
|
||||
ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
seg = NULL;
|
||||
seglen = 0;
|
||||
|
||||
while(queue == NULL || left > 0) {
|
||||
|
||||
seglen = left > pcb->mss? pcb->mss: left;
|
||||
|
||||
/* allocate memory for tcp_seg, and fill in fields */
|
||||
seg = memp_malloc(MEMP_TCP_SEG);
|
||||
if(seg == NULL) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
|
||||
goto memerr;
|
||||
}
|
||||
seg->next = NULL;
|
||||
seg->p = NULL;
|
||||
|
||||
|
||||
if(queue == NULL) {
|
||||
queue = seg;
|
||||
} else {
|
||||
for(useg = queue; useg->next != NULL; useg = useg->next);
|
||||
useg->next = seg;
|
||||
}
|
||||
|
||||
/* If copy is set, memory should be allocated
|
||||
and data copied into pbuf, otherwise data comes from
|
||||
ROM or other static memory, and need not be copied. If
|
||||
optdata is != NULL, we have options instead of data. */
|
||||
if(optdata != NULL) {
|
||||
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
seg->dataptr = seg->p->payload;
|
||||
} else if(copy) {
|
||||
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy\n"));
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
if(arg != NULL) {
|
||||
bcopy(ptr, seg->p->payload, seglen);
|
||||
}
|
||||
seg->dataptr = seg->p->payload;
|
||||
} else {
|
||||
/* Do not copy the data. */
|
||||
if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n"));
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
p->payload = ptr;
|
||||
seg->dataptr = ptr;
|
||||
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
|
||||
pbuf_free(p);
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
|
||||
goto memerr;
|
||||
}
|
||||
++queuelen;
|
||||
pbuf_chain(seg->p, p);
|
||||
}
|
||||
if(queuelen > TCP_SND_QUEUELEN) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN));
|
||||
goto memerr;
|
||||
}
|
||||
|
||||
seg->len = seglen;
|
||||
/* if((flags & TCP_SYN) || (flags & TCP_FIN)) {
|
||||
++seg->len;
|
||||
}*/
|
||||
|
||||
/* build TCP header */
|
||||
if(pbuf_header(seg->p, TCP_HLEN)) {
|
||||
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
|
||||
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.err;
|
||||
#endif /* TCP_STATS */
|
||||
goto memerr;
|
||||
}
|
||||
seg->tcphdr = seg->p->payload;
|
||||
seg->tcphdr->src = htons(pcb->local_port);
|
||||
seg->tcphdr->dest = htons(pcb->remote_port);
|
||||
seg->tcphdr->seqno = htonl(seqno);
|
||||
seg->tcphdr->urgp = 0;
|
||||
TCPH_FLAGS_SET(seg->tcphdr, flags);
|
||||
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */
|
||||
|
||||
if(optdata == NULL) {
|
||||
TCPH_OFFSET_SET(seg->tcphdr, 5 << 4);
|
||||
} else {
|
||||
TCPH_OFFSET_SET(seg->tcphdr, (5 + optlen / 4) << 4);
|
||||
/* Copy options into data portion of segment.
|
||||
Options can thus only be sent in non data carrying
|
||||
segments such as SYN|ACK. */
|
||||
bcopy(optdata, seg->dataptr, optlen);
|
||||
}
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",
|
||||
ntohl(seg->tcphdr->seqno),
|
||||
ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
|
||||
flags));
|
||||
|
||||
left -= seglen;
|
||||
seqno += seglen;
|
||||
ptr = (void *)((char *)ptr + seglen);
|
||||
}
|
||||
|
||||
|
||||
/* Go to the last segment on the ->unsent queue. */
|
||||
if(pcb->unsent == NULL) {
|
||||
useg = NULL;
|
||||
} else {
|
||||
for(useg = pcb->unsent; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
/* If there is room in the last pbuf on the unsent queue,
|
||||
chain the first pbuf on the queue together with that. */
|
||||
if(useg != NULL &&
|
||||
TCP_TCPLEN(useg) != 0 &&
|
||||
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
|
||||
!(flags & (TCP_SYN | TCP_FIN)) &&
|
||||
useg->len + queue->len <= pcb->mss) {
|
||||
/* Remove TCP header from first segment. */
|
||||
pbuf_header(queue->p, -TCP_HLEN);
|
||||
pbuf_chain(useg->p, queue->p);
|
||||
useg->len += queue->len;
|
||||
useg->next = queue->next;
|
||||
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: chaining, new len %u\n", useg->len));
|
||||
if(seg == queue) {
|
||||
seg = NULL;
|
||||
}
|
||||
memp_free(MEMP_TCP_SEG, queue);
|
||||
} else {
|
||||
if(useg == NULL) {
|
||||
pcb->unsent = queue;
|
||||
|
||||
} else {
|
||||
useg->next = queue;
|
||||
}
|
||||
}
|
||||
if((flags & TCP_SYN) || (flags & TCP_FIN)) {
|
||||
++len;
|
||||
}
|
||||
pcb->snd_lbb += len;
|
||||
pcb->snd_buf -= len;
|
||||
pcb->snd_queuelen = queuelen;
|
||||
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
|
||||
#ifdef LWIP_DEBUG
|
||||
if(pcb->snd_queuelen != 0) {
|
||||
ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
|
||||
/* Set the PSH flag in the last segment that we enqueued, but only
|
||||
if the segment has data (indicated by seglen > 0). */
|
||||
if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
|
||||
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
memerr:
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.memerr;
|
||||
#endif /* TCP_STATS */
|
||||
|
||||
if(queue != NULL) {
|
||||
tcp_segs_free(queue);
|
||||
}
|
||||
#ifdef LWIP_DEBUG
|
||||
if(pcb->snd_queuelen != 0) {
|
||||
ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
|
||||
pcb->unsent != NULL);
|
||||
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
|
||||
return ERR_MEM;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* find out what we can send and send it */
|
||||
err_t
|
||||
tcp_output(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
struct tcp_seg *seg, *useg;
|
||||
u32_t wnd;
|
||||
#if TCP_CWND_DEBUG
|
||||
int i = 0;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
/* First, check if we are invoked by the TCP input processing
|
||||
code. If so, we do not output anything. Instead, we rely on the
|
||||
input processing code to call us when input processing is done
|
||||
with. */
|
||||
if(tcp_input_pcb == pcb) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
wnd = MIN(pcb->snd_wnd, pcb->cwnd);
|
||||
|
||||
|
||||
seg = pcb->unsent;
|
||||
|
||||
/* If the TF_ACK_NOW flag is set, we check if there is data that is
|
||||
to be sent. If data is to be sent out, we'll just piggyback our
|
||||
acknowledgement with the outgoing segment. If no data will be
|
||||
sent (either because the ->unsent queue is empty or because the
|
||||
window doesn't allow it) we'll have to construct an empty ACK
|
||||
segment and send it. */
|
||||
if(pcb->flags & TF_ACK_NOW &&
|
||||
(seg == NULL ||
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: (ACK) could not allocate pbuf\n"));
|
||||
return ERR_BUF;
|
||||
}
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: sending ACK for %lu\n", pcb->rcv_nxt));
|
||||
if(pbuf_header(p, TCP_HLEN)) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: (ACK) no room for TCP header in pbuf.\n"));
|
||||
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.err;
|
||||
#endif /* TCP_STATS */
|
||||
pbuf_free(p);
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(pcb->local_port);
|
||||
tcphdr->dest = htons(pcb->remote_port);
|
||||
tcphdr->seqno = htonl(pcb->snd_nxt);
|
||||
tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
TCPH_FLAGS_SET(tcphdr, TCP_ACK);
|
||||
tcphdr->wnd = htons(pcb->rcv_wnd);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_OFFSET_SET(tcphdr, 5 << 4);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL,
|
||||
IP_PROTO_TCP);
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if TCP_OUTPUT_DEBUG
|
||||
if(seg == NULL) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent));
|
||||
}
|
||||
#endif /* TCP_OUTPUT_DEBUG */
|
||||
#if TCP_CWND_DEBUG
|
||||
if(seg == NULL) {
|
||||
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd,
|
||||
pcb->lastack));
|
||||
} else {
|
||||
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd,
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
|
||||
ntohl(seg->tcphdr->seqno), pcb->lastack));
|
||||
}
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
while(seg != NULL &&
|
||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
|
||||
pcb->rtime = 0;
|
||||
#if TCP_CWND_DEBUG
|
||||
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n",
|
||||
pcb->snd_wnd, pcb->cwnd, wnd,
|
||||
ntohl(seg->tcphdr->seqno) + seg->len -
|
||||
pcb->lastack,
|
||||
ntohl(seg->tcphdr->seqno), pcb->lastack, i));
|
||||
++i;
|
||||
#endif /* TCP_CWND_DEBUG */
|
||||
|
||||
pcb->unsent = seg->next;
|
||||
|
||||
if(pcb->state != SYN_SENT) {
|
||||
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK);
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
tcp_output_segment(seg, pcb);
|
||||
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
|
||||
if(TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
|
||||
pcb->snd_max = pcb->snd_nxt;
|
||||
}
|
||||
/* put segment on unacknowledged list if length > 0 */
|
||||
if(TCP_TCPLEN(seg) > 0) {
|
||||
seg->next = NULL;
|
||||
if(pcb->unacked == NULL) {
|
||||
pcb->unacked = seg;
|
||||
|
||||
|
||||
} else {
|
||||
for(useg = pcb->unacked; useg->next != NULL; useg = useg->next);
|
||||
useg->next = seg;
|
||||
}
|
||||
/* seg->rtime = 0;*/
|
||||
} else {
|
||||
tcp_seg_free(seg);
|
||||
}
|
||||
seg = pcb->unsent;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void
|
||||
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
{
|
||||
u16_t len;
|
||||
struct netif *netif;
|
||||
|
||||
/* The TCP header has already been constructed, but the ackno and
|
||||
wnd fields remain. */
|
||||
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
|
||||
|
||||
/* silly window avoidance */
|
||||
if(pcb->rcv_wnd < pcb->mss) {
|
||||
seg->tcphdr->wnd = 0;
|
||||
} else {
|
||||
seg->tcphdr->wnd = htons(pcb->rcv_wnd);
|
||||
}
|
||||
|
||||
/* If we don't have a local IP address, we get one by
|
||||
calling ip_route(). */
|
||||
if(ip_addr_isany(&(pcb->local_ip))) {
|
||||
netif = ip_route(&(pcb->remote_ip));
|
||||
if(netif == NULL) {
|
||||
return;
|
||||
}
|
||||
ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
|
||||
}
|
||||
|
||||
pcb->rtime = 0;
|
||||
|
||||
if(pcb->rttest == 0) {
|
||||
pcb->rttest = tcp_ticks;
|
||||
pcb->rtseq = ntohl(seg->tcphdr->seqno);
|
||||
|
||||
DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq));
|
||||
}
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n",
|
||||
htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
|
||||
seg->len));
|
||||
|
||||
len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
|
||||
|
||||
seg->p->len -= len;
|
||||
seg->p->tot_len -= len;
|
||||
|
||||
seg->p->payload = seg->tcphdr;
|
||||
|
||||
seg->tcphdr->chksum = 0;
|
||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
|
||||
&(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.xmit;
|
||||
#endif /* TCP_STATS */
|
||||
|
||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL,
|
||||
IP_PROTO_TCP);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
tcp_rst(u32_t seqno, u32_t ackno,
|
||||
struct ip_addr *local_ip, struct ip_addr *remote_ip,
|
||||
u16_t local_port, u16_t remote_port)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM);
|
||||
if(p == NULL) {
|
||||
if(p == NULL) {
|
||||
DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(pbuf_header(p, TCP_HLEN)) {
|
||||
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_send_data: no room for TCP header in pbuf.\n"));
|
||||
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.err;
|
||||
#endif /* TCP_STATS */
|
||||
return;
|
||||
}
|
||||
|
||||
tcphdr = p->payload;
|
||||
tcphdr->src = htons(local_port);
|
||||
tcphdr->dest = htons(remote_port);
|
||||
tcphdr->seqno = htonl(seqno);
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
|
||||
tcphdr->wnd = htons(TCP_WND);
|
||||
tcphdr->urgp = 0;
|
||||
TCPH_OFFSET_SET(tcphdr, 5 << 4);
|
||||
|
||||
tcphdr->chksum = 0;
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
|
||||
#ifdef TCP_STATS
|
||||
++stats.tcp.xmit;
|
||||
#endif /* TCP_STATS */
|
||||
ip_output(p, local_ip, remote_ip, TCP_TTL, IP_PROTO_TCP);
|
||||
pbuf_free(p);
|
||||
DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
tcp_rexmit(struct tcp_pcb *pcb)
|
||||
{
|
||||
struct tcp_seg *seg;
|
||||
|
||||
if(pcb->unacked == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move all unacked segments to the unsent queue. */
|
||||
for(seg = pcb->unacked; seg->next != NULL; seg = seg->next);
|
||||
|
||||
seg->next = pcb->unsent;
|
||||
pcb->unsent = pcb->unacked;
|
||||
|
||||
pcb->unacked = NULL;
|
||||
|
||||
|
||||
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
|
||||
|
||||
++pcb->nrtx;
|
||||
pcb->rtime = 0;
|
||||
|
||||
/* Don't take any rtt measurements after retransmitting. */
|
||||
pcb->rttest = 0;
|
||||
|
||||
/* Do the actual retransmission. */
|
||||
tcp_output(pcb);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
453
src/core/udp.c
Normal file
453
src/core/udp.c
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* udp.c
|
||||
*
|
||||
* The code for the User Datagram Protocol UDP.
|
||||
*
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#include "lwip/debug.h"
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/icmp.h"
|
||||
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include "arch/perf.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
/* The list of UDP PCBs. */
|
||||
#if LWIP_UDP
|
||||
static struct udp_pcb *udp_pcbs = NULL;
|
||||
|
||||
static struct udp_pcb *pcb_cache = NULL;
|
||||
#endif /* LWIP_UDP */
|
||||
|
||||
#if UDP_DEBUG
|
||||
int udp_debug_print(struct udp_hdr *udphdr);
|
||||
#endif /* UDP_DEBUG */
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
udp_init(void)
|
||||
{
|
||||
udp_pcbs = pcb_cache = NULL;
|
||||
}
|
||||
|
||||
#if LWIP_UDP
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* udp_lookup:
|
||||
*
|
||||
* An experimental feature that will be changed in future versions. Do
|
||||
* not depend on it yet...
|
||||
*/
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#ifdef LWIP_DEBUG
|
||||
u8_t
|
||||
udp_lookup(struct ip_hdr *iphdr, struct netif *inp)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
struct udp_hdr *udphdr;
|
||||
u16_t src, dest;
|
||||
|
||||
PERF_START;
|
||||
|
||||
udphdr = (struct udp_hdr *)(u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t);
|
||||
|
||||
src = NTOHS(udphdr->src);
|
||||
dest = NTOHS(udphdr->dest);
|
||||
|
||||
pcb = pcb_cache;
|
||||
if(pcb != NULL &&
|
||||
pcb->remote_port == src &&
|
||||
pcb->local_port == dest &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
return 1;
|
||||
} else {
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if(pcb->remote_port == src &&
|
||||
pcb->local_port == dest &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
pcb_cache = pcb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pcb == NULL) {
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if(pcb->local_port == dest &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PERF_STOP("udp_lookup");
|
||||
|
||||
if(pcb != NULL) {
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
udp_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
struct udp_hdr *udphdr;
|
||||
struct udp_pcb *pcb;
|
||||
struct ip_hdr *iphdr;
|
||||
u16_t src, dest;
|
||||
|
||||
PERF_START;
|
||||
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.recv;
|
||||
#endif /* UDP_STATS */
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
pbuf_header(p, -(UDP_HLEN + IPH_HL(iphdr) * 4));
|
||||
|
||||
udphdr = (struct udp_hdr *)((u8_t *)p->payload - UDP_HLEN);
|
||||
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %d\n", p->tot_len));
|
||||
|
||||
src = NTOHS(udphdr->src);
|
||||
dest = NTOHS(udphdr->dest);
|
||||
|
||||
#if UDP_DEBUG
|
||||
udp_debug_print(udphdr);
|
||||
#endif /* UDP_DEBUG */
|
||||
|
||||
/* Demultiplex packet. First, go for a perfect match. */
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n",
|
||||
pcb->local_port, ntohs(udphdr->dest)));
|
||||
if(pcb->remote_port == src &&
|
||||
pcb->local_port == dest &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pcb == NULL) {
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n",
|
||||
pcb->local_port, dest));
|
||||
if(pcb->local_port == dest &&
|
||||
(ip_addr_isany(&pcb->remote_ip) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check checksum if this is a match or if it was directed at us. */
|
||||
/* if(pcb != NULL ||
|
||||
ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {*/
|
||||
if(pcb != NULL) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: calculating checksum\n"));
|
||||
pbuf_header(p, UDP_HLEN);
|
||||
#ifdef IPv6
|
||||
if(iphdr->nexthdr == IP_PROTO_UDPLITE) {
|
||||
#else
|
||||
if(IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
|
||||
#endif /* IPv4 */
|
||||
/* Do the UDP Lite checksum */
|
||||
if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.chkerr;
|
||||
++stats.udp.drop;
|
||||
#endif /* UDP_STATS */
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if(udphdr->chksum != 0) {
|
||||
if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
||||
(struct ip_addr *)&(iphdr->dest),
|
||||
IP_PROTO_UDP, p->tot_len) != 0) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: UDP datagram discarded due to failing checksum\n"));
|
||||
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.chkerr;
|
||||
++stats.udp.drop;
|
||||
#endif /* UDP_STATS */
|
||||
pbuf_free(p);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
pbuf_header(p, -UDP_HLEN);
|
||||
if(pcb != NULL) {
|
||||
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
|
||||
} else {
|
||||
DEBUGF(UDP_DEBUG, ("udp_input: not for us.\n"));
|
||||
|
||||
/* No match was found, send ICMP destination port unreachable unless
|
||||
destination address was broadcast/multicast. */
|
||||
|
||||
if(!ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) &&
|
||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
||||
|
||||
/* deconvert from host to network byte order */
|
||||
udphdr->src = htons(udphdr->src);
|
||||
udphdr->dest = htons(udphdr->dest);
|
||||
|
||||
/* adjust pbuf pointer */
|
||||
p->payload = iphdr;
|
||||
icmp_dest_unreach(p, ICMP_DUR_PORT);
|
||||
}
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.proterr;
|
||||
++stats.udp.drop;
|
||||
#endif /* UDP_STATS */
|
||||
pbuf_free(p);
|
||||
}
|
||||
} else {
|
||||
pbuf_free(p);
|
||||
}
|
||||
end:
|
||||
|
||||
PERF_STOP("udp_input");
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
{
|
||||
struct udp_hdr *udphdr;
|
||||
struct netif *netif;
|
||||
struct ip_addr *src_ip;
|
||||
err_t err;
|
||||
struct pbuf *hdr;
|
||||
|
||||
/* hdr will point to the UDP header pbuf if an extra header pbuf has
|
||||
to be allocated. */
|
||||
hdr = NULL;
|
||||
|
||||
if(pbuf_header(p, UDP_HLEN)) {
|
||||
hdr = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
|
||||
if(hdr == NULL) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
pbuf_chain(hdr, p);
|
||||
p = hdr;
|
||||
}
|
||||
|
||||
udphdr = p->payload;
|
||||
udphdr->src = htons(pcb->local_port);
|
||||
udphdr->dest = htons(pcb->remote_port);
|
||||
udphdr->chksum = 0x0000;
|
||||
|
||||
if((netif = ip_route(&(pcb->remote_ip))) == NULL) {
|
||||
DEBUGF(UDP_DEBUG, ("udp_send: No route to 0x%lx\n", pcb->remote_ip.addr));
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.rterr;
|
||||
#endif /* UDP_STATS */
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
if(ip_addr_isany(&pcb->local_ip)) {
|
||||
src_ip = &(netif->ip_addr);
|
||||
} else {
|
||||
src_ip = &(pcb->local_ip);
|
||||
}
|
||||
|
||||
DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %d\n", p->tot_len));
|
||||
|
||||
if(pcb->flags & UDP_FLAGS_UDPLITE) {
|
||||
udphdr->len = htons(pcb->chksum_len);
|
||||
/* calculate checksum */
|
||||
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &(pcb->remote_ip),
|
||||
IP_PROTO_UDP, pcb->chksum_len);
|
||||
if(udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
}
|
||||
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDPLITE, netif);
|
||||
} else {
|
||||
udphdr->len = htons(p->tot_len);
|
||||
/* calculate checksum */
|
||||
if((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
||||
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &pcb->remote_ip,
|
||||
IP_PROTO_UDP, p->tot_len);
|
||||
if(udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
}
|
||||
}
|
||||
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDP, netif);
|
||||
}
|
||||
|
||||
if(hdr != NULL) {
|
||||
pbuf_dechain(hdr);
|
||||
pbuf_free(hdr);
|
||||
}
|
||||
|
||||
#ifdef UDP_STATS
|
||||
++stats.udp.xmit;
|
||||
#endif /* UDP_STATS */
|
||||
return err;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct udp_pcb *ipcb;
|
||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||
pcb->local_port = port;
|
||||
|
||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
||||
if(pcb == ipcb) {
|
||||
/* Already on the list, just return. */
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* We need to place the PCB on the list. */
|
||||
pcb->next = udp_pcbs;
|
||||
udp_pcbs = pcb;
|
||||
|
||||
DEBUGF(UDP_DEBUG, ("udp_bind: bound to port %d\n", port));
|
||||
return ERR_OK;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
err_t
|
||||
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
||||
{
|
||||
struct udp_pcb *ipcb;
|
||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||
pcb->remote_port = port;
|
||||
|
||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
||||
if(pcb == ipcb) {
|
||||
/* Already on the list, just return. */
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
/* We need to place the PCB on the list. */
|
||||
pcb->next = udp_pcbs;
|
||||
udp_pcbs = pcb;
|
||||
return ERR_OK;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
udp_recv(struct udp_pcb *pcb,
|
||||
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||
struct ip_addr *addr, u16_t port),
|
||||
void *recv_arg)
|
||||
{
|
||||
pcb->recv = recv;
|
||||
pcb->recv_arg = recv_arg;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
udp_remove(struct udp_pcb *pcb)
|
||||
{
|
||||
struct udp_pcb *pcb2;
|
||||
|
||||
if(udp_pcbs == pcb) {
|
||||
udp_pcbs = udp_pcbs->next;
|
||||
} else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
||||
if(pcb2->next != NULL && pcb2->next == pcb) {
|
||||
pcb2->next = pcb->next;
|
||||
}
|
||||
}
|
||||
|
||||
memp_free(MEMP_UDP_PCB, pcb);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
struct udp_pcb *
|
||||
udp_new(void) {
|
||||
struct udp_pcb *pcb;
|
||||
pcb = memp_malloc(MEMP_UDP_PCB);
|
||||
if(pcb != NULL) {
|
||||
bzero(pcb, sizeof(struct udp_pcb));
|
||||
return pcb;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#if UDP_DEBUG
|
||||
int
|
||||
udp_debug_print(struct udp_hdr *udphdr)
|
||||
{
|
||||
DEBUGF(UDP_DEBUG, ("UDP header:\n"));
|
||||
DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(UDP_DEBUG, ("| %5d | %5d | (src port, dest port)\n",
|
||||
ntohs(udphdr->src), ntohs(udphdr->dest)));
|
||||
DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
||||
DEBUGF(UDP_DEBUG, ("| %5d | 0x%04x | (len, chksum)\n",
|
||||
ntohs(udphdr->len), ntohs(udphdr->chksum)));
|
||||
DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
||||
return 0;
|
||||
}
|
||||
#endif /* UDP_DEBUG */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
#endif /* LWIP_UDP */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user