LIBLWIP - updated to LwIP trunk

commit a4a41b9023ef5b3a7c4a1cd82fb167fc63e706df
Author: goldsimon <goldsimon@gmx.de>
Date:   Wed Sep 26 21:50:42 2012 +0200

- This also brings in LwIP's IPv6 codebase

Signed-off-by: Tomas Hruby <tom@minix3.org>
This commit is contained in:
Ambarisha B 2012-07-05 05:02:06 +05:30 committed by Lionel Sambuc
parent 9d66e2299d
commit 7e55dbac33
116 changed files with 12137 additions and 2644 deletions

View file

@ -1,6 +1,6 @@
LIB = lwip
CPPFLAGS += -I${.CURDIR}/include/ -D_SYSTEM
CPPFLAGS += -I${.CURDIR}/include/ -I${.CURDIR}/include/ipv4 -I${.CURDIR}/include/ipv6 -D_SYSTEM
#.include "${.CURDIR}/api/Makefile.inc"
.include "${.CURDIR}/core/Makefile.inc"
@ -9,3 +9,4 @@ CPPFLAGS += -I${.CURDIR}/include/ -D_SYSTEM
SRCS += sys_arch.c
.include <bsd.lib.mk>
.include <bsd.own.mk>

View file

@ -72,10 +72,11 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal
conn = netconn_alloc(t, callback);
if (conn != NULL) {
msg.function = do_newconn;
err_t err;
msg.msg.msg.n.proto = proto;
msg.msg.conn = conn;
if (TCPIP_APIMSG(&msg) != ERR_OK) {
TCPIP_APIMSG((&msg), lwip_netconn_do_newconn, err);
if (err != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
@ -109,13 +110,13 @@ netconn_delete(struct netconn *conn)
return ERR_OK;
}
msg.function = do_delconn;
msg.function = lwip_netconn_do_delconn;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
netconn_free(conn);
/* don't care for return value of do_delconn since it only calls void functions */
/* don't care for return value of lwip_netconn_do_delconn since it only calls void functions */
return ERR_OK;
}
@ -141,12 +142,11 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
msg.function = do_getaddr;
msg.msg.conn = conn;
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.ipaddr = ip_2_ipX(addr);
msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local;
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_getaddr, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -170,11 +170,10 @@ netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_bind;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_bind, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -196,12 +195,29 @@ netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_connect;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */
err = tcpip_apimsg(&msg);
#if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW)
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
#endif /* (LWIP_UDP || LWIP_RAW) */
{
/* The TCP version waits for the connect to succeed,
so always needs to use message passing. */
msg.function = lwip_netconn_do_connect;
err = tcpip_apimsg(&msg);
}
#endif /* LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW) && LWIP_TCP
else
#endif /* (LWIP_UDP || LWIP_RAW) && LWIP_TCP */
#if (LWIP_UDP || LWIP_RAW)
{
/* UDP and RAW only set flags, so we can use core-locking. */
TCPIP_APIMSG(&msg, lwip_netconn_do_connect, err);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -221,9 +237,8 @@ netconn_disconnect(struct netconn *conn)
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect;
msg.msg.conn = conn;
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_disconnect, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -240,6 +255,7 @@ netconn_disconnect(struct netconn *conn)
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
#if LWIP_TCP
struct api_msg msg;
err_t err;
@ -248,15 +264,19 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_listen;
msg.msg.conn = conn;
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_listen, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
@ -301,16 +321,15 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
if (newconn == NULL) {
/* connection has been closed */
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
return ERR_CLSD;
/* connection has been aborted */
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
return ERR_ABRT;
}
#if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */
msg.function = do_recv;
msg.msg.conn = conn;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
/* don't care for the return value of lwip_netconn_do_recv */
TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv);
#endif /* TCP_LISTEN_BACKLOG */
*new_conn = newconn;
@ -366,20 +385,22 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#endif /* LWIP_SO_RCVTIMEO*/
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
#if (LWIP_UDP || LWIP_RAW)
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
#endif /* (LWIP_UDP || LWIP_RAW) */
{
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
/* don't care for the return value of lwip_netconn_do_recv */
TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv);
}
/* If we are closed, we indicate that we no longer wish to use the socket */
@ -402,7 +423,9 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
}
#endif /* (LWIP_UDP || LWIP_RAW) */
#if LWIP_SO_RCVBUF
SYS_ARCH_DEC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
@ -426,7 +449,7 @@ err_t
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
{
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
return netconn_recv_data(conn, (void **)new_buf);
}
@ -453,7 +476,10 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
#if (LWIP_UDP || LWIP_RAW)
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
#endif /* (LWIP_UDP || LWIP_RAW) */
{
struct pbuf *p = NULL;
/* This is not a listening netconn, since recvmbox is set */
@ -473,12 +499,15 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
buf->p = p;
buf->ptr = p;
buf->port = 0;
ip_addr_set_any(&buf->addr);
ipX_addr_set_any(LWIP_IPV6, &buf->addr);
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
} else
}
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
{
#if (LWIP_UDP || LWIP_RAW)
return netconn_recv_data(conn, (void **)new_buf);
@ -499,18 +528,22 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
void
netconn_recved(struct netconn *conn, u32_t length)
{
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
#if LWIP_TCP
if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) &&
(netconn_get_noautorecved(conn))) {
struct api_msg msg;
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
msg.msg.msg.r.len = length;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
/* don't care for the return value of lwip_netconn_do_recv */
TCPIP_APIMSG_NOERR(&msg, lwip_netconn_do_recv);
}
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(length);
#endif /* LWIP_TCP */
}
/**
@ -527,7 +560,7 @@ err_t
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
{
if (buf != NULL) {
ip_addr_set(&buf->addr, addr);
ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr);
buf->port = port;
return netconn_send(conn, buf);
}
@ -550,10 +583,9 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_send, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -569,31 +601,61 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
* - NETCONN_COPY: data will be copied into memory belonging to the stack
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
* @param bytes_written pointer to a location that receives the number of written bytes
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags, size_t *bytes_written)
{
struct api_msg msg;
err_t err;
u8_t dontblock;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
if (size == 0) {
return ERR_OK;
}
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
if (dontblock && !bytes_written) {
/* This implies netconn_write() cannot be used for non-blocking send, since
it has no way to return the number of bytes written. */
return ERR_VAL;
}
/* @todo: for non-blocking write, check if 'size' would ever fit into
snd_queue or snd_buf */
msg.function = do_write;
/* non-blocking write sends as much */
msg.msg.conn = conn;
msg.msg.msg.w.dataptr = dataptr;
msg.msg.msg.w.apiflags = apiflags;
msg.msg.msg.w.len = size;
#if LWIP_SO_SNDTIMEO
if (conn->send_timeout != 0) {
/* get the time we started, which is later compared to
sys_now() + conn->send_timeout */
msg.msg.msg.w.time_started = sys_now();
} else {
msg.msg.msg.w.time_started = 0;
}
#endif /* LWIP_SO_SNDTIMEO */
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_write, err);
if ((err == ERR_OK) && (bytes_written != NULL)) {
if (dontblock
#if LWIP_SO_SNDTIMEO
|| (conn->send_timeout != 0)
#endif /* LWIP_SO_SNDTIMEO */
) {
/* nonblocking write: maybe the data has been sent partly */
*bytes_written = msg.msg.msg.w.len;
} else {
/* blocking call succeeded: all data has been sent if it */
*bytes_written = size;
}
}
NETCONN_SET_SAFE_ERR(conn, err);
return err;
@ -614,11 +676,11 @@ netconn_close_shutdown(struct netconn *conn, u8_t how)
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.function = lwip_netconn_do_close;
msg.msg.conn = conn;
/* shutting down both ends is the same as closing */
msg.msg.msg.sd.shut = how;
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of lwip_netconn_do_close,
don't use TCPIP_APIMSG here */
err = tcpip_apimsg(&msg);
@ -651,7 +713,7 @@ netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
}
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/**
* Join multicast groups for UDP netconns.
*
@ -673,17 +735,16 @@ netconn_join_leave_group(struct netconn *conn,
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_join_leave_group;
msg.msg.conn = conn;
msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.netif_addr = netif_addr;
msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr);
msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr);
msg.msg.msg.jl.join_or_leave = join_or_leave;
err = TCPIP_APIMSG(&msg);
TCPIP_APIMSG(&msg, lwip_netconn_do_join_leave_group, err);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
@ -716,7 +777,7 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr)
msg.err = &err;
msg.sem = &sem;
tcpip_callback(do_gethostbyname, &msg);
tcpip_callback(lwip_netconn_do_gethostbyname, &msg);
sys_sem_wait(&sem);
sys_sem_free(&sem);

View file

@ -51,6 +51,7 @@
#include "lwip/tcpip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/mld6.h"
#include <string.h>
@ -62,8 +63,8 @@
/* forward declarations */
#if LWIP_TCP
static err_t do_writemore(struct netconn *conn);
static void do_close_internal(struct netconn *conn);
static err_t lwip_netconn_do_writemore(struct netconn *conn);
static void lwip_netconn_do_close_internal(struct netconn *conn);
#endif
#if LWIP_RAW
@ -112,7 +113,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
buf->p = q;
buf->ptr = q;
ip_addr_copy(buf->addr, *ip_current_src_addr());
ipX_addr_copy(PCB_ISIPV6(pcb), buf->addr, *ipX_current_src_addr());
buf->port = pcb->protocol;
len = q->tot_len;
@ -120,7 +121,9 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
netbuf_delete(buf);
return 0;
} else {
#if LWIP_SO_RCVBUF
SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
}
@ -173,17 +176,16 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
} else {
buf->p = p;
buf->ptr = p;
ip_addr_set(&buf->addr, addr);
ipX_addr_set_ipaddr(ip_current_is_v6(), &buf->addr, addr);
buf->port = port;
#if LWIP_NETBUF_RECVINFO
{
const struct ip_hdr* iphdr = ip_current_header();
/* get the UDP header - always in the first pbuf, ensured by udp_input */
const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
const struct udp_hdr* udphdr = ipX_next_header_ptr();
#if LWIP_CHECKSUM_ON_COPY
buf->flags = NETBUF_FLAG_DESTADDR;
#endif /* LWIP_CHECKSUM_ON_COPY */
ip_addr_set(&buf->toaddr, ip_current_dest_addr());
ipX_addr_set(ip_current_is_v6(), &buf->toaddr, ipX_current_dest_addr());
buf->toport_chksum = udphdr->dest;
}
#endif /* LWIP_NETBUF_RECVINFO */
@ -194,7 +196,9 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
netbuf_delete(buf);
return;
} else {
#if LWIP_SO_RCVBUF
SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
}
@ -248,7 +252,9 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
/* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
return ERR_MEM;
} else {
#if LWIP_SO_RCVBUF
SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
}
@ -276,9 +282,9 @@ poll_tcp(void *arg, struct tcp_pcb *pcb)
LWIP_ASSERT("conn != NULL", (conn != NULL));
if (conn->state == NETCONN_WRITE) {
do_writemore(conn);
lwip_netconn_do_writemore(conn);
} else if (conn->state == NETCONN_CLOSE) {
do_close_internal(conn);
lwip_netconn_do_close_internal(conn);
}
/* @todo: implement connect timeout here? */
@ -312,9 +318,9 @@ sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
LWIP_ASSERT("conn != NULL", (conn != NULL));
if (conn->state == NETCONN_WRITE) {
do_writemore(conn);
lwip_netconn_do_writemore(conn);
} else if (conn->state == NETCONN_CLOSE) {
do_close_internal(conn);
lwip_netconn_do_close_internal(conn);
}
if (conn) {
@ -379,7 +385,7 @@ err_tcp(void *arg, err_t err)
if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
(old_state == NETCONN_CONNECT)) {
/* calling do_writemore/do_close_internal is not necessary
/* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
since the pcb has already been deleted! */
int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
SET_NONBLOCKING_CONNECT(conn, 0);
@ -450,6 +456,14 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
/* When returning != ERR_OK, the pcb is aborted in tcp_process(),
so do nothing here! */
/* remove all references to this netconn from the pcb */
struct tcp_pcb* pcb = newconn->pcb.tcp;
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_poll(pcb, NULL, 4);
tcp_err(pcb, NULL);
/* remove reference from to the pcb from this netconn */
newconn->pcb.tcp = NULL;
/* no need to drain since we know the recvmbox is empty. */
sys_mbox_free(&newconn->recvmbox);
@ -467,7 +481,7 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
/**
* Create a new pcb of a specific type.
* Called from do_newconn().
* Called from lwip_netconn_do_newconn().
*
* @param msg the api_msg_msg describing the connection type
* @return msg->conn->err, but the return value is currently ignored
@ -482,46 +496,50 @@ pcb_new(struct api_msg_msg *msg)
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
if(msg->conn->pcb.raw == NULL) {
msg->err = ERR_MEM;
break;
if(msg->conn->pcb.raw != NULL) {
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
}
raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
if(msg->conn->pcb.udp == NULL) {
msg->err = ERR_MEM;
break;
}
if(msg->conn->pcb.udp != NULL) {
#if LWIP_UDPLITE
if (msg->conn->type==NETCONN_UDPLITE) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
}
if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
}
#endif /* LWIP_UDPLITE */
if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
}
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
}
udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
if(msg->conn->pcb.tcp == NULL) {
msg->err = ERR_MEM;
break;
if(msg->conn->pcb.tcp != NULL) {
setup_tcp(msg->conn);
}
setup_tcp(msg->conn);
break;
#endif /* LWIP_TCP */
default:
/* Unsupported netconn type, e.g. protocol disabled */
msg->err = ERR_VAL;
break;
return;
}
if (msg->conn->pcb.ip == NULL) {
msg->err = ERR_MEM;
}
#if LWIP_IPV6
else {
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
ip_set_v6(msg->conn->pcb.ip, 1);
}
}
#endif /* LWIP_IPV6 */
}
/**
@ -531,7 +549,7 @@ pcb_new(struct api_msg_msg *msg)
* @param msg the api_msg_msg describing the connection type
*/
void
do_newconn(struct api_msg_msg *msg)
lwip_netconn_do_newconn(struct api_msg_msg *msg)
{
msg->err = ERR_OK;
if(msg->conn->pcb.tcp == NULL) {
@ -569,10 +587,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
conn->type = t;
conn->pcb.tcp = NULL;
#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
(DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
size = DEFAULT_RAW_RECVMBOX_SIZE;
#else
/* If all sizes are the same, every compiler should optimize this switch to nothing, */
switch(NETCONNTYPE_GROUP(t)) {
#if LWIP_RAW
case NETCONN_RAW:
@ -591,18 +606,15 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
#endif /* LWIP_TCP */
default:
LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
break;
goto free_and_return;
}
#endif
if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
memp_free(MEMP_NETCONN, conn);
return NULL;
goto free_and_return;
}
if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
sys_sem_free(&conn->op_completed);
memp_free(MEMP_NETCONN, conn);
return NULL;
goto free_and_return;
}
#if LWIP_TCP
@ -614,19 +626,25 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
conn->socket = -1;
#endif /* LWIP_SOCKET */
conn->callback = callback;
conn->recv_avail = 0;
#if LWIP_TCP
conn->current_msg = NULL;
conn->write_offset = 0;
#endif /* LWIP_TCP */
#if LWIP_SO_SNDTIMEO
conn->send_timeout = 0;
#endif /* LWIP_SO_SNDTIMEO */
#if LWIP_SO_RCVTIMEO
conn->recv_timeout = 0;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
conn->recv_avail = 0;
#endif /* LWIP_SO_RCVBUF */
conn->flags = 0;
return conn;
free_and_return:
memp_free(MEMP_NETCONN, conn);
return NULL;
}
/**
@ -674,7 +692,7 @@ netconn_drain(struct netconn *conn)
if (sys_mbox_valid(&conn->recvmbox)) {
while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
if(mem != NULL) {
p = (struct pbuf*)mem;
/* pcb might be set to NULL already by err_tcp() */
@ -726,13 +744,13 @@ netconn_drain(struct netconn *conn)
* @param conn the TCP netconn to close
*/
static void
do_close_internal(struct netconn *conn)
lwip_netconn_do_close_internal(struct netconn *conn)
{
err_t err;
u8_t shut, shut_rx, shut_tx, close;
LWIP_ASSERT("invalid conn", (conn != NULL));
LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
@ -764,21 +782,21 @@ do_close_internal(struct netconn *conn)
}
}
/* Try to close the connection */
if (shut == NETCONN_SHUT_RDWR) {
if (close) {
err = tcp_close(conn->pcb.tcp);
} else {
err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
}
if (err == ERR_OK) {
/* Closing succeeded */
conn->current_msg->err = ERR_OK;
conn->current_msg = NULL;
conn->state = NETCONN_NONE;
/* Set back some callback pointers as conn is going away */
conn->pcb.tcp = NULL;
/* Trigger select() in socket layer. Make sure everybody notices activity
on the connection, error first! */
if (close) {
/* Set back some callback pointers as conn is going away */
conn->pcb.tcp = NULL;
/* Trigger select() in socket layer. Make sure everybody notices activity
on the connection, error first! */
API_EVENT(conn, NETCONN_EVT_ERROR, 0);
}
if (shut_rx) {
@ -811,14 +829,15 @@ do_close_internal(struct netconn *conn)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_delconn(struct api_msg_msg *msg)
lwip_netconn_do_delconn(struct api_msg_msg *msg)
{
/* @todo TCP: abort running write/connect? */
if ((msg->conn->state != NETCONN_NONE) &&
(msg->conn->state != NETCONN_LISTEN) &&
(msg->conn->state != NETCONN_CONNECT)) {
/* this only happens for TCP netconns */
LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
msg->err = ERR_INPROGRESS;
} else {
LWIP_ASSERT("blocking connect in progress",
@ -847,8 +866,8 @@ do_delconn(struct api_msg_msg *msg)
msg->conn->state = NETCONN_CLOSE;
msg->msg.sd.shut = NETCONN_SHUT_RDWR;
msg->conn->current_msg = msg;
do_close_internal(msg->conn);
/* API_EVENT is called inside do_close_internal, before releasing
lwip_netconn_do_close_internal(msg->conn);
/* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
the application thread, so we can return at this point! */
return;
#endif /* LWIP_TCP */
@ -877,7 +896,7 @@ do_delconn(struct api_msg_msg *msg)
* the IP address and port to bind to
*/
void
do_bind(struct api_msg_msg *msg)
lwip_netconn_do_bind(struct api_msg_msg *msg)
{
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
@ -910,13 +929,13 @@ do_bind(struct api_msg_msg *msg)
#if LWIP_TCP
/**
* TCP callback function if a connection (opened by tcp_connect/do_connect) has
* TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
* been established (or reset by the remote host).
*
* @see tcp.h (struct tcp_pcb.connected) for parameters and return values
*/
static err_t
do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct netconn *conn;
int was_blocking;
@ -936,7 +955,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
if (conn->current_msg != NULL) {
conn->current_msg->err = err;
}
if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
setup_tcp(conn);
}
was_blocking = !IN_NONBLOCKING_CONNECT(conn);
@ -944,12 +963,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
conn->current_msg = NULL;
conn->state = NETCONN_NONE;
if (!was_blocking) {
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
if (conn->last_err == ERR_INPROGRESS) {
conn->last_err = ERR_OK;
}
SYS_ARCH_UNPROTECT(lev);
NETCONN_SET_SAFE_ERR(conn, ERR_OK);
}
API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
@ -968,54 +982,63 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
* the IP address and port to connect to
*/
void
do_connect(struct api_msg_msg *msg)
lwip_netconn_do_connect(struct api_msg_msg *msg)
{
if (msg->conn->pcb.tcp == NULL) {
/* This may happen when calling netconn_connect() a second time */
msg->err = ERR_CLSD;
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed);
return;
}
} else {
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
break;
case NETCONN_RAW:
msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
break;
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
break;
case NETCONN_UDP:
msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
/* Prevent connect while doing any other action. */
if (msg->conn->state != NETCONN_NONE) {
msg->err = ERR_ISCONN;
} else {
setup_tcp(msg->conn);
msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
msg->msg.bc.port, do_connected);
if (msg->err == ERR_OK) {
u8_t non_blocking = netconn_is_nonblocking(msg->conn);
msg->conn->state = NETCONN_CONNECT;
SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
if (non_blocking) {
msg->err = ERR_INPROGRESS;
} else {
msg->conn->current_msg = msg;
/* sys_sem_signal() is called from do_connected (or err_tcp()),
* when the connection is established! */
return;
case NETCONN_TCP:
/* Prevent connect while doing any other action. */
if (msg->conn->state != NETCONN_NONE) {
msg->err = ERR_ISCONN;
} else {
setup_tcp(msg->conn);
msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
msg->msg.bc.port, lwip_netconn_do_connected);
if (msg->err == ERR_OK) {
u8_t non_blocking = netconn_is_nonblocking(msg->conn);
msg->conn->state = NETCONN_CONNECT;
SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
if (non_blocking) {
msg->err = ERR_INPROGRESS;
} else {
msg->conn->current_msg = msg;
/* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
* when the connection is established! */
return;
}
}
}
}
break;
/* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */
sys_sem_signal(&msg->conn->op_completed);
return;
#endif /* LWIP_TCP */
default:
LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
break;
default:
LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
break;
}
}
sys_sem_signal(&msg->conn->op_completed);
/* For all other protocols, netconn_connect() calls TCPIP_APIMSG(),
so use TCPIP_APIMSG_ACK() here. */
TCPIP_APIMSG_ACK(msg);
}
/**
@ -1026,7 +1049,7 @@ do_connect(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection to disconnect
*/
void
do_disconnect(struct api_msg_msg *msg)
lwip_netconn_do_disconnect(struct api_msg_msg *msg)
{
#if LWIP_UDP
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
@ -1040,6 +1063,7 @@ do_disconnect(struct api_msg_msg *msg)
TCPIP_APIMSG_ACK(msg);
}
#if LWIP_TCP
/**
* Set a TCP pcb contained in a netconn into listen mode
* Called from netconn_listen.
@ -1047,21 +1071,32 @@ do_disconnect(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_listen(struct api_msg_msg *msg)
lwip_netconn_do_listen(struct api_msg_msg *msg)
{
#if LWIP_TCP
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
msg->err = ERR_CONN;
if (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
if (msg->conn->state == NETCONN_NONE) {
struct tcp_pcb* lpcb;
#if LWIP_IPV6
if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) {
#if TCP_LISTEN_BACKLOG
struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else /* TCP_LISTEN_BACKLOG */
struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
lpcb = tcp_listen_dual(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
} else
#endif /* LWIP_IPV6 */
{
#if TCP_LISTEN_BACKLOG
lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else /* TCP_LISTEN_BACKLOG */
lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
}
if (lpcb == NULL) {
/* in this case, the old pcb is still allocated */
msg->err = ERR_MEM;
@ -1088,12 +1123,14 @@ do_listen(struct api_msg_msg *msg)
}
}
}
} else {
msg->err = ERR_ARG;
}
}
}
#endif /* LWIP_TCP */
TCPIP_APIMSG_ACK(msg);
}
#endif /* LWIP_TCP */
/**
* Send some data on a RAW or UDP pcb contained in a netconn
@ -1102,7 +1139,7 @@ do_listen(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_send(struct api_msg_msg *msg)
lwip_netconn_do_send(struct api_msg_msg *msg)
{
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
@ -1112,29 +1149,29 @@ do_send(struct api_msg_msg *msg)
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
if (ip_addr_isany(&msg->msg.b->addr)) {
if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else {
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr));
}
break;
#endif
#if LWIP_UDP
case NETCONN_UDP:
#if LWIP_CHECKSUM_ON_COPY
if (ip_addr_isany(&msg->msg.b->addr)) {
if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
} else {
msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
&msg->msg.b->addr, msg->msg.b->port,
ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port,
msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
}
#else /* LWIP_CHECKSUM_ON_COPY */
if (ip_addr_isany(&msg->msg.b->addr)) {
if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
} else {
msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
break;
@ -1147,6 +1184,7 @@ do_send(struct api_msg_msg *msg)
TCPIP_APIMSG_ACK(msg);
}
#if LWIP_TCP
/**
* Indicate data has been received from a TCP pcb contained in a netconn
* Called from netconn_recv
@ -1154,12 +1192,11 @@ do_send(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_recv(struct api_msg_msg *msg)
lwip_netconn_do_recv(struct api_msg_msg *msg)
{
#if LWIP_TCP
msg->err = ERR_OK;
if (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
#if TCP_LISTEN_BACKLOG
if (msg->conn->pcb.tcp->state == LISTEN) {
tcp_accepted(msg->conn->pcb.tcp);
@ -1175,14 +1212,12 @@ do_recv(struct api_msg_msg *msg)
}
}
}
#endif /* LWIP_TCP */
TCPIP_APIMSG_ACK(msg);
}
#if LWIP_TCP
/**
* See if more data needs to be written from a previous call to netconn_write.
* Called initially from do_write. If the first call can't send all data
* Called initially from lwip_netconn_do_write. If the first call can't send all data
* (because of low memory or empty send-buffer), this function is called again
* from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
* blocking application thread (waiting in netconn_write) is released.
@ -1192,9 +1227,9 @@ do_recv(struct api_msg_msg *msg)
* ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
*/
static err_t
do_writemore(struct netconn *conn)
lwip_netconn_do_writemore(struct netconn *conn)
{
err_t err = ERR_OK;
err_t err;
void *dataptr;
u16_t len, available;
u8_t write_finished = 0;
@ -1210,62 +1245,78 @@ do_writemore(struct netconn *conn)
LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
conn->write_offset < conn->current_msg->msg.w.len);
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
diff = conn->current_msg->msg.w.len - conn->write_offset;
if (diff > 0xffffUL) { /* max_u16_t */
len = 0xffff;
#if LWIP_TCPIP_CORE_LOCKING
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
#endif
apiflags |= TCP_WRITE_FLAG_MORE;
} else {
len = (u16_t)diff;
}
available = tcp_sndbuf(conn->pcb.tcp);
if (available < len) {
/* don't try to write more than sendbuf */
len = available;
#if LWIP_TCPIP_CORE_LOCKING
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
#endif
apiflags |= TCP_WRITE_FLAG_MORE;
}
if (dontblock && (len < conn->current_msg->msg.w.len)) {
/* failed to send all data at once -> nonblocking write not possible */
err = ERR_MEM;
}
if (err == ERR_OK) {
LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
}
if (dontblock && (err == ERR_MEM)) {
/* nonblocking write failed */
#if LWIP_SO_SNDTIMEO
if ((conn->send_timeout != 0) &&
((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
write_finished = 1;
err = ERR_WOULDBLOCK;
/* let poll_tcp check writable space to mark the pcb
writable again */
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
/* let select mark this pcb as non-writable. */
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
} else {
if (conn->write_offset == 0) {
/* nothing has been written */
err = ERR_WOULDBLOCK;
conn->current_msg->msg.w.len = 0;
} else {
/* partial write */
err = ERR_OK;
conn->current_msg->msg.w.len = conn->write_offset;
}
} else
#endif /* LWIP_SO_SNDTIMEO */
{
dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
diff = conn->current_msg->msg.w.len - conn->write_offset;
if (diff > 0xffffUL) { /* max_u16_t */
len = 0xffff;
#if LWIP_TCPIP_CORE_LOCKING
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
#endif
apiflags |= TCP_WRITE_FLAG_MORE;
} else {
len = (u16_t)diff;
}
available = tcp_sndbuf(conn->pcb.tcp);
if (available < len) {
/* don't try to write more than sendbuf */
len = available;
IF (DONTBLOCK){
if (!len) {
err = ERR_WOULDBLOCK;
goto err_mem;
}
} else {
#if LWIP_TCPIP_CORE_LOCKING
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
#endif
apiflags |= TCP_WRITE_FLAG_MORE;
}
}
LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
/* if OK or memory error, check available space */
if (((err == ERR_OK) || (err == ERR_MEM)) &&
((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
let select mark this pcb as non-writable. */
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
if ((err == ERR_OK) || (err == ERR_MEM)) {
err_mem:
if (dontblock && (len < conn->current_msg->msg.w.len)) {
/* non-blocking write did not write everything: mark the pcb non-writable
and let poll_tcp check writable space to mark the pcb writable again */
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
} else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
(tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
/* The queued byte- or pbuf-count exceeds the configured low-water limit,
let select mark this pcb as non-writable. */
API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
}
}
if (err == ERR_OK) {
conn->write_offset += len;
if (conn->write_offset == conn->current_msg->msg.w.len) {
if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
/* return sent length */
conn->current_msg->msg.w.len = conn->write_offset;
/* everything was written */
write_finished = 1;
conn->write_offset = 0;
}
tcp_output(conn->pcb.tcp);
} else if (err == ERR_MEM) {
} else if ((err == ERR_MEM) && !dontblock) {
/* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
we do NOT return to the application thread, since ERR_MEM is
only a temporary error! */
@ -1273,16 +1324,16 @@ do_writemore(struct netconn *conn)
/* tcp_write returned ERR_MEM, try tcp_output anyway */
tcp_output(conn->pcb.tcp);
#if LWIP_TCPIP_CORE_LOCKING
#if LWIP_TCPIP_CORE_LOCKING
conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
#endif
#endif
} else {
/* On errors != ERR_MEM, we don't try writing any more but return
the error to the application thread. */
write_finished = 1;
conn->current_msg->msg.w.len = 0;
}
}
if (write_finished) {
/* everything was written: set back connection state
and back to application task */
@ -1311,19 +1362,19 @@ do_writemore(struct netconn *conn)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_write(struct api_msg_msg *msg)
lwip_netconn_do_write(struct api_msg_msg *msg)
{
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
} else {
if (msg->conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
#if LWIP_TCP
if (msg->conn->state != NETCONN_NONE) {
/* netconn is connecting, closing or in blocking write */
msg->err = ERR_INPROGRESS;
} else if (msg->conn->pcb.tcp != NULL) {
msg->conn->state = NETCONN_WRITE;
/* set all the variables used by do_writemore */
/* set all the variables used by lwip_netconn_do_writemore */
LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
msg->conn->write_offset == 0);
LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
@ -1331,7 +1382,7 @@ do_write(struct api_msg_msg *msg)
msg->conn->write_offset = 0;
#if LWIP_TCPIP_CORE_LOCKING
msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
if (do_writemore(msg->conn) != ERR_OK) {
if (lwip_netconn_do_writemore(msg->conn) != ERR_OK) {
LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
UNLOCK_TCPIP_CORE();
sys_arch_sem_wait(&msg->conn->op_completed, 0);
@ -1339,10 +1390,10 @@ do_write(struct api_msg_msg *msg)
LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
}
#else /* LWIP_TCPIP_CORE_LOCKING */
do_writemore(msg->conn);
lwip_netconn_do_writemore(msg->conn);
#endif /* LWIP_TCPIP_CORE_LOCKING */
/* for both cases: if do_writemore was called, don't ACK the APIMSG
since do_writemore ACKs it! */
/* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
since lwip_netconn_do_writemore ACKs it! */
return;
} else {
msg->err = ERR_CONN;
@ -1366,12 +1417,16 @@ do_write(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_getaddr(struct api_msg_msg *msg)
lwip_netconn_do_getaddr(struct api_msg_msg *msg)
{
if (msg->conn->pcb.ip != NULL) {
*(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
msg->conn->pcb.ip->remote_ip);
if (msg->msg.ad.local) {
ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr),
msg->conn->pcb.ip->local_ip);
} else {
ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr),
msg->conn->pcb.ip->remote_ip);
}
msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
@ -1419,15 +1474,16 @@ do_getaddr(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_close(struct api_msg_msg *msg)
lwip_netconn_do_close(struct api_msg_msg *msg)
{
#if LWIP_TCP
/* @todo: abort running write/connect? */
if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
/* this only happens for TCP netconns */
LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
msg->err = ERR_INPROGRESS;
} else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
} else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) {
if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
/* LISTEN doesn't support half shutdown */
msg->err = ERR_CONN;
@ -1440,8 +1496,8 @@ do_close(struct api_msg_msg *msg)
msg->conn->write_offset == 0);
msg->conn->state = NETCONN_CLOSE;
msg->conn->current_msg = msg;
do_close_internal(msg->conn);
/* for tcp netconns, do_close_internal ACKs the message */
lwip_netconn_do_close_internal(msg->conn);
/* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
return;
}
} else
@ -1452,7 +1508,7 @@ do_close(struct api_msg_msg *msg)
sys_sem_signal(&msg->conn->op_completed);
}
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/**
* Join multicast groups for UDP netconns.
* Called from netconn_join_leave_group
@ -1460,7 +1516,7 @@ do_close(struct api_msg_msg *msg)
* @param msg the api_msg_msg pointing to the connection
*/
void
do_join_leave_group(struct api_msg_msg *msg)
lwip_netconn_do_join_leave_group(struct api_msg_msg *msg)
{
if (ERR_IS_FATAL(msg->conn->last_err)) {
msg->err = msg->conn->last_err;
@ -1468,10 +1524,28 @@ do_join_leave_group(struct api_msg_msg *msg)
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
} else {
msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
#if LWIP_IPV6 && LWIP_IPV6_MLD
if (PCB_ISIPV6(msg->conn->pcb.udp)) {
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr),
ipX_2_ip6(msg->msg.jl.multiaddr));
} else {
msg->err = mld6_leavegroup(ipX_2_ip6(msg->msg.jl.netif_addr),
ipX_2_ip6(msg->msg.jl.multiaddr));
}
}
else
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
{
#if LWIP_IGMP
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = igmp_joingroup(ipX_2_ip(msg->msg.jl.netif_addr),
ipX_2_ip(msg->msg.jl.multiaddr));
} else {
msg->err = igmp_leavegroup(ipX_2_ip(msg->msg.jl.netif_addr),
ipX_2_ip(msg->msg.jl.multiaddr));
}
#endif /* LWIP_IGMP */
}
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
@ -1485,7 +1559,7 @@ do_join_leave_group(struct api_msg_msg *msg)
}
TCPIP_APIMSG_ACK(msg);
}
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
@ -1494,7 +1568,7 @@ do_join_leave_group(struct api_msg_msg *msg)
* signaling the semaphore.
*/
static void
do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
lwip_netconn_do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{
struct dns_api_msg *msg = (struct dns_api_msg*)arg;
@ -1520,11 +1594,11 @@ do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
* @param arg the dns_api_msg pointing to the query
*/
void
do_gethostbyname(void *arg)
lwip_netconn_do_gethostbyname(void *arg)
{
struct dns_api_msg *msg = (struct dns_api_msg*)arg;
*msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
*msg->err = dns_gethostbyname(msg->name, msg->addr, lwip_netconn_do_dns_found, msg);
if (*msg->err != ERR_INPROGRESS) {
/* on error or immediate success, wake up the application
* task waiting in netconn_gethostbyname */

View file

@ -49,14 +49,14 @@ static const char *err_strerr[] = {
"Operation in progress.", /* ERR_INPROGRESS -5 */
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Connection aborted.", /* ERR_ABRT -8 */
"Connection reset.", /* ERR_RST -9 */
"Connection closed.", /* ERR_CLSD -10 */
"Not connected.", /* ERR_CONN -11 */
"Illegal argument.", /* ERR_ARG -12 */
"Address in use.", /* ERR_USE -13 */
"Low-level netif error.", /* ERR_IF -14 */
"Already connected.", /* ERR_ISCONN -15 */
"Address in use.", /* ERR_USE -8 */
"Already connected.", /* ERR_ISCONN -9 */
"Connection aborted.", /* ERR_ABRT -10 */
"Connection reset.", /* ERR_RST -11 */
"Connection closed.", /* ERR_CLSD -12 */
"Not connected.", /* ERR_CONN -13 */
"Illegal argument.", /* ERR_ARG -14 */
"Low-level netif error.", /* ERR_IF -15 */
};
/**

View file

@ -61,7 +61,7 @@ netbuf *netbuf_new(void)
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
ip_addr_set_any(&buf->addr);
ipX_addr_set_any(LWIP_IPV6, &buf->addr);
buf->port = 0;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
@ -69,7 +69,7 @@ netbuf *netbuf_new(void)
#endif /* LWIP_CHECKSUM_ON_COPY */
buf->toport_chksum = 0;
#if LWIP_NETBUF_RECVINFO
ip_addr_set_any(&buf->toaddr);
ipX_addr_set_any(LWIP_IPV6, &buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;

View file

@ -49,7 +49,7 @@
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
ip_addr_t *addrs;
ip_addr_t *addr_list[2];
ip_addr_t addr;
char *aliases;
};
@ -180,7 +180,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
}
/* first thing to do: set *result to nothing */
*result = NULL;
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
@ -197,10 +197,10 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
/* query host IP address */
err = netconn_gethostbyname(name, &(h->addr));
err = netconn_gethostbyname(name, &h->addr);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
*h_errnop = ENSRNOTFOUND;
*h_errnop = HOST_NOT_FOUND;
return -1;
}
@ -209,13 +209,14 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
hostname[namelen] = 0;
/* fill hostent */
h->addrs = &(h->addr);
h->addr_list[0] = &h->addr;
h->addr_list[1] = NULL;
h->aliases = NULL;
ret->h_name = (char*)hostname;
ret->h_aliases = &(h->aliases);
ret->h_name = hostname;
ret->h_aliases = &h->aliases;
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char**)&(h->addrs);
ret->h_addr_list = (char**)&h->addr_list;
/* set result != NULL */
*result = ret;

View file

@ -41,8 +41,8 @@
/**
* Call netif_add() inside the tcpip_thread context.
*/
void
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
static void
netifapi_do_netif_add(struct netifapi_msg_msg *msg)
{
if (!netif_add( msg->netif,
msg->msg.add.ipaddr,
@ -61,8 +61,8 @@ do_netifapi_netif_add(struct netifapi_msg_msg *msg)
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
void
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
static void
netifapi_do_netif_set_addr(struct netifapi_msg_msg *msg)
{
netif_set_addr( msg->netif,
msg->msg.add.ipaddr,
@ -76,8 +76,8 @@ do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
void
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
static void
netifapi_do_netif_common(struct netifapi_msg_msg *msg)
{
if (msg->msg.common.errtfunc != NULL) {
msg->err = msg->msg.common.errtfunc(msg->netif);
@ -104,7 +104,7 @@ netifapi_netif_add(struct netif *netif,
netif_input_fn input)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
msg.function = netifapi_do_netif_add;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
@ -129,7 +129,7 @@ netifapi_netif_set_addr(struct netif *netif,
ip_addr_t *gw)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_set_addr;
msg.function = netifapi_do_netif_set_addr;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
@ -149,7 +149,7 @@ netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;
msg.function = netifapi_do_netif_common;
msg.msg.netif = netif;
msg.msg.msg.common.voidfunc = voidfunc;
msg.msg.msg.common.errtfunc = errtfunc;

File diff suppressed because it is too large Load diff

View file

@ -103,6 +103,11 @@ tcpip_thread(void *arg)
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ETHERNET */
#if LWIP_IPV6
if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) {
ip6_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_IPV6 */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
@ -117,12 +122,6 @@ tcpip_thread(void *arg)
break;
#endif /* LWIP_NETIF_API */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
@ -136,6 +135,17 @@ tcpip_thread(void *arg)
break;
#endif /* LWIP_TCPIP_TIMEOUT */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_CALLBACK_STATIC:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
@ -172,22 +182,22 @@ tcpip_input(struct pbuf *p, struct netif *inp)
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return ERR_VAL;
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
@ -316,30 +326,6 @@ tcpip_apimsg(struct api_msg *apimsg)
return ERR_VAL;
}
#if LWIP_TCPIP_CORE_LOCKING
/**
* Call the lower part of a netconn_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
*/
err_t
tcpip_apimsg_lock(struct api_msg *apimsg)
{
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return apimsg->msg.err;
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if LWIP_NETIF_API
@ -392,6 +378,52 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Allocate a structure for a static callback message and initialize it.
* This is intended to be used to send "static" messages from interrupt context.
*
* @param function the function to call
* @param ctx parameter passed to function
* @return a struct pointer to pass to tcpip_trycallback().
*/
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return NULL;
}
msg->type = TCPIP_MSG_CALLBACK_STATIC;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
return (struct tcpip_callback_msg*)msg;
}
/**
* Free a callback message allocated by tcpip_callbackmsg_new().
*
* @param msg the message to free
*/
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
{
memp_free(MEMP_TCPIP_MSG_API, msg);
}
/**
* Try to post a callback-message to the tcpip_thread mbox
* This is intended to be used to send "static" messages from interrupt context.
*
* @param msg pointer to the message to post
* @return sys_mbox_trypost() return code
*/
err_t
tcpip_trycallback(struct tcpip_callback_msg* msg)
{
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return sys_mbox_trypost(&mbox, msg);
}
/**
* Initialize this module:
* - initialize all sub modules

View file

@ -1,5 +1,5 @@
.PATH: \
${.CURDIR}/core ${.CURDIR}/core/ipv4 ${.CURDIR}/core/snmp
${.CURDIR}/core ${.CURDIR}/core/ipv4 ${.CURDIR}/core/ipv6 ${.CURDIR}/core/snmp
SRCS += \
def.c \
@ -18,15 +18,24 @@ SRCS += \
memp.c \
pbuf.c \
stats.c \
inet_chksum.c \
\
ip.c \
ip4.c \
igmp.c \
icmp.c \
ip_addr.c \
ip4_addr.c \
ip_frag.c \
inet.c \
autoip.c \
inet_chksum.c \
\
dhcp6.c \
ethip6.c \
icmp6.c \
inet6.c \
ip6.c \
ip6_addr.c \
ip6_frag.c \
mld6.c \
nd6.c \
\
mib_structs.c \
mib2.c \

View file

@ -76,7 +76,6 @@
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/dns.h"
@ -84,6 +83,13 @@
#include <string.h>
/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using
* LWIP_RAND() (this overrides DHCP_GLOBAL_XID)
*/
#ifndef DHCP_CREATE_RAND_XID
#define DHCP_CREATE_RAND_XID 1
#endif
/** Default for DHCP_GLOBAL_XID is 0xABCD0000
* This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
* #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
@ -115,7 +121,7 @@
#define DHCP_OPTION_IDX_T2 5
#define DHCP_OPTION_IDX_SUBNET_MASK 6
#define DHCP_OPTION_IDX_ROUTER 7
#define DHCP_OPTION_IDX_DNS_SERVER 8
#define DHCP_OPTION_IDX_DNS_SERVER 8
#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
/** Holds the decoded option values, only valid while in dhcp_recv.
@ -126,6 +132,11 @@ u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
@todo: move this into struct dhcp? */
u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
#ifdef DHCP_GLOBAL_XID
static u32_t xid;
static u8_t xid_initialised;
#endif /* DHCP_GLOBAL_XID */
#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0)
#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1)
#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0)
@ -164,6 +175,9 @@ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
#if LWIP_NETIF_HOSTNAME
static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif);
#endif /* LWIP_NETIF_HOSTNAME */
/* always add the DHCP options trailer to end and pad */
static void dhcp_option_trailer(struct dhcp *dhcp);
@ -295,17 +309,7 @@ dhcp_select(struct netif *netif)
dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
#if LWIP_NETIF_HOSTNAME
if (netif->hostname != NULL) {
const char *p = (const char*)netif->hostname;
u8_t namelen = (u8_t)strlen(p);
if (namelen > 0) {
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
while (*p) {
dhcp_option_byte(dhcp, *p++);
}
}
}
dhcp_option_hostname(dhcp, netif);
#endif /* LWIP_NETIF_HOSTNAME */
dhcp_option_trailer(dhcp);
@ -563,12 +567,10 @@ dhcp_handle_ack(struct netif *netif)
#if LWIP_DNS
/* DNS servers */
n = 0;
while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) {
for(n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
ip_addr_t dns_addr;
ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
dns_setserver(n, &dns_addr);
n++;
}
#endif /* LWIP_DNS */
}
@ -592,6 +594,23 @@ dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
netif->dhcp = dhcp;
}
/** Removes a struct dhcp from a netif.
*
* ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
* struct dhcp since the memory is passed back to the heap.
*
* @param netif the netif from which to remove the struct dhcp
*/
void dhcp_cleanup(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
if (netif->dhcp != NULL) {
mem_free(netif->dhcp);
netif->dhcp = NULL;
}
}
/**
* Start DHCP negotiation for a network interface.
*
@ -659,7 +678,7 @@ dhcp_start(struct netif *netif)
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
return ERR_MEM;
}
dhcp->pcb->so_options |= SOF_BROADCAST;
ip_set_option(dhcp->pcb, SOF_BROADCAST);
/* set up local and remote port for the pcb */
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
@ -709,7 +728,7 @@ dhcp_inform(struct netif *netif)
return;
}
dhcp.pcb = pcb;
dhcp.pcb->so_options |= SOF_BROADCAST;
ip_set_option(dhcp.pcb, SOF_BROADCAST);
udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
}
@ -762,7 +781,10 @@ dhcp_network_changed(struct netif *netif)
default:
dhcp->tries = 0;
#if LWIP_DHCP_AUTOIP_COOP
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
autoip_stop(netif);
dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
}
#endif /* LWIP_DHCP_AUTOIP_COOP */
dhcp_discover(netif);
break;
@ -938,6 +960,11 @@ dhcp_bind(struct netif *netif)
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
}
/* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */
if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) {
dhcp->t1_timeout = 0;
}
if (dhcp->subnet_mask_given) {
/* copy offered network mask */
ip_addr_copy(sn_mask, dhcp->offered_sn_mask);
@ -945,11 +972,11 @@ dhcp_bind(struct netif *netif)
/* subnet mask not given, choose a safe subnet mask given the network class */
u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
if (first_octet <= 127) {
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000));
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
} else if (first_octet >= 192) {
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00));
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
} else {
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000));
ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
}
}
@ -959,7 +986,7 @@ dhcp_bind(struct netif *netif)
/* copy network address */
ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
/* use first host address on network as gateway */
ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001));
ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
}
#if LWIP_DHCP_AUTOIP_COOP
@ -1004,20 +1031,6 @@ dhcp_renew(struct netif *netif)
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
#if LWIP_NETIF_HOSTNAME
if (netif->hostname != NULL) {
const char *p = (const char*)netif->hostname;
u8_t namelen = (u8_t)strlen(p);
if (namelen > 0) {
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
while (*p) {
dhcp_option_byte(dhcp, *p++);
}
}
}
#endif /* LWIP_NETIF_HOSTNAME */
#if 0
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
@ -1027,6 +1040,11 @@ dhcp_renew(struct netif *netif)
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
#endif
#if LWIP_NETIF_HOSTNAME
dhcp_option_hostname(dhcp, netif);
#endif /* LWIP_NETIF_HOSTNAME */
/* append DHCP message trailer */
dhcp_option_trailer(dhcp);
@ -1068,17 +1086,7 @@ dhcp_rebind(struct netif *netif)
dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
#if LWIP_NETIF_HOSTNAME
if (netif->hostname != NULL) {
const char *p = (const char*)netif->hostname;
u8_t namelen = (u8_t)strlen(p);
if (namelen > 0) {
LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
while (*p) {
dhcp_option_byte(dhcp, *p++);
}
}
}
dhcp_option_hostname(dhcp, netif);
#endif /* LWIP_NETIF_HOSTNAME */
#if 0
@ -1161,6 +1169,9 @@ dhcp_release(struct netif *netif)
err_t result;
u16_t msecs;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n"));
if (dhcp == NULL) {
return ERR_ARG;
}
/* idle DHCP client */
dhcp_set_state(dhcp, DHCP_OFF);
@ -1290,6 +1301,29 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value)
dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
}
#if LWIP_NETIF_HOSTNAME
static void
dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif)
{
if (netif->hostname != NULL) {
size_t namelen = strlen(netif->hostname);
if (namelen > 0) {
u8_t len;
const char *p = netif->hostname;
/* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME
and 1 byte for trailer) */
size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3;
LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available);
len = LWIP_MIN(namelen, available);
dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len);
while (len--) {
dhcp_option_byte(dhcp, *p++);
}
}
}
}
#endif /* LWIP_NETIF_HOSTNAME */
/**
* Extract the DHCP message and the DHCP options.
*
@ -1367,44 +1401,44 @@ again:
offset--;
break;
case(DHCP_OPTION_SUBNET_MASK):
LWIP_ASSERT("len == 4", len == 4);
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;
break;
case(DHCP_OPTION_ROUTER):
decode_len = 4; /* only copy the first given router */
LWIP_ASSERT("len >= decode_len", len >= decode_len);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_ROUTER;
break;
case(DHCP_OPTION_DNS_SERVER):
/* special case: there might be more than one server */
LWIP_ASSERT("len % 4 == 0", len % 4 == 0);
LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;);
/* limit number of DNS servers */
decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);
LWIP_ASSERT("len >= decode_len", len >= decode_len);
LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_DNS_SERVER;
break;
case(DHCP_OPTION_LEASE_TIME):
LWIP_ASSERT("len == 4", len == 4);
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_LEASE_TIME;
break;
case(DHCP_OPTION_OVERLOAD):
LWIP_ASSERT("len == 1", len == 1);
LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_OVERLOAD;
break;
case(DHCP_OPTION_MESSAGE_TYPE):
LWIP_ASSERT("len == 1", len == 1);
LWIP_ERROR("len == 1", len == 1, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_MSG_TYPE;
break;
case(DHCP_OPTION_SERVER_ID):
LWIP_ASSERT("len == 4", len == 4);
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_SERVER_ID;
break;
case(DHCP_OPTION_T1):
LWIP_ASSERT("len == 4", len == 4);
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_T1;
break;
case(DHCP_OPTION_T2):
LWIP_ASSERT("len == 4", len == 4);
LWIP_ERROR("len == 4", len == 4, return ERR_VAL;);
decode_idx = DHCP_OPTION_IDX_T2;
break;
default:
@ -1418,32 +1452,39 @@ again:
u16_t copy_len;
decode_next:
LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);
LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx));
copy_len = LWIP_MIN(decode_len, 4);
pbuf_copy_partial(q, &value, copy_len, val_offset);
if (decode_len > 4) {
/* decode more than one u32_t */
LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0);
if (!dhcp_option_given(dhcp, decode_idx)) {
copy_len = LWIP_MIN(decode_len, 4);
pbuf_copy_partial(q, &value, copy_len, val_offset);
if (decode_len > 4) {
/* decode more than one u32_t */
LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;);
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
decode_len -= 4;
val_offset += 4;
decode_idx++;
goto decode_next;
} else if (decode_len == 4) {
value = ntohl(value);
} else {
LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;);
value = ((u8_t*)&value)[0];
}
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, htonl(value));
decode_len -= 4;
val_offset += 4;
decode_idx++;
goto decode_next;
} else if (decode_len == 4) {
value = ntohl(value);
} else {
LWIP_ASSERT("invalid decode_len", decode_len == 1);
value = ((u8_t*)&value)[0];
dhcp_set_option_value(dhcp, decode_idx, value);
}
dhcp_got_option(dhcp, decode_idx);
dhcp_set_option_value(dhcp, decode_idx, value);
}
if (offset >= q->len) {
offset -= q->len;
offset_max -= q->len;
q = q->next;
options = (u8_t*)q->payload;
if ((offset < offset_max) && offset_max) {
q = q->next;
LWIP_ASSERT("next pbuf was null", q);
options = (u8_t*)q->payload;
} else {
// We've run out of bytes, probably no end marker. Don't proceed.
break;
}
}
}
/* is this an overloaded message? */
@ -1606,10 +1647,12 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
* with a packet analyser). We simply increment for each new request.
* Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
* at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
static u32_t xid = 0xABCD0000;
#else
#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
static u32_t xid;
static u8_t xid_initialised = 0;
#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
static u32_t xid = 0xABCD0000;
#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
#else
if (!xid_initialised) {
xid = DHCP_GLOBAL_XID;
xid_initialised = !xid_initialised;
@ -1630,7 +1673,11 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
/* reuse transaction identifier in retransmissions */
if (dhcp->tries == 0) {
xid++;
#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
xid = LWIP_RAND();
#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
xid++;
#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
}
dhcp->xid = xid;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
@ -1660,7 +1707,7 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
ip_addr_set_zero(&dhcp->msg_out->giaddr);
for (i = 0; i < DHCP_CHADDR_LEN; i++) {
/* copy netif hardware address, pad with zeroes */
dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/;
}
for (i = 0; i < DHCP_SNAME_LEN; i++) {
dhcp->msg_out->sname[i] = 0;
@ -1714,9 +1761,8 @@ dhcp_option_trailer(struct dhcp *dhcp)
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
/* packet is too small, or not 4 byte aligned? */
while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
/* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) &&
(dhcp->options_out_len < DHCP_OPTIONS_LEN)) {
/* add a fill/padding byte */
dhcp->msg_out->options[dhcp->options_out_len++] = 0;
}

View file

@ -694,7 +694,7 @@ dns_check_entry(u8_t i)
case DNS_STATE_DONE: {
/* if the time to live is nul */
if (--pEntry->ttl == 0) {
if ((pEntry->ttl == 0) || (--pEntry->ttl == 0)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
/* flush this entry */
pEntry->state = DNS_STATE_UNUSED;
@ -816,6 +816,13 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t
if (pEntry->found) {
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
}
if (pEntry->ttl == 0) {
/* RFC 883, page 29: "Zero values are
interpreted to mean that the RR can only be used for the
transaction in progress, and should not be cached."
-> flush this entry now */
goto flushentry;
}
/* deallocate memory and return */
goto memerr;
} else {
@ -838,6 +845,7 @@ responseerr:
if (pEntry->found) {
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
}
flushentry:
/* flush this entry */
pEntry->state = DNS_STATE_UNUSED;
pEntry->found = NULL;
@ -922,6 +930,7 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
* name is already in the local names table.
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
* for resolution if no errors are present.
* - ERR_ARG: dns client not initialized or invalid hostname
*
* @param hostname the hostname that is to be queried
* @param addr pointer to a ip_addr_t where to store the address if it is already
@ -941,7 +950,7 @@ dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback foun
if ((dns_pcb == NULL) || (addr == NULL) ||
(!hostname) || (!hostname[0]) ||
(strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
return ERR_VAL;
return ERR_ARG;
}
#if LWIP_HAVE_LOOPIF

View file

@ -60,6 +60,7 @@
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 2
# endif
u16_t lwip_standard_chksum(void *dataptr, int len);
#endif
/* If none set: */
#ifndef LWIP_CHKSUM_ALGORITHM
@ -77,7 +78,7 @@
* @note accumulator size limits summable length to 64k
* @note host endianess is irrelevant (p3 RFC1071)
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, u16_t len)
{
u32_t acc;
@ -131,7 +132,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
* @return host order (!) lwip checksum (non-inverted Internet sum)
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;
@ -187,7 +188,7 @@ lwip_standard_chksum(void *dataptr, int len)
* by Curt McDowell, Broadcom Corp. December 8th, 2005
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;
@ -256,30 +257,13 @@ lwip_standard_chksum(void *dataptr, int len)
}
#endif
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len)
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
static u16_t
inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped;
u8_t swapped = 0;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; q != NULL; q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
@ -299,12 +283,7 @@ inet_chksum_pseudo(struct pbuf *p,
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
@ -329,18 +308,69 @@ inet_chksum_pseudo(struct pbuf *p,
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo_partial(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len)
inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip_addr_t *src, ip_addr_t *dest)
{
u32_t acc;
u32_t addr;
addr = ip4_addr_get_u32(src);
acc = (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
}
#if LWIP_IPV6
/**
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
* IPv6 addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ipv6 address (used for checksum of pseudo header)
* @param dst destination ipv6 address (used for checksum of pseudo header)
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip6_addr_t *src, ip6_addr_t *dest)
{
u32_t acc = 0;
u32_t addr;
u8_t addr_part;
for (addr_part = 0; addr_part < 4; addr_part++) {
addr = src->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = dest->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
}
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
}
#endif /* LWIP_IPV6 */
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
static u16_t
inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, u32_t acc)
{
struct pbuf *q;
u8_t swapped;
u8_t swapped = 0;
u16_t chklen;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
@ -365,12 +395,7 @@ inet_chksum_pseudo_partial(struct pbuf *p,
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
@ -382,6 +407,76 @@ inet_chksum_pseudo_partial(struct pbuf *p,
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum_pseudo_partial:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest)
{
u32_t acc;
u32_t addr;
addr = ip4_addr_get_u32(src);
acc = (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
}
#if LWIP_IPV6
/**
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
* IPv6 addresses are expected to be in network byte order. Will only compute for a
* portion of the payload.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ipv6 address (used for checksum of pseudo header)
* @param dst destination ipv6 address (used for checksum of pseudo header)
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
* @param chksum_len number of payload bytes used to compute chksum
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest)
{
u32_t acc = 0;
u32_t addr;
u8_t addr_part;
for (addr_part = 0; addr_part < 4; addr_part++) {
addr = src->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = dest->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
}
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
}
#endif /* LWIP_IPV6 */
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarily for IP

View file

@ -56,6 +56,10 @@
#include "lwip/dns.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "lwip/ip6.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
#include "lwip/api.h"
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
@ -66,9 +70,6 @@
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
#endif
#if (!LWIP_ARP && ARP_QUEUEING)
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_UDPLITE)
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
@ -87,6 +88,7 @@
#if (!LWIP_UDP && LWIP_DNS)
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
#endif
@ -99,30 +101,41 @@
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
#endif
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
#endif
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
#endif
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)))
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
#endif
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
#endif
#endif /* !MEMP_MEM_MALLOC */
#if (LWIP_TCP && (TCP_WND > 0xffff))
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
#endif
#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
#endif
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
#endif
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
#endif
#if (LWIP_NETIF_API && (NO_SYS==1))
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
#endif
#if (!LWIP_NETCONN && LWIP_SOCKET)
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
#endif
@ -144,13 +157,6 @@
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
#endif
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
#endif
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
#endif
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
#endif
@ -160,9 +166,6 @@
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
#endif
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
#endif
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
#endif
@ -172,8 +175,8 @@
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif
#if LWIP_IGMP && !defined(LWIP_RAND)
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#if (LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
#error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
@ -184,6 +187,32 @@
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
#endif
#if LWIP_NETCONN && LWIP_TCP
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
#endif
#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
#endif
#endif /* LWIP_NETCONN && LWIP_TCP */
#if LWIP_SOCKET
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
#if SO_ACCEPTCONN != SOF_ACCEPTCONN
#error "SO_ACCEPTCONN != SOF_ACCEPTCONN"
#endif
#if SO_REUSEADDR != SOF_REUSEADDR
#error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
#endif
#if SO_KEEPALIVE != SOF_KEEPALIVE
#error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE"
#endif
#if SO_BROADCAST != SOF_BROADCAST
#error "WARNING: SO_BROADCAST != SOF_BROADCAST"
#endif
#if SO_LINGER != SOF_LINGER
#error "WARNING: SO_LINGER != SOF_LINGER"
#endif
#endif /* LWIP_SOCKET */
/* Compile-time checks for deprecated options.
@ -207,48 +236,54 @@
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef LWIP_DEBUG
static void
lwip_sanity_check(void)
{
/* Warnings */
#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
#define LWIP_DISABLE_TCP_SANITY_CHECKS 0
#endif
#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS
#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0
#endif
/* MEMP sanity checks */
#if !LWIP_DISABLE_MEMP_SANITY_CHECKS
#if LWIP_NETCONN
if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
#if MEMP_MEM_MALLOC
#if !MEMP_NUM_NETCONN && LWIP_SOCKET
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!"
#endif
#else /* MEMP_MEM_MALLOC */
#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error."
#endif
#endif /* MEMP_MEM_MALLOC */
#endif /* LWIP_NETCONN */
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
/* TCP sanity checks */
#if !LWIP_DISABLE_TCP_SANITY_CHECKS
#if LWIP_TCP
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
if (TCP_SND_BUF < 2 * TCP_MSS)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
if (TCP_SNDLOWAT >= TCP_SND_BUF)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n"));
if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n"));
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
if (TCP_WND < TCP_MSS)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SND_BUF < (2 * TCP_MSS)
#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS))
#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SNDLOWAT >= TCP_SND_BUF
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_WND < TCP_MSS
#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#endif /* LWIP_TCP */
#if LWIP_SOCKET
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
if (SO_REUSEADDR != SOF_REUSEADDR)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
if (SO_KEEPALIVE != SOF_KEEPALIVE)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
if (SO_BROADCAST != SOF_BROADCAST)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
if (SO_LINGER != SOF_LINGER)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
#endif /* LWIP_SOCKET */
}
#else /* LWIP_DEBUG */
#define lwip_sanity_check()
#endif /* LWIP_DEBUG */
#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */
/**
* Perform Sanity check of user-configurable values, and initialize all modules.
@ -256,9 +291,6 @@ lwip_sanity_check(void)
void
lwip_init(void)
{
/* Sanity check user-configurable values */
lwip_sanity_check();
/* Modules initialization */
stats_init();
#if !NO_SYS
@ -296,6 +328,13 @@ lwip_init(void)
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if LWIP_IPV6
ip6_init();
nd6_init();
#if LWIP_IPV6_MLD
mld6_init();
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if LWIP_TIMERS
sys_timeouts_init();

View file

@ -122,14 +122,6 @@ static err_t autoip_bind(struct netif *netif);
/* start sending probes for llipaddr */
static void autoip_start_probing(struct netif *netif);
/**
* Initialize this module
*/
void
autoip_init(void)
{
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
}
/** Set a statically allocated struct autoip to work with.
* Using this prevents autoip_start to allocate it using mem_malloc.
@ -170,8 +162,8 @@ autoip_handle_arp_conflict(struct netif *netif)
/* Somehow detect if we are defending or retreating */
unsigned char defend = 1; /* tbd */
if(defend) {
if(netif->autoip->lastconflict > 0) {
if (defend) {
if (netif->autoip->lastconflict > 0) {
/* retreat, there was a conflicting ARP in the last
* DEFEND_INTERVAL seconds
*/
@ -295,7 +287,7 @@ autoip_start(struct netif *netif)
struct autoip *autoip = netif->autoip;
err_t result = ERR_OK;
if(netif_is_up(netif)) {
if (netif_is_up(netif)) {
netif_set_down(netif);
}
@ -309,12 +301,12 @@ autoip_start(struct netif *netif)
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
netif->name[1], (u16_t)netif->num));
if(autoip == NULL) {
if (autoip == NULL) {
/* no AutoIP client attached yet? */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): starting new AUTOIP client\n"));
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
if(autoip == NULL) {
if (autoip == NULL) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): could not allocate autoip\n"));
return ERR_MEM;
@ -360,7 +352,7 @@ autoip_start_probing(struct netif *netif)
* accquiring and probing address
* compliant to RFC 3927 Section 2.2.1
*/
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
}
@ -404,7 +396,7 @@ autoip_tmr()
while (netif != NULL) {
/* only act on AutoIP configured interfaces */
if (netif->autoip != NULL) {
if(netif->autoip->lastconflict > 0) {
if (netif->autoip->lastconflict > 0) {
netif->autoip->lastconflict--;
}
@ -414,10 +406,10 @@ autoip_tmr()
switch(netif->autoip->state) {
case AUTOIP_STATE_PROBING:
if(netif->autoip->ttw > 0) {
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if(netif->autoip->sent_num >= PROBE_NUM) {
if (netif->autoip->sent_num >= PROBE_NUM) {
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
netif->autoip->sent_num = 0;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
@ -439,10 +431,10 @@ autoip_tmr()
break;
case AUTOIP_STATE_ANNOUNCING:
if(netif->autoip->ttw > 0) {
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if(netif->autoip->sent_num == 0) {
if (netif->autoip->sent_num == 0) {
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
* Now we can bind to an IP address and use it.
*
@ -458,7 +450,7 @@ autoip_tmr()
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++;
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
netif->autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0;
netif->autoip->ttw = 0;
@ -494,12 +486,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
*/
ip_addr_t sipaddr, dipaddr;
struct eth_addr netifaddr;
netifaddr.addr[0] = netif->hwaddr[0];
netifaddr.addr[1] = netif->hwaddr[1];
netifaddr.addr[2] = netif->hwaddr[2];
netifaddr.addr[3] = netif->hwaddr[3];
netifaddr.addr[4] = netif->hwaddr[4];
netifaddr.addr[5] = netif->hwaddr[5];
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules).

View file

@ -70,7 +70,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
* Currently only processes icmp echo requests and sends
* out the echo response.
*
* @param p the icmp echo request packet, p->payload pointing to the ip header
* @param p the icmp echo request packet, p->payload pointing to the icmp header
* @param inp the netif on which this packet was received
*/
void
@ -87,10 +87,9 @@ icmp_input(struct pbuf *p, struct netif *inp)
ICMP_STATS_INC(icmp.recv);
snmp_inc_icmpinmsgs();
iphdr = (struct ip_hdr *)p->payload;
iphdr = (struct ip_hdr *)ip_current_header();
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
if (p->len < sizeof(u16_t)*2) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
goto lenerr;
}
@ -110,13 +109,13 @@ icmp_input(struct pbuf *p, struct netif *inp)
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip_addr_ismulticast(&current_iphdr_dest)) {
if (ip_addr_ismulticast(ip_current_dest_addr())) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */
@ -190,12 +189,16 @@ icmp_input(struct pbuf *p, struct netif *inp)
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
ICMPH_TYPE_SET(iecho, ICMP_ER);
#if CHECKSUM_GEN_ICMP
/* adjust the checksum */
if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
}
#else /* CHECKSUM_GEN_ICMP */
iecho->chksum = 0;
#endif /* CHECKSUM_GEN_ICMP */
/* Set the correct TTL and recalculate the header checksum. */
IPH_TTL_SET(iphdr, ICMP_TTL);

View file

@ -100,7 +100,7 @@ Steve Reynolds
*/
#define IGMP_TTL 1
#define IGMP_MINLEN 8
#define ROUTER_ALERT 0x9404
#define ROUTER_ALERT 0x9404U
#define ROUTER_ALERTLEN 4
/*
@ -139,7 +139,6 @@ static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
static err_t igmp_remove_group(struct igmp_group *group);
static void igmp_timeout( struct igmp_group *group);
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
static void igmp_stop_timer(struct igmp_group *group);
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
static void igmp_send(struct igmp_group *group, u8_t type);
@ -382,14 +381,13 @@ igmp_remove_group(struct igmp_group *group)
/**
* Called from ip_input() if a new IGMP packet is received.
*
* @param p received igmp packet, p->payload pointing to the ip header
* @param p received igmp packet, p->payload pointing to the igmp header
* @param inp network interface on which the packet was received
* @param dest destination ip address of the igmp packet
*/
void
igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
{
struct ip_hdr * iphdr;
struct igmp_msg* igmp;
struct igmp_group* group;
struct igmp_group* groupref;
@ -397,8 +395,7 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
IGMP_STATS_INC(igmp.recv);
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
iphdr = (struct ip_hdr *)p->payload;
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
if (p->len < IGMP_MINLEN) {
pbuf_free(p);
IGMP_STATS_INC(igmp.lenerr);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
@ -406,9 +403,9 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src));
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
/* Now calculate and check the checksum */
@ -702,19 +699,10 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time)
if (max_time == 0) {
max_time = 1;
}
#ifdef LWIP_RAND
/* ensure the random value is > 0 */
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
}
/**
* Stop a timer for an igmp_group
*
* @param group the igmp_group for which to stop the timer
*/
static void
igmp_stop_timer(struct igmp_group *group)
{
group->timer = 0;
#endif /* LWIP_RAND */
}
/**

View file

@ -83,7 +83,7 @@
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept custom port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port))
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept DHCP client port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
@ -93,20 +93,8 @@
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
#endif /* LWIP_DHCP */
/**
* The interface that provided the packet for the current callback
* invocation.
*/
struct netif *current_netif;
/**
* Header of the input packet currently being processed.
*/
const struct ip_hdr *current_header;
/** Source IP address of current_header */
ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
ip_addr_t current_iphdr_dest;
/** Global data for both IPv4 and IPv6 */
struct ip_globals ip_data;
/** The IP header ID of the next outgoing IP packet */
static u16_t ip_id;
@ -125,8 +113,15 @@ ip_route(ip_addr_t *dest)
{
struct netif *netif;
#ifdef LWIP_HOOK_IP4_ROUTE
netif = LWIP_HOOK_IP4_ROUTE(dest);
if (netif != NULL) {
return netif;
}
#endif
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) {
for (netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
@ -147,6 +142,41 @@ ip_route(ip_addr_t *dest)
}
#if IP_FORWARD
/**
* Determine whether an IP address is in a reserved set of addresses
* that may not be forwarded, or whether datagrams to that destination
* may be forwarded.
* @param p the packet to forward
* @param dest the destination IP address
* @return 1: can forward 0: discard
*/
static int
ip_canforward(struct pbuf *p)
{
u32_t addr = ip4_addr_get_u32(ip_current_dest_addr());
if (p->flags & PBUF_FLAG_LLBCAST) {
/* don't route link-layer broadcasts */
return 0;
}
if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) {
/* don't route link-layer multicasts unless the destination address is an IP
multicast address */
return 0;
}
if (IP_EXPERIMENTAL(addr)) {
return 0;
}
if (IP_CLASSA(addr)) {
u32_t net = addr & IP_CLASSA_NET;
if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) {
/* don't route loopback packets */
return 0;
}
}
return 1;
}
/**
* Forwards an IP packet. It finds an appropriate route for the
* packet, decrements the TTL value of the packet, adjusts the
@ -163,28 +193,35 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
PERF_START;
if (!ip_canforward(p)) {
goto return_noroute;
}
/* RFC3927 2.7: do not forward link-local addresses */
if (ip_addr_islinklocal(&current_iphdr_dest)) {
if (ip_addr_islinklocal(ip_current_dest_addr())) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
goto return_noroute;
}
/* Find network interface where to forward this IP packet to. */
netif = ip_route(&current_iphdr_dest);
netif = ip_route(ip_current_dest_addr());
if (netif == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
/* @todo: send ICMP_DUR_NET? */
goto return_noroute;
}
#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF
/* Do not forward packets onto the same network interface on which
* they arrived. */
if (netif == inp) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
goto return_noroute;
}
#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */
/* decrement TTL */
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
@ -201,23 +238,37 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
}
/* Incrementally update the IP checksum. */
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
} else {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
}
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
IP_STATS_INC(ip.fw);
IP_STATS_INC(ip.xmit);
snmp_inc_ipforwdatagrams();
PERF_STOP("ip_forward");
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu)) {
if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) {
#if IP_FRAG
ip_frag(p, netif, ip_current_dest_addr());
#else /* IP_FRAG */
/* @todo: send ICMP Destination Unreacheable code 13 "Communication administratively prohibited"? */
#endif /* IP_FRAG */
} else {
/* send ICMP Destination Unreacheable code 4: "Fragmentation Needed and DF Set" */
icmp_dest_unreach(p, ICMP_DUR_FRAG);
}
return;
}
/* transmit pbuf on chosen interface */
netif->output(netif, p, &current_iphdr_dest);
netif->output(netif, p, ip_current_dest_addr());
return;
return_noroute:
snmp_inc_ipoutnoroutes();
@ -264,6 +315,13 @@ ip_input(struct pbuf *p, struct netif *inp)
return ERR_OK;
}
#ifdef LWIP_HOOK_IP4_INPUT
if (LWIP_HOOK_IP4_INPUT(p, inp)) {
/* the packet has been eaten */
return ERR_OK;
}
#endif
/* obtain IP header length in number of 32-bit words */
iphdr_hlen = IPH_HL(iphdr);
/* calculate IP header length in bytes */
@ -311,13 +369,13 @@ ip_input(struct pbuf *p, struct netif *inp)
pbuf_realloc(p, iphdr_len);
/* copy IP addresses to aligned ip_addr_t */
ip_addr_copy(current_iphdr_dest, iphdr->dest);
ip_addr_copy(current_iphdr_src, iphdr->src);
ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest);
ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src);
/* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
if (ip_addr_ismulticast(&current_iphdr_dest)) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
if (ip_addr_ismulticast(ip_current_dest_addr())) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) {
netif = inp;
} else {
netif = NULL;
@ -340,9 +398,9 @@ ip_input(struct pbuf *p, struct netif *inp)
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
/* unicast to this interface address? */
if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
if (ip_addr_cmp(ip_current_dest_addr(), &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
ip_addr_isbroadcast(ip_current_dest_addr(), netif)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
@ -352,7 +410,7 @@ ip_input(struct pbuf *p, struct netif *inp)
/* connections to link-local addresses must persist after changing
the netif's address (RFC3927 ch. 1.9) */
if ((netif->autoip != NULL) &&
ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
ip_addr_cmp(ip_current_dest_addr(), &(netif->autoip->llipaddr))) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
@ -400,10 +458,10 @@ ip_input(struct pbuf *p, struct netif *inp)
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
if (check_ip_src && !ip_addr_isany(&current_iphdr_src))
if (check_ip_src && !ip_addr_isany(ip_current_src_addr()))
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
{ if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
(ip_addr_ismulticast(&current_iphdr_src))) {
{ if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) ||
(ip_addr_ismulticast(ip_current_src_addr()))) {
/* packet source is not valid */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
/* free (drop) packet pbufs */
@ -421,7 +479,7 @@ ip_input(struct pbuf *p, struct netif *inp)
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
/* non-broadcast packet? */
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
} else
@ -480,14 +538,16 @@ ip_input(struct pbuf *p, struct netif *inp)
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
current_netif = inp;
current_header = iphdr;
ip_data.current_netif = inp;
ip_data.current_ip4_header = iphdr;
ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4;
#if LWIP_RAW
/* raw input did not eat the packet? */
if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
{
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
@ -513,14 +573,15 @@ ip_input(struct pbuf *p, struct netif *inp)
#endif /* LWIP_ICMP */
#if LWIP_IGMP
case IP_PROTO_IGMP:
igmp_input(p, inp, &current_iphdr_dest);
igmp_input(p, inp, ip_current_dest_addr());
break;
#endif /* LWIP_IGMP */
default:
#if LWIP_ICMP
/* send ICMP destination protocol unreachable unless is was a broadcast */
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
!ip_addr_ismulticast(&current_iphdr_dest)) {
if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) &&
!ip_addr_ismulticast(ip_current_dest_addr())) {
pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO);
}
@ -535,10 +596,12 @@ ip_input(struct pbuf *p, struct netif *inp)
}
}
current_netif = NULL;
current_header = NULL;
ip_addr_set_any(&current_iphdr_src);
ip_addr_set_any(&current_iphdr_dest);
/* @todo: this is not really necessary... */
ip_data.current_netif = NULL;
ip_data.current_ip4_header = NULL;
ip_data.current_ip_header_tot_len = 0;
ip_addr_set_any(ip_current_src_addr());
ip_addr_set_any(ip_current_dest_addr());
return ERR_OK;
}
@ -625,7 +688,7 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
}
#if CHECKSUM_GEN_IP_INLINE
for (i = 0; i < optlen_aligned; i += sizeof(u16_t)) {
for (i = 0; i < optlen_aligned/2; i++) {
chk_sum += ((u16_t*)p->payload)[i];
}
#endif /* CHECKSUM_GEN_IP_INLINE */
@ -657,9 +720,10 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
IPH_TOS_SET(iphdr, tos);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_v_hl_tos;
chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_LEN_SET(iphdr, htons(p->tot_len));
#if CHECKSUM_GEN_IP_INLINE
@ -801,9 +865,9 @@ ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
return ERR_RTE;
}
netif->addr_hint = addr_hint;
NETIF_SET_HWADDRHINT(netif, addr_hint);
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
netif->addr_hint = NULL;
NETIF_SET_HWADDRHINT(netif, NULL);
return err;
}
@ -817,9 +881,6 @@ void
ip_debug_print(struct pbuf *p)
{
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
u8_t *payload;
payload = (u8_t *)iphdr + IP_HLEN;
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));

View file

@ -93,7 +93,7 @@ ip4_addr_netmask_valid(u32_t netmask)
u32_t nm_hostorder = lwip_htonl(netmask);
/* first, check for the first zero */
for (mask = 1U << 31 ; mask != 0; mask >>= 1) {
for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
if ((nm_hostorder & mask) == 0) {
break;
}

View file

@ -0,0 +1 @@
IPv6 support in lwIP is very experimental.

View file

@ -1,11 +1,11 @@
/**
* @file
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
*
* DHCPv6.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@ -32,11 +32,19 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Author: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#include "lwip/inet.h"
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#endif /* LWIP_IPV6_DHCP6 */

View file

@ -0,0 +1,193 @@
/**
* @file
*
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_ETHERNET
#include "lwip/ethip6.h"
#include "lwip/nd6.h"
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp6.h"
#include <string.h>
#define ETHTYPE_IPV6 0x86DD
/** The ethernet address */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_addr {
PACK_STRUCT_FIELD(u8_t addr[6]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Ethernet header */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
/**
* Send an IPv6 packet on the network using netif->linkoutput
* The ethernet header is filled in before sending.
*
* @params netif the lwIP network interface on which to send the packet
* @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
* @params src the source MAC address to be copied into the ethernet header
* @params dst the destination MAC address to be copied into the ethernet header
* @return ERR_OK if the packet was sent, any other err_t on failure
*/
static err_t
ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
{
struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!",
(netif->hwaddr_len == 6));
SMEMCPY(&ethhdr->dest, dst, 6);
SMEMCPY(&ethhdr->src, src, 6);
ethhdr->type = PP_HTONS(ETHTYPE_IPV6);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p));
/* send the packet */
return netif->linkoutput(netif, p);
}
/**
* Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
*
* For IPv6 multicast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* For unicast addresses, ...
*
* @TODO anycast addresses
*
* @param netif The lwIP network interface which the IP packet will be sent on.
* @param q The pbuf(s) containing the IP packet to be sent.
* @param ip6addr The IP address of the packet destination.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or etharp_send_ip().
*/
err_t
ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
{
struct eth_addr dest;
s8_t i;
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("etharp_output: could not allocate room for header.\n"));
return ERR_BUF;
}
/* multicast destination IP address? */
if (ip6_addr_ismulticast(ip6addr)) {
/* Hash IP multicast address to MAC address.*/
dest.addr[0] = 0x33;
dest.addr[1] = 0x33;
dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0];
dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1];
dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2];
dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
}
/* We have a unicast destination IP address */
/* TODO anycast? */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return ERR_MEM;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
}
/* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
(neighbor_cache[i].state == ND6_DELAY) ||
(neighbor_cache[i].state == ND6_PROBE)) {
/* Send out. */
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
}
/* We should queue packet on this interface. */
pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
return nd6_queue_packet(i, q);
}
#endif /* LWIP_IPV6 && LWIP_ETHERNET */

View file

@ -0,0 +1,337 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
#include "lwip/stats.h"
#include <string.h>
#ifndef LWIP_ICMP6_DATASIZE
#define LWIP_ICMP6_DATASIZE 8
#endif
#if LWIP_ICMP6_DATASIZE == 0
#define LWIP_ICMP6_DATASIZE 8
#endif
/* Forward declarations */
static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
/**
* Process an input ICMPv6 message. Called by ip6_input.
*
* Will generate a reply for echo requests. Other messages are forwarded
* to nd6_input, or mld6_input.
*
* @param p the mld packet, p->payload pointing to the icmpv6 header
* @param inp the netif on which this packet was received
*/
void
icmp6_input(struct pbuf *p, struct netif *inp)
{
struct icmp6_hdr *icmp6hdr;
struct pbuf * r;
ip6_addr_t * reply_src;
ICMP6_STATS_INC(icmp6.recv);
/* Check that ICMPv6 header fits in payload */
if (p->len < sizeof(struct icmp6_hdr)) {
/* drop short packets */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.lenerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
icmp6hdr = (struct icmp6_hdr *)p->payload;
#if LWIP_ICMP6_CHECKSUM_CHECK
if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
ip6_current_dest_addr()) != 0) {
/* Checksum failed */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.chkerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
#endif /* LWIP_ICMP6_CHECKSUM_CHECK */
switch (icmp6hdr->type) {
case ICMP6_TYPE_NA: /* Neighbor advertisement */
case ICMP6_TYPE_NS: /* Neighbor solicitation */
case ICMP6_TYPE_RA: /* Router advertisement */
case ICMP6_TYPE_RD: /* Redirect */
case ICMP6_TYPE_PTB: /* Packet too big */
nd6_input(p, inp);
return;
break;
case ICMP6_TYPE_RS:
#if LWIP_IPV6_FORWARD
/* TODO implement router functionality */
#endif
break;
#if LWIP_IPV6_MLD
case ICMP6_TYPE_MLQ:
case ICMP6_TYPE_MLR:
case ICMP6_TYPE_MLD:
mld6_input(p, inp);
return;
break;
#endif
case ICMP6_TYPE_EREQ:
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
/* drop */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.drop);
return;
}
#endif /* LWIP_MULTICAST_PING */
/* Allocate reply. */
r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
if (r == NULL) {
/* drop */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.memerr);
return;
}
/* Copy echo request. */
if (pbuf_copy(r, p) != ERR_OK) {
/* drop */
pbuf_free(p);
pbuf_free(r);
ICMP6_STATS_INC(icmp6.err);
return;
}
/* Determine reply source IPv6 address. */
#if LWIP_MULTICAST_PING
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
reply_src = ip6_select_source_address(inp, ip6_current_src_addr());
if (reply_src == NULL) {
/* drop */
pbuf_free(p);
pbuf_free(r);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
}
else
#endif /* LWIP_MULTICAST_PING */
{
reply_src = ip6_current_dest_addr();
}
/* Set fields in reply. */
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
/* Send reply. */
ICMP6_STATS_INC(icmp6.xmit);
ip6_output_if(r, reply_src, ip6_current_src_addr(),
LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
pbuf_free(r);
break;
default:
ICMP6_STATS_INC(icmp6.proterr);
ICMP6_STATS_INC(icmp6.drop);
break;
}
pbuf_free(p);
}
/**
* Send an icmpv6 'destination unreachable' packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IPv6 header
* @param c ICMPv6 code for the unreachable type
*/
void
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
{
icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
}
/**
* Send an icmpv6 'packet too big' packet.
*
* @param p the input packet for which the 'packet too big' should be sent,
* p->payload pointing to the IPv6 header
* @param mtu the maximum mtu that we can accept
*/
void
icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
{
icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
}
/**
* Send an icmpv6 'time exceeded' packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IPv6 header
* @param c ICMPv6 code for the time exceeded type
*/
void
icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
{
icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
}
/**
* Send an icmpv6 'parameter problem' packet.
*
* @param p the input packet for which the 'param problem' should be sent,
* p->payload pointing to the IP header
* @param c ICMPv6 code for the param problem type
* @param pointer the pointer to the byte where the parameter is found
*/
void
icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
{
icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
}
/**
* Send an ICMPv6 packet in response to an incoming packet.
*
* @param p the input packet for which the response should be sent,
* p->payload pointing to the IPv6 header
* @param code Code of the ICMPv6 header
* @param data Additional 32-bit parameter in the ICMPv6 header
* @param type Type of the ICMPv6 header
*/
static void
icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
{
struct pbuf *q;
struct icmp6_hdr *icmp6hdr;
ip6_addr_t *reply_src, *reply_dest;
ip6_addr_t reply_src_local, reply_dest_local;
struct ip6_hdr *ip6hdr;
struct netif *netif;
/* ICMPv6 header + IPv6 header + data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
ICMP6_STATS_INC(icmp6.memerr);
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp 6message",
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
icmp6hdr = (struct icmp6_hdr *)q->payload;
icmp6hdr->type = type;
icmp6hdr->code = code;
icmp6hdr->data = data;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
IP6_HLEN + LWIP_ICMP6_DATASIZE);
/* Get the destination address and netif for this ICMP message. */
if ((ip_current_netif() == NULL) ||
((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
/* Special case, as ip6_current_xxx is either NULL, or points
* to a different packet than the one that expired.
* We must use the addresses that are stored in the expired packet. */
ip6hdr = (struct ip6_hdr *)p->payload;
/* copy from packed address to aligned address */
ip6_addr_copy(reply_dest_local, ip6hdr->src);
ip6_addr_copy(reply_src_local, ip6hdr->dest);
reply_dest = &reply_dest_local;
reply_src = &reply_src_local;
netif = ip6_route(reply_src, reply_dest);
if (netif == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
}
else {
netif = ip_current_netif();
reply_dest = ip6_current_src_addr();
/* Select an address to use as source. */
reply_src = ip6_select_source_address(netif, reply_dest);
if (reply_src == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
}
/* calculate checksum */
icmp6hdr->chksum = 0;
icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
reply_src, reply_dest);
ICMP6_STATS_INC(icmp6.xmit);
ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
pbuf_free(q);
}
#endif /* LWIP_ICMP6 && LWIP_IPV6 */

View file

@ -0,0 +1,51 @@
/**
* @file
*
* INET v6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/inet6.h"
/** @see ip6_addr.c for implementation of functions. */
#endif /* LWIP_IPV6 */

1028
lib/liblwip/core/ipv6/ip6.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,251 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
* Functions for handling IPv6 addresses.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
/* used by IP6_ADDR_ANY in ip6_addr.h */
const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
#ifndef isprint
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
#endif
/**
* Check whether "cp" is a valid ascii representation
* of an IPv6 address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
*
* @param cp IPv6 address in ascii represenation (e.g. "FF01::1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
ip6addr_aton(const char *cp, ip6_addr_t *addr)
{
u32_t addr_index, zero_blocks, current_block_index, current_block_value;
const char * s;
/* Count the number of colons, to count the number of blocks in a "::" sequence
zero_blocks may be 1 even if there are no :: sequences */
zero_blocks = 8;
for (s = cp; *s != 0; s++) {
if (*s == ':')
zero_blocks--;
else if (!isxdigit(*s))
break;
}
/* parse each block */
addr_index = 0;
current_block_index = 0;
current_block_value = 0;
for (s = cp; *s != 0; s++) {
if (*s == ':') {
if (addr) {
if (current_block_index & 0x1) {
addr->addr[addr_index++] |= current_block_value;
}
else {
addr->addr[addr_index] = current_block_value << 16;
}
}
current_block_index++;
current_block_value = 0;
if (current_block_index > 7) {
/* address too long! */
return 0;
} if (s[1] == ':') {
s++;
/* "::" found, set zeros */
while (zero_blocks-- > 0) {
if (current_block_index & 0x1) {
addr_index++;
}
else {
if (addr) {
addr->addr[addr_index] = 0;
}
}
current_block_index++;
}
}
} else if (isxdigit(*s)) {
/* add current digit */
current_block_value = (current_block_value << 4) +
(isdigit(*s) ? *s - '0' :
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
} else {
/* unexpected digit, space? CRLF? */
break;
}
}
if (addr) {
if (current_block_index & 0x1) {
addr->addr[addr_index++] |= current_block_value;
}
else {
addr->addr[addr_index] = current_block_value << 16;
}
}
/* convert to network byte order. */
if (addr) {
for (addr_index = 0; addr_index < 4; addr_index++) {
addr->addr[addr_index] = htonl(addr->addr[addr_index]);
}
}
if (current_block_index != 7) {
return 0;
}
return 1;
}
/**
* Convert numeric IPv6 address into ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip6 address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* represenation of addr
*/
char *
ip6addr_ntoa(const ip6_addr_t *addr)
{
static char str[40];
return ip6addr_ntoa_r(addr, str, 40);
}
/**
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
*
* @param addr ip6 address in network order to convert
* @param buf target buffer where the string is stored
* @param buflen length of buf
* @return either pointer to buf which now holds the ASCII
* representation of addr or NULL if buf was too small
*/
char *
ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
{
u32_t current_block_index, current_block_value;
s32_t zero_flag, i;
i = 0;
zero_flag = 0; /* used to indicate a zero chain for "::' */
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
/* get the current 16-bit block */
current_block_value = htonl(addr->addr[current_block_index >> 1]);
if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16;
}
current_block_value &= 0xffff;
if (current_block_value == 0) {
/* generate empty block "::" */
if (!zero_flag) {
if (current_block_index > 0) {
zero_flag = 1;
buf[i++] = ':';
if (i >= buflen) return NULL;
}
}
}
else {
if (current_block_index > 0) {
buf[i++] = ':';
if (i >= buflen) return NULL;
}
if ((current_block_value & 0xf000) == 0) {
zero_flag = 1;
}
else {
buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
zero_flag = 0;
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
zero_flag = 0;
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
zero_flag = 0;
if (i >= buflen) return NULL;
}
buf[i++] = xchar((current_block_value & 0xf));
if (i >= buflen) return NULL;
zero_flag = 0;
}
}
buf[i] = 0;
return buf;
}
#endif /* LWIP_IPV6 */

View file

@ -0,0 +1,697 @@
/**
* @file
*
* IPv6 fragmentation and reassembly.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#include "lwip/ip6_frag.h"
#include "lwip/ip6.h"
#include "lwip/icmp6.h"
#include "lwip/nd6.h"
#include "lwip/pbuf.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
/** Setting this to 0, you can turn off checking the fragments for overlapping
* regions. The code gets a little smaller. Only use this if you know that
* overlapping won't occur on your network! */
#ifndef IP_REASS_CHECK_OVERLAP
#define IP_REASS_CHECK_OVERLAP 1
#endif /* IP_REASS_CHECK_OVERLAP */
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
* is set to 1, so one datagram can be reassembled at a time, only. */
#ifndef IP_REASS_FREE_OLDEST
#define IP_REASS_FREE_OLDEST 1
#endif /* IP_REASS_FREE_OLDEST */
#define IP_REASS_FLAG_LASTFRAG 0x01
/** This is a helper struct which holds the starting
* offset and the ending offset of this fragment to
* easily chain the fragments.
* It has the same packing requirements as the IPv6 header, since it replaces
* the Fragment Header in memory in incoming fragments to keep
* track of the various fragments.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_reass_helper {
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
PACK_STRUCT_FIELD(u16_t start);
PACK_STRUCT_FIELD(u16_t end);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* static variables */
static struct ip6_reassdata *reassdatagrams;
static u16_t ip6_reass_pbufcount;
/* Forward declarations. */
static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr);
#if IP_REASS_FREE_OLDEST
static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed);
#endif /* IP_REASS_FREE_OLDEST */
void
ip6_reass_tmr(void)
{
struct ip6_reassdata *r, *tmp;
r = reassdatagrams;
while (r != NULL) {
/* Decrement the timer. Once it reaches 0,
* clean up the incomplete fragment assembly */
if (r->timer > 0) {
r->timer--;
r = r->next;
} else {
/* reassembly timed out */
tmp = r;
/* get the next pointer before freeing */
r = r->next;
/* free the helper struct and all enqueued pbufs */
ip6_reass_free_complete_datagram(tmp);
}
}
}
/**
* Free a datagram (struct ip6_reassdata) and all its pbufs.
* Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
* sends an ICMP time exceeded packet.
*
* @param ipr datagram to free
*/
static void
ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
{
struct ip6_reassdata *prev;
u16_t pbufs_freed = 0;
u8_t clen;
struct pbuf *p;
struct ip6_reass_helper *iprh;
#if LWIP_ICMP6
iprh = (struct ip6_reass_helper *)ipr->p->payload;
if (iprh->start == 0) {
/* The first fragment was received, send ICMP time exceeded. */
/* First, de-queue the first pbuf from r->p. */
p = ipr->p;
ipr->p = iprh->next_pbuf;
/* Then, move back to the original header (we are now pointing to Fragment header). */
if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) {
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
}
else {
icmp6_time_exceeded(p, ICMP6_TE_FRAG);
}
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(p);
}
#endif /* LWIP_ICMP6 */
/* First, free all received pbufs. The individual pbufs need to be released
separately as they have not yet been chained */
p = ipr->p;
while (p != NULL) {
struct pbuf *pcur;
iprh = (struct ip6_reass_helper *)p->payload;
pcur = p;
/* get the next pointer before freeing */
p = iprh->next_pbuf;
clen = pbuf_clen(pcur);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(pcur);
}
/* Then, unchain the struct ip6_reassdata from the list and free it. */
if (ipr == reassdatagrams) {
reassdatagrams = ipr->next;
} else {
prev = reassdatagrams;
while (prev != NULL) {
if (prev->next == ipr) {
break;
}
prev = prev->next;
}
if (prev != NULL) {
prev->next = ipr->next;
}
}
memp_free(MEMP_IP6_REASSDATA, ipr);
/* Finally, update number of pbufs in reassembly queue */
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
ip6_reass_pbufcount -= pbufs_freed;
}
#if IP_REASS_FREE_OLDEST
/**
* Free the oldest datagram to make room for enqueueing new fragments.
* The datagram ipr is not freed!
*
* @param ipr ip6_reassdata for the current fragment
* @param pbufs_needed number of pbufs needed to enqueue
* (used for freeing other datagrams if not enough space)
*/
static void
ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed)
{
struct ip6_reassdata *r, *oldest;
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
* but don't free the current datagram! */
do {
r = oldest = reassdatagrams;
while (r != NULL) {
if (r != ipr) {
if (r->timer <= oldest->timer) {
/* older than the previous oldest */
oldest = r;
}
}
r = r->next;
}
if (oldest != NULL) {
ip6_reass_free_complete_datagram(oldest);
}
} while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL));
}
#endif /* IP_REASS_FREE_OLDEST */
/**
* Reassembles incoming IPv6 fragments into an IPv6 datagram.
*
* @param p points to the IPv6 Fragment Header
* @param len the length of the payload (after Fragment Header)
* @return NULL if reassembly is incomplete, pbuf pointing to
* IPv6 Header if reassembly is complete
*/
struct pbuf *
ip6_reass(struct pbuf *p)
{
struct ip6_reassdata *ipr, *ipr_prev;
struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct ip6_frag_hdr * frag_hdr;
u16_t offset, len;
u8_t clen, valid = 1;
struct pbuf *q;
IP6_FRAG_STATS_INC(ip6_frag.recv);
frag_hdr = (struct ip6_frag_hdr *) p->payload;
clen = pbuf_clen(p);
offset = ntohs(frag_hdr->_fragment_offset);
/* Calculate fragment length from IPv6 payload length.
* Adjust for headers before Fragment Header.
* And finally adjust by Fragment Header length. */
len = ntohs(ip6_current_header()->_plen);
len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN;
len -= IP6_FRAG_HLEN;
/* Look for the datagram the fragment belongs to in the current datagram queue,
* remembering the previous in the queue for later dequeueing. */
for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {
/* Check if the incoming fragment matches the one currently present
in the reassembly buffer. If so, we proceed with copying the
fragment into the buffer. */
if ((frag_hdr->_identification == ipr->identification) &&
ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) &&
ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) {
IP6_FRAG_STATS_INC(ip6_frag.cachehit);
break;
}
ipr_prev = ipr;
}
if (ipr == NULL) {
/* Enqueue a new datagram into the datagram queue */
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
if (ipr == NULL) {
#if IP_REASS_FREE_OLDEST
/* Make room and try again. */
ip6_reass_remove_oldest_datagram(ipr, clen);
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
if (ipr == NULL)
#endif /* IP_REASS_FREE_OLDEST */
{
IP6_FRAG_STATS_INC(ip6_frag.memerr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
memset(ipr, 0, sizeof(struct ip6_reassdata));
ipr->timer = IP_REASS_MAXAGE;
/* enqueue the new structure to the front of the list */
ipr->next = reassdatagrams;
reassdatagrams = ipr;
/* Use the current IPv6 header for src/dest address reference.
* Eventually, we will replace it when we get the first fragment
* (it might be this one, in any case, it is done later). */
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
/* copy the fragmented packet id. */
ipr->identification = frag_hdr->_identification;
/* copy the nexth field */
ipr->nexth = frag_hdr->_nexth;
}
/* Check if we are allowed to enqueue more datagrams. */
if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
ip6_reass_remove_oldest_datagram(ipr, clen);
if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)
#endif /* IP_REASS_FREE_OLDEST */
{
/* @todo: send ICMPv6 time exceeded here? */
/* drop this pbuf */
IP6_FRAG_STATS_INC(ip6_frag.memerr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
/* Overwrite Fragment Header with our own helper struct. */
iprh = (struct ip6_reass_helper *)p->payload;
iprh->next_pbuf = NULL;
iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
/* find the right place to insert this pbuf */
/* Iterate through until we either get to the end of the list (append),
* or we find on with a larger offset (insert). */
for (q = ipr->p; q != NULL;) {
iprh_tmp = (struct ip6_reass_helper*)q->payload;
if (iprh->start < iprh_tmp->start) {
#if IP_REASS_CHECK_OVERLAP
if (iprh->end > iprh_tmp->start) {
/* fragment overlaps with following, throw away */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
if (iprh_prev != NULL) {
if (iprh->start < iprh_prev->end) {
/* fragment overlaps with previous, throw away */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
#endif /* IP_REASS_CHECK_OVERLAP */
/* the new pbuf should be inserted before this */
iprh->next_pbuf = q;
if (iprh_prev != NULL) {
/* not the fragment with the lowest offset */
iprh_prev->next_pbuf = p;
} else {
/* fragment with the lowest offset */
ipr->p = p;
}
break;
} else if(iprh->start == iprh_tmp->start) {
/* received the same datagram twice: no need to keep the datagram */
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
#if IP_REASS_CHECK_OVERLAP
} else if(iprh->start < iprh_tmp->end) {
/* overlap: no need to keep the new datagram */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
#endif /* IP_REASS_CHECK_OVERLAP */
} else {
/* Check if the fragments received so far have no gaps. */
if (iprh_prev != NULL) {
if (iprh_prev->end != iprh_tmp->start) {
/* There is a fragment missing between the current
* and the previous fragment */
valid = 0;
}
}
}
q = iprh_tmp->next_pbuf;
iprh_prev = iprh_tmp;
}
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
if (q == NULL) {
if (iprh_prev != NULL) {
/* this is (for now), the fragment with the highest offset:
* chain it to the last fragment */
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
#endif /* IP_REASS_CHECK_OVERLAP */
iprh_prev->next_pbuf = p;
if (iprh_prev->end != iprh->start) {
valid = 0;
}
} else {
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
ipr->p == NULL);
#endif /* IP_REASS_CHECK_OVERLAP */
/* this is the first fragment we ever received for this ip datagram */
ipr->p = p;
}
}
/* Track the current number of pbufs current 'in-flight', in order to limit
the number of fragments that may be enqueued at any one time */
ip6_reass_pbufcount += clen;
/* Remember IPv6 header if this is the first fragment. */
if (iprh->start == 0) {
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
}
/* If this is the last fragment, calculate total packet length. */
if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
ipr->datagram_len = iprh->end;
}
/* Additional validity tests: we have received first and last fragment. */
iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload;
if (iprh_tmp->start != 0) {
valid = 0;
}
if (ipr->datagram_len == 0) {
valid = 0;
}
/* Final validity test: no gaps between current and last fragment. */
iprh_prev = iprh;
q = iprh->next_pbuf;
while ((q != NULL) && valid) {
iprh = (struct ip6_reass_helper*)q->payload;
if (iprh_prev->end != iprh->start) {
valid = 0;
break;
}
iprh_prev = iprh;
q = iprh->next_pbuf;
}
if (valid) {
/* All fragments have been received */
/* chain together the pbufs contained within the ip6_reassdata list. */
iprh = (struct ip6_reass_helper*) ipr->p->payload;
while(iprh != NULL) {
if (iprh->next_pbuf != NULL) {
/* Save next helper struct (will be hidden in next step). */
iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload;
/* hide the fragment header for every succeding fragment */
pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN);
pbuf_cat(ipr->p, iprh->next_pbuf);
}
else {
iprh_tmp = NULL;
}
iprh = iprh_tmp;
}
/* Adjust datagram length by adding header lengths. */
ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr)
+ IP6_FRAG_HLEN
- IP6_HLEN ;
/* Set payload length in ip header. */
ipr->iphdr->_plen = htons(ipr->datagram_len);
/* Get the furst pbuf. */
p = ipr->p;
/* Restore Fragment Header in first pbuf. Mark as "single fragment"
* packet. Restore nexth. */
frag_hdr = (struct ip6_frag_hdr *) p->payload;
frag_hdr->_nexth = ipr->nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = 0;
frag_hdr->_identification = 0;
/* release the sources allocate for the fragment queue entry */
if (reassdatagrams == ipr) {
/* it was the first in the list */
reassdatagrams = ipr->next;
} else {
/* it wasn't the first, so it must have a valid 'prev' */
LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
ipr_prev->next = ipr->next;
}
memp_free(MEMP_IP6_REASSDATA, ipr);
/* adjust the number of pbufs currently queued for reassembly. */
ip6_reass_pbufcount -= pbuf_clen(p);
/* Move pbuf back to IPv6 header. */
if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) {
LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
pbuf_free(p);
return NULL;
}
/* Return the pbuf chain */
return p;
}
/* the datagram is not (yet?) reassembled completely */
return NULL;
nullreturn:
pbuf_free(p);
return NULL;
}
#endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_FRAG
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void)
{
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
}
/** Free a struct pbuf_custom_ref */
static void
ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
{
LWIP_ASSERT("p != NULL", p != NULL);
memp_free(MEMP_FRAG_PBUF, p);
}
/** Free-callback function to free a 'struct pbuf_custom_ref', called by
* pbuf_free. */
static void
ip6_frag_free_pbuf_custom(struct pbuf *p)
{
struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
LWIP_ASSERT("pcr != NULL", pcr != NULL);
LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
if (pcr->original != NULL) {
pbuf_free(pcr->original);
}
ip6_frag_free_pbuf_custom_ref(pcr);
}
/**
* Fragment an IPv6 datagram if too large for the netif or path MTU.
*
* Chop the datagram in MTU sized chunks and send them in order
* by pointing PBUF_REFs into p
*
* @param p ipv6 packet to send
* @param netif the netif on which to send
* @param dest destination ipv6 address to which to send
*
* @return ERR_OK if sent successfully, err_t otherwise
*/
err_t
ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest)
{
struct ip6_hdr *original_ip6hdr;
struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr * frag_hdr;
struct pbuf *rambuf;
struct pbuf *newpbuf;
static u32_t identification;
u16_t nfb;
u16_t left, cop;
u16_t mtu;
u16_t fragment_offset = 0;
u16_t last;
u16_t poff = IP6_HLEN;
u16_t newpbuflen = 0;
u16_t left_to_copy;
identification++;
original_ip6hdr = (struct ip6_hdr *)p->payload;
mtu = nd6_get_destination_mtu(dest, netif);
/* TODO we assume there are no options in the unfragmentable part (IPv6 header). */
left = p->tot_len - IP6_HLEN;
nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;
while (left) {
last = (left <= nfb);
/* Fill this fragment */
cop = last ? left : nfb;
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
* but limited to the size of an mtu.
*/
rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
if (rambuf == NULL) {
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP6_HLEN + IP6_FRAG_HLEN)));
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
p->tot_len -= poff;
left_to_copy = cop;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
/* Is this pbuf already empty? */
if (!newpbuflen) {
p = p->next;
continue;
}
pcr = ip6_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
/* Mirror this pbuf, although we might not need all of it. */
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
if (newpbuf == NULL) {
ip6_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
pbuf_ref(p);
pcr->original = p;
pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
* so that it is removed when pbuf_dechain is later called on rambuf.
*/
pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen;
if (left_to_copy) {
p = p->next;
}
}
poff = newpbuflen;
/* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = htonl(identification);
IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);
/* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated.
*/
IP6_FRAG_STATS_INC(ip6_frag.xmit);
netif->output_ip6(netif, rambuf, dest);
/* Unfortunately we can't reuse rambuf - the hardware may still be
* using the buffer. Instead we free it (and the ensuing chain) and
* recreate it next time round the loop. If we're lucky the hardware
* will have already sent the packet, the free will really free, and
* there will be zero memory penalty.
*/
pbuf_free(rambuf);
left -= cop;
fragment_offset += cop;
}
return ERR_OK;
}
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */

View file

@ -0,0 +1,580 @@
/**
* @file
*
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
/* Based on igmp.c implementation of igmp v2 protocol */
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */
#include "lwip/mld6.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include <string.h>
/*
* MLD constants
*/
#define MLD6_HL 1
#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500)
#define MLD6_GROUP_NON_MEMBER 0
#define MLD6_GROUP_DELAYING_MEMBER 1
#define MLD6_GROUP_IDLE_MEMBER 2
/* The list of joined groups. */
static struct mld_group* mld_group_list;
/* Forward declarations. */
static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr);
static err_t mld6_free_group(struct mld_group *group);
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
static void mld6_send(struct mld_group *group, u8_t type);
/**
* Stop MLD processing on interface
*
* @param netif network interface on which stop MLD processing
*/
err_t
mld6_stop(struct netif *netif)
{
struct mld_group *group = mld_group_list;
struct mld_group *prev = NULL;
struct mld_group *next;
/* look for groups joined on this interface further down the list */
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == mld_group_list) {
mld_group_list = next;
}
/* is there a "previous" group defined? */
if (prev != NULL) {
prev->next = next;
}
/* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
} else {
/* change the "previous" */
prev = group;
}
/* move to "next" */
group = next;
}
return ERR_OK;
}
/**
* Report MLD memberships for this interface
*
* @param netif network interface on which report MLD memberships
*/
void
mld6_report_groups(struct netif *netif)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if (group->netif == netif) {
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
group = group->next;
}
}
/**
* Search for a group that is joined on a netif
*
* @param ifp the network interface for which to look
* @param addr the group ipv6 address to search for
* @return a struct mld_group* if the group has been found,
* NULL if the group wasn't found.
*/
struct mld_group *
mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) {
return group;
}
group = group->next;
}
return NULL;
}
/**
* create a new group
*
* @param ifp the network interface for which to create
* @param addr the new group ipv6
* @return a struct mld_group*,
* NULL on memory error.
*/
static struct mld_group *
mld6_new_group(struct netif *ifp, ip6_addr_t *addr)
{
struct mld_group *group;
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
if (group != NULL) {
group->netif = ifp;
ip6_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = mld_group_list;
mld_group_list = group;
}
return group;
}
/**
* Remove a group in the mld_group_list and free
*
* @param group the group to remove
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
static err_t
mld6_free_group(struct mld_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (mld_group_list == group) {
mld_group_list = group->next;
} else {
/* look for group further down the list */
struct mld_group *tmpGroup;
for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not find group */
if (tmpGroup == NULL)
err = ERR_ARG;
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
return err;
}
/**
* Process an input MLD message. Called by icmp6_input.
*
* @param p the mld packet, p->payload pointing to the icmpv6 header
* @param inp the netif on which this packet was received
*/
void
mld6_input(struct pbuf *p, struct netif *inp)
{
struct mld_header * mld_hdr;
struct mld_group* group;
MLD6_STATS_INC(mld6.recv);
/* Check that mld header fits in packet. */
if (p->len < sizeof(struct mld_header)) {
/* TODO debug message */
pbuf_free(p);
MLD6_STATS_INC(mld6.lenerr);
MLD6_STATS_INC(mld6.drop);
return;
}
mld_hdr = (struct mld_header *)p->payload;
switch (mld_hdr->type) {
case ICMP6_TYPE_MLQ: /* Multicast listener query. */
{
/* Is it a general query? */
if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
ip6_addr_isany(&(mld_hdr->multicast_address))) {
MLD6_STATS_INC(mld6.rx_general);
/* Report all groups, except all nodes group, and if-local groups. */
group = mld_group_list;
while (group != NULL) {
if ((group->netif == inp) &&
(!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
(!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
mld6_delayed_report(group, mld_hdr->max_resp_delay);
}
group = group->next;
}
}
else {
/* Have we joined this group?
* We use IP6 destination address to have a memory aligned copy.
* mld_hdr->multicast_address should be the same. */
MLD6_STATS_INC(mld6.rx_group);
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
if (group != NULL) {
/* Schedule a report. */
mld6_delayed_report(group, mld_hdr->max_resp_delay);
}
}
break; /* ICMP6_TYPE_MLQ */
}
case ICMP6_TYPE_MLR: /* Multicast listener report. */
{
/* Have we joined this group?
* We use IP6 destination address to have a memory aligned copy.
* mld_hdr->multicast_address should be the same. */
MLD6_STATS_INC(mld6.rx_report);
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
if (group != NULL) {
/* If we are waiting to report, cancel it. */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
group->timer = 0; /* stopped */
group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
}
}
break; /* ICMP6_TYPE_MLR */
}
case ICMP6_TYPE_MLD: /* Multicast listener done. */
{
/* Do nothing, router will query us. */
break; /* ICMP6_TYPE_MLD */
}
default:
MLD6_STATS_INC(mld6.proterr);
MLD6_STATS_INC(mld6.drop);
break;
}
pbuf_free(p);
}
/**
* Join a group on a network interface.
*
* @param srcaddr ipv6 address of the network interface which should
* join a new group. If IP6_ADDR_ANY, join on all netifs
* @param groupaddr the ipv6 address of the group to join
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
*/
err_t
mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct mld_group *group;
struct netif *netif;
u8_t match;
u8_t i;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we join this interface ? */
match = 0;
if (ip6_addr_isany(srcaddr)) {
match = 1;
}
else {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
match = 1;
break;
}
}
}
if (match) {
/* find group or create a new one if not found */
group = mld6_lookfor_group(netif, groupaddr);
if (group == NULL) {
/* Joining a new group. Create a new group entry. */
group = mld6_new_group(netif, groupaddr);
if (group == NULL) {
return ERR_MEM;
}
/* Activate this address on the MAC layer. */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER);
}
/* Report our membership. */
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
/* Increment group use */
group->use++;
err = ERR_OK;
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* Leave a group on a network interface.
*
* @param srcaddr ipv6 address of the network interface which should
* leave the group. If IP6_ISANY, leave on all netifs
* @param groupaddr the ipv6 address of the group to leave
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
*/
err_t
mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct mld_group *group;
struct netif *netif;
u8_t match;
u8_t i;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we leave this interface ? */
match = 0;
if (ip6_addr_isany(srcaddr)) {
match = 1;
}
else {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
match = 1;
break;
}
}
}
if (match) {
/* find group */
group = mld6_lookfor_group(netif, groupaddr);
if (group != NULL) {
/* Leave if there is no other use of the group */
if (group->use <= 1) {
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
MLD6_STATS_INC(mld6.tx_leave);
mld6_send(group, ICMP6_TYPE_MLD);
}
/* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER);
}
/* Free the group */
mld6_free_group(group);
} else {
/* Decrement group use */
group->use--;
}
/* Leave on this interface */
err = ERR_OK;
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* Periodic timer for mld processing. Must be called every
* MLD6_TMR_INTERVAL milliseconds (100).
*
* When a delaying member expires, a membership report is sent.
*/
void
mld6_tmr(void)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER;
}
}
}
group = group->next;
}
}
/**
* Schedule a delayed membership report for a group
*
* @param group the mld_group for which "delaying" membership report
* should be sent
* @param maxresp the max resp delay provided in the query
*/
static void
mld6_delayed_report(struct mld_group *group, u16_t maxresp)
{
/* Convert maxresp from milliseconds to tmr ticks */
maxresp = maxresp / MLD6_TMR_INTERVAL;
if (maxresp == 0) {
maxresp = 1;
}
#ifdef LWIP_RAND
/* Randomize maxresp. (if LWIP_RAND is supported) */
maxresp = (LWIP_RAND() % (maxresp - 1)) + 1;
#endif /* LWIP_RAND */
/* Apply timer value if no report has been scheduled already. */
if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) ||
((group->group_state == MLD6_GROUP_DELAYING_MEMBER) &&
((group->timer == 0) || (maxresp < group->timer)))) {
group->timer = maxresp;
group->group_state = MLD6_GROUP_DELAYING_MEMBER;
}
}
/**
* Send a MLD message (report or done).
*
* An IPv6 hop-by-hop options header with a router alert option
* is prepended.
*
* @param group the group to report or quit
* @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
*/
static void
mld6_send(struct mld_group *group, u8_t type)
{
struct mld_header * mld_hdr;
struct pbuf * p;
ip6_addr_t * src_addr;
/* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) {
/* We couldn't allocate a suitable pbuf. drop it. */
if (p != NULL) {
pbuf_free(p);
}
MLD6_STATS_INC(mld6.memerr);
return;
}
/* Move to make room for Hop-by-hop options header. */
if (pbuf_header(p, -IP6_HBH_HLEN)) {
pbuf_free(p);
MLD6_STATS_INC(mld6.lenerr);
return;
}
/* Select our source address. */
if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) {
/* This is a special case, when we are performing duplicate address detection.
* We must join the multicast group, but we don't have a valid address yet. */
src_addr = IP6_ADDR_ANY;
} else {
/* Use link-local address as source address. */
src_addr = netif_ip6_addr(group->netif, 0);
}
/* MLD message header pointer. */
mld_hdr = (struct mld_header *)p->payload;
/* Set fields. */
mld_hdr->type = type;
mld_hdr->code = 0;
mld_hdr->chksum = 0;
mld_hdr->max_resp_delay = 0;
mld_hdr->reserved = 0;
ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
src_addr, &(group->group_address));
/* Add hop-by-hop headers options: router alert with MLD value. */
ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
/* Send the packet out. */
MLD6_STATS_INC(mld6.xmit);
ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif);
pbuf_free(p);
}
#endif /* LWIP_IPV6 */

1785
lib/liblwip/core/ipv6/nd6.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -78,9 +78,10 @@
void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element;
memp_t poolnr;
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
#if MEM_USE_POOLS_TRY_BIGGER_POOL
@ -113,9 +114,9 @@ again:
/* save the pool number this element came from */
element->poolnr = poolnr;
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
element++;
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
return element;
return ret;
}
/**
@ -128,13 +129,13 @@ again:
void
mem_free(void *rmem)
{
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
struct memp_malloc_helper *hmem;
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
/* get the original struct memp_malloc_helper */
hmem--;
hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
@ -190,7 +191,9 @@ static struct mem *ram_end;
static struct mem *lfree;
/** concurrent access protection */
#if !NO_SYS
static sys_mutex_t mem_mutex;
#endif
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
@ -518,7 +521,7 @@ mem_malloc(mem_size_t size)
sys_mutex_lock(&mem_mutex);
LWIP_MEM_ALLOC_PROTECT();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* run as long as a mem_free disturbed mem_malloc */
/* run as long as a mem_free disturbed mem_malloc or mem_trim */
do {
local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
@ -532,12 +535,14 @@ mem_malloc(mem_size_t size)
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
/* allow mem_free to run */
/* allow mem_free or mem_trim to run */
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
local_mem_free_count = mem_free_count;
/* If mem_free or mem_trim have run, we have to restart since they
could have altered our current struct mem. */
local_mem_free_count = 1;
break;
}
mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
if ((!mem->used) &&
@ -581,15 +586,27 @@ mem_malloc(mem_size_t size)
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_malloc_adjust_lfree:
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
if (mem == lfree) {
struct mem *cur = lfree;
/* Find next free block after mem and update lowest free pointer */
while (lfree->used && lfree != ram_end) {
while (cur->used && cur != ram_end) {
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
/* prevent high interrupt latency... */
LWIP_MEM_ALLOC_PROTECT();
lfree = (struct mem *)(void *)&ram[lfree->next];
if (mem_free_count != 0) {
/* If mem_free or mem_trim have run, we have to restart since they
could have altered our current struct mem or lfree. */
goto mem_malloc_adjust_lfree;
}
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
cur = (struct mem *)(void *)&ram[cur->next];
}
lfree = cur;
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
LWIP_MEM_ALLOC_UNPROTECT();

View file

@ -58,6 +58,9 @@
#include "lwip/snmp_msg.h"
#include "lwip/dns.h"
#include "netif/ppp_oe.h"
#include "lwip/nd6.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#include <string.h>
@ -176,19 +179,20 @@ static u8_t memp_memory[MEM_ALIGNMENT - 1
#if MEMP_SANITY_CHECK
/**
* Check that memp-lists don't form a circle
* Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
*/
static int
memp_sanity(void)
{
s16_t i, c;
struct memp *m, *n;
s16_t i;
struct memp *t, *h;
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 < 0) {
t = memp_tab[i];
if(t != NULL) {
for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) {
if (t == h) {
return 0;
}
}
@ -282,17 +286,25 @@ memp_overflow_check_all(void)
u16_t i, j;
struct memp *p;
#if !MEMP_SEPARATE_POOLS
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
#if MEMP_SEPARATE_POOLS
p = (struct memp *)(memp_bases[i]);
#endif /* MEMP_SEPARATE_POOLS */
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_overflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
#if !MEMP_SEPARATE_POOLS
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
#if MEMP_SEPARATE_POOLS
p = (struct memp *)(memp_bases[i]);
#endif /* MEMP_SEPARATE_POOLS */
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_underflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
@ -310,9 +322,13 @@ memp_overflow_init(void)
struct memp *p;
u8_t *m;
#if !MEMP_SEPARATE_POOLS
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
#if MEMP_SEPARATE_POOLS
p = (struct memp *)(memp_bases[i]);
#endif /* MEMP_SEPARATE_POOLS */
for (j = 0; j < memp_num[i]; ++j) {
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;

View file

@ -40,6 +40,7 @@
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
@ -59,6 +60,12 @@
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif /* LWIP_DHCP */
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_IPV6_MLD
#include "lwip/mld6.h"
#endif /* LWIP_IPV6_MLD */
#if LWIP_NETIF_STATUS_CALLBACK
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
@ -75,6 +82,12 @@
struct netif *netif_list;
struct netif *netif_default;
static u8_t netif_num;
#if LWIP_IPV6
static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr);
#endif /* LWIP_IPV6 */
#if LWIP_HAVE_LOOPIF
static struct netif loop_netif;
@ -137,7 +150,9 @@ struct netif *
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
{
static u8_t netifnum = 0;
#if LWIP_IPV6
u32_t i;
#endif
LWIP_ASSERT("No init function given", init != NULL);
@ -145,6 +160,13 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip6_addr_set_zero(&netif->ip6_addr[i]);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
}
netif->output_ip6 = netif_null_output_ip6;
#endif /* LWIP_IPV6 */
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
@ -154,6 +176,17 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_IPV6_AUTOCONFIG
/* IPv6 address autoconfiguration not enabled by default */
netif->ip6_autoconfig_enabled = 0;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/* netif not under DHCPv6 control by default */
netif->dhcp6 = NULL;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
@ -163,6 +196,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = NULL;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
@ -170,11 +206,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
/* remember netif specific state information data */
netif->state = state;
netif->num = netifnum++;
netif->num = netif_num++;
netif->input = input;
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
NETIF_SET_HWADDRHINT(netif, NULL);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
@ -245,6 +279,10 @@ netif_remove(struct netif *netif)
igmp_stop(netif);
}
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/* stop MLD processing */
mld6_stop(netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
if (netif_is_up(netif)) {
/* set netif down before removing (call callback function) */
netif_set_down(netif);
@ -273,6 +311,11 @@ netif_remove(struct netif *netif)
/* reset default netif */
netif_set_default(NULL);
}
#if LWIP_NETIF_REMOVE_CALLBACK
if (netif->remove_callback) {
netif->remove_callback(netif);
}
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
}
@ -325,16 +368,16 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
struct tcp_pcb_listen *lpcb;
/* address is actually being changed? */
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
if (ip_addr_cmp(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr))
#if LWIP_AUTOIP
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
&& !ip_addr_islinklocal(&(pcb->local_ip))
&& !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
@ -348,11 +391,11 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
}
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* PCB bound to current local interface address? */
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) &&
(ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_set(&(lpcb->local_ip), ipaddr);
ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr);
}
}
}
@ -471,6 +514,16 @@ void netif_set_up(struct netif *netif)
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/* send mld memberships */
mld6_report_groups( netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
/* Send Router Solicitation messages. */
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
}
}
}
@ -491,6 +544,11 @@ void netif_set_down(struct netif *netif)
snmp_get_sysuptime(&netif->ts);
#endif
#if LWIP_ARP
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_cleanup_netif(netif);
}
#endif /* LWIP_ARP */
NETIF_STATUS_CALLBACK(netif);
}
}
@ -507,6 +565,19 @@ void netif_set_status_callback(struct netif *netif, netif_status_callback_fn sta
}
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
/**
* Set callback to be called when the interface has been removed
*/
void
netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback)
{
if (netif) {
netif->remove_callback = remove_callback;
}
}
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
/**
* Called by a driver when its link goes up
*/
@ -541,6 +612,10 @@ void netif_set_link_up(struct netif *netif )
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/* send mld memberships */
mld6_report_groups( netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
}
NETIF_LINK_CALLBACK(netif);
}
@ -750,3 +825,72 @@ netif_poll_all(void)
}
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_IPV6
s8_t
netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr)
{
s8_t i;
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) {
return i;
}
}
return -1;
}
void
netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit)
{
u8_t i, addr_index;
/* Link-local prefix. */
netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul);
netif->ip6_addr[0].addr[1] = 0;
/* Generate interface ID. */
if (from_mac_48bit) {
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
((u32_t)(netif->hwaddr[1]) << 16) |
((u32_t)(netif->hwaddr[2]) << 8) |
(0xff));
netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) |
((u32_t)(netif->hwaddr[3]) << 16) |
((u32_t)(netif->hwaddr[4]) << 8) |
(netif->hwaddr[5]));
}
else {
/* Use hwaddr directly as interface ID. */
netif->ip6_addr[0].addr[2] = 0;
netif->ip6_addr[0].addr[3] = 0;
addr_index = 3;
for (i = 0; i < 8; i++) {
if (i == 4) {
addr_index--;
}
netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03));
}
}
/* Set address state. */
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* Will perform duplicate address detection (DAD). */
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
#else
/* Consider address valid. */
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
#endif /* LWIP_IPV6_AUTOCONFIG */
}
static err_t
netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr)
{
(void)netif;
(void)p;
(void)ipaddr;
return ERR_IF;
}
#endif /* LWIP_IPV6 */

View file

@ -70,7 +70,7 @@
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "arch/perf.h"
#if TCP_QUEUE_OOSEQ
#if LWIP_TCP && TCP_QUEUE_OOSEQ
#include "lwip/tcp_impl.h"
#endif
#if LWIP_CHECKSUM_ON_COPY
@ -84,18 +84,25 @@
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ
#define PBUF_POOL_IS_EMPTY()
#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
#ifndef PBUF_POOL_FREE_OOSEQ
#define PBUF_POOL_FREE_OOSEQ 1
#endif /* PBUF_POOL_FREE_OOSEQ */
#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
#if PBUF_POOL_FREE_OOSEQ
#if !NO_SYS
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
#include "lwip/tcpip.h"
#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \
if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
SYS_ARCH_PROTECT(old_level); \
pbuf_free_ooseq_pending = 0; \
SYS_ARCH_UNPROTECT(old_level); \
} } while(0)
#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
#endif /* !NO_SYS */
volatile u8_t pbuf_free_ooseq_pending;
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
static u8_t pbuf_free_ooseq_queued;
/**
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
* if we run out of pool pbufs. It's better to give priority to new packets
@ -104,15 +111,17 @@ static u8_t pbuf_free_ooseq_queued;
* This must be done in the correct thread context therefore this function
* can only be used with NO_SYS=0 and through tcpip_callback.
*/
static void
pbuf_free_ooseq(void* arg)
#if !NO_SYS
static
#endif /* !NO_SYS */
void
pbuf_free_ooseq(void)
{
struct tcp_pcb* pcb;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_UNUSED_ARG(arg);
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_queued = 0;
pbuf_free_ooseq_pending = 0;
SYS_ARCH_UNPROTECT(old_level);
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
@ -126,29 +135,42 @@ pbuf_free_ooseq(void* arg)
}
}
#if !NO_SYS
/**
* Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq().
*/
static void
pbuf_free_ooseq_callback(void *arg)
{
LWIP_UNUSED_ARG(arg);
pbuf_free_ooseq();
}
#endif /* !NO_SYS */
/** Queue a call to pbuf_free_ooseq if not already queued. */
static void
pbuf_pool_is_empty(void)
{
#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_pending = 1;
SYS_ARCH_UNPROTECT(old_level);
#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
u8_t queued;
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
queued = pbuf_free_ooseq_queued;
pbuf_free_ooseq_queued = 1;
queued = pbuf_free_ooseq_pending;
pbuf_free_ooseq_pending = 1;
SYS_ARCH_UNPROTECT(old_level);
if(!queued) {
/* queue a call to pbuf_free_ooseq if not already queued */
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_queued = 0;
SYS_ARCH_UNPROTECT(old_level);
}
PBUF_POOL_FREE_OOSEQ_QUEUE_CALL();
}
#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
}
#endif /* PBUF_POOL_FREE_OOSEQ */
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
/**
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
@ -190,21 +212,21 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
/* determine header offset */
offset = 0;
switch (layer) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset += PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset += PBUF_IP_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset += PBUF_LINK_HLEN;
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
offset = 0;
break;
default:
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
@ -336,7 +358,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
* @param p pointer to the custom pbuf to initialize (already allocated)
* @param payload_mem pointer to the buffer that is used for payload and headers,
* must be at least big enough to hold 'length' plus the header size,
* may be NULL if set later
* may be NULL if set later.
* ATTENTION: The caller is responsible for correct alignment of this buffer!!
* @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
* big enough to hold 'length' plus the header size
*/
@ -348,35 +371,35 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
/* determine header offset */
offset = 0;
switch (l) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset += PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset += PBUF_IP_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset += PBUF_LINK_HLEN;
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
offset = 0;
break;
default:
LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
return NULL;
}
if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) {
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
return NULL;
}
p->pbuf.next = NULL;
if (payload_mem != NULL) {
p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset);
} else {
p->pbuf.payload = NULL;
}
@ -840,7 +863,6 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
/* iterate through pbuf chain */
do
{
LWIP_ASSERT("p_to != NULL", p_to != NULL);
/* copy one part of the original chain */
if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
/* complete current p_from fits into current p_to */
@ -853,17 +875,18 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
offset_to += len;
offset_from += len;
LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
if (offset_to == p_to->len) {
/* on to next p_to (if any) */
offset_to = 0;
p_to = p_to->next;
}
LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
if (offset_from >= p_from->len) {
/* on to next p_from (if any) */
offset_from = 0;
p_from = p_from->next;
}
if (offset_to == p_to->len) {
/* on to next p_to (if any) */
offset_to = 0;
p_to = p_to->next;
LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;);
}
if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
/* don't copy more than one packet! */

View file

@ -49,6 +49,8 @@
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include <string.h>
@ -79,29 +81,47 @@ raw_input(struct pbuf *p, struct netif *inp)
struct ip_hdr *iphdr;
s16_t proto;
u8_t eaten = 0;
#if LWIP_IPV6
struct ip6_hdr *ip6hdr;
#endif /* LWIP_IPV6 */
LWIP_UNUSED_ARG(inp);
iphdr = (struct ip_hdr *)p->payload;
proto = IPH_PROTO(iphdr);
#if LWIP_IPV6
if (IPH_V(iphdr) == 6) {
ip6hdr = (struct ip6_hdr *)p->payload;
proto = IP6H_NEXTH(ip6hdr);
}
else
#endif /* LWIP_IPV6 */
{
proto = IPH_PROTO(iphdr);
}
prev = NULL;
pcb = raw_pcbs;
/* loop through all raw pcbs until the packet is eaten by one */
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if ((pcb->protocol == IP_PROTO_ANY || pcb->protocol == proto) &&
(ip_addr_isany(&pcb->local_ip) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
#if LWIP_IPV6
&& !PCB_ISIPV6(pcb)
#endif /* LWIP_IPV6 */
)
#endif /* IP_SOF_BROADCAST_RECV */
{
/* receive callback function available? */
if (pcb->recv != NULL) {
if (pcb->recv.ip4 != NULL) {
/* the receive callback function did not eat the packet? */
if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
if (eaten != 0) {
/* receive function ate the packet */
p = NULL;
eaten = 1;
@ -141,7 +161,7 @@ raw_input(struct pbuf *p, struct netif *inp)
err_t
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->local_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
return ERR_OK;
}
@ -161,7 +181,7 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
err_t
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->remote_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
return ERR_OK;
}
@ -183,7 +203,7 @@ void
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv.ip4 = recv;
pcb->recv_arg = recv_arg;
}
@ -204,13 +224,21 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
{
err_t err;
struct netif *netif;
ip_addr_t *src_ip;
ipX_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
s16_t header_size;
ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
header_size = (
#if LWIP_IPV6
PCB_ISIPV6(pcb) ? IP6_HLEN :
#endif /* LWIP_IPV6 */
IP_HLEN);
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, IP_HLEN)) {
if (pbuf_header(p, header_size)) {
/* allocate header in new pbuf */
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
/* new header pbuf could not be allocated? */
@ -218,22 +246,25 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
}
/* { first pbuf q points to header pbuf } */
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
} else {
/* first pbuf q equals given pbuf */
q = p;
if(pbuf_header(q, -IP_HLEN)) {
if(pbuf_header(q, -header_size)) {
LWIP_ASSERT("Can't restore header we just removed!", 0);
return ERR_MEM;
}
}
if ((netif = ip_route(ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
@ -242,32 +273,42 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
}
#if IP_SOF_BROADCAST
/* broadcast filter? */
if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
#if LWIP_IPV6
/* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */
if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
{
/* broadcast filter? */
if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
}
return ERR_VAL;
}
return ERR_VAL;
}
#endif /* IP_SOF_BROADCAST */
if (ip_addr_isany(&pcb->local_ip)) {
if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
#if LWIP_IPV6
if (src_ip == NULL) {
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
#endif /* LWIP_IPV6 */
} else {
/* use RAW PCB local IP address as source address */
src_ip = &(pcb->local_ip);
src_ip = &pcb->local_ip;
}
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */
if (q != p) {
@ -287,7 +328,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
err_t
raw_send(struct raw_pcb *pcb, struct pbuf *p)
{
return raw_sendto(pcb, p, &pcb->remote_ip);
return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip));
}
/**
@ -349,4 +390,26 @@ raw_new(u8_t proto)
return pcb;
}
#if LWIP_IPV6
/**
* Create a RAW PCB for IPv6.
*
* @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @param proto the protocol number (next header) of the IPv6 packet payload
* (e.g. IP6_NEXTH_ICMP6)
*
* @see raw_remove()
*/
struct raw_pcb *
raw_new_ip6(u8_t proto)
{
struct raw_pcb *pcb;
pcb = raw_new(proto);
ip_set_v6(pcb, 1);
return pcb;
}
#endif /* LWIP_IPV6 */
#endif /* LWIP_RAW */

View file

@ -43,10 +43,12 @@
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/ip_frag.h"
#include "lwip/mem.h"
#include "lwip/tcp_impl.h"
#include "lwip/udp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_structs.h"
#include "lwip/sys.h"
#include "netif/etharp.h"
/**
@ -71,7 +73,7 @@
#endif
#ifndef SNMP_GET_SYSUPTIME
#define SNMP_GET_SYSUPTIME(sysuptime)
#define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10))
#endif
static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
@ -1795,7 +1797,7 @@ void snmp_insert_udpidx_tree(struct udp_pcb *pcb)
u8_t level;
LWIP_ASSERT("pcb != NULL", pcb != NULL);
snmp_iptooid(&pcb->local_ip, &udpidx[0]);
snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]);
udpidx[4] = pcb->local_port;
udp_rn = &udp_root;
@ -1848,7 +1850,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
u8_t bindings, fc, level, del_cnt;
LWIP_ASSERT("pcb != NULL", pcb != NULL);
snmp_iptooid(&pcb->local_ip, &udpidx[0]);
snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]);
udpidx[4] = pcb->local_port;
/* count PCBs for a given binding
@ -1857,7 +1859,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
npcb = udp_pcbs;
while ((npcb != NULL))
{
if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) &&
if (ipX_addr_cmp(0, &npcb->local_ip, &pcb->local_ip) &&
(npcb->local_port == udpidx[4]))
{
bindings++;
@ -3879,17 +3881,17 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
{
u8_t id;
struct udp_pcb *pcb;
ip_addr_t ip;
ipX_addr_t ip;
u16_t port;
LWIP_UNUSED_ARG(len);
snmp_oidtoip(&od->id_inst_ptr[1], &ip);
snmp_oidtoip(&od->id_inst_ptr[1], (ip_addr_t*)&ip);
LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff));
port = (u16_t)od->id_inst_ptr[5];
pcb = udp_pcbs;
while ((pcb != NULL) &&
!(ip_addr_cmp(&pcb->local_ip, &ip) &&
!(ipX_addr_cmp(0, &pcb->local_ip, &ip) &&
(pcb->local_port == port)))
{
pcb = pcb->next;
@ -3903,8 +3905,8 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
{
case 1: /* udpLocalAddress */
{
ip_addr_t *dst = (ip_addr_t*)value;
*dst = pcb->local_ip;
ipX_addr_t *dst = (ipX_addr_t*)value;
ipX_addr_copy(0, *dst, pcb->local_ip);
}
break;
case 2: /* udpLocalPort */

View file

@ -90,7 +90,7 @@ snmp_init(void)
trap_msg.pcb = snmp1_pcb;
#ifdef SNMP_PRIVATE_MIB_INIT
/* If defined, rhis must be a function-like define to initialize the
/* If defined, this must be a function-like define to initialize the
* private MIB after the stack has been initialized.
* The private MIB can also be initialized in tcpip_callback (or after
* the stack is initialized), this define is only for convenience. */
@ -105,13 +105,28 @@ snmp_init(void)
static void
snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
{
/* move names back from outvb to invb */
int v;
struct snmp_varbind *vbi = msg_ps->invb.head;
struct snmp_varbind *vbo = msg_ps->outvb.head;
for (v=0; v<msg_ps->vb_idx; v++) {
vbi->ident_len = vbo->ident_len;
vbo->ident_len = 0;
vbi->ident = vbo->ident;
vbo->ident = NULL;
vbi = vbi->next;
vbo = vbo->next;
}
/* free outvb */
snmp_varbind_list_free(&msg_ps->outvb);
/* we send invb back */
msg_ps->outvb = msg_ps->invb;
msg_ps->invb.head = NULL;
msg_ps->invb.tail = NULL;
msg_ps->invb.count = 0;
msg_ps->error_status = error;
msg_ps->error_index = 1 + msg_ps->vb_idx;
/* error index must be 0 for error too big */
msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0;
snmp_send_response(msg_ps);
snmp_varbind_list_free(&msg_ps->outvb);
msg_ps->state = SNMP_MSG_EMPTY;
@ -182,7 +197,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
/* allocate output varbind */
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
vb->next = NULL;
@ -202,7 +216,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value != NULL)
{
en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
@ -297,7 +310,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
/* allocate output varbind */
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
vb->next = NULL;
@ -318,7 +330,6 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
vb->value_len <= SNMP_MAX_VALUE_SIZE);
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value != NULL)
{
mn->get_value(&object_def, vb->value_len, vb->value);
@ -331,6 +342,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
msg_ps->vb_ptr->ident = vb->ident;
msg_ps->vb_ptr->ident_len = vb->ident_len;
vb->ident = NULL;
vb->ident_len = 0;
memp_free(MEMP_SNMP_VARBIND, vb);
snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
}
@ -1305,7 +1318,6 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
struct snmp_varbind *vb;
vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
LWIP_ASSERT("vb != NULL",vb != NULL);
if (vb != NULL)
{
u8_t i;
@ -1319,9 +1331,9 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
/* allocate array of s32_t for our object identifier */
vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
if (vb->ident == NULL)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n"));
memp_free(MEMP_SNMP_VARBIND, vb);
return NULL;
}
@ -1343,9 +1355,9 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
/* allocate raw bytes for our object value */
vb->value = memp_malloc(MEMP_SNMP_VALUE);
LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
if (vb->value == NULL)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n"));
if (vb->ident != NULL)
{
memp_free(MEMP_SNMP_VALUE, vb->ident);
@ -1360,6 +1372,10 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
vb->value = NULL;
}
}
else
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n"));
}
return vb;
}

View file

@ -145,14 +145,7 @@ snmp_send_response(struct snmp_msg_pstat *m_stat)
/* pass 1, size error, encode packet ino the pbuf(s) */
ofs = snmp_resp_header_enc(m_stat, p);
if (m_stat->error_status == SNMP_ES_TOOBIG)
{
snmp_varbind_list_enc(&emptyvb, p, ofs);
}
else
{
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
}
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
switch (m_stat->error_status)
{
@ -224,6 +217,7 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
ip_addr_t dst_ip;
struct pbuf *p;
u16_t i,tot_len;
err_t err = ERR_OK;
for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
{
@ -233,55 +227,58 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
ip_addr_copy(trap_msg.dip, td->dip);
/* lookup current source address for this dst */
dst_if = ip_route(&td->dip);
ip_addr_copy(dst_ip, dst_if->ip_addr);
/* @todo: what about IPv6? */
trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
{
/* enterprise-Specific trap */
trap_msg.enterprise = eoid;
}
else
{
/* generic (MIB-II) trap */
snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
}
snmp_get_sysuptime(&trap_msg.ts);
if (dst_if != NULL) {
ip_addr_copy(dst_ip, dst_if->ip_addr);
/* @todo: what about IPv6? */
trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
{
/* enterprise-Specific trap */
trap_msg.enterprise = eoid;
}
else
{
/* generic (MIB-II) trap */
snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
}
snmp_get_sysuptime(&trap_msg.ts);
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
if (p != NULL)
{
u16_t ofs;
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
if (p != NULL)
{
u16_t ofs;
/* pass 1, encode packet ino the pbuf(s) */
ofs = snmp_trap_header_enc(&trap_msg, p);
snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
/* pass 1, encode packet ino the pbuf(s) */
ofs = snmp_trap_header_enc(&trap_msg, p);
snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
snmp_inc_snmpouttraps();
snmp_inc_snmpoutpkts();
snmp_inc_snmpouttraps();
snmp_inc_snmpoutpkts();
/** send to the TRAP destination */
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
/** send to the TRAP destination */
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
pbuf_free(p);
}
else
{
return ERR_MEM;
pbuf_free(p);
} else {
err = ERR_MEM;
}
} else {
/* routing error */
err = ERR_RTE;
}
}
}
return ERR_OK;
return err;
}
void

View file

@ -69,7 +69,7 @@ void stats_init(void)
#if LWIP_STATS_DISPLAY
void
stats_display_proto(struct stats_proto *proto, char *name)
stats_display_proto(struct stats_proto *proto, const char *name)
{
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
@ -88,9 +88,9 @@ stats_display_proto(struct stats_proto *proto, char *name)
#if IGMP_STATS
void
stats_display_igmp(struct stats_igmp *igmp)
stats_display_igmp(struct stats_igmp *igmp, const char *name)
{
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
@ -99,8 +99,8 @@ stats_display_igmp(struct stats_igmp *igmp)
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n\t", igmp->rx_group));
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", igmp->rx_general));
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
@ -110,7 +110,7 @@ stats_display_igmp(struct stats_igmp *igmp)
#if MEM_STATS || MEMP_STATS
void
stats_display_mem(struct stats_mem *mem, char *name)
stats_display_mem(struct stats_mem *mem, const char *name)
{
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
@ -159,9 +159,14 @@ stats_display(void)
LINK_STATS_DISPLAY();
ETHARP_STATS_DISPLAY();
IPFRAG_STATS_DISPLAY();
IP6_FRAG_STATS_DISPLAY();
IP_STATS_DISPLAY();
ND6_STATS_DISPLAY();
IP6_STATS_DISPLAY();
IGMP_STATS_DISPLAY();
MLD6_STATS_DISPLAY();
ICMP_STATS_DISPLAY();
ICMP6_STATS_DISPLAY();
UDP_STATS_DISPLAY();
TCP_STATS_DISPLAY();
MEM_STATS_DISPLAY();

View file

@ -45,6 +45,7 @@
#if !NO_SYS
#ifndef sys_msleep
/**
* Sleep for some ms. Timeouts are NOT processed while sleeping.
*
@ -62,5 +63,6 @@ sys_msleep(u32_t ms)
}
}
}
#endif /* sys_msleep */
#endif /* !NO_SYS */

View file

@ -52,9 +52,28 @@
#include "lwip/tcp_impl.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/nd6.h"
#include <string.h>
#ifndef TCP_LOCAL_PORT_RANGE_START
/* From http://www.iana.org/assignments/port-numbers:
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
#define TCP_LOCAL_PORT_RANGE_START 0xc000
#define TCP_LOCAL_PORT_RANGE_END 0xffff
#define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)
#endif
#if LWIP_TCP_KEEPALIVE
#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl)
#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl)
#else /* LWIP_TCP_KEEPALIVE */
#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE
#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT
#endif /* LWIP_TCP_KEEPALIVE */
const char * const tcp_state_str[] = {
"CLOSED",
"LISTEN",
@ -69,6 +88,9 @@ const char * const tcp_state_str[] = {
"TIME_WAIT"
};
/* last local TCP port */
static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START;
/* Incremented every coarse grained timer shot (typically every 500 ms). */
u32_t tcp_ticks;
const u8_t tcp_backoff[13] =
@ -91,19 +113,32 @@ struct tcp_pcb *tcp_tw_pcbs;
#define NUM_TCP_PCB_LISTS 4
#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3
/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
struct tcp_pcb **tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
&tcp_active_pcbs, &tcp_tw_pcbs};
/** Only used for temporary storage. */
struct tcp_pcb *tcp_tmp_pcb;
u8_t tcp_active_pcbs_changed;
/** Timer counter to handle calling slow-timer from tcp_tmr() */
static u8_t tcp_timer;
static u8_t tcp_timer_ctr;
static u16_t tcp_new_port(void);
/**
* Initialize this module.
*/
void
tcp_init(void)
{
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
}
/**
* Called periodically to dispatch TCP timers.
*
*/
void
tcp_tmr(void)
@ -139,7 +174,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
{
err_t err;
if (rst_on_unacked_data && (pcb->state != LISTEN)) {
if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
/* Not all data received by application, send RST to tell the remote
side about this. */
@ -148,17 +183,18 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
/* don't call tcp_abort here: we must not deallocate the pcb since
that might not be expected when calling tcp_close */
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
pcb->local_port, pcb->remote_port);
pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
tcp_pcb_purge(pcb);
/* TODO: to which state do we move now? */
/* move to TIME_WAIT since we close actively */
TCP_RMV(&tcp_active_pcbs, pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
TCP_RMV_ACTIVE(pcb);
if (pcb->state == ESTABLISHED) {
/* move to TIME_WAIT since we close actively */
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
} else {
/* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */
memp_free(MEMP_TCP_PCB, pcb);
}
return ERR_OK;
}
}
@ -173,8 +209,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
* is erroneous, but this should never happen as the pcb has in those cases
* been freed, and so any remaining handles are bogus. */
err = ERR_OK;
if(pcb->local_port != 0)
TCP_RMV(&tcp_bound_pcbs, pcb);
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
memp_free(MEMP_TCP_PCB, pcb);
pcb = NULL;
break;
@ -186,7 +223,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
break;
case SYN_SENT:
err = ERR_OK;
tcp_pcb_remove(&tcp_active_pcbs, pcb);
TCP_PCB_REMOVE_ACTIVE(pcb);
memp_free(MEMP_TCP_PCB, pcb);
pcb = NULL;
snmp_inc_tcpattemptfails();
@ -265,7 +302,9 @@ tcp_close(struct tcp_pcb *pcb)
/**
* Causes all or part of a full-duplex connection of this PCB to be shut down.
* This doesn't deallocate the PCB!
* This doesn't deallocate the PCB unless shutting down both sides!
* Shutting down both sides is the same as calling tcp_close, so if it succeds,
* the PCB should not be referenced any more.
*
* @param pcb PCB to shutdown
* @param shut_rx shut down receive side if this is != 0
@ -280,28 +319,32 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
return ERR_CONN;
}
if (shut_rx) {
/* shut down the receive side: free buffered data... */
/* shut down the receive side: set a flag not to receive any more data... */
pcb->flags |= TF_RXCLOSED;
if (shut_tx) {
/* shutting down the tx AND rx side is the same as closing for the raw API */
return tcp_close_shutdown(pcb, 1);
}
/* ... and free buffered data */
if (pcb->refused_data != NULL) {
pbuf_free(pcb->refused_data);
pcb->refused_data = NULL;
}
/* ... and set a flag not to receive any more data */
pcb->flags |= TF_RXCLOSED;
}
if (shut_tx) {
/* This can't happen twice since if it succeeds, the pcb's state is changed.
Only close in these states as the others directly deallocate the PCB */
switch (pcb->state) {
case SYN_RCVD:
case ESTABLISHED:
case CLOSE_WAIT:
return tcp_close_shutdown(pcb, 0);
default:
/* don't shut down other states */
break;
case SYN_RCVD:
case ESTABLISHED:
case CLOSE_WAIT:
return tcp_close_shutdown(pcb, shut_rx);
default:
/* Not (yet?) connected, cannot shutdown the TX side as that would bring us
into CLOSED state, where the PCB is deallocated. */
return ERR_CONN;
}
}
/* @todo: return another err_t if not in correct state or already shut? */
return ERR_OK;
}
@ -317,8 +360,6 @@ void
tcp_abandon(struct tcp_pcb *pcb, int reset)
{
u32_t seqno, ackno;
u16_t remote_port, local_port;
ip_addr_t remote_ip, local_ip;
#if LWIP_CALLBACK_API
tcp_err_fn errf;
#endif /* LWIP_CALLBACK_API */
@ -334,17 +375,14 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
tcp_pcb_remove(&tcp_tw_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb);
} else {
int send_rst = reset && (pcb->state != CLOSED);
seqno = pcb->snd_nxt;
ackno = pcb->rcv_nxt;
ip_addr_copy(local_ip, pcb->local_ip);
ip_addr_copy(remote_ip, pcb->remote_ip);
local_port = pcb->local_port;
remote_port = pcb->remote_port;
#if LWIP_CALLBACK_API
errf = pcb->errf;
#endif /* LWIP_CALLBACK_API */
errf_arg = pcb->callback_arg;
tcp_pcb_remove(&tcp_active_pcbs, pcb);
TCP_PCB_REMOVE_ACTIVE(pcb);
if (pcb->unacked != NULL) {
tcp_segs_free(pcb->unacked);
}
@ -356,12 +394,12 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
tcp_segs_free(pcb->ooseq);
}
#endif /* TCP_QUEUE_OOSEQ */
if (send_rst) {
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
}
memp_free(MEMP_TCP_PCB, pcb);
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
if (reset) {
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
}
}
}
@ -392,6 +430,7 @@ tcp_abort(struct tcp_pcb *pcb)
* to any local address
* @param port the local port to bind to
* @return ERR_USE if the port is already in use
* ERR_VAL if bind failed because the PCB is not in a valid state
* ERR_OK if bound
*/
err_t
@ -401,7 +440,7 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
int max_pcb_list = NUM_TCP_PCB_LISTS;
struct tcp_pcb *cpcb;
LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL);
#if SO_REUSE
/* Unless the REUSEADDR flag is set,
@ -409,15 +448,16 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
We do not dump TIME_WAIT pcb's; they can still be matched by incoming
packets using both local and remote IP addresses and ports to distinguish.
*/
#if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
if (ip_get_option(pcb, SOF_REUSEADDR)) {
max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
}
#endif /* SO_REUSE */
#endif /* SO_REUSE */
if (port == 0) {
port = tcp_new_port();
if (port == 0) {
return ERR_BUF;
}
}
/* Check if the address already is in use (on all lists) */
@ -428,13 +468,15 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
/* Omit checking for the same port if both pcbs have REUSEADDR set.
For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
tcp_connect. */
if (((pcb->so_options & SOF_REUSEADDR) == 0) ||
((cpcb->so_options & SOF_REUSEADDR) == 0))
if (!ip_get_option(pcb, SOF_REUSEADDR) ||
!ip_get_option(cpcb, SOF_REUSEADDR))
#endif /* SO_REUSE */
{
if (ip_addr_isany(&(cpcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
/* @todo: check accept_any_ip_version */
if (IP_PCB_IPVER_EQ(pcb, cpcb) &&
(ipX_addr_isany(PCB_ISIPV6(pcb), &cpcb->local_ip) ||
ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr)) ||
ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, ip_2_ipX(ipaddr)))) {
return ERR_USE;
}
}
@ -442,8 +484,8 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
}
}
if (!ip_addr_isany(ipaddr)) {
pcb->local_ip = *ipaddr;
if (!ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr))) {
ipX_addr_set(PCB_ISIPV6(pcb), &pcb->local_ip, ip_2_ipX(ipaddr));
}
pcb->local_port = port;
TCP_REG(&tcp_bound_pcbs, pcb);
@ -492,13 +534,14 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
return pcb;
}
#if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
if (ip_get_option(pcb, SOF_REUSEADDR)) {
/* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage
is declared (listen-/connection-pcb), we have to make sure now that
this port is only used once for every local IP. */
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if (lpcb->local_port == pcb->local_port) {
if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
if ((lpcb->local_port == pcb->local_port) &&
IP_PCB_IPVER_EQ(pcb, lpcb)) {
if (ipX_addr_cmp(PCB_ISIPV6(pcb), &lpcb->local_ip, &pcb->local_ip)) {
/* this address/port is already used */
return NULL;
}
@ -515,11 +558,17 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
lpcb->state = LISTEN;
lpcb->prio = pcb->prio;
lpcb->so_options = pcb->so_options;
lpcb->so_options |= SOF_ACCEPTCONN;
ip_set_option(lpcb, SOF_ACCEPTCONN);
lpcb->ttl = pcb->ttl;
lpcb->tos = pcb->tos;
ip_addr_copy(lpcb->local_ip, pcb->local_ip);
TCP_RMV(&tcp_bound_pcbs, pcb);
#if LWIP_IPV6
PCB_ISIPV6(lpcb) = PCB_ISIPV6(pcb);
lpcb->accept_any_ip_version = 0;
#endif /* LWIP_IPV6 */
ipX_addr_copy(PCB_ISIPV6(pcb), lpcb->local_ip, pcb->local_ip);
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
memp_free(MEMP_TCP_PCB, pcb);
#if LWIP_CALLBACK_API
lpcb->accept = tcp_accept_null;
@ -532,7 +581,29 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
return (struct tcp_pcb *)lpcb;
}
/**
#if LWIP_IPV6
/**
* Same as tcp_listen_with_backlog, but allows to accept IPv4 and IPv6
* connections, if the pcb's local address is set to ANY.
*/
struct tcp_pcb *
tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
{
struct tcp_pcb *lpcb;
lpcb = tcp_listen_with_backlog(pcb, backlog);
if ((lpcb != NULL) &&
ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
/* The default behavior is to accept connections on either
* IPv4 or IPv6, if not bound. */
/* @see NETCONN_FLAG_IPV6_V6ONLY for changing this behavior */
((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1;
}
return lpcb;
}
#endif /* LWIP_IPV6 */
/**
* Update the state that tracks the available window space to advertise.
*
* Returns how much extra window would be advertised if we sent an
@ -574,6 +645,9 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
{
int wnd_inflation;
/* pcb->state LISTEN not allowed here */
LWIP_ASSERT("don't call tcp_recved for listen-pcbs",
pcb->state != LISTEN);
LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
len <= 0xffff - pcb->rcv_wnd );
@ -598,35 +672,33 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
}
/**
* A nastly hack featuring 'goto' statements that allocates a
* new TCP local port.
* Allocate a new local TCP port.
*
* @return a new (free) local TCP port number
*/
static u16_t
tcp_new_port(void)
{
int i;
u8_t i;
u16_t n = 0;
struct tcp_pcb *pcb;
#ifndef TCP_LOCAL_PORT_RANGE_START
#define TCP_LOCAL_PORT_RANGE_START 4096
#define TCP_LOCAL_PORT_RANGE_END 0x7fff
#endif
static u16_t port = TCP_LOCAL_PORT_RANGE_START;
again:
if (++port > TCP_LOCAL_PORT_RANGE_END) {
port = TCP_LOCAL_PORT_RANGE_START;
again:
if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) {
tcp_port = TCP_LOCAL_PORT_RANGE_START;
}
/* Check all PCB lists. */
for (i = 1; i < NUM_TCP_PCB_LISTS; i++) {
for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == port) {
if (pcb->local_port == tcp_port) {
if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) {
return 0;
}
goto again;
}
}
}
return port;
return tcp_port;
}
/**
@ -647,46 +719,54 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
{
err_t ret;
u32_t iss;
u16_t old_local_port;
LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
if (ipaddr != NULL) {
pcb->remote_ip = *ipaddr;
ipX_addr_set(PCB_ISIPV6(pcb), &pcb->remote_ip, ip_2_ipX(ipaddr));
} else {
return ERR_VAL;
}
pcb->remote_port = port;
/* check if we have a route to the remote host */
if (ip_addr_isany(&(pcb->local_ip))) {
if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
/* no local IP address set, yet. */
struct netif *netif = ip_route(&(pcb->remote_ip));
if (netif == NULL) {
struct netif *netif;
ipX_addr_t *local_ip;
ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip);
if ((netif == NULL) || (local_ip == NULL)) {
/* Don't even try to send a SYN packet if we have no route
since that will fail. */
return ERR_RTE;
}
/* Use the netif's IP address as local address. */
ip_addr_copy(pcb->local_ip, netif->ip_addr);
/* Use the address as local address of the pcb. */
ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip);
}
old_local_port = pcb->local_port;
if (pcb->local_port == 0) {
pcb->local_port = tcp_new_port();
if (pcb->local_port == 0) {
return ERR_BUF;
}
}
#if SO_REUSE
if ((pcb->so_options & SOF_REUSEADDR) != 0) {
if (ip_get_option(pcb, SOF_REUSEADDR)) {
/* Since SOF_REUSEADDR allows reusing a local address, we have to make sure
now that the 5-tuple is unique. */
struct tcp_pcb *cpcb;
int i;
/* Don't check listen PCBs, check bound-, active- and TIME-WAIT PCBs. */
for (i = 1; i < NUM_TCP_PCB_LISTS; i++) {
/* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
if ((cpcb->local_port == pcb->local_port) &&
(cpcb->remote_port == port) &&
ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
IP_PCB_IPVER_EQ(cpcb, pcb) &&
ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, &pcb->local_ip) &&
ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->remote_ip, ip_2_ipX(ipaddr))) {
/* linux returns EISCONN here, but ERR_USE should be OK for us */
return ERR_USE;
}
@ -707,13 +787,13 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
The send MSS is updated when an MSS option is received. */
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
#if TCP_CALCULATE_EFF_SEND_MSS
pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
pcb->cwnd = 1;
pcb->ssthresh = pcb->mss * 10;
#if LWIP_CALLBACK_API
pcb->connected = connected;
#else /* LWIP_CALLBACK_API */
#else /* LWIP_CALLBACK_API */
LWIP_UNUSED_ARG(connected);
#endif /* LWIP_CALLBACK_API */
@ -722,8 +802,10 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
if (ret == ERR_OK) {
/* SYN segment was enqueued, changed the pcbs state now */
pcb->state = SYN_SENT;
TCP_RMV(&tcp_bound_pcbs, pcb);
TCP_REG(&tcp_active_pcbs, pcb);
if (old_local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
TCP_REG_ACTIVE(pcb);
snmp_inc_tcpactiveopens();
tcp_output(pcb);
@ -741,7 +823,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
void
tcp_slowtmr(void)
{
struct tcp_pcb *pcb, *pcb2, *prev;
struct tcp_pcb *pcb, *prev;
u16_t eff_wnd;
u8_t pcb_remove; /* flag if a PCB should be removed */
u8_t pcb_reset; /* flag if a RST should be sent when removing */
@ -750,7 +832,9 @@ tcp_slowtmr(void)
err = ERR_OK;
++tcp_ticks;
++tcp_timer_ctr;
tcp_slowtmr_start:
/* Steps through all of the active PCBs. */
prev = NULL;
pcb = tcp_active_pcbs;
@ -762,6 +846,12 @@ tcp_slowtmr(void)
LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
if (pcb->last_timer == tcp_timer_ctr) {
/* skip this pcb, we have already processed it */
pcb = pcb->next;
continue;
}
pcb->last_timer = tcp_timer_ctr;
pcb_remove = 0;
pcb_reset = 0;
@ -787,8 +877,9 @@ tcp_slowtmr(void)
}
} else {
/* Increase the retransmission timer if it is running */
if(pcb->rtime >= 0)
if(pcb->rtime >= 0) {
++pcb->rtime;
}
if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
/* Time for a retransmission. */
@ -824,42 +915,35 @@ tcp_slowtmr(void)
}
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
if (pcb->state == FIN_WAIT_2) {
if ((u32_t)(tcp_ticks - pcb->tmr) >
TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
++pcb_remove;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
/* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */
if (pcb->flags & TF_RXCLOSED) {
/* PCB was fully closed (either through close() or SHUT_RDWR):
normal FIN-WAIT timeout handling. */
if ((u32_t)(tcp_ticks - pcb->tmr) >
TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
++pcb_remove;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
}
}
}
/* Check if KEEPALIVE should be sent */
if((pcb->so_options & SOF_KEEPALIVE) &&
if(ip_get_option(pcb, SOF_KEEPALIVE) &&
((pcb->state == ESTABLISHED) ||
(pcb->state == CLOSE_WAIT))) {
#if LWIP_TCP_KEEPALIVE
if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
/ TCP_SLOW_INTERVAL)
#else
if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
#endif /* LWIP_TCP_KEEPALIVE */
(pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL)
{
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
++pcb_remove;
++pcb_reset;
}
#if LWIP_TCP_KEEPALIVE
else if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
(pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb))
/ TCP_SLOW_INTERVAL)
#else
else if((u32_t)(tcp_ticks - pcb->tmr) >
(pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)
/ TCP_SLOW_INTERVAL)
#endif /* LWIP_TCP_KEEPALIVE */
{
tcp_keepalive(pcb);
pcb->keep_cnt_sent++;
@ -897,6 +981,9 @@ tcp_slowtmr(void)
/* If the PCB should be removed, do it. */
if (pcb_remove) {
struct tcp_pcb *pcb2;
tcp_err_fn err_fn;
void *err_arg;
tcp_pcb_purge(pcb);
/* Remove PCB from tcp_active_pcbs list. */
if (prev != NULL) {
@ -908,15 +995,22 @@ tcp_slowtmr(void)
tcp_active_pcbs = pcb->next;
}
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
if (pcb_reset) {
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
pcb->local_port, pcb->remote_port);
pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
}
pcb2 = pcb->next;
memp_free(MEMP_TCP_PCB, pcb);
pcb = pcb2;
err_fn = pcb->errf;
err_arg = pcb->callback_arg;
pcb2 = pcb;
pcb = pcb->next;
memp_free(MEMP_TCP_PCB, pcb2);
tcp_active_pcbs_changed = 0;
TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT);
if (tcp_active_pcbs_changed) {
goto tcp_slowtmr_start;
}
} else {
/* get the 'next' element now and work with 'prev' below (in case of abort) */
prev = pcb;
@ -927,7 +1021,11 @@ tcp_slowtmr(void)
if (prev->polltmr >= prev->pollinterval) {
prev->polltmr = 0;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
tcp_active_pcbs_changed = 0;
TCP_EVENT_POLL(prev, err);
if (tcp_active_pcbs_changed) {
goto tcp_slowtmr_start;
}
/* if err == ERR_ABRT, 'prev' is already deallocated */
if (err == ERR_OK) {
tcp_output(prev);
@ -938,7 +1036,7 @@ tcp_slowtmr(void)
/* Steps through all of the TIME-WAIT PCBs. */
prev = NULL;
prev = NULL;
pcb = tcp_tw_pcbs;
while (pcb != NULL) {
LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
@ -953,6 +1051,7 @@ tcp_slowtmr(void)
/* If the PCB should be removed, do it. */
if (pcb_remove) {
struct tcp_pcb *pcb2;
tcp_pcb_purge(pcb);
/* Remove PCB from tcp_tw_pcbs list. */
if (prev != NULL) {
@ -963,9 +1062,9 @@ tcp_slowtmr(void)
LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
tcp_tw_pcbs = pcb->next;
}
pcb2 = pcb->next;
memp_free(MEMP_TCP_PCB, pcb);
pcb = pcb2;
pcb2 = pcb;
pcb = pcb->next;
memp_free(MEMP_TCP_PCB, pcb2);
} else {
prev = pcb;
pcb = pcb->next;
@ -982,34 +1081,78 @@ tcp_slowtmr(void)
void
tcp_fasttmr(void)
{
struct tcp_pcb *pcb = tcp_active_pcbs;
struct tcp_pcb *pcb;
++tcp_timer_ctr;
tcp_fasttmr_start:
pcb = tcp_active_pcbs;
while(pcb != NULL) {
struct tcp_pcb *next = pcb->next;
/* If there is data which was previously "refused" by upper layer */
if (pcb->refused_data != NULL) {
/* Notify again application with data previously received. */
err_t err;
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
if (err == ERR_OK) {
pcb->refused_data = NULL;
} else if (err == ERR_ABRT) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
pcb = NULL;
if (pcb->last_timer != tcp_timer_ctr) {
struct tcp_pcb *next;
pcb->last_timer = tcp_timer_ctr;
/* send delayed ACKs */
if (pcb->flags & TF_ACK_DELAY) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
tcp_ack_now(pcb);
tcp_output(pcb);
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
next = pcb->next;
/* If there is data which was previously "refused" by upper layer */
if (pcb->refused_data != NULL) {
tcp_active_pcbs_changed = 0;
tcp_process_refused_data(pcb);
if (tcp_active_pcbs_changed) {
/* application callback has changed the pcb list: restart the loop */
goto tcp_fasttmr_start;
}
}
pcb = next;
}
}
}
/** Pass pcb->refused_data to the recv callback */
err_t
tcp_process_refused_data(struct tcp_pcb *pcb)
{
err_t err;
u8_t refused_flags = pcb->refused_data->flags;
/* set pcb->refused_data to NULL in case the callback frees it and then
closes the pcb */
struct pbuf *refused_data = pcb->refused_data;
pcb->refused_data = NULL;
/* Notify again application with data previously received. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
if (err == ERR_OK) {
/* did refused_data include a FIN? */
if (refused_flags & PBUF_FLAG_TCP_FIN) {
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
if (err == ERR_ABRT) {
return ERR_ABRT;
}
}
/* send delayed ACKs */
if (pcb && (pcb->flags & TF_ACK_DELAY)) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
tcp_ack_now(pcb);
tcp_output(pcb);
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
pcb = next;
} else if (err == ERR_ABRT) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
/* Drop incoming packets because pcb is "full" (only if the incoming
segment contains data). */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
return ERR_ABRT;
} else {
/* data is still refused, pbuf is still valid (go on for ACK-only packets) */
pcb->refused_data = refused_data;
}
return ERR_OK;
}
/**
@ -1101,7 +1244,8 @@ tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
#endif /* LWIP_CALLBACK_API */
/**
* Kills the oldest active connection that has lower priority than prio.
* Kills the oldest active connection that has the same or lower priority than
* 'prio'.
*
* @param prio minimum priority
*/
@ -1218,6 +1362,7 @@ tcp_alloc(u8_t prio)
pcb->lastack = iss;
pcb->snd_lbb = iss;
pcb->tmr = tcp_ticks;
pcb->last_timer = tcp_timer_ctr;
pcb->polltmr = 0;
@ -1256,6 +1401,24 @@ tcp_new(void)
return tcp_alloc(TCP_PRIO_NORMAL);
}
#if LWIP_IPV6
/**
* Creates a new TCP-over-IPv6 protocol control block but doesn't
* place it on any of the TCP PCB lists.
* The pcb is not put on any list until binding using tcp_bind().
*
* @return a new tcp_pcb that initially is in state CLOSED
*/
struct tcp_pcb *
tcp_new_ip6(void)
{
struct tcp_pcb * pcb;
pcb = tcp_alloc(TCP_PRIO_NORMAL);
ip_set_v6(pcb, 1);
return pcb;
}
#endif /* LWIP_IPV6 */
/**
* Used to specify the argument that should be passed callback
* functions.
@ -1265,7 +1428,9 @@ tcp_new(void)
*/
void
tcp_arg(struct tcp_pcb *pcb, void *arg)
{
{
/* This function is allowed to be called for both listen pcbs and
connection pcbs. */
pcb->callback_arg = arg;
}
#if LWIP_CALLBACK_API
@ -1280,6 +1445,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg)
void
tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
{
LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN);
pcb->recv = recv;
}
@ -1293,6 +1459,7 @@ tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
void
tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
{
LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN);
pcb->sent = sent;
}
@ -1307,6 +1474,7 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
void
tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
{
LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN);
pcb->errf = err;
}
@ -1321,6 +1489,8 @@ tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
void
tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
{
/* This function is allowed to be called for both listen pcbs and
connection pcbs. */
pcb->accept = accept;
}
#endif /* LWIP_CALLBACK_API */
@ -1335,6 +1505,7 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
void
tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
{
LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN);
#if LWIP_CALLBACK_API
pcb->poll = poll;
#else /* LWIP_CALLBACK_API */
@ -1366,8 +1537,9 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
tcp_listen_pcbs.listen_pcbs != NULL);
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if ((lpcb->local_port == pcb->local_port) &&
(ip_addr_isany(&lpcb->local_ip) ||
ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
IP_PCB_IPVER_EQ(pcb, lpcb) &&
(ipX_addr_isany(PCB_ISIPV6(lpcb), &lpcb->local_ip) ||
ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) {
/* port and address of the listen pcb match the timed-out pcb */
LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
lpcb->accepts_pending > 0);
@ -1466,14 +1638,36 @@ tcp_next_iss(void)
* calculating the minimum of TCP_MSS and that netif's mtu (if set).
*/
u16_t
tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest
#if LWIP_IPV6
, ipX_addr_t *src, u8_t isipv6
#endif /* LWIP_IPV6 */
)
{
u16_t mss_s;
struct netif *outif;
s16_t mtu;
outif = ip_route(addr);
if ((outif != NULL) && (outif->mtu != 0)) {
mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
outif = ipX_route(isipv6, src, dest);
#if LWIP_IPV6
if (isipv6) {
/* First look in destination cache, to see if there is a Path MTU. */
mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif);
} else
#endif /* LWIP_IPV6 */
{
if (outif == NULL) {
return sendmss;
}
mtu = outif->mtu;
}
if (mtu != 0) {
mss_s = mtu - IP_HLEN - TCP_HLEN;
#if LWIP_IPV6
/* for IPv6, substract the difference in header size */
mss_s -= (IP6_HLEN - IP_HLEN);
#endif /* LWIP_IPV6 */
/* RFC 1122, chap 4.2.2.6:
* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
* We correct for TCP options in tcp_write(), and don't support IP options.

View file

@ -55,13 +55,18 @@
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "arch/perf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#if LWIP_ND6_TCP_REACHABILITY_HINTS
#include "lwip/nd6.h"
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
/* These variables are global to all functions involved in the input
processing of TCP segments. They are set by the tcp_input()
function. */
static struct tcp_seg inseg;
static struct tcp_hdr *tcphdr;
static struct ip_hdr *iphdr;
static u32_t seqno, ackno;
static u8_t flags;
static u16_t tcplen;
@ -85,7 +90,7 @@ static err_t tcp_timewait_input(struct tcp_pcb *pcb);
* the TCP finite state machine. This function is called by the IP layer (in
* ip_input()).
*
* @param p received TCP segment to process (p->payload pointing to the IP header)
* @param p received TCP segment to process (p->payload pointing to the TCP header)
* @param inp network interface on which this segment was received
*/
void
@ -99,57 +104,48 @@ tcp_input(struct pbuf *p, struct netif *inp)
#endif /* SO_REUSE */
u8_t hdrlen;
err_t err;
#if CHECKSUM_CHECK_TCP
u16_t chksum;
#endif /* CHECKSUM_CHECK_TCP */
PERF_START;
TCP_STATS_INC(tcp.recv);
snmp_inc_tcpinsegs();
iphdr = (struct ip_hdr *)p->payload;
tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
tcphdr = (struct tcp_hdr *)p->payload;
#if TCP_INPUT_DEBUG
tcp_debug_print(tcphdr);
#endif
/* remove header from payload */
if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
/* Check that TCP header fits in payload */
if (p->len < sizeof(struct tcp_hdr)) {
/* drop short packets */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
TCP_STATS_INC(tcp.lenerr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
goto dropped;
}
/* Don't even process incoming broadcasts/multicasts. */
if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
ip_addr_ismulticast(&current_iphdr_dest)) {
if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) ||
ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) {
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
goto dropped;
}
#if CHECKSUM_CHECK_TCP
/* Verify TCP checksum. */
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_TCP, p->tot_len) != 0) {
chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len,
ipX_current_src_addr(), ipX_current_dest_addr());
if (chksum != 0) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_TCP, p->tot_len)));
#if TCP_DEBUG
chksum));
tcp_debug_print(tcphdr);
#endif /* TCP_DEBUG */
TCP_STATS_INC(tcp.chkerr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
goto dropped;
}
#endif
#endif /* CHECKSUM_CHECK_TCP */
/* Move the payload pointer in the pbuf so that it points to the
TCP data instead of the TCP header. */
@ -158,10 +154,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* drop short packets */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
TCP_STATS_INC(tcp.lenerr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
goto dropped;
}
/* Convert fields in TCP header to host byte order. */
@ -184,10 +177,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
pcb->local_port == tcphdr->dest &&
IP_PCB_IPVER_INPUT_MATCH(pcb) &&
ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
@ -209,9 +202,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
pcb->local_port == tcphdr->dest &&
IP_PCB_IPVER_INPUT_MATCH(pcb) &&
ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
/* We don't really care enough to move this PCB to the front
of the list since we are not very likely to receive that
many segments for connections in TIME-WAIT. */
@ -227,22 +221,31 @@ tcp_input(struct pbuf *p, struct netif *inp)
prev = NULL;
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if (lpcb->local_port == tcphdr->dest) {
#if SO_REUSE
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
/* found an exact match */
break;
} else if(ip_addr_isany(&(lpcb->local_ip))) {
#if LWIP_IPV6
if (lpcb->accept_any_ip_version) {
/* found an ANY-match */
#if SO_REUSE
lpcb_any = lpcb;
lpcb_prev = prev;
}
#else /* SO_REUSE */
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
ip_addr_isany(&(lpcb->local_ip))) {
/* found a match */
break;
}
#endif /* SO_REUSE */
} else
#endif /* LWIP_IPV6 */
if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) {
if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) {
/* found an exact match */
break;
} else if (ipX_addr_isany(ip_current_is_v6(), &lpcb->local_ip)) {
/* found an ANY-match */
#if SO_REUSE
lpcb_any = lpcb;
lpcb_prev = prev;
#else /* SO_REUSE */
break;
#endif /* SO_REUSE */
}
}
}
prev = (struct tcp_pcb *)lpcb;
}
@ -291,28 +294,25 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* Set up a tcp_seg structure. */
inseg.next = NULL;
inseg.len = p->tot_len;
inseg.dataptr = p->payload;
inseg.p = p;
inseg.tcphdr = tcphdr;
recv_data = NULL;
recv_flags = 0;
if (flags & TCP_PSH) {
p->flags |= PBUF_FLAG_PUSH;
}
/* If there is data which was previously "refused" by upper layer */
if (pcb->refused_data != NULL) {
/* Notify again application with data previously received. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
if (err == ERR_OK) {
pcb->refused_data = NULL;
} else {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
/* drop incoming packets, because pcb is "full" */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
if ((tcp_process_refused_data(pcb) == ERR_ABRT) ||
((pcb->refused_data != NULL) && (tcplen > 0))) {
/* pcb has been aborted or refused data is still refused and the new
segment contains data */
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
goto aborted;
}
}
tcp_input_pcb = pcb;
@ -331,6 +331,12 @@ tcp_input(struct pbuf *p, struct netif *inp)
} else if (recv_flags & TF_CLOSED) {
/* The connection has been closed and we will deallocate the
PCB. */
if (!(pcb->flags & TF_RXCLOSED)) {
/* Connection closed although the application has only shut down the
tx side: call the PCB's err callback and indicate the closure to
ensure the application doesn't continue using the PCB. */
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD);
}
tcp_pcb_remove(&tcp_active_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb);
} else {
@ -346,6 +352,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
if (recv_data != NULL) {
LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
if (pcb->flags & TF_RXCLOSED) {
/* received data although already closed -> abort (send RST) to
notify the remote host that not all data has been processed */
@ -353,9 +360,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
tcp_abort(pcb);
goto aborted;
}
if (flags & TCP_PSH) {
recv_data->flags |= PBUF_FLAG_PUSH;
}
/* Notify application that data has been received. */
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
@ -373,14 +377,19 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* If a FIN segment was received, we call the callback
function with a NULL buffer to indicate EOF. */
if (recv_flags & TF_GOT_FIN) {
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
if (err == ERR_ABRT) {
goto aborted;
if (pcb->refused_data != NULL) {
/* Delay this if we have refused data. */
pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN;
} else {
/* correct rcv_wnd as the application won't call tcp_recved()
for the FIN's seqno */
if (pcb->rcv_wnd != TCP_WND) {
pcb->rcv_wnd++;
}
TCP_EVENT_CLOSED(pcb, err);
if (err == ERR_ABRT) {
goto aborted;
}
}
}
@ -414,15 +423,19 @@ aborted:
if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
tcp_rst(ackno, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
}
pbuf_free(p);
}
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
PERF_STOP("tcp_input");
return;
dropped:
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
}
/**
@ -443,15 +456,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
struct tcp_pcb *npcb;
err_t rc;
if (flags & TCP_RST) {
/* An incoming RST should be ignored. Return. */
return ERR_OK;
}
/* In the LISTEN state, we check for incoming SYN segments,
creates a new PCB, and responds with a SYN|ACK. */
if (flags & TCP_ACK) {
/* For incoming segments with the ACK flag set, respond with a
RST. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
tcp_rst(ackno + 1, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
} else if (flags & TCP_SYN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
#if TCP_LISTEN_BACKLOG
@ -473,14 +490,18 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
pcb->accepts_pending++;
#endif /* TCP_LISTEN_BACKLOG */
/* Set up the new PCB. */
ip_addr_copy(npcb->local_ip, current_iphdr_dest);
#if LWIP_IPV6
PCB_ISIPV6(npcb) = ip_current_is_v6();
#endif /* LWIP_IPV6 */
ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr());
ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr());
npcb->local_port = pcb->local_port;
ip_addr_copy(npcb->remote_ip, current_iphdr_src);
npcb->remote_port = tcphdr->src;
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
npcb->snd_wnd = tcphdr->wnd;
npcb->snd_wnd_max = tcphdr->wnd;
npcb->ssthresh = npcb->snd_wnd;
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
npcb->callback_arg = pcb->callback_arg;
@ -491,12 +512,13 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
npcb->so_options = pcb->so_options & SOF_INHERITED;
/* Register the new PCB so that we can begin receiving segments
for it. */
TCP_REG(&tcp_active_pcbs, npcb);
TCP_REG_ACTIVE(npcb);
/* Parse any options in the SYN. */
tcp_parseopt(npcb);
#if TCP_CALCULATE_EFF_SEND_MSS
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip,
&npcb->remote_ip, PCB_ISIPV6(npcb));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
snmp_inc_tcppassiveopens();
@ -538,8 +560,8 @@ tcp_timewait_input(struct tcp_pcb *pcb)
should be sent in reply */
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
/* If the SYN is in the window it is an error, send a reset */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
return ERR_OK;
}
} else if (flags & TCP_FIN) {
@ -632,11 +654,13 @@ tcp_process(struct tcp_pcb *pcb)
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->lastack = ackno;
pcb->snd_wnd = tcphdr->wnd;
pcb->snd_wnd_max = tcphdr->wnd;
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
pcb->state = ESTABLISHED;
#if TCP_CALCULATE_EFF_SEND_MSS
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip,
PCB_ISIPV6(pcb));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
/* Set ssthresh again after changing pcb->mss (already set in tcp_connect
@ -649,6 +673,7 @@ tcp_process(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
rseg = pcb->unacked;
pcb->unacked = rseg->next;
tcp_seg_free(rseg);
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
@ -659,8 +684,6 @@ tcp_process(struct tcp_pcb *pcb)
pcb->nrtx = 0;
}
tcp_seg_free(rseg);
/* Call the user specified function to call when sucessfully
* connected. */
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
@ -672,8 +695,8 @@ tcp_process(struct tcp_pcb *pcb)
/* received ACK? possibly a half-open connection */
else if (flags & TCP_ACK) {
/* send a RST to bring the other side in a non-synchronized state. */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
}
break;
case SYN_RCVD:
@ -715,8 +738,8 @@ tcp_process(struct tcp_pcb *pcb)
}
} else {
/* incorrect ACK number, send RST */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
}
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
@ -740,7 +763,7 @@ tcp_process(struct tcp_pcb *pcb)
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
TCP_RMV_ACTIVE(pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
} else {
@ -757,7 +780,7 @@ tcp_process(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
TCP_RMV_ACTIVE(pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
}
@ -767,7 +790,7 @@ tcp_process(struct tcp_pcb *pcb)
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
TCP_RMV_ACTIVE(pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
}
@ -832,7 +855,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
* data, and if so frees the memory of the buffered data. Next, is places the
* segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
* is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
* i it has been removed from the buffer.
* it has been removed from the buffer.
*
* If the incoming segment constitutes an ACK for a segment that was used for RTT
* estimation, the RTT is estimated here as well.
@ -852,6 +875,12 @@ tcp_receive(struct tcp_pcb *pcb)
u32_t right_wnd_edge;
u16_t new_tot_len;
int found_dupack = 0;
#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
u32_t ooseq_blen;
u16_t ooseq_qlen;
#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED);
if (flags & TCP_ACK) {
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
@ -861,9 +890,21 @@ tcp_receive(struct tcp_pcb *pcb)
(pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
(pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
pcb->snd_wnd = tcphdr->wnd;
/* keep track of the biggest window announced by the remote host to calculate
the maximum segment size */
if (pcb->snd_wnd_max < tcphdr->wnd) {
pcb->snd_wnd_max = tcphdr->wnd;
}
pcb->snd_wl1 = seqno;
pcb->snd_wl2 = ackno;
if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
if (pcb->snd_wnd == 0) {
if (pcb->persist_backoff == 0) {
/* start persist timer */
pcb->persist_cnt = 0;
pcb->persist_backoff = 1;
}
} else if (pcb->persist_backoff > 0) {
/* stop persist timer */
pcb->persist_backoff = 0;
}
LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
@ -910,8 +951,9 @@ tcp_receive(struct tcp_pcb *pcb)
/* Clause 5 */
if (pcb->lastack == ackno) {
found_dupack = 1;
if (pcb->dupacks + 1 > pcb->dupacks)
if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) {
++pcb->dupacks;
}
if (pcb->dupacks > 3) {
/* Inflate the congestion window, but not if it means that
the value overflows. */
@ -1018,6 +1060,13 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->rtime = 0;
pcb->polltmr = 0;
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
if (PCB_ISIPV6(pcb)) {
/* Inform neighbor reachability of forward progress. */
nd6_reachability_hint(ip6_current_src_addr());
}
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
} else {
/* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
pcb->acked = 0;
@ -1038,6 +1087,11 @@ tcp_receive(struct tcp_pcb *pcb)
next = pcb->unsent;
pcb->unsent = pcb->unsent->next;
#if TCP_OVERSIZE
if (pcb->unsent == NULL) {
pcb->unsent_oversize = 0;
}
#endif /* TCP_OVERSIZE */
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
/* Prevent ACK for FIN to generate a sent event */
@ -1086,8 +1140,10 @@ tcp_receive(struct tcp_pcb *pcb)
}
/* If the incoming segment contains data, we must process it
further. */
if (tcplen > 0) {
further unless the pcb already received a FIN.
(RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING,
LAST-ACK and TIME-WAIT: "Ignore the segment text.") */
if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) {
/* This code basically does three things:
+) If the incoming segment contains data that is the next
@ -1165,9 +1221,6 @@ tcp_receive(struct tcp_pcb *pcb)
LWIP_ASSERT("pbuf_header failed", 0);
}
}
/* KJM following line changed to use p->payload rather than inseg->p->payload
to fix bug #9076 */
inseg.dataptr = p->payload;
inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
}
@ -1228,8 +1281,7 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->ooseq = pcb->ooseq->next;
tcp_seg_free(old_ooseq);
}
}
else {
} else {
next = pcb->ooseq;
/* Remove all segments on ooseq that are covered by inseg already.
* FIN is copied from ooseq to inseg if present. */
@ -1338,6 +1390,13 @@ tcp_receive(struct tcp_pcb *pcb)
/* Acknowledge the segment(s). */
tcp_ack(pcb);
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
if (PCB_ISIPV6(pcb)) {
/* Inform neighbor reachability of forward progress. */
nd6_reachability_hint(ip6_current_src_addr());
}
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
} else {
/* We get here if the incoming segment is out-of-sequence. */
tcp_send_empty_ack(pcb);
@ -1462,8 +1521,32 @@ tcp_receive(struct tcp_pcb *pcb)
prev = next;
}
}
#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
/* Check that the data on ooseq doesn't exceed one of the limits
and throw away everything above that limit. */
ooseq_blen = 0;
ooseq_qlen = 0;
prev = NULL;
for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) {
struct pbuf *p = next->p;
ooseq_blen += p->tot_len;
ooseq_qlen += pbuf_clen(p);
if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) ||
(ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) {
/* too much ooseq data, dump this and everything after it */
tcp_segs_free(next);
if (prev == NULL) {
/* first ooseq segment is too much, dump the whole queue */
pcb->ooseq = NULL;
} else {
/* just dump 'next' and everything after it */
prev->next = NULL;
}
break;
}
}
#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
#endif /* TCP_QUEUE_OOSEQ */
}
} else {
/* The incoming segment is not withing the window. */

View file

@ -46,12 +46,17 @@
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/inet_chksum.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#if LWIP_TCP_TIMESTAMPS
#include "lwip/sys.h"
#endif
#include <string.h>
@ -131,6 +136,7 @@ tcp_send_fin(struct tcp_pcb *pcb)
if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
/* no SYN/FIN/RST flag in the header, we can add the FIN flag */
TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
pcb->flags |= TF_FIN;
return ERR_OK;
}
}
@ -166,7 +172,6 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
seg->flags = optflags;
seg->next = NULL;
seg->p = p;
seg->dataptr = p->payload;
seg->len = p->tot_len - optlen;
#if TCP_OVERSIZE_DBGCHECK
seg->oversize_left = 0;
@ -227,7 +232,7 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
LWIP_UNUSED_ARG(apiflags);
LWIP_UNUSED_ARG(first_seg);
/* always create MSS-sized pbufs */
alloc = TCP_MSS;
alloc = max_length;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
if (length < max_length) {
/* Should we allocate an oversized pbuf, or just the minimum
@ -367,6 +372,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
u16_t concat_chksummed = 0;
#endif /* TCP_CHECKSUM_ON_COPY */
err_t err;
/* don't allocate segments bigger than half the maximum window we ever received */
u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2);
#if LWIP_NETIF_TX_SINGLE_PBUF
/* Always copy to try to create single pbufs for TX */
@ -425,7 +432,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
/* Usable space at the end of the last unsent segment */
unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
space = pcb->mss - (last_unsent->len + unsent_optlen);
space = mss_local - (last_unsent->len + unsent_optlen);
/*
* Phase 1: Copy data directly into an oversized pbuf.
@ -476,7 +483,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
goto memerr;
}
#if TCP_OVERSIZE_DBGCHECK
last_unsent->oversize_left = oversize;
last_unsent->oversize_left += oversize;
#endif /* TCP_OVERSIZE_DBGCHECK */
TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
#if TCP_CHECKSUM_ON_COPY
@ -518,7 +525,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
while (pos < len) {
struct pbuf *p;
u16_t left = len - pos;
u16_t max_len = pcb->mss - optlen;
u16_t max_len = mss_local - optlen;
u16_t seglen = left > max_len ? max_len : left;
#if TCP_CHECKSUM_ON_COPY
u16_t chksum = 0;
@ -528,7 +535,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
if (apiflags & TCP_WRITE_FLAG_COPY) {
/* If copy is set, memory should be allocated and data copied
* into pbuf */
if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
goto memerr;
}
@ -590,10 +597,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
seg->chksum_swapped = chksum_swapped;
seg->flags |= TF_SEG_DATA_CHECKSUMMED;
#endif /* TCP_CHECKSUM_ON_COPY */
/* Fix dataptr for the nocopy case */
if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
seg->dataptr = (u8_t*)arg + pos;
}
/* first segment of to-be-queued data? */
if (queue == NULL) {
@ -635,6 +638,8 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
}
last_unsent->len += oversize_used;
#if TCP_OVERSIZE_DBGCHECK
LWIP_ASSERT("last_unsent->oversize_left >= oversize_used",
last_unsent->oversize_left >= oversize_used);
last_unsent->oversize_left -= oversize_used;
#endif /* TCP_OVERSIZE_DBGCHECK */
}
@ -773,6 +778,7 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
TCP_STATS_INC(tcp.memerr);
return ERR_MEM;
}
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
@ -814,7 +820,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
return ERR_OK;
}
#if LWIP_TCP_TIMESTAMPS
/* Build a timestamp option (12 bytes long) at the specified options pointer)
@ -870,14 +875,14 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
#endif
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
IP_PROTO_TCP, p->tot_len);
tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
&pcb->local_ip, &pcb->remote_ip);
#endif
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP, &(pcb->addr_hint));
ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos,
IP_PROTO_TCP, &pcb->addr_hint);
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos,
IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);
@ -901,6 +906,10 @@ tcp_output(struct tcp_pcb *pcb)
s16_t i = 0;
#endif /* TCP_CWND_DEBUG */
/* pcb->state LISTEN not allowed here */
LWIP_ASSERT("don't call tcp_output for listen-pcbs",
pcb->state != LISTEN);
/* 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
@ -984,6 +993,9 @@ tcp_output(struct tcp_pcb *pcb)
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
}
#if TCP_OVERSIZE_DBGCHECK
seg->oversize_left = 0;
#endif /* TCP_OVERSIZE_DBGCHECK */
tcp_output_segment(seg, pcb);
snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
@ -1029,13 +1041,6 @@ tcp_output(struct tcp_pcb *pcb)
}
#endif /* TCP_OVERSIZE */
if (seg != NULL && pcb->persist_backoff == 0 &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
/* prepare for persist timer */
pcb->persist_cnt = 0;
pcb->persist_backoff = 1;
}
pcb->flags &= ~TF_NAGLEMEMERR;
return ERR_OK;
}
@ -1050,7 +1055,6 @@ static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
{
u16_t len;
struct netif *netif;
u32_t *opts;
/** @bug Exclude retransmitted segments from this count. */
@ -1067,10 +1071,15 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
/* Add any requested options. NB MSS option is only set on SYN
packets, so ignore it here */
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)(seg->tcphdr + 1) % 4) == 0);
opts = (u32_t *)(void *)(seg->tcphdr + 1);
if (seg->flags & TF_SEG_OPTS_MSS) {
TCP_BUILD_MSS_OPTION(*opts);
u16_t mss;
#if TCP_CALCULATE_EFF_SEND_MSS
mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb));
#else /* TCP_CALCULATE_EFF_SEND_MSS */
mss = TCP_MSS;
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
*opts = TCP_BUILD_MSS_OPTION(mss);
opts += 1;
}
#if LWIP_TCP_TIMESTAMPS
@ -1082,19 +1091,22 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
}
#endif
/* 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_copy(pcb->local_ip, netif->ip_addr);
/* Set retransmission timer running if it is not currently enabled
This must be set before checking the route. */
if (pcb->rtime == -1) {
pcb->rtime = 0;
}
/* Set retransmission timer running if it is not currently enabled */
if(pcb->rtime == -1) {
pcb->rtime = 0;
/* If we don't have a local IP address, we get one by
calling ip_route(). */
if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
struct netif *netif;
ipX_addr_t *local_ip;
ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip);
if ((netif == NULL) || (local_ip == NULL)) {
return;
}
ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip);
}
if (pcb->rttest == 0) {
@ -1115,14 +1127,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
seg->p->payload = seg->tcphdr;
seg->tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
#if TCP_CHECKSUM_ON_COPY
{
u32_t acc;
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
u16_t chksum_slow = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
LWIP_ASSERT("data included but not checksummed",
@ -1130,9 +1140,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
}
/* rebuild TCP header checksum (TCP header changes for retransmissions!) */
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
acc = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip);
/* add payload checksum */
if (seg->chksum_swapped) {
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
@ -1150,19 +1159,19 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
}
#else /* TCP_CHECKSUM_ON_COPY */
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
#endif /* TCP_CHECKSUM_ON_COPY */
#if CHECKSUM_GEN_TCP
seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
#endif /* CHECKSUM_GEN_TCP */
#endif /* TCP_CHECKSUM_ON_COPY */
TCP_STATS_INC(tcp.xmit);
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP, &(pcb->addr_hint));
ipX_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip,
pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint);
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
ipX_output(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
pcb->tos, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
@ -1187,9 +1196,13 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
* @param remote_port the remote TCP port to send the segment to
*/
void
tcp_rst(u32_t seqno, u32_t ackno,
ip_addr_t *local_ip, ip_addr_t *remote_ip,
u16_t local_port, u16_t remote_port)
tcp_rst_impl(u32_t seqno, u32_t ackno,
ipX_addr_t *local_ip, ipX_addr_t *remote_ip,
u16_t local_port, u16_t remote_port
#if LWIP_IPV6
, u8_t isipv6
#endif /* LWIP_IPV6 */
)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
@ -1211,14 +1224,15 @@ tcp_rst(u32_t seqno, u32_t ackno,
tcphdr->chksum = 0;
tcphdr->urgp = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
snmp_inc_tcpoutrsts();
/* Send output with hardcoded TTL since we have no access to the pcb */
ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
#if CHECKSUM_GEN_TCP
tcphdr->chksum = ipX_chksum_pseudo(isipv6, p, IP_PROTO_TCP, p->tot_len,
local_ip, remote_ip);
#endif
/* Send output with hardcoded TTL/HL since we have no access to the pcb */
ipX_output(isipv6, p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
pbuf_free(p);
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
}
@ -1247,6 +1261,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb)
pcb->unsent = pcb->unacked;
/* unacked queue is now empty */
pcb->unacked = NULL;
/* last unsent hasn't changed, no need to reset unsent_oversize */
/* increment number of retransmissions */
++pcb->nrtx;
@ -1287,6 +1302,12 @@ tcp_rexmit(struct tcp_pcb *pcb)
}
seg->next = *cur_seg;
*cur_seg = seg;
#if TCP_OVERSIZE
if (seg->next == NULL) {
/* the retransmitted segment is last in unsent, so reset unsent_oversize */
pcb->unsent_oversize = 0;
}
#endif /* TCP_OVERSIZE */
++pcb->nrtx;
@ -1354,9 +1375,9 @@ tcp_keepalive(struct tcp_pcb *pcb)
struct pbuf *p;
struct tcp_hdr *tcphdr;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
@ -1369,18 +1390,17 @@ tcp_keepalive(struct tcp_pcb *pcb)
}
tcphdr = (struct tcp_hdr *)p->payload;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
&pcb->local_ip, &pcb->remote_ip);
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip,
pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint);
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);
@ -1407,11 +1427,9 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
u16_t len;
u8_t is_fin;
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: tcp_ticks %"U32_F
@ -1443,21 +1461,25 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
} else {
/* Data segment, copy in one byte from the head of the unacked queue */
*((char *)p->payload + TCP_HLEN) = *(char *)seg->dataptr;
char *d = ((char *)p->payload + TCP_HLEN);
/* Depending on whether the segment has already been sent (unacked) or not
(unsent), seg->p->payload points to the IP header or TCP header.
Ensure we copy the first TCP data byte: */
pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len);
}
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
&pcb->local_ip, &pcb->remote_ip);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
0, IP_PROTO_TCP, &pcb->addr_hint);
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);

View file

@ -42,6 +42,7 @@
#include "lwip/opt.h"
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#if LWIP_TIMERS
@ -49,14 +50,17 @@
#include "lwip/memp.h"
#include "lwip/tcpip.h"
#include "lwip/tcp_impl.h"
#include "lwip/ip_frag.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/nd6.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
@ -217,6 +221,54 @@ dns_timer(void *arg)
}
#endif /* LWIP_DNS */
#if LWIP_IPV6
/**
* Timer callback function that calls nd6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
nd6_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
nd6_tmr();
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
}
#if LWIP_IPV6_REASS
/**
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip6_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
ip6_reass_tmr();
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
}
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
/**
* Timer callback function that calls mld6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
mld6_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
mld6_tmr();
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
}
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
/** Initialize this module */
void sys_timeouts_init(void)
{
@ -239,6 +291,15 @@ void sys_timeouts_init(void)
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
#if LWIP_IPV6
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
#if LWIP_IPV6_REASS
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if NO_SYS
/* Initialise timestamp for sys_check_timeouts */
@ -355,22 +416,25 @@ sys_untimeout(sys_timeout_handler handler, void *arg)
void
sys_check_timeouts(void)
{
struct sys_timeo *tmptimeout;
u32_t diff;
sys_timeout_handler handler;
void *arg;
int had_one;
u32_t now;
now = sys_now();
if (next_timeout) {
struct sys_timeo *tmptimeout;
u32_t diff;
sys_timeout_handler handler;
void *arg;
u8_t had_one;
u32_t now;
now = sys_now();
/* this cares for wraparounds */
diff = LWIP_U32_DIFF(now, timeouts_last_time);
diff = now - timeouts_last_time;
do
{
#if PBUF_POOL_FREE_OOSEQ
PBUF_CHECK_FREE_OOSEQ();
#endif /* PBUF_POOL_FREE_OOSEQ */
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout->time <= diff) {
if (tmptimeout && (tmptimeout->time <= diff)) {
/* timeout has expired */
had_one = 1;
timeouts_last_time = now;

View file

@ -55,8 +55,12 @@
#include "lwip/memp.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/icmp6.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "arch/perf.h"
@ -64,10 +68,77 @@
#include <string.h>
#ifndef UDP_LOCAL_PORT_RANGE_START
/* From http://www.iana.org/assignments/port-numbers:
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
#define UDP_LOCAL_PORT_RANGE_START 0xc000
#define UDP_LOCAL_PORT_RANGE_END 0xffff
#define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)
#endif
/* last local UDP port */
static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START;
/* The list of UDP PCBs */
/* exported in udp.h (was static) */
struct udp_pcb *udp_pcbs;
/**
* Initialize this module.
*/
void
udp_init(void)
{
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
}
/**
* Allocate a new local UDP port.
*
* @return a new (free) local UDP port number
*/
static u16_t
udp_new_port(void)
{
u16_t n = 0;
struct udp_pcb *pcb;
again:
if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) {
udp_port = UDP_LOCAL_PORT_RANGE_START;
}
/* Check all PCBs. */
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == udp_port) {
if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) {
return 0;
}
goto again;
}
}
return udp_port;
#if 0
struct udp_pcb *ipcb = udp_pcbs;
while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) {
if (ipcb->local_port == udp_port) {
/* port is already used by another udp_pcb */
udp_port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
return 0;
}
return udp_port;
#endif
}
/**
* Process an incoming UDP datagram.
*
@ -76,7 +147,7 @@ struct udp_pcb *udp_pcbs;
* recv function. If no pcb is found or the datagram is incorrect, the
* pbuf is freed.
*
* @param p pbuf to be demultiplexed to a UDP PCB.
* @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header)
* @param inp network interface on which the datagram was received.
*
*/
@ -86,20 +157,17 @@ udp_input(struct pbuf *p, struct netif *inp)
struct udp_hdr *udphdr;
struct udp_pcb *pcb, *prev;
struct udp_pcb *uncon_pcb;
struct ip_hdr *iphdr;
u16_t src, dest;
u8_t local_match;
u8_t broadcast;
u8_t for_us;
PERF_START;
UDP_STATS_INC(udp.recv);
iphdr = (struct ip_hdr *)p->payload;
/* Check minimum length (IP header + UDP header)
* and move payload pointer to UDP header */
if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
/* Check minimum length (UDP header) */
if (p->len < UDP_HLEN) {
/* drop short packets */
LWIP_DEBUGF(UDP_DEBUG,
("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
@ -113,7 +181,11 @@ udp_input(struct pbuf *p, struct netif *inp)
udphdr = (struct udp_hdr *)p->payload;
/* is broadcast packet ? */
broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);
#if LWIP_IPV6
broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp);
#else /* LWIP_IPV6 */
broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp);
#endif /* LWIP_IPV6 */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
@ -124,13 +196,11 @@ udp_input(struct pbuf *p, struct netif *inp)
udp_debug_print(udphdr);
/* print the UDP source and destination */
LWIP_DEBUGF(UDP_DEBUG,
("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
#if LWIP_DHCP
pcb = NULL;
@ -142,9 +212,10 @@ udp_input(struct pbuf *p, struct netif *inp)
if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
/* accept the packe if
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- inp->dhcp->pcb->remote == ANY or iphdr->src */
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {
- inp->dhcp->pcb->remote == ANY or iphdr->src
(no need to check for IPv6 since the dhcp struct always uses IPv4) */
if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) {
pcb = inp->dhcp->pcb;
}
}
@ -162,38 +233,54 @@ udp_input(struct pbuf *p, struct netif *inp)
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
local_match = 0;
/* print the PCB local and remote address */
LWIP_DEBUGF(UDP_DEBUG,
("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip);
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip);
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));
/* compare PCB local addr+port to UDP destination addr+port */
if ((pcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||
if (pcb->local_port == dest) {
if (
#if LWIP_IPV6
((PCB_ISIPV6(pcb) && (ip_current_is_v6()) &&
(ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) ||
#if LWIP_IPV6_MLD
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6_MLD */
ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) ||
(!PCB_ISIPV6(pcb) &&
(ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) ||
ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(&current_iphdr_dest) ||
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))) {
#endif /* IP_SOF_BROADCAST_RECV */
local_match = 1;
if ((uncon_pcb == NULL) &&
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
/* the first unconnected matching PCB */
uncon_pcb = pcb;
(broadcast && ip_get_option(pcb, SOF_BROADCAST) &&
(ipX_addr_isany(0, &pcb->local_ip) ||
ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast &&
(ipX_addr_isany(0, &pcb->local_ip) ||
ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) {
#endif /* IP_SOF_BROADCAST_RECV */
local_match = 1;
if ((uncon_pcb == NULL) &&
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
/* the first unconnected matching PCB */
uncon_pcb = pcb;
}
}
}
/* compare PCB remote addr+port to UDP source addr+port */
if ((local_match != 0) &&
(pcb->remote_port == src) &&
(ip_addr_isany(&pcb->remote_ip) ||
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {
(pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) ||
ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) {
/* the first fully matching PCB */
if (prev != NULL) {
/* move the pcb to the front of udp_pcbs so that is
@ -215,12 +302,24 @@ udp_input(struct pbuf *p, struct netif *inp)
}
/* Check checksum if this is a match or if it was directed at us. */
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {
if (pcb != NULL) {
for_us = 1;
} else {
#if LWIP_IPV6
if (ip_current_is_v6()) {
for_us = netif_matches_ip6_addr(inp, ip6_current_dest_addr());
} else
#endif /* LWIP_IPV6 */
{
for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr());
}
}
if (for_us) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
#if LWIP_UDPLITE
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
/* Do the UDP Lite checksum */
#if CHECKSUM_CHECK_UDP
#if LWIP_UDPLITE
if (ip_current_header_proto() == IP_PROTO_UDPLITE) {
/* Do the UDP Lite checksum */
u16_t chklen = ntohs(udphdr->len);
if (chklen < sizeof(struct udp_hdr)) {
if (chklen == 0) {
@ -230,42 +329,26 @@ udp_input(struct pbuf *p, struct netif *inp)
} else {
/* At least the UDP-Lite header must be covered by the
checksum! (Again, see RFC 3828 chap. 3.1) */
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
goto chkerr;
}
}
if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE,
p->tot_len, chklen,
ipX_current_src_addr(), ipX_current_dest_addr()) != 0) {
goto chkerr;
}
#endif /* CHECKSUM_CHECK_UDP */
} else
#endif /* LWIP_UDPLITE */
{
#if CHECKSUM_CHECK_UDP
if (udphdr->chksum != 0) {
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_UDP, p->tot_len) != 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len,
ipX_current_src_addr(),
ipX_current_dest_addr()) != 0) {
goto chkerr;
}
}
#endif /* CHECKSUM_CHECK_UDP */
}
#endif /* CHECKSUM_CHECK_UDP */
if(pbuf_header(p, -UDP_HLEN)) {
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
@ -277,32 +360,45 @@ udp_input(struct pbuf *p, struct netif *inp)
if (pcb != NULL) {
snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&
((pcb->so_options & SOF_REUSEADDR) != 0)) {
if ((broadcast ||
#if LWIP_IPV6
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6 */
ip_addr_ismulticast(ip_current_dest_addr())) &&
ip_get_option(pcb, SOF_REUSEADDR)) {
/* pass broadcast- or multicast packets to all multicast pcbs
if SOF_REUSEADDR is set on the first match */
struct udp_pcb *mpcb;
u8_t p_header_changed = 0;
s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN);
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
if (mpcb != pcb) {
/* compare PCB local addr+port to UDP destination addr+port */
if ((mpcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IPV6
((PCB_ISIPV6(mpcb) &&
(ip6_addr_ismulticast(ip6_current_dest_addr()) ||
ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) ||
(!PCB_ISIPV6(mpcb) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) ||
ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(&current_iphdr_dest) ||
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
(broadcast && ip_get_option(mpcb, SOF_BROADCAST)))))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))) {
(broadcast))))) {
#endif /* IP_SOF_BROADCAST_RECV */
/* pass a copy of the packet to all local matches */
if (mpcb->recv != NULL) {
if (mpcb->recv.ip4 != NULL) {
struct pbuf *q;
/* for that, move payload to IP header again */
if (p_header_changed == 0) {
pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
pbuf_header(p, hdrs_len);
p_header_changed = 1;
}
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
@ -310,8 +406,16 @@ udp_input(struct pbuf *p, struct netif *inp)
err_t err = pbuf_copy(q, p);
if (err == ERR_OK) {
/* move payload to UDP data */
pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
pbuf_header(q, -hdrs_len);
#if LWIP_IPV6
if (PCB_ISIPV6(mpcb)) {
mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src);
}
else
#endif /* LWIP_IPV6 */
{
mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
}
}
}
}
@ -320,14 +424,22 @@ udp_input(struct pbuf *p, struct netif *inp)
}
if (p_header_changed) {
/* and move payload to UDP data again */
pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
pbuf_header(p, -hdrs_len);
}
}
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
/* callback */
if (pcb->recv != NULL) {
if (pcb->recv.ip4 != NULL) {
/* now the recv function is responsible for freeing p */
pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src);
}
else
#endif /* LWIP_IPV6 */
{
pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
}
} else {
/* no recv function registered? then we have to free the pbuf! */
pbuf_free(p);
@ -336,17 +448,19 @@ udp_input(struct pbuf *p, struct netif *inp)
} else {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
#if LWIP_ICMP
#if LWIP_ICMP || LWIP_ICMP6
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!broadcast &&
!ip_addr_ismulticast(&current_iphdr_dest)) {
#if LWIP_IPV6
!ip6_addr_ismulticast(ip6_current_dest_addr()) &&
#endif /* LWIP_IPV6 */
!ip_addr_ismulticast(ip_current_dest_addr())) {
/* move payload pointer back to ip header */
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
icmp_dest_unreach(p, ICMP_DUR_PORT);
pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN);
icmp_port_unreach(ip_current_is_v6(), p);
}
#endif /* LWIP_ICMP */
#endif /* LWIP_ICMP || LWIP_ICMP6 */
UDP_STATS_INC(udp.proterr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpnoports();
@ -357,6 +471,17 @@ udp_input(struct pbuf *p, struct netif *inp)
}
end:
PERF_STOP("udp_input");
return;
#if CHECKSUM_CHECK_UDP
chkerr:
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
PERF_STOP("udp_input");
#endif /* CHECKSUM_CHECK_UDP */
}
/**
@ -381,7 +506,7 @@ err_t
udp_send(struct udp_pcb *pcb, struct pbuf *p)
{
/* send to the packet using remote ip and port stored in the pcb */
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port);
}
#if LWIP_CHECKSUM_ON_COPY
@ -392,7 +517,7 @@ udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
u8_t have_chksum, u16_t chksum)
{
/* send to the packet using remote ip and port stored in the pcb */
return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port,
have_chksum, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
@ -429,20 +554,34 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
{
#endif /* LWIP_CHECKSUM_ON_COPY */
struct netif *netif;
ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
/* find the outgoing network interface for this packet */
#if LWIP_IPV6 || LWIP_IGMP
if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) {
/* For multicast, find a netif based on source address. */
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
dst_ip_route = &pcb->local_ip;
} else
#endif /* LWIP_IPV6 */
{
#if LWIP_IGMP
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
#else
netif = ip_route(dst_ip);
dst_ip_route = ip_2_ipX(&pcb->multicast_ip);
#endif /* LWIP_IGMP */
}
}
#endif /* LWIP_IPV6 || LWIP_IGMP */
/* find the outgoing network interface for this packet */
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route);
/* no outgoing network interface could be found? */
if (netif == NULL) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip));
LWIP_DEBUGF(UDP_DEBUG, ("\n"));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
@ -491,10 +630,15 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
ip_addr_t *src_ip;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
u8_t ip_proto;
#if IP_SOF_BROADCAST
/* broadcast filter? */
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
if (!ip_get_option(pcb, SOF_BROADCAST) &&
#if LWIP_IPV6
!PCB_ISIPV6(pcb) &&
#endif /* LWIP_IPV6 */
ip_addr_isbroadcast(dst_ip, netif) ) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
return ERR_VAL;
@ -504,7 +648,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
/* if the PCB is not yet bound to a port, bind it here */
if (pcb->local_port == 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
if (err != ERR_OK) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
return err;
@ -520,8 +664,10 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p (only if p contains data) */
pbuf_chain(q, p);
}
/* first pbuf q points to header pbuf */
LWIP_DEBUGF(UDP_DEBUG,
("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
@ -542,20 +688,60 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
/* Multicast Loop? */
#if LWIP_IGMP
if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {
if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) &&
#if LWIP_IPV6
(
#if LWIP_IPV6_MLD
(PCB_ISIPV6(pcb) &&
ip6_addr_ismulticast(ip_2_ip6(dst_ip))) ||
#endif /* LWIP_IPV6_MLD */
(!PCB_ISIPV6(pcb) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
ip_addr_ismulticast(dst_ip)))) {
q->flags |= PBUF_FLAG_MCASTLOOP;
}
#endif /* LWIP_IGMP */
/* PCB local address is IP_ANY_ADDR? */
if (ip_addr_isany(&pcb->local_ip)) {
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) {
src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip)));
if (src_ip == NULL) {
/* No suitable source address was found. */
if (q != p) {
/* free the header pbuf */
pbuf_free(q);
/* p is still referenced by the caller, and will live on */
}
return ERR_RTE;
}
} else {
/* use UDP PCB local IPv6 address as source address, if still valid. */
if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) {
/* Address isn't valid anymore. */
if (q != p) {
/* free the header pbuf */
pbuf_free(q);
/* p is still referenced by the caller, and will live on */
}
return ERR_RTE;
}
src_ip = ipX_2_ip(&pcb->local_ip);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* check if UDP PCB local IP address is correct
* this could be an old address if netif->ip_addr has changed */
if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) {
/* local_ip doesn't match, drop the packet */
if (q != p) {
/* free the header pbuf */
@ -566,7 +752,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
return ERR_VAL;
}
/* use UDP PCB local IP address as source address */
src_ip = &(pcb->local_ip);
src_ip = ipX_2_ip(&(pcb->local_ip));
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
@ -594,33 +780,28 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
udphdr->len = htons(chklen_hdr);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
IP_PROTO_UDPLITE, q->tot_len,
#if !LWIP_CHECKSUM_ON_COPY
chklen);
#else /* !LWIP_CHECKSUM_ON_COPY */
(have_chksum ? UDP_HLEN : chklen));
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
chklen = UDP_HLEN;
}
#endif /* LWIP_CHECKSUM_ON_COPY */
udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE,
q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#endif /* !LWIP_CHECKSUM_ON_COPY */
#endif /* LWIP_CHECKSUM_ON_COPY */
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) {
udphdr->chksum = 0xffff;
}
#endif /* CHECKSUM_GEN_UDP */
/* output to IP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
ip_proto = IP_PROTO_UDPLITE;
} else
#endif /* LWIP_UDPLITE */
{ /* UDP */
@ -628,19 +809,21 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
udphdr->len = htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
/* Checksum is mandatory over IPv6. */
if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
u16_t udpchksum;
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
u32_t acc;
udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
q->tot_len, UDP_HLEN);
udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP,
q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
acc = udpchksum + (u16_t)~(chksum);
udpchksum = FOLD_U32T(acc);
} else
#endif /* LWIP_CHECKSUM_ON_COPY */
{
udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len,
ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
@ -650,17 +833,16 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
udphdr->chksum = udpchksum;
}
#endif /* CHECKSUM_GEN_UDP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
/* output to IP */
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
ip_proto = IP_PROTO_UDP;
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto));
/* output to IP */
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* TODO: must this be increased even if error occured? */
snmp_inc_udpoutdatagrams();
@ -702,7 +884,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
u8_t rebind;
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
ip_addr_debug_print(UDP_DEBUG, ipaddr);
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
rebind = 0;
@ -720,17 +902,17 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
PCB is alread bound to, unless *all* PCBs with that port have tha
REUSEADDR flag set. */
#if SO_REUSE
else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
((ipcb->so_options & SOF_REUSEADDR) == 0)) {
else if (!ip_get_option(pcb, SOF_REUSEADDR) &&
!ip_get_option(ipcb, SOF_REUSEADDR)) {
#else /* SO_REUSE */
/* port matches that of PCB in list and REUSEADDR not set -> reject */
else {
#endif /* SO_REUSE */
if ((ipcb->local_port == port) &&
if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) &&
/* IP address matches, or one is IP_ADDR_ANY? */
(ip_addr_isany(&(ipcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
(ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) ||
ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) ||
ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) {
/* other PCB already binds to this local IP and port */
LWIP_DEBUGF(UDP_DEBUG,
("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
@ -739,28 +921,12 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
}
}
ip_addr_set(&pcb->local_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
/* no port specified? */
if (port == 0) {
#ifndef UDP_LOCAL_PORT_RANGE_START
#define UDP_LOCAL_PORT_RANGE_START 4096
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
#endif
port = UDP_LOCAL_PORT_RANGE_START;
ipcb = udp_pcbs;
while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
if (ipcb->local_port == port) {
/* port is already used by another udp_pcb */
port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
port = udp_new_port();
if (port == 0) {
/* no more ports available in local range */
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
return ERR_USE;
@ -774,13 +940,12 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
pcb->next = udp_pcbs;
udp_pcbs = pcb;
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
pcb->local_port));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
return ERR_OK;
}
/**
* Connect an UDP PCB.
*
@ -804,39 +969,44 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
struct udp_pcb *ipcb;
if (pcb->local_port == 0) {
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
ip_addr_set(&pcb->remote_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
pcb->remote_port = port;
pcb->flags |= UDP_FLAGS_CONNECTED;
/** TODO: this functionality belongs in upper layers */
#ifdef LWIP_UDP_TODO
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
struct netif *netif;
#if LWIP_IPV6
if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
{
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
struct netif *netif;
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n",
ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip))));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
/** TODO: this will bind the udp pcb locally, to the interface which
is used to route output packets to the remote address. However, we
might want to accept incoming packets on any interface! */
ipX_addr_copy(0, pcb->local_ip, netif->ip_addr);
} else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
ipX_addr_set_any(0, &pcb->local_ip);
}
/** TODO: this will bind the udp pcb locally, to the interface which
is used to route output packets to the remote address. However, we
might want to accept incoming packets on any interface! */
pcb->local_ip = netif->ip_addr;
} else if (ip_addr_isany(&pcb->remote_ip)) {
pcb->local_ip.addr = 0;
}
#endif
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip),
pcb->remote_port));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
&pcb->remote_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));
/* Insert UDP PCB into the list of active UDP PCBs. */
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
@ -860,7 +1030,7 @@ void
udp_disconnect(struct udp_pcb *pcb)
{
/* reset remote address association */
ip_addr_set_any(&pcb->remote_ip);
ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip);
pcb->remote_port = 0;
/* mark PCB as unconnected */
pcb->flags &= ~UDP_FLAGS_CONNECTED;
@ -879,7 +1049,7 @@ void
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv.ip4 = recv;
pcb->recv_arg = recv_arg;
}
@ -939,6 +1109,25 @@ udp_new(void)
return pcb;
}
#if LWIP_IPV6
/**
* Create a UDP PCB for IPv6.
*
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @see udp_remove()
*/
struct udp_pcb *
udp_new_ip6(void)
{
struct udp_pcb *pcb;
pcb = udp_new();
ip_set_v6(pcb, 1);
return pcb;
}
#endif /* LWIP_IPV6 */
#if UDP_DEBUG
/**
* Print UDP header information for debug purposes.

View file

@ -89,8 +89,7 @@ struct autoip
};
/** Init srand, has to be called before entering mainloop */
void autoip_init(void);
#define autoip_init() /* Compatibility define, no init needed. */
/** Set a struct autoip allocated by the application to work with */
void autoip_set_struct(struct netif *netif, struct autoip *autoip);

View file

@ -37,33 +37,37 @@
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#if LWIP_IPV6 && LWIP_ICMP6
#include "lwip/icmp6.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
#define ICMP_IR 16 /* information reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};
@ -104,6 +108,16 @@ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#endif /* LWIP_ICMP */
#if (LWIP_IPV6 && LWIP_ICMP6)
#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \
icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \
icmp_dest_unreach(pbuf, ICMP_DUR_PORT))
#elif LWIP_ICMP
#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT)
#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
#define icmp_port_unreach(isipv6, pbuf)
#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
#ifdef __cplusplus
}
#endif

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_CHKSUM_H__
#define __LWIP_INET_CHKSUM_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/** Swap the bytes in an u16_t: much like htons() for little-endian */
#ifndef SWAP_BYTES_IN_WORD
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
#endif /* SWAP_BYTES_IN_WORD */
/** Split an u32_t in two u16_ts and add them up */
#ifndef FOLD_U32T
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#endif
#if LWIP_CHECKSUM_ON_COPY
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
as u16_t */
#ifndef LWIP_CHKSUM_COPY
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
#define LWIP_CHKSUM_COPY_ALGORITHM 1
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#endif /* LWIP_CHKSUM_COPY */
#else /* LWIP_CHECKSUM_ON_COPY */
#define LWIP_CHKSUM_COPY_ALGORITHM 0
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
extern "C" {
#endif
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len);
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len);
#if LWIP_CHKSUM_COPY_ALGORITHM
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */

View file

@ -29,14 +29,15 @@
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#ifndef __LWIP_IP4_H__
#define __LWIP_IP4_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
@ -54,60 +55,6 @@ extern "C" {
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP 6
#define IP_PROTO_ANY 255 /* using a IANA reserved value */
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
/* ip addresses in network byte order */ \
ip_addr_t local_ip; \
ip_addr_t remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
#ifdef PACK_STRUCT_USE_INCLUDES
@ -115,18 +62,20 @@ struct ip_pcb {
#endif
PACK_STRUCT_BEGIN
struct ip_hdr {
/* version / header length / type of service */
PACK_STRUCT_FIELD(u16_t _v_hl_tos);
/* version / header length */
PACK_STRUCT_FIELD(u8_t _v_hl);
/* type of service */
PACK_STRUCT_FIELD(u8_t _tos);
/* total length */
PACK_STRUCT_FIELD(u16_t _len);
/* identification */
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
PACK_STRUCT_FIELD(u16_t _offset);
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
#define IP_RF 0x8000U /* reserved fragment flag */
#define IP_DF 0x4000U /* dont fragment flag */
#define IP_MF 0x2000U /* more fragments flag */
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
/* time to live */
PACK_STRUCT_FIELD(u8_t _ttl);
/* protocol*/
@ -142,9 +91,9 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
#define IPH_V(hdr) ((hdr)->_v_hl >> 4)
#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f)
#define IPH_TOS(hdr) ((hdr)->_tos)
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)
@ -152,7 +101,8 @@ PACK_STRUCT_END
#define IPH_PROTO(hdr) ((hdr)->_proto)
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl))
#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos)
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
@ -160,16 +110,8 @@ PACK_STRUCT_END
#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
/** The interface that provided the packet for the current callback invocation. */
extern struct netif *current_netif;
/** Header of the input packet currently being processed. */
extern const struct ip_hdr *current_header;
/** Source IP address of current_header */
extern ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
extern ip_addr_t current_iphdr_dest;
#define ip_init() /* Compatibility define, not init needed. */
#define ip_init() /* Compatibility define, no init needed. */
struct netif *ip_route(ip_addr_t *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
@ -186,18 +128,8 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
u16_t optlen);
#endif /* IP_OPTIONS_SEND */
/** Get the interface that received the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_netif() (current_netif)
/** Get the IP header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_header() (current_header)
/** Source IP address of current_header */
#define ip_current_src_addr() (&current_iphdr_src)
/** Destination IP address of current_header */
#define ip_current_dest_addr() (&current_iphdr_dest)
#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL)
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);

View file

@ -29,8 +29,8 @@
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#ifndef __LWIP_IP4_ADDR_H__
#define __LWIP_IP4_ADDR_H__
#include "lwip/opt.h"
#include "lwip/def.h"

View file

@ -70,12 +70,15 @@ struct pbuf * ip_reass(struct pbuf *p);
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
#ifndef __LWIP_PBUF_CUSTOM_REF__
#define __LWIP_PBUF_CUSTOM_REF__
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);

View file

@ -0,0 +1,58 @@
/**
* @file
*
* IPv6 address autoconfiguration as per RFC 4862.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
* IPv6 address autoconfiguration as per RFC 4862.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_DHCP6_H__
#define __LWIP_IP6_DHCP6_H__
#include "lwip/opt.h"
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
struct dhcp6
{
/*TODO: implement DHCP6*/
};
#endif /* LWIP_IPV6_DHCP6 */
#endif /* __LWIP_IP6_DHCP6_H__ */

View file

@ -0,0 +1,68 @@
/**
* @file
*
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_ETHIP6_H__
#define __LWIP_ETHIP6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 && LWIP_ETHERNET */
#endif /* __LWIP_ETHIP6_H__ */

View file

@ -0,0 +1,152 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_ICMP6_H__
#define __LWIP_ICMP6_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
enum icmp6_type {
ICMP6_TYPE_DUR = 1, /* Destination unreachable */
ICMP6_TYPE_PTB = 2, /* Packet too big */
ICMP6_TYPE_TE = 3, /* Time exceeded */
ICMP6_TYPE_PP = 4, /* Parameter problem */
ICMP6_TYPE_PE1 = 100, /* Private experimentation */
ICMP6_TYPE_PE2 = 101, /* Private experimentation */
ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */
ICMP6_TYPE_EREQ = 128, /* Echo request */
ICMP6_TYPE_EREP = 129, /* Echo reply */
ICMP6_TYPE_MLQ = 130, /* Multicast listener query */
ICMP6_TYPE_MLR = 131, /* Multicast listener report */
ICMP6_TYPE_MLD = 132, /* Multicast listener done */
ICMP6_TYPE_RS = 133, /* Router solicitation */
ICMP6_TYPE_RA = 134, /* Router advertisement */
ICMP6_TYPE_NS = 135, /* Neighbor solicitation */
ICMP6_TYPE_NA = 136, /* Neighbor advertisement */
ICMP6_TYPE_RD = 137, /* Redirect */
ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */
ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */
ICMP6_TYPE_MRT = 153, /* Multicast router termination */
ICMP6_TYPE_PE3 = 200, /* Private experimentation */
ICMP6_TYPE_PE4 = 201, /* Private experimentation */
ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */
};
enum icmp6_dur_code {
ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */
ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */
ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */
ICMP6_DUR_ADDRESS = 3, /* Address unreachable */
ICMP6_DUR_PORT = 4, /* Port unreachable */
ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */
ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */
};
enum icmp6_te_code {
ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */
ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */
};
enum icmp6_pp_code {
ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */
ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */
ICMP6_PP_OPTION = 2 /* Unrecognized IPv6 option encountered */
};
/** This is the standard ICMP6 header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp6_hdr {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t data);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** This is the ICMP6 header adapted for echo req/resp. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp6_echo_hdr {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
void icmp6_input(struct pbuf *p, struct netif *inp);
void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c);
void icmp6_packet_too_big(struct pbuf *p, u32_t mtu);
void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c);
void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer);
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_ICMP6_H__ */

View file

@ -0,0 +1,92 @@
/**
* @file
*
* INET v6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_INET6_H__
#define __LWIP_INET6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/** For compatibility with BSD code */
struct in6_addr {
union {
u8_t u8_addr[16];
u32_t u32_addr[4];
} un;
#define s6_addr un.u32_addr
};
#define IN6ADDR_ANY_INIT {0,0,0,0}
#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)}
#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \
(target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \
(target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \
(target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];}
#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \
(target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \
(target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \
(target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3];}
/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */
#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr))
/* directly map this to the lwip internal functions */
#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr)
#define inet6_ntoa(addr) ip6addr_ntoa((ip6_addr_t*)&(addr))
#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen)
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_INET6_H__ */

View file

@ -0,0 +1,197 @@
/**
* @file
*
* IPv6 layer.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_H__
#define __LWIP_IP6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip.h"
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IP6_HLEN 40
#define IP6_NEXTH_HOPBYHOP 0
#define IP6_NEXTH_TCP 6
#define IP6_NEXTH_UDP 17
#define IP6_NEXTH_ENCAPS 41
#define IP6_NEXTH_ROUTING 43
#define IP6_NEXTH_FRAGMENT 44
#define IP6_NEXTH_ICMP6 58
#define IP6_NEXTH_NONE 59
#define IP6_NEXTH_DESTOPTS 60
#define IP6_NEXTH_UDPLITE 136
/* The IPv6 header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_hdr {
/* version / traffic class / flow label */
PACK_STRUCT_FIELD(u32_t _v_tc_fl);
/* payload length */
PACK_STRUCT_FIELD(u16_t _plen);
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* hop limit */
PACK_STRUCT_FIELD(u8_t _hoplim);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(ip6_addr_p_t src);
PACK_STRUCT_FIELD(ip6_addr_p_t dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Hop-by-hop router alert option. */
#define IP6_HBH_HLEN 8
#define IP6_PAD1_OPTION 0
#define IP6_PADN_ALERT_OPTION 1
#define IP6_ROUTER_ALERT_OPTION 5
#define IP6_ROUTER_ALERT_VALUE_MLD 0
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_hbh_hdr {
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* header length */
PACK_STRUCT_FIELD(u8_t _hlen);
/* router alert option type */
PACK_STRUCT_FIELD(u8_t _ra_opt_type);
/* router alert option data len */
PACK_STRUCT_FIELD(u8_t _ra_opt_dlen);
/* router alert option data */
PACK_STRUCT_FIELD(u16_t _ra_opt_data);
/* PadN option type */
PACK_STRUCT_FIELD(u8_t _padn_opt_type);
/* PadN option data len */
PACK_STRUCT_FIELD(u8_t _padn_opt_dlen);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Fragment header. */
#define IP6_FRAG_HLEN 8
#define IP6_FRAG_OFFSET_MASK 0xfff8
#define IP6_FRAG_MORE_FLAG 0x0001
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_frag_hdr {
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* reserved */
PACK_STRUCT_FIELD(u8_t reserved);
/* fragment offset */
PACK_STRUCT_FIELD(u16_t _fragment_offset);
/* fragmented packet identification */
PACK_STRUCT_FIELD(u32_t _identification);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f)
#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff)
#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff)
#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen))
#define IP6H_NEXTH(hdr) ((hdr)->_nexth)
#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6)
#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim)
#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl)))
#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen)
#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth)
#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl)
#define ip6_init() /* TODO should we init current addresses and header pointer? */
struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest);
ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest);
err_t ip6_input(struct pbuf *p, struct netif *inp);
err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
u8_t hl, u8_t tc, u8_t nexth);
err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
u8_t hl, u8_t tc, u8_t nexth, struct netif *netif);
#if LWIP_NETIF_HWADDRHINT
err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT */
#if LWIP_IPV6_MLD
err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value);
#endif /* LWIP_IPV6_MLD */
#define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \
ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL)
#if IP6_DEBUG
void ip6_debug_print(struct pbuf *p);
#else
#define ip6_debug_print(p)
#endif /* IP6_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_IP6_H__ */

View file

@ -0,0 +1,286 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
* Structs and macros for handling IPv6 addresses.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_ADDR_H__
#define __LWIP_IP6_ADDR_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/* This is the aligned version of ip6_addr_t,
used as local variable, on the stack, etc. */
struct ip6_addr {
u32_t addr[4];
};
/* This is the packed version of ip6_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_addr_packed {
PACK_STRUCT_FIELD(u32_t addr[4]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** ip6_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip6_addr_t as well as on ip6_addr_p_t. */
typedef struct ip6_addr ip6_addr_t;
typedef struct ip6_addr_packed ip6_addr_p_t;
/** IP6_ADDR_ANY can be used as a fixed IPv6 address
* for the wildcard
*/
extern const ip6_addr_t ip6_addr_any;
#define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any)
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IPv6 partial address given by byte-parts. */
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IPv6 partial address given by byte-parts.
Little-endian version, stored in network order (no htonl). */
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
/** Access address in 16-bit block */
#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0])) & 0xffff)
#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1])) & 0xffff)
#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2])) & 0xffff)
#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3])) & 0xffff)
/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */
#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \
(dest).addr[1] = (src).addr[1]; \
(dest).addr[2] = (src).addr[2]; \
(dest).addr[3] = (src).addr[3];}while(0)
/** Safely copy one IPv6 address to another (src may be NULL) */
#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \
(dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \
(dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \
(dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0)
/** Set complete address to zero */
#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = 0;}while(0)
/** Set address to ipv6 'any' (no need for htonl()) */
#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr)
/** Set address to ipv6 loopback address */
#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
/** Safely copy one IPv6 address to another and change byte order
* from host- to network-order. */
#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \
(dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \
(dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \
(dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0)
/**
* Determine if two IPv6 address are on the same network.
*
* @arg addr1 IPv6 address 1
* @arg addr2 IPv6 address 2
* @return !0 if the network identifiers of both address match
*/
#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
((addr1)->addr[1] == (addr2)->addr[1]))
#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
((addr1)->addr[1] == (addr2)->addr[1]) && \
((addr1)->addr[2] == (addr2)->addr[2]) && \
((addr1)->addr[3] == (addr2)->addr[3]))
#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL)
#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \
(((ip6addr)->addr[0] == 0) && \
((ip6addr)->addr[1] == 0) && \
((ip6addr)->addr[2] == 0) && \
((ip6addr)->addr[3] == 0)))
#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL))
#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL))
#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL))
#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL))
#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL))
#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL))
#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL))
#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL))
#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf)
#define IP6_MULTICAST_SCOPE_RESERVED 0x0
#define IP6_MULTICAST_SCOPE_RESERVED0 0x0
#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1
#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2
#define IP6_MULTICAST_SCOPE_RESERVED3 0x3
#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4
#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5
#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8
#define IP6_MULTICAST_SCOPE_GLOBAL 0xe
#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf
#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL))
#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL))
#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL))
#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL))
#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL))
#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL))
/* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */
#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000002UL)))
#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0)
#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \
(((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) )
#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \
(ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}while(0)
#define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[1] == 0) && \
((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \
((ip6addr)->addr[3] == htonl(0xff000000UL | (htonl((sn_addr)->addr[3]) & 0x00ffffffUL))))
/* IPv6 address states. */
#define IP6_ADDR_INVALID 0x00
#define IP6_ADDR_TENTATIVE 0x08
#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */
#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */
#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */
#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */
#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */
#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */
#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */
#define IP6_ADDR_VALID 0x10
#define IP6_ADDR_PREFERRED 0x30
#define IP6_ADDR_DEPRECATED 0x50
#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID)
#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE)
#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
#define ip6_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \
ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0))
int ip6addr_aton(const char *cp, ip6_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ip6addr_ntoa(const ip6_addr_t *addr);
char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_IP6_ADDR_H__ */

View file

@ -0,0 +1,102 @@
/**
* @file
*
* IPv6 fragmentation and reassembly.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_FRAG_H__
#define __LWIP_IP6_FRAG_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
/* The IPv6 reassembly timer interval in milliseconds. */
#define IP6_REASS_TMR_INTERVAL 1000
/* IPv6 reassembly helper struct.
* This is exported because memp needs to know the size.
*/
struct ip6_reassdata {
struct ip6_reassdata *next;
struct pbuf *p;
struct ip6_hdr * iphdr;
u32_t identification;
u16_t datagram_len;
u8_t nexth;
u8_t timer;
};
#define ip6_reass_init() /* Compatibility define */
void ip6_reass_tmr(void);
struct pbuf * ip6_reass(struct pbuf *p);
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
#ifndef __LWIP_PBUF_CUSTOM_REF__
#define __LWIP_PBUF_CUSTOM_REF__
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest);
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP6_FRAG_H__ */

View file

@ -0,0 +1,118 @@
/**
* @file
*
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_MLD6_H__
#define __LWIP_MLD6_H__
#include "lwip/opt.h"
#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
struct mld_group {
/** next link */
struct mld_group *next;
/** interface on which the group is active */
struct netif *netif;
/** multicast address */
ip6_addr_t group_address;
/** signifies we were the last person to report */
u8_t last_reporter_flag;
/** current state of the group */
u8_t group_state;
/** timer for reporting */
u16_t timer;
/** counter of simultaneous uses */
u8_t use;
};
/** Multicast listener report/query/done message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct mld_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t max_resp_delay);
PACK_STRUCT_FIELD(u16_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define MLD6_TMR_INTERVAL 100 /* Milliseconds */
/* MAC Filter Actions, these are passed to a netif's
* mld_mac_filter callback function. */
#define MLD6_DEL_MAC_FILTER 0
#define MLD6_ADD_MAC_FILTER 1
#define mld6_init() /* TODO should we init tables? */
err_t mld6_stop(struct netif *netif);
void mld6_report_groups(struct netif *netif);
void mld6_tmr(void);
struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr);
void mld6_input(struct pbuf *p, struct netif *inp);
err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */
#endif /* __LWIP_MLD6_H__ */

View file

@ -0,0 +1,369 @@
/**
* @file
*
* Neighbor discovery and stateless address autoconfiguration for IPv6.
* Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
* (Address autoconfiguration).
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_ND6_H__
#define __LWIP_ND6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Struct for tables. */
struct nd6_neighbor_cache_entry {
ip6_addr_t next_hop_address;
struct netif * netif;
u8_t lladdr[NETIF_MAX_HWADDR_LEN];
/*u32_t pmtu;*/
#if LWIP_ND6_QUEUEING
/** Pointer to queue of pending outgoing packets on this entry. */
struct nd6_q_entry *q;
#else /* LWIP_ND6_QUEUEING */
/** Pointer to a single pending outgoing packet on this entry. */
struct pbuf *q;
#endif /* LWIP_ND6_QUEUEING */
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time;
u32_t delay_time;
u32_t probes_sent;
u32_t stale_time;
} counter;
};
struct nd6_destination_cache_entry {
ip6_addr_t destination_addr;
ip6_addr_t next_hop_addr;
u32_t pmtu;
u32_t age;
};
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif * netif;
u32_t invalidation_timer;
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry * neighbor_entry;
u32_t invalidation_timer;
u8_t flags;
};
enum nd6_neighbor_cache_entry_state {
ND6_NO_ENTRY = 0,
ND6_INCOMPLETE,
ND6_REACHABLE,
ND6_STALE,
ND6_DELAY,
ND6_PROBE
};
#if LWIP_ND6_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct nd6_q_entry {
struct nd6_q_entry *next;
struct pbuf *p;
};
#endif /* LWIP_ND6_QUEUEING */
/** Neighbor solicitation message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ns_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Neighbor advertisement message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct na_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u8_t reserved[3]);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ND6_FLAG_ROUTER (0x80)
#define ND6_FLAG_SOLICITED (0x40)
#define ND6_FLAG_OVERRIDE (0x20)
/** Router solicitation message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct rs_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Router advertisement message header. */
#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80)
#define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40)
#define ND6_RA_FLAG_HOME_AGENT (0x20)
#define ND6_RA_PREFERENCE_MASK (0x18)
#define ND6_RA_PREFERENCE_HIGH (0x08)
#define ND6_RA_PREFERENCE_MEDIUM (0x00)
#define ND6_RA_PREFERENCE_LOW (0x18)
#define ND6_RA_PREFERENCE_DISABLED (0x10)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ra_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u8_t current_hop_limit);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u16_t router_lifetime);
PACK_STRUCT_FIELD(u32_t reachable_time);
PACK_STRUCT_FIELD(u32_t retrans_timer);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Redirect message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct redirect_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
PACK_STRUCT_FIELD(ip6_addr_p_t destination_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Link-layer address option. */
#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01)
#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct lladdr_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Prefix information option. */
#define ND6_OPTION_TYPE_PREFIX_INFO (0x03)
#define ND6_PREFIX_FLAG_ON_LINK (0x80)
#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40)
#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20)
#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct prefix_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t prefix_length);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u32_t valid_lifetime);
PACK_STRUCT_FIELD(u32_t preferred_lifetime);
PACK_STRUCT_FIELD(u8_t reserved2[3]);
PACK_STRUCT_FIELD(u8_t site_prefix_length);
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Redirected header option. */
#define ND6_OPTION_TYPE_REDIR_HDR (0x04)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct redirected_header_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t reserved[6]);
/* Portion of redirected packet follows. */
/* PACK_STRUCT_FIELD(u8_t redirected[8]); */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** MTU option. */
#define ND6_OPTION_TYPE_MTU (0x05)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct mtu_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u16_t reserved);
PACK_STRUCT_FIELD(u32_t mtu);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Route information option. */
#define ND6_OPTION_TYPE_ROUTE_INFO (24)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct route_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t prefix_length);
PACK_STRUCT_FIELD(u8_t preference);
PACK_STRUCT_FIELD(u32_t route_lifetime);
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* the possible states of an IP address */
#define IP6_ADDRESS_STATE_INVALID (0)
#define IP6_ADDRESS_STATE_VALID (0x4)
#define IP6_ADDRESS_STATE_PREFERRED (0x5) /* includes valid */
#define IP6_ADDRESS_STATE_DEPRECATED (0x6) /* includes valid */
#define IP6_ADDRESS_STATE_TENTATIV (0x8)
/** 1 second period */
#define ND6_TMR_INTERVAL 1000
/* Router tables. */
/* TODO make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];
extern struct nd6_destination_cache_entry destination_cache[];
extern struct nd6_prefix_list_entry prefix_list[];
extern struct nd6_router_list_entry default_router_list[];
/* Default values, can be updated by a RA message. */
extern u32_t reachable_time;
extern u32_t retrans_timer;
#define nd6_init() /* TODO should we init tables? */
void nd6_tmr(void);
void nd6_input(struct pbuf *p, struct netif *inp);
s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif);
s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif);
u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif);
err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
#if LWIP_ND6_TCP_REACHABILITY_HINTS
void nd6_reachability_hint(ip6_addr_t * ip6addr);
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_ND6_H__ */

View file

@ -73,23 +73,50 @@ extern "C" {
/** If a nonblocking write has been rejected before, poll_tcp needs to
check if the netconn is writable again */
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
#if LWIP_IPV6
/** If this flag is set then only IPv6 communication is allowed on the
netconn. As per RFC#3493 this features defaults to OFF allowing
dual-stack usage by default. */
#define NETCONN_FLAG_IPV6_V6ONLY 0x20
#endif /* LWIP_IPV6 */
/* Helpers to process several netconn_types by the same code */
#define NETCONNTYPE_GROUP(t) (t&0xF0)
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
#define NETCONNTYPE_GROUP(t) ((t)&0xF0)
#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0)
#if LWIP_IPV6
#define NETCONN_TYPE_IPV6 0x08
#define NETCONNTYPE_ISIPV6(t) ((t)&0x08)
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM)
#else /* LWIP_IPV6 */
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
#endif /* LWIP_IPV6 */
/** Protocol family and type of the netconn */
enum netconn_type {
NETCONN_INVALID = 0,
NETCONN_INVALID = 0,
/* NETCONN_TCP Group */
NETCONN_TCP = 0x10,
NETCONN_TCP = 0x10,
#if LWIP_IPV6
NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */,
#endif /* LWIP_IPV6 */
/* NETCONN_UDP Group */
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM= 0x22,
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM = 0x22,
#if LWIP_IPV6
NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */,
NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */,
NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */,
#endif /* LWIP_IPV6 */
/* NETCONN_RAW Group */
NETCONN_RAW = 0x40
NETCONN_RAW = 0x40
#if LWIP_IPV6
,
NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */
#endif /* LWIP_IPV6 */
};
/** Current state of the netconn. Non-TCP netconns are always
@ -111,13 +138,13 @@ enum netconn_evt {
NETCONN_EVT_ERROR
};
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** Used for netconn_join_leave_group() */
enum netconn_igmp {
NETCONN_JOIN,
NETCONN_LEAVE
};
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
/* forward-declare some structs to avoid to include their headers */
struct ip_pcb;
@ -159,6 +186,11 @@ struct netconn {
#if LWIP_SOCKET
int socket;
#endif /* LWIP_SOCKET */
#if LWIP_SO_SNDTIMEO
/** timeout to wait for sending data (which means enqueueing data for sending
in internal buffers) */
s32_t send_timeout;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVTIMEO
/** timeout to wait for new data to be received
(or connections to arrive for listening netconns) */
@ -168,12 +200,11 @@ struct netconn {
/** maximum amount of bytes queued in recvmbox
not used for TCP: adjust TCP_WND instead! */
int recv_bufsize;
#endif /* LWIP_SO_RCVBUF */
/** number of bytes currently in recvmbox to be received,
tested against recv_bufsize to limit bytes on recvmbox
for UDP and RAW
@todo: should only be necessary with LWIP_SO_RCVBUF==1 */
for UDP and RAW, used for FIONREAD */
s16_t recv_avail;
#endif /* LWIP_SO_RCVBUF */
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
u8_t flags;
#if LWIP_TCP
@ -231,18 +262,34 @@ void netconn_recved(struct netconn *conn, u32_t length);
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
ip_addr_t *addr, u16_t port);
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags);
err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags, size_t *bytes_written);
#define netconn_write(conn, dataptr, size, apiflags) \
netconn_write_partly(conn, dataptr, size, apiflags, NULL)
err_t netconn_close(struct netconn *conn);
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#endif /* LWIP_DNS */
#if LWIP_IPV6
#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL)
#if LWIP_IPV6_MLD
#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\
ERR_VAL)
#endif /* LWIP_IPV6_MLD*/
#endif /* LWIP_IPV6 */
#define netconn_err(conn) ((conn)->last_err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
@ -263,6 +310,12 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
#if LWIP_SO_SNDTIMEO
/** Set the send timeout in milliseconds */
#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout))
/** Get the send timeout in milliseconds */
#define netconn_get_sendtimeout(conn) ((conn)->send_timeout)
#endif /* LWIP_SO_SNDTIMEO */
#if LWIP_SO_RCVTIMEO
/** Set the receive timeout in milliseconds */
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))

View file

@ -48,9 +48,10 @@
extern "C" {
#endif
/* For the netconn API, these values are use as a bitmask! */
#define NETCONN_SHUT_RD 1
#define NETCONN_SHUT_WR 2
#define NETCONN_SHUT_RDWR 3
#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
/* IP addresses and port numbers are expected to be in
* the same byte order as in the corresponding pcb.
@ -66,45 +67,48 @@ struct api_msg_msg {
err_t err;
/** Depending on the executed function, one of these union members is used */
union {
/** used for do_send */
/** used for lwip_netconn_do_send */
struct netbuf *b;
/** used for do_newconn */
/** used for lwip_netconn_do_newconn */
struct {
u8_t proto;
} n;
/** used for do_bind and do_connect */
/** used for lwip_netconn_do_bind and lwip_netconn_do_connect */
struct {
ip_addr_t *ipaddr;
u16_t port;
} bc;
/** used for do_getaddr */
/** used for lwip_netconn_do_getaddr */
struct {
ip_addr_t *ipaddr;
ipX_addr_t *ipaddr;
u16_t *port;
u8_t local;
} ad;
/** used for do_write */
/** used for lwip_netconn_do_write */
struct {
const void *dataptr;
size_t len;
u8_t apiflags;
#if LWIP_SO_SNDTIMEO
u32_t time_started;
#endif /* LWIP_SO_SNDTIMEO */
} w;
/** used for do_recv */
/** used for lwip_netconn_do_recv */
struct {
u32_t len;
} r;
/** used for do_close (/shutdown) */
/** used for lwip_netconn_do_close (/shutdown) */
struct {
u8_t shut;
} sd;
#if LWIP_IGMP
/** used for do_join_leave_group */
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** used for lwip_netconn_do_join_leave_group */
struct {
ip_addr_t *multiaddr;
ip_addr_t *netif_addr;
ipX_addr_t *multiaddr;
ipX_addr_t *netif_addr;
enum netconn_igmp join_or_leave;
} jl;
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if TCP_LISTEN_BACKLOG
struct {
u8_t backlog;
@ -124,9 +128,9 @@ struct api_msg {
};
#if LWIP_DNS
/** As do_gethostbyname requires more arguments but doesn't require a netconn,
/** As lwip_netconn_do_gethostbyname requires more arguments but doesn't require a netconn,
it has its own struct (to avoid struct api_msg getting bigger than necessary).
do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
(see netconn_gethostbyname). */
struct dns_api_msg {
/** Hostname to query or dotted IP address string */
@ -141,24 +145,24 @@ struct dns_api_msg {
};
#endif /* LWIP_DNS */
void do_newconn ( struct api_msg_msg *msg);
void do_delconn ( struct api_msg_msg *msg);
void do_bind ( struct api_msg_msg *msg);
void do_connect ( struct api_msg_msg *msg);
void do_disconnect ( struct api_msg_msg *msg);
void do_listen ( struct api_msg_msg *msg);
void do_send ( struct api_msg_msg *msg);
void do_recv ( struct api_msg_msg *msg);
void do_write ( struct api_msg_msg *msg);
void do_getaddr ( struct api_msg_msg *msg);
void do_close ( struct api_msg_msg *msg);
void do_shutdown ( struct api_msg_msg *msg);
#if LWIP_IGMP
void do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP */
void lwip_netconn_do_newconn ( struct api_msg_msg *msg);
void lwip_netconn_do_delconn ( struct api_msg_msg *msg);
void lwip_netconn_do_bind ( struct api_msg_msg *msg);
void lwip_netconn_do_connect ( struct api_msg_msg *msg);
void lwip_netconn_do_disconnect ( struct api_msg_msg *msg);
void lwip_netconn_do_listen ( struct api_msg_msg *msg);
void lwip_netconn_do_send ( struct api_msg_msg *msg);
void lwip_netconn_do_recv ( struct api_msg_msg *msg);
void lwip_netconn_do_write ( struct api_msg_msg *msg);
void lwip_netconn_do_getaddr ( struct api_msg_msg *msg);
void lwip_netconn_do_close ( struct api_msg_msg *msg);
void lwip_netconn_do_shutdown ( struct api_msg_msg *msg);
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
void lwip_netconn_do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
void do_gethostbyname(void *arg);
void lwip_netconn_do_gethostbyname(void *arg);
#endif /* LWIP_DNS */
struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);

View file

@ -204,27 +204,6 @@ extern "C" {
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#ifndef errno
extern int errno;
#endif

View file

@ -1,6 +0,0 @@
#ifndef __MINIX_AUTOIP_H__
#define __MINIX_AUTOIP_H__
#include "ipv4/lwip/autoip.h"
#endif /* __MINIX_AUTOIP_H__ */

View file

@ -33,6 +33,7 @@
#define __LWIP_DEBUG_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
/** lower two bits indicate debug level
* - 0 all

View file

@ -47,10 +47,6 @@ extern "C" {
#define NULL ((void *)0)
#endif
/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
/* Endianess-optimized shifting of two u8_t to create one u16_t */
#if BYTE_ORDER == LITTLE_ENDIAN
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)

View file

@ -106,6 +106,9 @@ PACK_STRUCT_END
#endif
void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
void dhcp_cleanup(struct netif *netif);
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/

View file

@ -38,6 +38,10 @@
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/** DNS timer period */
#define DNS_TMR_INTERVAL 1000
@ -111,6 +115,10 @@ int dns_local_removehost(const char *hostname, const ip_addr_t *addr)
err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS */
#endif /* __LWIP_DNS_H__ */

View file

@ -57,20 +57,19 @@ typedef s8_t err_t;
#define ERR_INPROGRESS -5 /* Operation in progress */
#define ERR_VAL -6 /* Illegal value. */
#define ERR_WOULDBLOCK -7 /* Operation would block. */
#define ERR_USE -8 /* Address in use. */
#define ERR_ISCONN -9 /* Already connected. */
#define ERR_IS_FATAL(e) ((e) < ERR_VAL)
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
#define ERR_ABRT -8 /* Connection aborted. */
#define ERR_RST -9 /* Connection reset. */
#define ERR_CLSD -10 /* Connection closed. */
#define ERR_CONN -11 /* Not connected. */
#define ERR_ABRT -10 /* Connection aborted. */
#define ERR_RST -11 /* Connection reset. */
#define ERR_CLSD -12 /* Connection closed. */
#define ERR_CONN -13 /* Not connected. */
#define ERR_ARG -12 /* Illegal argument. */
#define ERR_ARG -14 /* Illegal argument. */
#define ERR_USE -13 /* Address in use. */
#define ERR_IF -14 /* Low-level netif error */
#define ERR_ISCONN -15 /* Already connected. */
#define ERR_IF -15 /* Low-level netif error */
#ifdef LWIP_DEBUG

View file

@ -1,6 +0,0 @@
#ifndef __MINIX_ICMP_H__
#define __MINIX_ICMP_H__
#include "ipv4/lwip/icmp.h"
#endif /* __MINIX_ICMP_H__ */

View file

@ -1,6 +0,0 @@
#ifndef __MINIX_IGMP_H__
#define __MINIX_IGMP_H__
#include "ipv4/lwip/igmp.h"
#endif /* __MINIX_IGMP_H__ */

View file

@ -1,6 +0,0 @@
#ifndef __MINIX_INET_H__
#define __MINIX_INET_H__
#include "ipv4/lwip/inet.h"
#endif /* __MINIX_INET_H__ */

View file

@ -1,6 +1,112 @@
#ifndef __MINIX_INET_CHKSUM_H__
#define __MINIX_INET_CHKSUM_H__
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_CHKSUM_H__
#define __LWIP_INET_CHKSUM_H__
#include "ipv4/lwip/inet_chksum.h"
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/** Swap the bytes in an u16_t: much like htons() for little-endian */
#ifndef SWAP_BYTES_IN_WORD
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
#endif /* SWAP_BYTES_IN_WORD */
/** Split an u32_t in two u16_ts and add them up */
#ifndef FOLD_U32T
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#endif
#if LWIP_CHECKSUM_ON_COPY
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
as u16_t */
#ifndef LWIP_CHKSUM_COPY
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
#define LWIP_CHKSUM_COPY_ALGORITHM 1
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#endif /* LWIP_CHKSUM_COPY */
#else /* LWIP_CHECKSUM_ON_COPY */
#define LWIP_CHKSUM_COPY_ALGORITHM 0
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
extern "C" {
#endif
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip_addr_t *src, ip_addr_t *dest);
u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto,
u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest);
#if LWIP_CHKSUM_COPY_ALGORITHM
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#if LWIP_IPV6
u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip6_addr_t *src, ip6_addr_t *dest);
u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest);
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
((isipv6) ? \
ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest)))
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
((isipv6) ? \
ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest)))
#else /* LWIP_IPV6 */
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
inet_chksum_pseudo(p, proto, proto_len, src, dest)
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */
#endif /* __MINIX_INET_CHKSUM_H__ */

View file

@ -43,11 +43,11 @@ extern "C" {
/** x.X.x: Minor version of the stack */
#define LWIP_VERSION_MINOR 4U
/** x.x.X: Revision of the stack */
#define LWIP_VERSION_REVISION 0U
#define LWIP_VERSION_REVISION 1U
/** For release candidates, this is set to 1..254
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
#define LWIP_VERSION_RC 1U
#define LWIP_VERSION_RC 0U
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
#define LWIP_RC_RELEASE 255U

View file

@ -1,6 +1,254 @@
#ifndef __MINIX_IP_H__
#define __MINIX_IP_H__
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#include "lwip/ip4.h"
#include "lwip/ip6.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
#if LWIP_IPV6
#define IP_PCB_ISIPV6_MEMBER u8_t isipv6;
#define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6)
#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \
((pcb)->isipv6 != 0) : \
((pcb)->isipv6 == 0))
#define PCB_ISIPV6(pcb) ((pcb)->isipv6)
#else
#define IP_PCB_ISIPV6_MEMBER
#define IP_PCB_IPVER_EQ(pcb1, pcb2) 1
#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1
#define PCB_ISIPV6(pcb) 0
#endif /* LWIP_IPV6 */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
IP_PCB_ISIPV6_MEMBER \
/* ip addresses in network byte order */ \
ipX_addr_t local_ip; \
ipX_addr_t remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
/*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */
#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */
#define SOF_REUSEADDR 0x04U /* allow local address reuse */
#define SOF_KEEPALIVE 0x08U /* keep connections alive */
/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */
#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */
#define SOF_LINGER 0x80U /* linger on close if data present */
/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */
/*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
/* Global variables of this module, kept in a struct for efficient access using base+index. */
struct ip_globals
{
/** The interface that provided the packet for the current callback invocation. */
struct netif *current_netif;
/** Header of the input packet currently being processed. */
const struct ip_hdr *current_ip4_header;
#if LWIP_IPV6
/** Header of the input IPv6 packet currently being processed. */
const struct ip6_hdr *current_ip6_header;
#endif /* LWIP_IPV6 */
/** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */
u16_t current_ip_header_tot_len;
/** Source IP address of current_header */
ipX_addr_t current_iphdr_src;
/** Destination IP address of current_header */
ipX_addr_t current_iphdr_dest;
};
extern struct ip_globals ip_data;
/** Get the interface that received the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_netif() (ip_data.current_netif)
/** Get the IP header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_header() (ip_data.current_ip4_header)
/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */
#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len)
/** Source IP address of current_header */
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
/** Destination IP address of current_header */
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
#if LWIP_IPV6
/** Get the IPv6 header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip6_current_header() (ip_data.current_ip6_header)
/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */
#define ip_current_is_v6() (ip6_current_header() != NULL)
/** Source IPv6 address of current_header */
#define ip6_current_src_addr() (ipX_2_ip6(&ip_data.current_iphdr_src))
/** Destination IPv6 address of current_header */
#define ip6_current_dest_addr() (ipX_2_ip6(&ip_data.current_iphdr_dest))
/** Get the transport layer protocol */
#define ip_current_header_proto() (ip_current_is_v6() ? \
IP6H_NEXTH(ip6_current_header()) :\
IPH_PROTO(ip_current_header()))
/** Get the transport layer header */
#define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \
(u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len()))
/** Set an IP_PCB to IPv6 (IPv4 is the default) */
#define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0)
/** Source IP4 address of current_header */
#define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src))
/** Destination IP4 address of current_header */
#define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest))
#else /* LWIP_IPV6 */
/** Always returns FALSE when only supporting IPv4 */
#define ip_current_is_v6() 0
/** Get the transport layer protocol */
#define ip_current_header_proto() IPH_PROTO(ip_current_header())
/** Get the transport layer header */
#define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len()))
/** Source IP4 address of current_header */
#define ip_current_src_addr() (&ip_data.current_iphdr_src)
/** Destination IP4 address of current_header */
#define ip_current_dest_addr() (&ip_data.current_iphdr_dest)
#endif /* LWIP_IPV6 */
/** Union source address of current_header */
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
/** Union destination address of current_header */
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
/** Gets an IP pcb option (SOF_* flags) */
#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt))
/** Sets an IP pcb option (SOF_* flags) */
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
/** Resets an IP pcb option (SOF_* flags) */
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#if LWIP_IPV6
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
((isipv6) ? \
ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \
ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto))
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
((isipv6) ? \
ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \
ip_output_if(p, (src), (dest), ttl, tos, proto, netif))
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
((isipv6) ? \
ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \
ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint))
#define ipX_route(isipv6, src, dest) \
((isipv6) ? \
ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \
ip_route(ipX_2_ip(dest)))
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
((isipv6) ? \
ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \
ip_netif_get_local_ipX(netif))
#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p))
#else /* LWIP_IPV6 */
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
ip_output(p, src, dest, ttl, tos, proto)
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
ip_output_if(p, src, dest, ttl, tos, proto, netif)
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
#define ipX_route(isipv6, src, dest) \
ip_route(ipX_2_ip(dest))
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
ip_netif_get_local_ipX(netif)
#define ipX_debug_print(is_ipv6, p) ip_debug_print(p)
#endif /* LWIP_IPV6 */
#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \
(netif) = ipX_route(isipv6, src, dest); \
(ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \
}while(0)
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_H__ */
#include "ipv4/lwip/ip.h"
#endif /* __MINIX_IP_H__ */

View file

@ -1,6 +1,130 @@
#ifndef __MINIX_IPADDR_H__
#define __MINIX_IPADDR_H__
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "ipv4/lwip/ip_addr.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#endif /* __MINIX_IPADDR_H__ */
#include "lwip/ip4_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6
/* A union struct for both IP version's addresses. */
typedef union {
ip_addr_t ip4;
ip6_addr_t ip6;
} ipX_addr_t;
/** These functions only exist for type-safe conversion from ip_addr_t to
ip6_addr_t and back */
#ifdef LWIP_ALLOW_STATIC_FN_IN_HEADER
static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr)
{ return (ip6_addr_t*)ipaddr;}
static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr)
{ return (ip_addr_t*)ip6addr; }
static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr)
{ return (ipX_addr_t*)ipaddr; }
static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr)
{ return (ipX_addr_t*)ip6addr; }
#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */
#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr))
#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr))
#define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr)
#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr)
#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/
#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6))
#define ipX_2_ip(ipaddr) (&((ipaddr)->ip4))
#define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_copy((dest).ip6, (src).ip6); }else{ \
ip_addr_copy((dest).ip4, (src).ip4); }}while(0)
#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \
ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0)
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \
ip_addr_set(ipX_2_ip(dest), src); }}while(0)
#define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \
ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0)
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \
ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \
ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2)))
#define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \
ip6_addr_isany(ipX_2_ip6(ipaddr)) : \
ip_addr_isany(ipX_2_ip(ipaddr)))
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \
ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \
ip_addr_ismulticast(ipX_2_ip(ipaddr)))
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \
ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \
ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0)
#else /* LWIP_IPV6 */
typedef ip_addr_t ipX_addr_t;
#define ipX_2_ip(ipaddr) (ipaddr)
#define ip_2_ipX(ipaddr) (ipaddr)
#define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src)
#define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src)
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src)
#define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr)
#define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr)
#define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr)
#define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src)
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2)
#define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr)
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr)
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View file

@ -1,6 +0,0 @@
#ifndef __MINIX_FRAG_IP_FRAG_H__
#define __MINIX_FRAG_IP_FRAG_H__
#include "ipv4/lwip/ip_frag.h"
#endif /* __MINIX_FRAG_IP_FRAG_H__ */

View file

@ -44,6 +44,7 @@ extern "C" {
#include <stdlib.h>
typedef size_t mem_size_t;
#define MEM_SIZE_F SZT_F
/* aliases for C library malloc() */
#define mem_init()
@ -69,7 +70,7 @@ typedef size_t mem_size_t;
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
* 65535 leaves some room for alignment...
*/
#if MEM_SIZE > 64000l
#if MEM_SIZE > 64000L
typedef u32_t mem_size_t;
#define MEM_SIZE_F U32_F
#else

View file

@ -47,7 +47,7 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg),
#if IP_REASSEMBLY
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
#endif /* IP_REASSEMBLY */
#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPV6_FRAG
LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
@ -63,9 +63,9 @@ LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#endif /* NO_SYS==0 */
#if ARP_QUEUEING
#if LWIP_ARP && ARP_QUEUEING
LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
#endif /* ARP_QUEUEING */
#endif /* LWIP_ARP && ARP_QUEUEING */
#if LWIP_IGMP
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
@ -91,6 +91,19 @@ LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE,
LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
#if LWIP_IPV6 && LWIP_ND6_QUEUEING
LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE")
#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */
#if LWIP_IPV6 && LWIP_IPV6_REASS
LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA")
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_MLD
LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP")
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/*
* A list of pools of pbuf's used by LWIP.
*

View file

@ -35,6 +35,7 @@
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -47,7 +48,7 @@ extern "C" {
struct netbuf {
struct pbuf *p, *ptr;
ip_addr_t addr;
ipX_addr_t addr;
u16_t port;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
@ -55,7 +56,7 @@ struct netbuf {
#endif /* LWIP_CHECKSUM_ON_COPY */
u16_t toport_chksum;
#if LWIP_NETBUF_RECVINFO
ip_addr_t toaddr;
ipX_addr_t toaddr;
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
};
@ -81,12 +82,12 @@ void netbuf_first (struct netbuf *buf);
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
#define netbuf_len(buf) ((buf)->p->tot_len)
#define netbuf_fromaddr(buf) (&((buf)->addr))
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr)
#define netbuf_fromaddr(buf) (ipX_2_ip(&((buf)->addr)))
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr)
#define netbuf_fromport(buf) ((buf)->port)
#if LWIP_NETBUF_RECVINFO
#define netbuf_destaddr(buf) (&((buf)->toaddr))
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr)
#define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr)))
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr)
#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
#endif /* LWIP_NETBUF_RECVINFO */
#if LWIP_CHECKSUM_ON_COPY
@ -94,6 +95,16 @@ void netbuf_first (struct netbuf *buf);
(buf)->toport_chksum = chksum; } while(0)
#endif /* LWIP_CHECKSUM_ON_COPY */
#if LWIP_IPV6
#define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr)))
#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr)
#define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr)))
#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr)
#endif /* LWIP_IPV6 */
#define netbuf_fromaddr_ipX(buf) (&((buf)->addr))
#define netbuf_destaddr_ipX(buf) (&((buf)->toaddr))
#ifdef __cplusplus
}
#endif

View file

@ -38,6 +38,10 @@
#include "lwip/inet.h"
#include "lwip/sockets.h"
#ifdef __cplusplus
extern "C" {
#endif
/* some rarely used options */
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
#define LWIP_DNS_API_DECLARE_H_ERRNO 1
@ -111,6 +115,10 @@ int lwip_getaddrinfo(const char *nodename,
lwip_getaddrinfo(nodname, servname, hints, res)
#endif /* LWIP_COMPAT_SOCKETS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS && LWIP_SOCKET */
#endif /* __LWIP_NETDB_H__ */

View file

@ -39,6 +39,7 @@
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
@ -48,6 +49,9 @@ struct dhcp;
#if LWIP_AUTOIP
struct autoip;
#endif
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#ifdef __cplusplus
extern "C" {
@ -117,6 +121,18 @@ typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
*/
typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr);
#if LWIP_IPV6
/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet
* shall be sent. For ethernet netif, set this to 'nd_output' and set
* 'linkoutput'.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (p->payload points to IP header)
* @param ipaddr The IPv6 address to which the packet shall be sent
*/
typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p,
ip6_addr_t *ipaddr);
#endif /* LWIP_IPV6 */
/** Function prototype for netif->linkoutput functions. Only used for ethernet
* netifs. This function is called by ARP when a packet shall be sent.
*
@ -129,6 +145,11 @@ typedef void (*netif_status_callback_fn)(struct netif *netif);
/** Function prototype for netif igmp_mac_filter functions */
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
ip_addr_t *group, u8_t action);
#if LWIP_IPV6 && LWIP_IPV6_MLD
/** Function prototype for netif mld_mac_filter functions */
typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif,
ip6_addr_t *group, u8_t action);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
@ -142,6 +163,13 @@ struct netif {
ip_addr_t netmask;
ip_addr_t gw;
#if LWIP_IPV6
/** Array of IPv6 addresses for this netif. */
ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
/** The state of each IPv6 address (Tentative, Preferred, etc).
* @see ip6_addr.h */
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6 */
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
netif_input_fn input;
@ -153,6 +181,12 @@ struct netif {
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
netif_linkoutput_fn linkoutput;
#if LWIP_IPV6
/** This function is called by the IPv6 module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
netif_output_ip6_fn output_ip6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
/** This function is called when the netif state is set to up or down
*/
@ -163,6 +197,10 @@ struct netif {
*/
netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
/** This function is called when the netif has been removed */
netif_status_callback_fn remove_callback;
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
/** This field can be set by the device driver and could point
* to state information for the device. */
void *state;
@ -174,6 +212,18 @@ struct netif {
/** the AutoIP client state information for this netif */
struct autoip *autoip;
#endif
#if LWIP_IPV6_AUTOCONFIG
/** is this netif enabled for IPv6 autoconfiguration */
u8_t ip6_autoconfig_enabled;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
/** Number of Router Solicitation messages that remain to be sent. */
u8_t rs_count;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/** the DHCPv6 client state information for this netif */
struct dhcp6 *dhcp6;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_HOSTNAME
/* the hostname for this netif, NULL is a valid value */
char* hostname;
@ -208,10 +258,15 @@ struct netif {
u32_t ifoutdiscards;
#endif /* LWIP_SNMP */
#if LWIP_IGMP
/** This function could be called to add or delete a entry in the multicast
/** This function could be called to add or delete an entry in the multicast
filter table of the ethernet MAC.*/
netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/** This function could be called to add or delete an entry in the IPv6 multicast
filter table of the ethernet MAC. */
netif_mld_mac_filter_fn mld_mac_filter;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_NETIF_HWADDRHINT
u8_t *addr_hint;
#endif /* LWIP_NETIF_HWADDRHINT */
@ -280,6 +335,9 @@ void netif_set_down(struct netif *netif);
#if LWIP_NETIF_STATUS_CALLBACK
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback);
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
void netif_set_link_up(struct netif *netif);
void netif_set_link_down(struct netif *netif);
@ -308,6 +366,20 @@ void netif_poll_all(void);
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_IPV6
#define netif_ip6_addr(netif, i) (&((netif)->ip6_addr[(i)]))
#define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[(i)])
#define netif_ip6_addr_set_state(netif, i, state) ((netif)->ip6_addr_state[(i)] = (state))
s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr);
void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit);
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_HWADDRHINT
#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint))
#else /* LWIP_NETIF_HWADDRHINT */
#define NETIF_SET_HWADDRHINT(netif, hint)
#endif /* LWIP_NETIF_HWADDRHINT */
#ifdef __cplusplus
}
#endif

View file

@ -309,9 +309,11 @@
/**
* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.
* (requires NO_SYS==0)
* The default number of timeouts is calculated here for all enabled modules.
* The formula expects settings to be either '0' or '1'.
*/
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT 3
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))
#endif
/**
@ -432,11 +434,14 @@
#endif
/**
* ARP_QUEUEING==1: Outgoing packets are queued during hardware address
* resolution.
* ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
* resolution. By default, only the most recent packet is queued per IP address.
* This is sufficient for most protocols and mainly reduces TCP connection
* startup time. Set this to 1 if you know your application sends more than one
* packet in a row to an IP address that is not in the ARP cache.
*/
#ifndef ARP_QUEUEING
#define ARP_QUEUEING 1
#define ARP_QUEUEING 0
#endif
/**
@ -458,6 +463,8 @@
* Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
* If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
* If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
* Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan)
* that returns 1 to accept a packet or 0 to drop a packet.
*/
#ifndef ETHARP_SUPPORT_VLAN
#define ETHARP_SUPPORT_VLAN 0
@ -590,6 +597,26 @@
#define IP_SOF_BROADCAST_RECV 0
#endif
/**
* IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back
* out on the netif where it was received. This should only be used for
* wireless networks.
* ATTENTION: When this is 1, make sure your netif driver correctly marks incoming
* link-layer-broadcast/multicast packets as such using the corresponding pbuf flags!
*/
#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF
#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0
#endif
/**
* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first
* local TCP/UDP pcb (default==0). This can prevent creating predictable port
* numbers after booting a device.
*/
#ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS
#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0
#endif
/*
----------------------------------
---------- ICMP options ----------
@ -943,10 +970,11 @@
/**
* TCP_SND_BUF: TCP sender buffer space (bytes).
* TCP_SND_BUF: TCP sender buffer space (bytes).
* To achieve good performance, this should be at least 2 * TCP_MSS.
*/
#ifndef TCP_SND_BUF
#define TCP_SND_BUF 256
#define TCP_SND_BUF (2 * TCP_MSS)
#endif
/**
@ -954,7 +982,7 @@
* as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
*/
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF)/(TCP_MSS))
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
#endif
/**
@ -963,16 +991,32 @@
* TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).
*/
#ifndef TCP_SNDLOWAT
#define TCP_SNDLOWAT ((TCP_SND_BUF)/2)
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
#endif
/**
* TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater
* TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less
* than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below
* this number, select returns writable (combined with TCP_SNDLOWAT).
*/
#ifndef TCP_SNDQUEUELOWAT
#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2)
#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5)
#endif
/**
* TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb.
* Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
*/
#ifndef TCP_OOSEQ_MAX_BYTES
#define TCP_OOSEQ_MAX_BYTES 0
#endif
/**
* TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb.
* Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
*/
#ifndef TCP_OOSEQ_MAX_PBUFS
#define TCP_OOSEQ_MAX_PBUFS 0
#endif
/**
@ -1029,14 +1073,11 @@
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
* events (accept, sent, etc) that happen in the system.
* LWIP_CALLBACK_API==1: The PCB callback function is called directly
* for the event.
* for the event. This is the default.
*/
#ifndef LWIP_EVENT_API
#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API)
#define LWIP_EVENT_API 0
#define LWIP_CALLBACK_API 1
#else
#define LWIP_EVENT_API 1
#define LWIP_CALLBACK_API 0
#endif
@ -1099,6 +1140,14 @@
#define LWIP_NETIF_LINK_CALLBACK 0
#endif
/**
* LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called
* when a netif has been removed
*/
#ifndef LWIP_NETIF_REMOVE_CALLBACK
#define LWIP_NETIF_REMOVE_CALLBACK 0
#endif
/**
* LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table
* indices) in struct netif. TCP and UDP can make use of this to prevent
@ -1404,7 +1453,16 @@
#endif
/**
* LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
* SO_SNDTIMEO processing.
*/
#ifndef LWIP_SO_SNDTIMEO
#define LWIP_SO_SNDTIMEO 0
#endif
/**
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
* SO_RCVTIMEO processing.
*/
#ifndef LWIP_SO_RCVTIMEO
#define LWIP_SO_RCVTIMEO 0
@ -1440,6 +1498,18 @@
#define SO_REUSE_RXTOALL 0
#endif
/**
* LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of
* pending data in the network buffer. This is the way windows does it. It's
* the default for lwIP since it is smaller.
* LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next
* pending datagram in bytes. This is the way linux does it. This code is only
* here for compatibility.
*/
#ifndef LWIP_FIONREAD_LINUXMODE
#define LWIP_FIONREAD_LINUXMODE 0
#endif
/*
----------------------------------------
---------- Statistics options ----------
@ -1541,6 +1611,41 @@
#define SYS_STATS (NO_SYS == 0)
#endif
/**
* IP6_STATS==1: Enable IPv6 stats.
*/
#ifndef IP6_STATS
#define IP6_STATS (LWIP_IPV6)
#endif
/**
* ICMP6_STATS==1: Enable ICMP for IPv6 stats.
*/
#ifndef ICMP6_STATS
#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6)
#endif
/**
* IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats.
*/
#ifndef IP6_FRAG_STATS
#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS))
#endif
/**
* MLD6_STATS==1: Enable MLD for IPv6 stats.
*/
#ifndef MLD6_STATS
#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD)
#endif
/**
* ND6_STATS==1: Enable Neighbor discovery for IPv6 stats.
*/
#ifndef ND6_STATS
#define ND6_STATS (LWIP_IPV6)
#endif
#else
#define LINK_STATS 0
@ -1554,6 +1659,11 @@
#define MEMP_STATS 0
#define SYS_STATS 0
#define LWIP_STATS_DISPLAY 0
#define IP6_STATS 0
#define ICMP6_STATS 0
#define IP6_FRAG_STATS 0
#define MLD6_STATS 0
#define ND6_STATS 0
#endif /* LWIP_STATS */
@ -1746,6 +1856,13 @@
#ifndef CHECKSUM_GEN_TCP
#define CHECKSUM_GEN_TCP 1
#endif
/**
* CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets.
*/
#ifndef CHECKSUM_GEN_ICMP
#define CHECKSUM_GEN_ICMP 1
#endif
/**
* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.
@ -1776,6 +1893,259 @@
#define LWIP_CHECKSUM_ON_COPY 0
#endif
/*
---------------------------------------
---------- IPv6 options ---------------
---------------------------------------
*/
/**
* LWIP_IPV6==1: Enable IPv6
*/
#ifndef LWIP_IPV6
#define LWIP_IPV6 0
#endif
/**
* LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif.
*/
#ifndef LWIP_IPV6_NUM_ADDRESSES
#define LWIP_IPV6_NUM_ADDRESSES 3
#endif
/**
* LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs
*/
#ifndef LWIP_IPV6_FORWARD
#define LWIP_IPV6_FORWARD 0
#endif
/**
* LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC)
*/
#ifndef LWIP_ICMP6
#define LWIP_ICMP6 (LWIP_IPV6)
#endif
/**
* LWIP_ICMP6_DATASIZE: bytes from original packet to send back in
* ICMPv6 error messages.
*/
#ifndef LWIP_ICMP6_DATASIZE
#define LWIP_ICMP6_DATASIZE 8
#endif
/**
* LWIP_ICMP6_HL: default hop limit for ICMPv6 messages
*/
#ifndef LWIP_ICMP6_HL
#define LWIP_ICMP6_HL 255
#endif
/**
* LWIP_ICMP6_CHECKSUM_CHECK==1: verify checksum on ICMPv6 packets
*/
#ifndef LWIP_ICMP6_CHECKSUM_CHECK
#define LWIP_ICMP6_CHECKSUM_CHECK 1
#endif
/**
* LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol.
*/
#ifndef LWIP_IPV6_MLD
#define LWIP_IPV6_MLD (LWIP_IPV6)
#endif
/**
* MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined.
*/
#ifndef MEMP_NUM_MLD6_GROUP
#define MEMP_NUM_MLD6_GROUP 4
#endif
/**
* LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big.
*/
#ifndef LWIP_IPV6_FRAG
#define LWIP_IPV6_FRAG 0
#endif
/**
* LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented
*/
#ifndef LWIP_IPV6_REASS
#define LWIP_IPV6_REASS (LWIP_IPV6)
#endif
/**
* LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address
* is being resolved.
*/
#ifndef LWIP_ND6_QUEUEING
#define LWIP_ND6_QUEUEING (LWIP_IPV6)
#endif
/**
* MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution.
*/
#ifndef MEMP_NUM_ND6_QUEUE
#define MEMP_NUM_ND6_QUEUE 20
#endif
/**
* LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache
*/
#ifndef LWIP_ND6_NUM_NEIGHBORS
#define LWIP_ND6_NUM_NEIGHBORS 10
#endif
/**
* LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache
*/
#ifndef LWIP_ND6_NUM_DESTINATIONS
#define LWIP_ND6_NUM_DESTINATIONS 10
#endif
/**
* LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache
*/
#ifndef LWIP_ND6_NUM_PREFIXES
#define LWIP_ND6_NUM_PREFIXES 5
#endif
/**
* LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache
*/
#ifndef LWIP_ND6_NUM_ROUTERS
#define LWIP_ND6_NUM_ROUTERS 3
#endif
/**
* LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send
* (neighbor solicit and router solicit)
*/
#ifndef LWIP_ND6_MAX_MULTICAST_SOLICIT
#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3
#endif
/**
* LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages
* to send during neighbor reachability detection.
*/
#ifndef LWIP_ND6_MAX_UNICAST_SOLICIT
#define LWIP_ND6_MAX_UNICAST_SOLICIT 3
#endif
/**
* Unused: See ND RFC (time in milliseconds).
*/
#ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME
#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000
#endif
/**
* Unused: See ND RFC
*/
#ifndef LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT
#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3
#endif
/**
* LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds).
* May be updated by router advertisement messages.
*/
#ifndef LWIP_ND6_REACHABLE_TIME
#define LWIP_ND6_REACHABLE_TIME 30000
#endif
/**
* LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages
*/
#ifndef LWIP_ND6_RETRANS_TIMER
#define LWIP_ND6_RETRANS_TIMER 1000
#endif
/**
* LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation
* message is sent, during neighbor reachability detection.
*/
#ifndef LWIP_ND6_DELAY_FIRST_PROBE_TIME
#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000
#endif
/**
* LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update
* Reachable time and retransmission timers, and netif MTU.
*/
#ifndef LWIP_ND6_ALLOW_RA_UPDATES
#define LWIP_ND6_ALLOW_RA_UPDATES 1
#endif
/**
* LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during
* network startup.
*/
#ifndef LWIP_IPV6_SEND_ROUTER_SOLICIT
#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1
#endif
/**
* LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery
* with reachability hints for connected destinations. This helps avoid sending
* unicast neighbor solicitation messages.
*/
#ifndef LWIP_ND6_TCP_REACHABILITY_HINTS
#define LWIP_ND6_TCP_REACHABILITY_HINTS 1
#endif
/**
* LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862.
*/
#ifndef LWIP_IPV6_AUTOCONFIG
#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6)
#endif
/**
* LWIP_IPV6_DUP_DETECT_ATTEMPTS: Number of duplicate address detection attempts.
*/
#ifndef LWIP_IPV6_DUP_DETECT_ATTEMPTS
#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1
#endif
/**
* LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration.
*/
#ifndef LWIP_IPV6_DHCP6
#define LWIP_IPV6_DHCP6 0
#endif
/*
---------------------------------------
---------- Hook options ---------------
---------------------------------------
*/
/* Hooks are undefined by default, define them to a function if you need them. */
/**
* LWIP_HOOK_IP4_INPUT(pbuf, input_netif):
* - called from ip_input() (IPv4)
* - pbuf: received struct pbuf passed to ip_input()
* - input_netif: struct netif on which the packet has been received
* Return values:
* - 0: Hook has not consumed the packet, packet is processed as normal
* - != 0: Hook has consumed the packet.
* If the hook consumed the packet, 'pbuf' is in the responsibility of the hook
* (i.e. free it when done).
*/
/**
* LWIP_HOOK_IP4_ROUTE(dest):
* - called from ip_route() (IPv4)
* - dest: destination IPv4 address
* Returns the destination netif or NULL if no destination netif is found. In
* that case, ip_route() continues as normal.
*/
/*
---------------------------------------
---------- Debugging options ----------
@ -2037,4 +2407,11 @@
#define DNS_DEBUG LWIP_DBG_OFF
#endif
/**
* IP6_DEBUG: Enable debugging for IPv6.
*/
#ifndef IP6_DEBUG
#define IP6_DEBUG LWIP_DBG_OFF
#endif
#endif /* __LWIP_OPT_H__ */

View file

@ -44,8 +44,15 @@ extern "C" {
* of IP_FRAG */
#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
/* @todo: We need a mechanism to prevent wasting memory in every pbuf
(TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */
#define PBUF_TRANSPORT_HLEN 20
#if LWIP_IPV6
#define PBUF_IP_HLEN 40
#else
#define PBUF_IP_HLEN 20
#endif
typedef enum {
PBUF_TRANSPORT,
@ -69,6 +76,12 @@ typedef enum {
#define PBUF_FLAG_IS_CUSTOM 0x02U
/** indicates this pbuf is UDP multicast to be looped back */
#define PBUF_FLAG_MCASTLOOP 0x04U
/** indicates this pbuf was received as link-level broadcast */
#define PBUF_FLAG_LLBCAST 0x08U
/** indicates this pbuf was received as link-level multicast */
#define PBUF_FLAG_LLMCAST 0x10U
/** indicates this pbuf includes a TCP FIN flag */
#define PBUF_FLAG_TCP_FIN 0x20U
struct pbuf {
/** next pbuf in singly linked pbuf chain */
@ -116,6 +129,24 @@ struct pbuf_custom {
};
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
#if LWIP_TCP && TCP_QUEUE_OOSEQ
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
#ifndef PBUF_POOL_FREE_OOSEQ
#define PBUF_POOL_FREE_OOSEQ 1
#endif /* PBUF_POOL_FREE_OOSEQ */
#if NO_SYS && PBUF_POOL_FREE_OOSEQ
extern volatile u8_t pbuf_free_ooseq_pending;
void pbuf_free_ooseq();
/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
at regular intervals from main level to check if ooseq pbufs need to be
freed! */
#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \
/* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \
ooseq queued pbufs now */ \
pbuf_free_ooseq(); }}while(0)
#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
#define pbuf_init()

View file

@ -40,6 +40,7 @@
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -60,6 +61,27 @@ struct raw_pcb;
typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ip_addr_t *addr);
#if LWIP_IPV6
/** Function prototype for raw pcb IPv6 receive callback functions.
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IPv6 address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ip6_addr_t *addr);
#endif /* LWIP_IPV6 */
#if LWIP_IPV6
#define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6;
#else
#define RAW_PCB_RECV_IP6
#endif /* LWIP_IPV6 */
struct raw_pcb {
/* Common members of all PCB types */
IP_PCB;
@ -69,7 +91,10 @@ struct raw_pcb {
u8_t protocol;
/** receive callback function */
raw_recv_fn recv;
union {
raw_recv_fn ip4;
RAW_PCB_RECV_IP6
} recv;
/* user-supplied argument for the recv callback */
void *recv_arg;
};
@ -85,6 +110,14 @@ void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *re
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
#if LWIP_IPV6
struct raw_pcb * raw_new_ip6 (u8_t proto);
#define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr))
#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr))
#define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg)
#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr))
#endif /* LWIP_IPV6 */
/* The following functions are the lower layer interface to RAW. */
u8_t raw_input (struct pbuf *p, struct netif *inp);
#define raw_init() /* Compatibility define, not init needed. */

View file

@ -42,6 +42,7 @@
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/inet6.h"
#ifdef __cplusplus
extern "C" {
@ -53,17 +54,34 @@ struct sockaddr_in {
u8_t sin_family;
u16_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
#define SIN_ZERO_LEN 8
char sin_zero[SIN_ZERO_LEN];
};
#if LWIP_IPV6
struct sockaddr_in6 {
u8_t sin6_len; /* length of this structure */
u8_t sin6_family; /* AF_INET6 */
u16_t sin6_port; /* Transport layer port # */
u32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
};
#endif /* LWIP_IPV6 */
struct sockaddr {
u8_t sa_len;
u8_t sa_family;
u16_t sa_data[14];
#if LWIP_IPV6
u8_t sa_data[22];
#else /* LWIP_IPV6 */
u8_t sa_data[14];
#endif /* LWIP_IPV6 */
};
#ifndef socklen_t
# define socklen_t u32_t
/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
to prevent this code from redefining it. */
#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
typedef u32_t socklen_t;
#endif
/* Socket protocol types (TCP/UDP/RAW) */
@ -118,12 +136,21 @@ struct linger {
#define AF_UNSPEC 0
#define AF_INET 2
#if LWIP_IPV6
#define AF_INET6 10
#else /* LWIP_IPV6 */
#define AF_INET6 AF_UNSPEC
#endif /* LWIP_IPV6 */
#define PF_INET AF_INET
#define PF_INET6 AF_INET6
#define PF_UNSPEC AF_UNSPEC
#define IPPROTO_IP 0
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#if LWIP_IPV6
#define IPPROTO_IPV6 41
#endif /* LWIP_IPV6 */
#define IPPROTO_UDPLITE 136
/* Flags we can use with send and recv. */
@ -151,6 +178,13 @@ struct linger {
#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */
#endif /* LWIP_TCP */
#if LWIP_IPV6
/*
* Options for level IPPROTO_IPV6
*/
#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */
#endif /* LWIP_IPV6 */
#if LWIP_UDP && LWIP_UDPLITE
/*
* Options for level IPPROTO_UDPLITE
@ -280,9 +314,9 @@ typedef struct ip_mreq {
#endif
#ifndef SHUT_RD
#define SHUT_RD 1
#define SHUT_WR 2
#define SHUT_RDWR 3
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#endif
/* FD_SET used for lwip_select */
@ -363,6 +397,7 @@ int lwip_fcntl(int s, int cmd, int val);
#define read(a,b,c) lwip_read(a,b,c)
#define write(a,b,c) lwip_write(a,b,c)
#define close(s) lwip_close(s)
#define fcntl(a,b,c) lwip_fcntl(a,b,c)
#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */
#endif /* LWIP_COMPAT_SOCKETS */

View file

@ -144,6 +144,21 @@ struct stats_ {
#if SYS_STATS
struct stats_sys sys;
#endif
#if IP6_STATS
struct stats_proto ip6;
#endif
#if ICMP6_STATS
struct stats_proto icmp6;
#endif
#if IP6_FRAG_STATS
struct stats_proto ip6_frag;
#endif
#if MLD6_STATS
struct stats_igmp mld6;
#endif
#if ND6_STATS
struct stats_proto nd6;
#endif
};
extern struct stats_ lwip_stats;
@ -190,7 +205,7 @@ void stats_init(void);
#if IGMP_STATS
#define IGMP_STATS_INC(x) STATS_INC(x)
#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP")
#else
#define IGMP_STATS_INC(x)
#define IGMP_STATS_DISPLAY()
@ -268,18 +283,58 @@ void stats_init(void);
#define SYS_STATS_DISPLAY()
#endif
#if IP6_STATS
#define IP6_STATS_INC(x) STATS_INC(x)
#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6")
#else
#define IP6_STATS_INC(x)
#define IP6_STATS_DISPLAY()
#endif
#if ICMP6_STATS
#define ICMP6_STATS_INC(x) STATS_INC(x)
#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6")
#else
#define ICMP6_STATS_INC(x)
#define ICMP6_STATS_DISPLAY()
#endif
#if IP6_FRAG_STATS
#define IP6_FRAG_STATS_INC(x) STATS_INC(x)
#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG")
#else
#define IP6_FRAG_STATS_INC(x)
#define IP6_FRAG_STATS_DISPLAY()
#endif
#if MLD6_STATS
#define MLD6_STATS_INC(x) STATS_INC(x)
#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1")
#else
#define MLD6_STATS_INC(x)
#define MLD6_STATS_DISPLAY()
#endif
#if ND6_STATS
#define ND6_STATS_INC(x) STATS_INC(x)
#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND")
#else
#define ND6_STATS_INC(x)
#define ND6_STATS_DISPLAY()
#endif
/* Display of statistics */
#if LWIP_STATS_DISPLAY
void stats_display(void);
void stats_display_proto(struct stats_proto *proto, char *name);
void stats_display_igmp(struct stats_igmp *igmp);
void stats_display_mem(struct stats_mem *mem, char *name);
void stats_display_proto(struct stats_proto *proto, const char *name);
void stats_display_igmp(struct stats_igmp *igmp, const char *name);
void stats_display_mem(struct stats_mem *mem, const char *name);
void stats_display_memp(struct stats_mem *mem, int index);
void stats_display_sys(struct stats_sys *sys);
#else /* LWIP_STATS_DISPLAY */
#define stats_display()
#define stats_display_proto(proto, name)
#define stats_display_igmp(igmp)
#define stats_display_igmp(igmp, name)
#define stats_display_mem(mem, name)
#define stats_display_memp(mem, index)
#define stats_display_sys(sys)

View file

@ -51,16 +51,22 @@ typedef u8_t sys_mbox_t;
#define sys_sem_wait(s)
#define sys_arch_sem_wait(s,t)
#define sys_sem_free(s)
#define sys_sem_valid(s) 0
#define sys_sem_set_invalid(s)
#define sys_mutex_new(mu) ERR_OK
#define sys_mutex_lock(mu)
#define sys_mutex_unlock(mu)
#define sys_mutex_free(mu)
#define sys_mutex_valid(mu) 0
#define sys_mutex_set_invalid(mu)
#define sys_mbox_new(m, s) ERR_OK
#define sys_mbox_fetch(m,d)
#define sys_mbox_tryfetch(m,d)
#define sys_mbox_post(m,d)
#define sys_mbox_trypost(m,d)
#define sys_mbox_free(m)
#define sys_mbox_valid(m)
#define sys_mbox_set_invalid(m)
#define sys_thread_new(n,t,a,s,p)

View file

@ -36,12 +36,13 @@
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/icmp.h"
#include "lwip/err.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -156,11 +157,11 @@ enum tcp_state {
*/
#define TCP_PCB_COMMON(type) \
type *next; /* for the linked list */ \
enum tcp_state state; /* TCP state */ \
u8_t prio; \
void *callback_arg; \
/* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
DEF_ACCEPT_CALLBACK \
enum tcp_state state; /* TCP state */ \
u8_t prio; \
/* ports are in host byte order */ \
u16_t local_port
@ -187,21 +188,23 @@ struct tcp_pcb {
/* the rest of the fields are in host byte order
as we have to do some math with them */
/* Timers */
u8_t polltmr, pollinterval;
u8_t last_timer;
u32_t tmr;
/* receiver variables */
u32_t rcv_nxt; /* next seqno expected */
u16_t rcv_wnd; /* receiver window available */
u16_t rcv_ann_wnd; /* receiver window to announce */
u32_t rcv_ann_right_edge; /* announced right edge of window */
/* Timers */
u32_t tmr;
u8_t polltmr, pollinterval;
/* Retransmission timer. */
s16_t rtime;
u16_t mss; /* maximum segment size */
/* RTT (round trip time) estimation variables */
u32_t rttest; /* RTT estimate in 500ms ticks */
u32_t rtseq; /* sequence number being timed */
@ -211,24 +214,25 @@ struct tcp_pcb {
u8_t nrtx; /* number of retransmissions */
/* fast retransmit/recovery */
u32_t lastack; /* Highest acknowledged seqno. */
u8_t dupacks;
u32_t lastack; /* Highest acknowledged seqno. */
/* congestion avoidance/control variables */
u16_t cwnd;
u16_t cwnd;
u16_t ssthresh;
/* sender variables */
u32_t snd_nxt; /* next new seqno to be sent */
u16_t snd_wnd; /* sender window */
u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
window update. */
u32_t snd_lbb; /* Sequence number of next byte to be buffered. */
u16_t snd_wnd; /* sender window */
u16_t snd_wnd_max; /* the maximum sender window announced by the remote host */
u16_t acked;
u16_t snd_buf; /* Available buffer space for sending (in bytes). */
#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)
#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
#if TCP_OVERSIZE
@ -271,7 +275,7 @@ struct tcp_pcb {
#endif /* LWIP_TCP_KEEPALIVE */
/* Persist timer counter */
u32_t persist_cnt;
u8_t persist_cnt;
/* Persist timer back-off */
u8_t persist_backoff;
@ -279,7 +283,7 @@ struct tcp_pcb {
u8_t keep_cnt_sent;
};
struct tcp_pcb_listen {
struct tcp_pcb_listen {
/* Common members of all PCB types */
IP_PCB;
/* Protocol specific PCB members */
@ -289,6 +293,9 @@ struct tcp_pcb_listen {
u8_t backlog;
u8_t accepts_pending;
#endif /* TCP_LISTEN_BACKLOG */
#if LWIP_IPV6
u8_t accept_any_ip_version;
#endif /* LWIP_IPV6 */
};
#if LWIP_EVENT_API
@ -333,7 +340,7 @@ void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
(((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
#else /* TCP_LISTEN_BACKLOG */
#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
pcb->state == LISTEN)
(pcb)->state == LISTEN)
#endif /* TCP_LISTEN_BACKLOG */
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
@ -367,6 +374,19 @@ err_t tcp_output (struct tcp_pcb *pcb);
const char* tcp_debug_state_str(enum tcp_state s);
#if LWIP_IPV6
struct tcp_pcb * tcp_new_ip6 (void);
#define tcp_bind_ip6(pcb, ip6addr, port) \
tcp_bind(pcb, ip6_2_ip(ip6addr), port)
#define tcp_connect_ip6(pcb, ip6addr, port, connected) \
tcp_connect(pcb, ip6_2_ip(ip6addr), port, connected)
struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
#define tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
#else /* LWIP_IPV6 */
#define tcp_listen_dual_with_backlog(pcb, backlog) tcp_listen_with_backlog(pcb, backlog)
#define tcp_listen_dual(pcb) tcp_listen(pcb)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}

View file

@ -37,12 +37,13 @@
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/icmp.h"
#include "lwip/err.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -51,7 +52,7 @@ extern "C" {
/* Functions for interfacing with TCP: */
/* Lower layer interface to TCP: */
#define tcp_init() /* Compatibility define, no init needed. */
void tcp_init (void); /* Initialize this module. */
void tcp_tmr (void); /* Must be called every
TCP_TMR_INTERVAL
ms. (Typically 250 ms). */
@ -71,6 +72,7 @@ void tcp_rexmit (struct tcp_pcb *pcb);
void tcp_rexmit_rto (struct tcp_pcb *pcb);
void tcp_rexmit_fast (struct tcp_pcb *pcb);
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
err_t tcp_process_refused_data(struct tcp_pcb *pcb);
/**
* This is the Nagle algorithm: try to combine user data to send as few TCP
@ -84,15 +86,16 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb);
#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \
((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \
(((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \
((tpcb)->unsent->len >= (tpcb)->mss))) \
((tpcb)->unsent->len >= (tpcb)->mss))) || \
((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \
) ? 1 : 0)
#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)
#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0)
#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0)
#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0)
#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0)
#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0)
#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0)
#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0)
#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0)
/* is b<=a<=c? */
#if 0 /* see bug #10548 */
#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))
@ -170,11 +173,9 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)
#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)
#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)
#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))
#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))
#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))
#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags))
@ -278,7 +279,6 @@ PACK_STRUCT_END
struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */
void *dataptr; /* pointer to the TCP data in the pbuf */
u16_t len; /* the TCP length of this segment */
#if TCP_OVERSIZE_DBGCHECK
u16_t oversize_left; /* Extra bytes available at the end of the last
@ -302,14 +302,12 @@ struct tcp_seg {
(flags & TF_SEG_OPTS_TS ? 12 : 0)
/** This returns a TCP header option for MSS in an u32_t */
#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \
((u32_t)4 << 16) | \
(((u32_t)TCP_MSS / 256) << 8) | \
(TCP_MSS & 255))
#define TCP_BUILD_MSS_OPTION(mss) htonl(0x02040000 | ((mss) & 0xFFFF))
/* Global variables: */
extern struct tcp_pcb *tcp_input_pcb;
extern u32_t tcp_ticks;
extern u8_t tcp_active_pcbs_changed;
/* The TCP PCB lists. */
union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */
@ -396,6 +394,24 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */
#endif /* LWIP_DEBUG */
#define TCP_REG_ACTIVE(npcb) \
do { \
TCP_REG(&tcp_active_pcbs, npcb); \
tcp_active_pcbs_changed = 1; \
} while (0)
#define TCP_RMV_ACTIVE(npcb) \
do { \
TCP_RMV(&tcp_active_pcbs, npcb); \
tcp_active_pcbs_changed = 1; \
} while (0)
#define TCP_PCB_REMOVE_ACTIVE(pcb) \
do { \
tcp_pcb_remove(&tcp_active_pcbs, pcb); \
tcp_active_pcbs_changed = 1; \
} while (0)
/* Internal functions: */
struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);
@ -427,9 +443,20 @@ err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags);
void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
void tcp_rst(u32_t seqno, u32_t ackno,
ip_addr_t *local_ip, ip_addr_t *remote_ip,
u16_t local_port, u16_t remote_port);
void tcp_rst_impl(u32_t seqno, u32_t ackno,
ipX_addr_t *local_ip, ipX_addr_t *remote_ip,
u16_t local_port, u16_t remote_port
#if LWIP_IPV6
, u8_t isipv6
#endif /* LWIP_IPV6 */
);
#if LWIP_IPV6
#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \
tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6)
#else /* LWIP_IPV6 */
#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \
tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port)
#endif /* LWIP_IPV6 */
u32_t tcp_next_iss(void);
@ -437,7 +464,16 @@ void tcp_keepalive(struct tcp_pcb *pcb);
void tcp_zero_window_probe(struct tcp_pcb *pcb);
#if TCP_CALCULATE_EFF_SEND_MSS
u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr);
u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest
#if LWIP_IPV6
, ipX_addr_t *src, u8_t isipv6
#endif /* LWIP_IPV6 */
);
#if LWIP_IPV6
#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest, src, isipv6)
#else /* LWIP_IPV6 */
#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest)
#endif /* LWIP_IPV6 */
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
#if LWIP_CALLBACK_API

View file

@ -59,14 +59,29 @@ extern "C" {
extern sys_mutex_t lock_tcpip_core;
#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core)
#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core)
#define TCPIP_APIMSG(m) tcpip_apimsg_lock(m)
#ifdef LWIP_DEBUG
#define TCIP_APIMSG_SET_ERR(m, e) (m)->msg.err = e /* catch functions that don't set err */
#else
#define TCIP_APIMSG_SET_ERR(m, e)
#endif
#define TCPIP_APIMSG_NOERR(m,f) do { \
TCIP_APIMSG_SET_ERR(m, ERR_VAL); \
LOCK_TCPIP_CORE(); \
f(&((m)->msg)); \
UNLOCK_TCPIP_CORE(); \
} while(0)
#define TCPIP_APIMSG(m,f,e) do { \
TCPIP_APIMSG_NOERR(m,f); \
(e) = (m)->msg.err; \
} while(0)
#define TCPIP_APIMSG_ACK(m)
#define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m)
#define TCPIP_NETIFAPI_ACK(m)
#else /* LWIP_TCPIP_CORE_LOCKING */
#define LOCK_TCPIP_CORE()
#define UNLOCK_TCPIP_CORE()
#define TCPIP_APIMSG(m) tcpip_apimsg(m)
#define TCPIP_APIMSG_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0)
#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed)
#define TCPIP_NETIFAPI(m) tcpip_netifapi(m)
#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
@ -77,13 +92,13 @@ typedef void (*tcpip_init_done_fn)(void *arg);
/** Function prototype for functions passed to tcpip_callback() */
typedef void (*tcpip_callback_fn)(void *ctx);
/* Forward declarations */
struct tcpip_callback_msg;
void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
#if LWIP_NETCONN
err_t tcpip_apimsg(struct api_msg *apimsg);
#if LWIP_TCPIP_CORE_LOCKING
err_t tcpip_apimsg_lock(struct api_msg *apimsg);
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
err_t tcpip_input(struct pbuf *p, struct netif *inp);
@ -98,6 +113,10 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
#define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1)
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx);
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg);
err_t tcpip_trycallback(struct tcpip_callback_msg* msg);
/* free pbufs or heap memory from another context without blocking */
err_t pbuf_free_callback(struct pbuf *p);
err_t mem_free_callback(void *m);
@ -119,7 +138,8 @@ enum tcpip_msg_type {
TCPIP_MSG_TIMEOUT,
TCPIP_MSG_UNTIMEOUT,
#endif /* LWIP_TCPIP_TIMEOUT */
TCPIP_MSG_CALLBACK
TCPIP_MSG_CALLBACK,
TCPIP_MSG_CALLBACK_STATIC
};
struct tcpip_msg {

View file

@ -41,7 +41,9 @@
#if LWIP_TIMERS
#include "lwip/err.h"
#if !NO_SYS
#include "lwip/sys.h"
#endif
#ifdef __cplusplus
extern "C" {

View file

@ -40,6 +40,7 @@
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -87,6 +88,26 @@ struct udp_pcb;
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *addr, u16_t port);
#if LWIP_IPV6
/** Function prototype for udp pcb IPv6 receive callback functions
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IPv6 address from which the packet was received
* @param port the remote port from which the packet was received
*/
typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip6_addr_t *addr, u16_t port);
#endif /* LWIP_IPV6 */
#if LWIP_IPV6
#define UDP_PCB_RECV_IP6 udp_recv_ip6_fn ip6;
#else
#define UDP_PCB_RECV_IP6
#endif /* LWIP_IPV6 */
struct udp_pcb {
/* Common members of all PCB types */
@ -111,7 +132,10 @@ struct udp_pcb {
#endif /* LWIP_UDPLITE */
/** receive callback function */
udp_recv_fn recv;
union {
udp_recv_fn ip4;
UDP_PCB_RECV_IP6
}recv;
/** user-supplied argument for the recv callback */
void *recv_arg;
};
@ -154,7 +178,27 @@ err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
/* The following functions are the lower layer interface to UDP. */
void udp_input (struct pbuf *p, struct netif *inp);
#define udp_init() /* Compatibility define, not init needed. */
void udp_init (void);
#if LWIP_IPV6
struct udp_pcb * udp_new_ip6(void);
#define udp_bind_ip6(pcb, ip6addr, port) \
udp_bind(pcb, ip6_2_ip(ip6addr), port)
#define udp_connect_ip6(pcb, ip6addr, port) \
udp_connect(pcb, ip6_2_ip(ip6addr), port)
#define udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \
udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg)
#define udp_sendto_ip6(pcb, pbuf, ip6addr, port) \
udp_sendto(pcb, pbuf, ip6_2_ip(ip6addr), port)
#define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \
udp_sendto_if(pcb, pbuf, ip6_2_ip(ip6addr), port, netif)
#if LWIP_CHECKSUM_ON_COPY
#define udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \
udp_sendto_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, have_chk, chksum)
#define udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \
udp_sendto_if_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, netif, have_chk, chksum)
#endif /*LWIP_CHECKSUM_ON_COPY */
#endif /* LWIP_IPV6 */
#if UDP_DEBUG
void udp_debug_print(struct udp_hdr *udphdr);

View file

@ -235,7 +235,7 @@
* interfaces. If you are going to run lwIP on a device with only one network
* interface, define this to 0.
*/
#define IP_FORWARD 0
#define IP_FORWARD 1
/**
* IP_OPTIONS: Defines the behavior for IP options.

View file

@ -94,8 +94,8 @@ PACK_STRUCT_BEGIN
* if 'type' in ethernet header is ETHTYPE_VLAN.
* See IEEE802.Q */
struct eth_vlan_hdr {
PACK_STRUCT_FIELD(u16_t tpid);
PACK_STRUCT_FIELD(u16_t prio_vid);
PACK_STRUCT_FIELD(u16_t tpid);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@ -134,11 +134,12 @@ PACK_STRUCT_END
/** 5 seconds period */
#define ARP_TMR_INTERVAL 5000
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
#define ETHTYPE_VLAN 0x8100
#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */
#define ETHTYPE_ARP 0x0806U
#define ETHTYPE_IP 0x0800U
#define ETHTYPE_VLAN 0x8100U
#define ETHTYPE_IPV6 0x86DDU
#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */
#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */
/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
* or known to be 32-bit aligned within the protocol header. */
@ -190,6 +191,7 @@ err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
* nodes to update an entry in their ARP cache.
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
void etharp_cleanup_netif(struct netif *netif);
#if ETHARP_SUPPORT_STATIC_ENTRIES
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);

View file

@ -34,14 +34,44 @@
#ifndef __NETIF_SLIPIF_H__
#define __NETIF_SLIPIF_H__
#include "lwip/opt.h"
#include "lwip/netif.h"
/** Set this to 1 to start a thread that blocks reading on the serial line
* (using sio_read()).
*/
#ifndef SLIP_USE_RX_THREAD
#define SLIP_USE_RX_THREAD !NO_SYS
#endif
/** Set this to 1 to enable functions to pass in RX bytes from ISR context.
* If enabled, slipif_received_byte[s]() process incoming bytes and put assembled
* packets on a queue, which is fed into lwIP from slipif_poll().
* If disabled, slipif_poll() polls the serila line (using sio_tryread()).
*/
#ifndef SLIP_RX_FROM_ISR
#define SLIP_RX_FROM_ISR 0
#endif
/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets
* received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available.
* If disabled, packets will be dropped if more than one packet is received.
*/
#ifndef SLIP_RX_QUEUE
#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR
#endif
#ifdef __cplusplus
extern "C" {
#endif
err_t slipif_init(struct netif * netif);
void slipif_poll(struct netif *netif);
#if SLIP_RX_FROM_ISR
void slipif_process_rxqueue(struct netif *netif);
void slipif_received_byte(struct netif *netif, u8_t data);
void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len);
#endif /* SLIP_RX_FROM_ISR */
#ifdef __cplusplus
}

View file

@ -0,0 +1,33 @@
/**
* @file
* This file is a posix wrapper for lwip/netdb.h.
*/
/*
* 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.
*
*/
#include "lwip/netdb.h"

View file

@ -0,0 +1,33 @@
/**
* @file
* This file is a posix wrapper for lwip/sockets.h.
*/
/*
* 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.
*
*/
#include "lwip/sockets.h"

View file

@ -55,6 +55,7 @@
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "netif/etharp.h"
#include "lwip/ip6.h"
#if PPPOE_SUPPORT
#include "netif/ppp_oe.h"
@ -65,13 +66,22 @@
const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
const struct eth_addr ethzero = {{0,0,0,0,0,0}};
/** The 24-bit IANA multicast OUI is 01-00-5e: */
#define LL_MULTICAST_ADDR_0 0x01
#define LL_MULTICAST_ADDR_1 0x00
#define LL_MULTICAST_ADDR_2 0x5e
#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
/** the time an ARP entry stays valid after its last update,
* for ARP_TMR_INTERVAL = 5000, this is
* (240 * 5) seconds = 20 minutes.
*/
#define ARP_MAXAGE 240
#define ARP_MAXAGE 240
/** Re-request a used ARP entry 1 minute before it would expire to prevent
* breaking a steadily used connection because the ARP entry timed out. */
#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12)
/** the time an ARP entry stays pending after first request,
* for ARP_TMR_INTERVAL = 5000, this is
* (2 * 5) seconds = 10 seconds.
@ -86,24 +96,26 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
enum etharp_state {
ETHARP_STATE_EMPTY = 0,
ETHARP_STATE_PENDING,
ETHARP_STATE_STABLE
ETHARP_STATE_STABLE,
ETHARP_STATE_STABLE_REREQUESTING
#if ETHARP_SUPPORT_STATIC_ENTRIES
,ETHARP_STATE_STATIC
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
};
struct etharp_entry {
#if ARP_QUEUEING
/** Pointer to queue of pending outgoing packets on this ARP entry. */
struct etharp_q_entry *q;
#else /* ARP_QUEUEING */
/** Pointer to a single pending outgoing packet on this ARP entry. */
struct pbuf *q;
#endif /* ARP_QUEUEING */
ip_addr_t ipaddr;
struct eth_addr ethaddr;
#if LWIP_SNMP
struct netif *netif;
#endif /* LWIP_SNMP */
struct eth_addr ethaddr;
u8_t state;
u8_t ctime;
#if ETHARP_SUPPORT_STATIC_ENTRIES
u8_t static_entry;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
};
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
@ -116,7 +128,9 @@ static u8_t etharp_cached_entry;
the cache (even if this means removing an active entry or so). */
#define ETHARP_FLAG_TRY_HARD 1
#define ETHARP_FLAG_FIND_ONLY 2
#if ETHARP_SUPPORT_STATIC_ENTRIES
#define ETHARP_FLAG_STATIC_ENTRY 4
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
#if LWIP_NETIF_HWADDRHINT
#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
@ -125,8 +139,6 @@ static u8_t etharp_cached_entry;
#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
#endif /* LWIP_NETIF_HWADDRHINT */
static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/* Some checks, instead of etharp_init(): */
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
@ -154,34 +166,32 @@ free_etharp_q(struct etharp_q_entry *q)
memp_free(MEMP_ARP_QUEUE, r);
}
}
#else /* ARP_QUEUEING */
/** Compatibility define: free the queued pbuf */
#define free_etharp_q(q) pbuf_free(q)
#endif /* ARP_QUEUEING */
/** Clean up ARP table entries */
static void
free_entry(int i)
etharp_free_entry(int i)
{
/* remove from SNMP ARP index tree */
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
#if ARP_QUEUEING
/* and empty packet queue */
if (arp_table[i].q != NULL) {
/* remove all queued packets */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
free_etharp_q(arp_table[i].q);
arp_table[i].q = NULL;
}
#endif /* ARP_QUEUEING */
/* recycle entry for re-use */
/* recycle entry for re-use */
arp_table[i].state = ETHARP_STATE_EMPTY;
#if ETHARP_SUPPORT_STATIC_ENTRIES
arp_table[i].static_entry = 0;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
#ifdef LWIP_DEBUG
/* for debugging, clean out the complete entry */
arp_table[i].ctime = 0;
#if LWIP_SNMP
arp_table[i].netif = NULL;
#endif /* LWIP_SNMP */
ip_addr_set_zero(&arp_table[i].ipaddr);
arp_table[i].ethaddr = ethzero;
#endif /* LWIP_DEBUG */
@ -204,7 +214,7 @@ etharp_tmr(void)
u8_t state = arp_table[i].state;
if (state != ETHARP_STATE_EMPTY
#if ETHARP_SUPPORT_STATIC_ENTRIES
&& (arp_table[i].static_entry == 0)
&& (state != ETHARP_STATE_STATIC)
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
) {
arp_table[i].ctime++;
@ -213,9 +223,14 @@ etharp_tmr(void)
(arp_table[i].ctime >= ARP_MAXPENDING))) {
/* pending or stable entry has become old! */
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
/* clean up entries that have just been expired */
free_entry(i);
etharp_free_entry(i);
}
else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
/* Reset state to stable, so that the next transmitted packet will
re-send an ARP request. */
arp_table[i].state = ETHARP_STATE_STABLE;
}
#if ARP_QUEUEING
/* still pending entry? (not expired) */
@ -249,17 +264,15 @@ etharp_tmr(void)
* entry is found or could be recycled.
*/
static s8_t
find_entry(ip_addr_t *ipaddr, u8_t flags)
etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
{
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
s8_t empty = ARP_TABLE_SIZE;
u8_t i = 0, age_pending = 0, age_stable = 0;
#if ARP_QUEUEING
/* oldest entry with packets on queue */
s8_t old_queue = ARP_TABLE_SIZE;
/* its age */
u8_t age_queue = 0;
#endif /* ARP_QUEUEING */
/**
* a) do a search through the cache, remember candidates
@ -280,29 +293,27 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
u8_t state = arp_table[i].state;
/* no empty entry found yet and now we do find one? */
if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i));
/* remember first empty entry */
empty = i;
} else if (state != ETHARP_STATE_EMPTY) {
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i));
/* found exact IP address match, simply bail out */
return i;
}
/* pending entry? */
if (state == ETHARP_STATE_PENDING) {
/* pending with queued packets? */
#if ARP_QUEUEING
if (arp_table[i].q != NULL) {
if (arp_table[i].ctime >= age_queue) {
old_queue = i;
age_queue = arp_table[i].ctime;
}
} else
#endif /* ARP_QUEUEING */
/* pending without queued packets? */
{
if (arp_table[i].ctime >= age_pending) {
@ -311,10 +322,10 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
}
}
/* stable entry? */
} else if (state == ETHARP_STATE_STABLE) {
} else if (state >= ETHARP_STATE_STABLE) {
#if ETHARP_SUPPORT_STATIC_ENTRIES
/* don't record old_stable for static entries since they never expire */
if (arp_table[i].static_entry == 0)
if (state < ETHARP_STATE_STATIC)
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
{
/* remember entry with oldest stable entry in oldest, its age in maxtime */
@ -332,7 +343,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
/* or no empty entry found and not allowed to recycle? */
((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n"));
return (s8_t)ERR_MEM;
}
@ -348,38 +359,34 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
/* 1) empty entry available? */
if (empty < ARP_TABLE_SIZE) {
i = empty;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
} else {
/* 2) found recyclable stable entry? */
if (old_stable < ARP_TABLE_SIZE) {
/* recycle oldest stable*/
i = old_stable;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
#if ARP_QUEUEING
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
/* no queued packets should exist on stable entries */
LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
#endif /* ARP_QUEUEING */
/* 3) found recyclable pending entry without queued packets? */
} else if (old_pending < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_pending;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
#if ARP_QUEUEING
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
/* 4) found recyclable pending entry with queued packets? */
} else if (old_queue < ARP_TABLE_SIZE) {
/* recycle oldest pending (queued packets are free in free_entry) */
/* recycle oldest pending (queued packets are free in etharp_free_entry) */
i = old_queue;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
#endif /* ARP_QUEUEING */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
/* no empty or recyclable entries found */
} else {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n"));
return (s8_t)ERR_MEM;
}
/* { empty or recyclable entry found } */
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
free_entry(i);
etharp_free_entry(i);
}
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
@ -392,9 +399,6 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
}
arp_table[i].ctime = 0;
#if ETHARP_SUPPORT_STATIC_ENTRIES
arp_table[i].static_entry = 0;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
return (err_t)i;
}
@ -442,11 +446,11 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct
* @see pbuf_free()
*/
static err_t
update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
s8_t i;
LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
@ -454,11 +458,11 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
if (ip_addr_isany(ipaddr) ||
ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find or create ARP entry */
i = find_entry(ipaddr, flags);
i = etharp_find_entry(ipaddr, flags);
/* bail out if no entry could be found */
if (i < 0) {
return (err_t)i;
@ -467,27 +471,26 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
#if ETHARP_SUPPORT_STATIC_ENTRIES
if (flags & ETHARP_FLAG_STATIC_ENTRY) {
/* record static type */
arp_table[i].static_entry = 1;
}
arp_table[i].state = ETHARP_STATE_STATIC;
} else
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
{
/* mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
}
/* mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
#if LWIP_SNMP
/* record network interface */
arp_table[i].netif = netif;
#endif /* LWIP_SNMP */
/* insert in SNMP ARP index tree */
snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
/* update address */
ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
/* reset time stamp */
arp_table[i].ctime = 0;
#if ARP_QUEUEING
/* this is where we will send out queued packets! */
#if ARP_QUEUEING
while (arp_table[i].q != NULL) {
struct pbuf *p;
/* remember remainder of queue */
@ -498,12 +501,16 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
p = q->p;
/* now queue entry can be freed */
memp_free(MEMP_ARP_QUEUE, q);
#else /* ARP_QUEUEING */
if (arp_table[i].q != NULL) {
struct pbuf *p = arp_table[i].q;
arp_table[i].q = NULL;
#endif /* ARP_QUEUEING */
/* send the queued IP packet */
etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
/* free the queued IP packet */
pbuf_free(p);
}
#endif /* ARP_QUEUEING */
return ERR_OK;
}
@ -530,7 +537,7 @@ etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
return ERR_RTE;
}
return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
}
/** Remove a static entry from the ARP table previously added with a call to
@ -549,23 +556,39 @@ etharp_remove_static_entry(ip_addr_t *ipaddr)
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
/* find or create ARP entry */
i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
/* bail out if no entry could be found */
if (i < 0) {
return (err_t)i;
}
if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
(arp_table[i].static_entry == 0)) {
if (arp_table[i].state != ETHARP_STATE_STATIC) {
/* entry wasn't a static entry, cannot remove it */
return ERR_ARG;
}
/* entry found, free it */
free_entry(i);
etharp_free_entry(i);
return ERR_OK;
}
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
/**
* Remove all ARP table entries of the specified netif.
*
* @param netif points to a network interface
*/
void etharp_cleanup_netif(struct netif *netif)
{
u8_t i;
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
u8_t state = arp_table[i].state;
if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) {
etharp_free_entry(i);
}
}
}
/**
* Finds (stable) ethernet/IP address pair from ARP table
* using interface and IP address index.
@ -588,8 +611,8 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
LWIP_UNUSED_ARG(netif);
i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
*eth_ret = &arp_table[i].ethaddr;
*ip_ret = &arp_table[i].ipaddr;
return i;
@ -626,7 +649,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
ethhdr = (struct eth_hdr *)p->payload;
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
#if ETHARP_SUPPORT_VLAN
if (ethhdr->type == ETHTYPE_VLAN) {
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
}
#endif /* ETHARP_SUPPORT_VLAN */
@ -643,7 +666,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
/* update the source IP address in the cache, if present */
/* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
* back soon (for example, if the destination IP address is ours. */
update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
}
#endif /* ETHARP_TRUST_IP_MAC */
@ -691,7 +714,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
ethhdr = (struct eth_hdr *)p->payload;
hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
#if ETHARP_SUPPORT_VLAN
if (ethhdr->type == ETHTYPE_VLAN) {
if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
}
#endif /* ETHARP_SUPPORT_VLAN */
@ -700,11 +723,10 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
(hdr->hwlen != ETHARP_HWADDR_LEN) ||
(hdr->protolen != sizeof(ip_addr_t)) ||
(hdr->proto != PP_HTONS(ETHTYPE_IP)) ||
(ethhdr->type != PP_HTONS(ETHTYPE_ARP))) {
(hdr->proto != PP_HTONS(ETHTYPE_IP))) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type));
("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
pbuf_free(p);
@ -737,7 +759,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
can result in directly sending the queued packets for this host.
ARP message not directed to us?
-> update the source IP address in the cache, if present */
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
/* now act on the message itself */
@ -814,6 +836,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
pbuf_free(p);
}
/** Just a small helper function that sends a pbuf to an ethernet address
* in the arp_table specified by the index 'arp_idx'.
*/
static err_t
etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
{
LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE",
arp_table[arp_idx].state >= ETHARP_STATE_STABLE);
/* if arp table entry is about to expire: re-request it,
but only if its state is ETHARP_STATE_STABLE to prevent flooding the
network with ARP requests if this address is used frequently. */
if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) &&
(arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {
if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;
}
}
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
&arp_table[arp_idx].ethaddr);
}
/**
* Resolve and fill-in Ethernet address header for outgoing IP packet.
*
@ -835,7 +879,13 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
err_t
etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
{
struct eth_addr *dest, mcastaddr;
struct eth_addr *dest;
struct eth_addr mcastaddr;
ip_addr_t *dst_addr = ipaddr;
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("q != NULL", q != NULL);
LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
@ -846,8 +896,6 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
return ERR_BUF;
}
/* assume unresolved Ethernet address */
dest = NULL;
/* Determine on destination hardware address. Broadcasts and multicasts
* are special, other IP addresses are looked up in the ARP table. */
@ -858,9 +906,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
/* multicast destination IP address? */
} else if (ip_addr_ismulticast(ipaddr)) {
/* Hash IP multicast address to MAC address.*/
mcastaddr.addr[0] = 0x01;
mcastaddr.addr[1] = 0x00;
mcastaddr.addr[2] = 0x5e;
mcastaddr.addr[0] = LL_MULTICAST_ADDR_0;
mcastaddr.addr[1] = LL_MULTICAST_ADDR_1;
mcastaddr.addr[2] = LL_MULTICAST_ADDR_2;
mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
mcastaddr.addr[4] = ip4_addr3(ipaddr);
mcastaddr.addr[5] = ip4_addr4(ipaddr);
@ -868,17 +916,30 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
dest = &mcastaddr;
/* unicast destination IP address? */
} else {
/* outside local network? */
s8_t i;
/* outside local network? if so, this can neither be a global broadcast nor
a subnet broadcast. */
if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
!ip_addr_islinklocal(ipaddr)) {
/* interface has default gateway? */
if (!ip_addr_isany(&netif->gw)) {
/* send to hardware address of default gateway IP address */
ipaddr = &(netif->gw);
/* no default gateway available */
} else {
/* no route to destination error (default gateway missing) */
return ERR_RTE;
#if LWIP_AUTOIP
struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
sizeof(struct eth_hdr));
/* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
a link-local source address must always be "directly to its destination
on the same physical link. The host MUST NOT send the packet to any
router for forwarding". */
if (!ip_addr_islinklocal(&iphdr->src))
#endif /* LWIP_AUTOIP */
{
/* interface has default gateway? */
if (!ip_addr_isany(&netif->gw)) {
/* send to hardware address of default gateway IP address */
dst_addr = &(netif->gw);
/* no default gateway available */
} else {
/* no route to destination error (default gateway missing) */
return ERR_RTE;
}
}
}
#if LWIP_NETIF_HWADDRHINT
@ -887,19 +948,30 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
u8_t etharp_cached_entry = *(netif->addr_hint);
if (etharp_cached_entry < ARP_TABLE_SIZE) {
#endif /* LWIP_NETIF_HWADDRHINT */
if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
(ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
/* the per-pcb-cached entry is stable and the right one! */
ETHARP_STATS_INC(etharp.cachehit);
return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
&arp_table[etharp_cached_entry].ethaddr);
return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
}
#if LWIP_NETIF_HWADDRHINT
}
}
#endif /* LWIP_NETIF_HWADDRHINT */
/* queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, ipaddr, q);
/* find stable entry: do this here since this is a critical path for
throughput and etharp_find_entry() is kind of slow */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
(ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
/* found an existing, stable entry */
ETHARP_SET_HINT(netif, i);
return etharp_output_to_arp_index(netif, q, i);
}
}
/* no stable entry found, use the (slower) query function:
queue on destination Ethernet address belonging to ipaddr */
return etharp_query(netif, dst_addr, q);
}
/* continuation for multicast/broadcast destinations */
@ -957,7 +1029,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
}
/* find entry in ARP cache, ask to create entry if queueing packet */
i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
/* could not find or create entry? */
if (i < 0) {
@ -977,7 +1049,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* { i is either a STABLE or (new or existing) PENDING entry } */
LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
((arp_table[i].state == ETHARP_STATE_PENDING) ||
(arp_table[i].state == ETHARP_STATE_STABLE)));
(arp_table[i].state >= ETHARP_STATE_STABLE)));
/* do we have a pending entry? or an implicit query request? */
if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
@ -997,14 +1069,14 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* packet given? */
LWIP_ASSERT("q != NULL", q != NULL);
/* stable entry? */
if (arp_table[i].state == ETHARP_STATE_STABLE) {
if (arp_table[i].state >= ETHARP_STATE_STABLE) {
/* we have a valid IP->Ethernet address mapping */
ETHARP_SET_HINT(netif, i);
/* send the packet */
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
/* pending entry? (either just created or already pending */
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
#if ARP_QUEUEING /* queue the given q packet */
/* entry is still pending, queue the given packet 'q' */
struct pbuf *p;
int copy_needed = 0;
/* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
@ -1036,6 +1108,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* packet could be taken over? */
if (p != NULL) {
/* queue packet ... */
#if ARP_QUEUEING
struct etharp_q_entry *new_entry;
/* allocate a new arp queue entry */
new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
@ -1060,18 +1133,23 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
/* the pool MEMP_ARP_QUEUE is empty */
pbuf_free(p);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
/* { result == ERR_MEM } through initialization */
result = ERR_MEM;
}
#else /* ARP_QUEUEING */
/* always queue one packet per ARP request only, freeing a previously queued packet */
if (arp_table[i].q != NULL) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
pbuf_free(arp_table[i].q);
}
arp_table[i].q = p;
result = ERR_OK;
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
#endif /* ARP_QUEUEING */
} else {
ETHARP_STATS_INC(etharp.memerr);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
/* { result == ERR_MEM } through initialization */
result = ERR_MEM;
}
#else /* ARP_QUEUEING */
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
/* { result == ERR_MEM } through initialization */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
#endif /* ARP_QUEUEING */
}
return result;
}
@ -1109,6 +1187,8 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
const u8_t * ethdst_hwaddr;
#endif /* LWIP_AUTOIP */
LWIP_ASSERT("netif != NULL", netif != NULL);
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
@ -1199,6 +1279,16 @@ ethernet_input(struct pbuf *p, struct netif *netif)
{
struct eth_hdr* ethhdr;
u16_t type;
#if LWIP_ARP || ETHARP_SUPPORT_VLAN
s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
if (p->len <= SIZEOF_ETH_HDR) {
/* a packet with only an ethernet header (or less) is not valid for us */
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
goto free_and_return;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = (struct eth_hdr *)p->payload;
@ -1214,14 +1304,25 @@ ethernet_input(struct pbuf *p, struct netif *netif)
#if ETHARP_SUPPORT_VLAN
if (type == PP_HTONS(ETHTYPE_VLAN)) {
struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
/* a packet with only an ethernet/vlan header (or less) is not valid for us */
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
goto free_and_return;
}
#if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
#ifdef ETHARP_VLAN_CHECK_FN
if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
#elif defined(ETHARP_VLAN_CHECK)
if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
#endif
/* silently ignore this packet: not for our VLAN */
pbuf_free(p);
return ERR_OK;
}
#endif /* ETHARP_VLAN_CHECK */
#endif /* defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
type = vlan->tpid;
ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
}
#endif /* ETHARP_SUPPORT_VLAN */
@ -1229,6 +1330,20 @@ ethernet_input(struct pbuf *p, struct netif *netif)
netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
#endif /* LWIP_ARP_FILTER_NETIF*/
if (ethhdr->dest.addr[0] & 1) {
/* this might be a multicast or broadcast packet */
if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) {
if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) &&
(ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) {
/* mark the pbuf as link-layer multicast */
p->flags |= PBUF_FLAG_LLMCAST;
}
} else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
/* mark the pbuf as link-layer broadcast */
p->flags |= PBUF_FLAG_LLBCAST;
}
}
switch (type) {
#if LWIP_ARP
/* IP packet? */
@ -1241,7 +1356,7 @@ ethernet_input(struct pbuf *p, struct netif *netif)
etharp_ip_input(netif, p);
#endif /* ETHARP_TRUST_IP_MAC */
/* skip Ethernet header */
if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
if(pbuf_header(p, -ip_hdr_offset)) {
LWIP_ASSERT("Can't move over header in packet", 0);
goto free_and_return;
} else {
@ -1268,6 +1383,19 @@ ethernet_input(struct pbuf *p, struct netif *netif)
break;
#endif /* PPPOE_SUPPORT */
#if LWIP_IPV6
case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
/* skip Ethernet header */
if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
LWIP_ASSERT("Can't move over header in packet", 0);
goto free_and_return;
} else {
/* pass to IPv6 layer */
ip6_input(p, netif);
}
break;
#endif /* LWIP_IPV6 */
default:
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);

View file

@ -50,9 +50,9 @@
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include <lwip/stats.h>
#include <lwip/snmp.h>
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
@ -239,6 +239,7 @@ ethernetif_input(struct netif *netif)
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
@ -305,6 +306,9 @@ ethernetif_init(struct netif *netif)
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);

View file

@ -68,7 +68,7 @@
#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
#include "ppp.h"
#include "ppp_impl.h"
#include "pppdebug.h"
#include "fsm.h"

Some files were not shown because too many files have changed in this diff Show more