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:
parent
9d66e2299d
commit
7e55dbac33
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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(¤t_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(¤t_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);
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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(¤t_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(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_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(¤t_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(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_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(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest),
|
||||
ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_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, ¤t_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(¤t_iphdr_dest)) {
|
||||
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_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(¤t_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(¤t_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(¤t_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(¤t_iphdr_src))
|
||||
if (check_ip_src && !ip_addr_isany(ip_current_src_addr()))
|
||||
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
|
||||
{ if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) ||
|
||||
(ip_addr_ismulticast(¤t_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(¤t_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, ¤t_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(¤t_iphdr_dest, inp) &&
|
||||
!ip_addr_ismulticast(¤t_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(¤t_iphdr_src);
|
||||
ip_addr_set_any(¤t_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"));
|
|
@ -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;
|
||||
}
|
1
lib/liblwip/core/ipv6/README
Normal file
1
lib/liblwip/core/ipv6/README
Normal file
|
@ -0,0 +1 @@
|
|||
IPv6 support in lwIP is very experimental.
|
|
@ -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 */
|
193
lib/liblwip/core/ipv6/ethip6.c
Normal file
193
lib/liblwip/core/ipv6/ethip6.c
Normal 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(ðhdr->dest, dst, 6);
|
||||
SMEMCPY(ðhdr->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 */
|
337
lib/liblwip/core/ipv6/icmp6.c
Normal file
337
lib/liblwip/core/ipv6/icmp6.c
Normal 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 */
|
51
lib/liblwip/core/ipv6/inet6.c
Normal file
51
lib/liblwip/core/ipv6/inet6.c
Normal 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
1028
lib/liblwip/core/ipv6/ip6.c
Normal file
File diff suppressed because it is too large
Load diff
251
lib/liblwip/core/ipv6/ip6_addr.c
Normal file
251
lib/liblwip/core/ipv6/ip6_addr.c
Normal 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 */
|
697
lib/liblwip/core/ipv6/ip6_frag.c
Normal file
697
lib/liblwip/core/ipv6/ip6_frag.c
Normal 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 */
|
580
lib/liblwip/core/ipv6/mld6.c
Normal file
580
lib/liblwip/core/ipv6/mld6.c
Normal 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
1785
lib/liblwip/core/ipv6/nd6.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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! */
|
||||
|
|
|
@ -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), ¤t_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(¤t_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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(¤t_iphdr_dest, inp) ||
|
||||
ip_addr_ismulticast(¤t_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), ¤t_iphdr_src) &&
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_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), ¤t_iphdr_src) &&
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_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), ¤t_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), ¤t_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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(¤t_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), ¤t_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), ¤t_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(¤t_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), ¤t_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, ¤t_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, ¤t_iphdr_src, ¤t_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(¤t_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), ¤t_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(¤t_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(¤t_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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
@ -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() (¤t_iphdr_src)
|
||||
/** Destination IP address of current_header */
|
||||
#define ip_current_dest_addr() (¤t_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);
|
|
@ -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"
|
|
@ -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);
|
||||
|
|
58
lib/liblwip/include/ipv6/lwip/dhcp6.h
Normal file
58
lib/liblwip/include/ipv6/lwip/dhcp6.h
Normal 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__ */
|
68
lib/liblwip/include/ipv6/lwip/ethip6.h
Normal file
68
lib/liblwip/include/ipv6/lwip/ethip6.h
Normal 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__ */
|
152
lib/liblwip/include/ipv6/lwip/icmp6.h
Normal file
152
lib/liblwip/include/ipv6/lwip/icmp6.h
Normal 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__ */
|
92
lib/liblwip/include/ipv6/lwip/inet6.h
Normal file
92
lib/liblwip/include/ipv6/lwip/inet6.h
Normal 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__ */
|
||||
|
197
lib/liblwip/include/ipv6/lwip/ip6.h
Normal file
197
lib/liblwip/include/ipv6/lwip/ip6.h
Normal 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__ */
|
286
lib/liblwip/include/ipv6/lwip/ip6_addr.h
Normal file
286
lib/liblwip/include/ipv6/lwip/ip6_addr.h
Normal 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__ */
|
102
lib/liblwip/include/ipv6/lwip/ip6_frag.h
Normal file
102
lib/liblwip/include/ipv6/lwip/ip6_frag.h
Normal 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__ */
|
118
lib/liblwip/include/ipv6/lwip/mld6.h
Normal file
118
lib/liblwip/include/ipv6/lwip/mld6.h
Normal 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__ */
|
369
lib/liblwip/include/ipv6/lwip/nd6.h
Normal file
369
lib/liblwip/include/ipv6/lwip/nd6.h
Normal 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__ */
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MINIX_AUTOIP_H__
|
||||
#define __MINIX_AUTOIP_H__
|
||||
|
||||
#include "ipv4/lwip/autoip.h"
|
||||
|
||||
#endif /* __MINIX_AUTOIP_H__ */
|
|
@ -33,6 +33,7 @@
|
|||
#define __LWIP_DEBUG_H__
|
||||
|
||||
#include "lwip/arch.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/** lower two bits indicate debug level
|
||||
* - 0 all
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)*/
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MINIX_ICMP_H__
|
||||
#define __MINIX_ICMP_H__
|
||||
|
||||
#include "ipv4/lwip/icmp.h"
|
||||
|
||||
#endif /* __MINIX_ICMP_H__ */
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MINIX_IGMP_H__
|
||||
#define __MINIX_IGMP_H__
|
||||
|
||||
#include "ipv4/lwip/igmp.h"
|
||||
|
||||
#endif /* __MINIX_IGMP_H__ */
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __MINIX_INET_H__
|
||||
#define __MINIX_INET_H__
|
||||
|
||||
#include "ipv4/lwip/inet.h"
|
||||
|
||||
#endif /* __MINIX_INET_H__ */
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -41,7 +41,9 @@
|
|||
#if LWIP_TIMERS
|
||||
|
||||
#include "lwip/err.h"
|
||||
#if !NO_SYS
|
||||
#include "lwip/sys.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
33
lib/liblwip/include/posix/netdb.h
Normal file
33
lib/liblwip/include/posix/netdb.h
Normal 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"
|
33
lib/liblwip/include/posix/sys/socket.h
Normal file
33
lib/liblwip/include/posix/sys/socket.h
Normal 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"
|
|
@ -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(ðhdr->dest, ðbroadcast)) {
|
||||
/* 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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue