... and finally, we got a first working version of a dual-stack lwIP runnin IPv4 and IPv6 in parallel - big thanks to Ivan Delamer! (this is work in progress, so please beware, test a lot and report problems!)

This commit is contained in:
goldsimon 2011-05-17 19:35:14 +00:00
parent f3c1686a40
commit 4bfbe7ebeb
40 changed files with 3930 additions and 978 deletions

View File

@ -6,6 +6,10 @@ HISTORY
++ New features:
2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt)
* nearly the whole stack: Finally, we got decent IPv6 support, big thanks to
Ivan! (this is work in progress: we're just post release anyway :-)
2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage)
* tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static
memory message

View File

@ -372,7 +372,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
#endif /* LWIP_SO_RCVTIMEO*/
#if LWIP_TCP
if (conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
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
@ -434,7 +434,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);
}
@ -461,7 +461,7 @@ 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 (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
struct pbuf *p = NULL;
/* This is not a listening netconn, since recvmbox is set */
@ -481,7 +481,11 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
buf->p = p;
buf->ptr = p;
buf->port = 0;
ip_addr_set_any(&buf->addr);
#if LWIP_IPV6
ip6_addr_set_any(&buf->addr.ip6);
#else /* LWIP_IPV6 */
ip_addr_set_any(&buf->addr.ip4);
#endif /* LWIP_IPV6 */
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
@ -508,7 +512,7 @@ void
netconn_recved(struct netconn *conn, u32_t length)
{
#if LWIP_TCP
if ((conn != NULL) && (conn->type == NETCONN_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. */
@ -540,7 +544,15 @@ 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);
#if LWIP_IPV6
if (conn->pcb.ip->isipv6) {
ip6_addr_set(&buf->addr.ip6, (ip6_addr_t *)addr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&buf->addr.ip4, addr);
}
buf->port = port;
return netconn_send(conn, buf);
}
@ -591,7 +603,7 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl
err_t err;
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;
}
@ -664,7 +676,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.
*
@ -696,7 +708,7 @@ netconn_join_leave_group(struct netconn *conn,
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**

View File

@ -51,6 +51,7 @@
#include "lwip/tcpip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/mld6.h"
#include <string.h>
@ -112,7 +113,15 @@ 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());
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_copy(buf->addr.ip6, *ip6_current_src_addr());
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_copy(buf->addr.ip4, *ip_current_src_addr());
}
buf->port = pcb->protocol;
len = q->tot_len;
@ -175,9 +184,30 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
} else {
buf->p = p;
buf->ptr = p;
ip_addr_set(&buf->addr, addr);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
ip6_addr_set(&buf->addr.ip6, (ip6_addr_t *)addr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&buf->addr.ip4, addr);
}
buf->port = port;
#if LWIP_NETBUF_RECVINFO
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
/* get the UDP header - always in the first pbuf, ensured by udp_input */
const struct udp_hdr* udphdr = (void*)(((char*)ip6_current_header()) +
ip6_current_header_tot_len());
#if LWIP_CHECKSUM_ON_COPY
buf->flags = NETBUF_FLAG_DESTADDR;
#endif /* LWIP_CHECKSUM_ON_COPY */
ip6_addr_set(&buf->toaddr.ip6, ip6_current_dest_addr());
buf->toport_chksum = udphdr->dest;
}
else
#endif /* LWIP_IPV6 */
{
const struct ip_hdr* iphdr = ip_current_header();
/* get the UDP header - always in the first pbuf, ensured by udp_input */
@ -185,7 +215,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
#if LWIP_CHECKSUM_ON_COPY
buf->flags = NETBUF_FLAG_DESTADDR;
#endif /* LWIP_CHECKSUM_ON_COPY */
ip_addr_set(&buf->toaddr, ip_current_dest_addr());
ip_addr_set(&buf->toaddr.ip4, ip_current_dest_addr());
buf->toport_chksum = udphdr->dest;
}
#endif /* LWIP_NETBUF_RECVINFO */
@ -487,7 +517,15 @@ pcb_new(struct api_msg_msg *msg)
switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
case NETCONN_RAW:
msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
msg->conn->pcb.raw = raw_new_ip6(msg->msg.n.proto);
}
else
#endif /* LWIP_IPV6 */
{
msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
}
if(msg->conn->pcb.raw == NULL) {
msg->err = ERR_MEM;
break;
@ -497,17 +535,25 @@ pcb_new(struct api_msg_msg *msg)
#endif /* LWIP_RAW */
#if LWIP_UDP
case NETCONN_UDP:
msg->conn->pcb.udp = udp_new();
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
msg->conn->pcb.udp = udp_new_ip6();
}
else
#endif /* LWIP_IPV6 */
{
msg->conn->pcb.udp = udp_new();
}
if(msg->conn->pcb.udp == NULL) {
msg->err = ERR_MEM;
break;
}
#if LWIP_UDPLITE
if (msg->conn->type==NETCONN_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) {
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);
@ -515,7 +561,15 @@ pcb_new(struct api_msg_msg *msg)
#endif /* LWIP_UDP */
#if LWIP_TCP
case NETCONN_TCP:
msg->conn->pcb.tcp = tcp_new();
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
msg->conn->pcb.tcp = tcp_new_ip6();
}
else
#endif /* LWIP_IPV6 */
{
msg->conn->pcb.tcp = tcp_new();
}
if(msg->conn->pcb.tcp == NULL) {
msg->err = ERR_MEM;
break;
@ -680,7 +734,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() */
@ -738,7 +792,7 @@ do_close_internal(struct netconn *conn)
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);
@ -824,7 +878,7 @@ do_delconn(struct api_msg_msg *msg)
(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("msg->conn->type == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
msg->err = ERR_INPROGRESS;
} else {
LWIP_ASSERT("blocking connect in progress",
@ -942,7 +996,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);
@ -1056,7 +1110,7 @@ do_listen(struct api_msg_msg *msg)
} 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) {
#if TCP_LISTEN_BACKLOG
struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
@ -1113,29 +1167,62 @@ 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 LWIP_IPV6
if (msg->conn->pcb.ip->isipv6) {
if (ip6_addr_isany(&msg->msg.b->addr.ip6)) {
msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
} else {
msg->err = raw_sendto_ip6(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr.ip6);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&msg->msg.b->addr.ip4)) {
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, &msg->msg.b->addr.ip4);
}
break;
#endif
#if LWIP_UDP
case NETCONN_UDP:
#if LWIP_CHECKSUM_ON_COPY
if (ip_addr_isany(&msg->msg.b->addr)) {
#if LWIP_IPV6
if (msg->conn->pcb.ip->isipv6) {
if (ip6_addr_isany(&msg->msg.b->addr.ip6)) {
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_ip6(msg->conn->pcb.udp, msg->msg.b->p,
&msg->msg.b->addr.ip6, msg->msg.b->port,
msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&msg->msg.b->addr.ip4)) {
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,
&msg->msg.b->addr.ip4, 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 LWIP_IPV6
if (msg->conn->pcb.ip->isipv6) {
if (ip6_addr_isany(&msg->msg.b->addr.ip6)) {
msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
} else {
msg->err = udp_sendto_ip6(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr.ip6, msg->msg.b->port);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&msg->msg.b->addr.ip4)) {
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, &msg->msg.b->addr.ip4, msg->msg.b->port);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
break;
@ -1160,7 +1247,7 @@ do_recv(struct api_msg_msg *msg)
{
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);
@ -1315,7 +1402,7 @@ 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 */
@ -1368,8 +1455,20 @@ void
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 LWIP_IPV6
if (msg->conn->pcb.ip->isipv6) {
if (msg->msg.ad.local) {
ip6_addr_set((ip6_addr_t *)msg->msg.ad.ipaddr, &(msg->conn->pcb.ip->local_ip.ip6));
} else {
ip6_addr_set((ip6_addr_t *)msg->msg.ad.ipaddr, &(msg->conn->pcb.ip->remote_ip.ip6));
}
}
else
#endif /* LWIP_IPV6 */
{
*(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip.ip4 :
msg->conn->pcb.ip->remote_ip.ip4);
}
msg->err = ERR_OK;
switch (NETCONNTYPE_GROUP(msg->conn->type)) {
@ -1424,9 +1523,9 @@ do_close(struct api_msg_msg *msg)
/* @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("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;
@ -1451,7 +1550,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
@ -1467,10 +1566,24 @@ 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 (msg->conn->pcb.udp->isipv6) {
if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
msg->err = mld6_joingroup((ip6_addr_t *)msg->msg.jl.netif_addr, (ip6_addr_t *)msg->msg.jl.multiaddr);
} else {
msg->err = mld6_leavegroup((ip6_addr_t *)msg->msg.jl.netif_addr, (ip6_addr_t *)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(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
} else {
msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
}
#endif /* LWIP_IGMP */
}
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
@ -1484,7 +1597,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
/**

View File

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

View File

@ -58,6 +58,16 @@
#include <string.h>
/* Check that the family member of a struct sockaddr matches the socket's IP version */
#if LWIP_IPV6
#define SOCK_ADDR_MATCH(name, sock) \
((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
(((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
#else /* LWIP_IPV6 */
#define SOCK_ADDR_MATCH(name, sock) (((name)->sa_family) == AF_INET)
#endif /* LWIP_IPV6 */
#define NUM_SOCKETS MEMP_NUM_NETCONN
/** Contains all internal pointers and states used for a socket */
@ -259,7 +269,7 @@ alloc_socket(struct netconn *newconn, int accepted)
sockets[i].rcvevent = 0;
/* TCP sendbuf is empty, but the socket is not yet writable until connected
* (unless it has been created by accept()). */
sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
sockets[i].errevent = 0;
sockets[i].err = 0;
sockets[i].select_waiting = 0;
@ -313,10 +323,19 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
struct lwip_sock *sock, *nsock;
struct netconn *newconn;
ip_addr_t naddr;
union {
ip_addr_t ip4;
#if LWIP_IPV6
ip6_addr_t ip6;
#endif /* LWIP_IPV6 */
} naddr;
u16_t port;
int newsock;
struct sockaddr_in sin;
struct sockaddr tempaddr;
struct sockaddr_in * sin;
#if LWIP_IPV6
struct sockaddr_in6 * sin6;
#endif /* LWIP_IPV6 */
err_t err;
SYS_ARCH_DECL_PROTECT(lev);
@ -344,7 +363,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
netconn_set_noautorecved(newconn, 1);
/* get the IP address and port of the remote host */
err = netconn_peer(newconn, &naddr, &port);
err = netconn_peer(newconn, &naddr.ip4, &port);
if (err != ERR_OK) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
netconn_delete(newconn);
@ -357,16 +376,34 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
*/
if (NULL != addr) {
LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
memset(&tempaddr, 0, sizeof(tempaddr));
if (*addrlen > sizeof(sin))
*addrlen = sizeof(sin);
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(newconn->type)) {
sin6 = (struct sockaddr_in6 *)&tempaddr;
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
sin6->sin6_flowinfo = 0;
inet6_addr_from_ip6addr(&sin6->sin6_addr, &naddr.ip6);
MEMCPY(addr, &sin, *addrlen);
if (*addrlen > sin6->sin6_len)
*addrlen = sin6->sin6_len;
}
else
#endif /* LWIP_IPV6 */
{
sin = (struct sockaddr_in *)&tempaddr;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
inet_addr_from_ipaddr(&sin->sin_addr, &naddr.ip4);
if (*addrlen > sin->sin_len)
*addrlen = sin->sin_len;
}
MEMCPY(addr, &tempaddr, *addrlen);
}
newsock = alloc_socket(newconn, 1);
@ -390,7 +427,15 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
SYS_ARCH_UNPROTECT(lev);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(newconn->type)) {
ip6_addr_debug_print(SOCKETS_DEBUG, &naddr.ip6);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_debug_print(SOCKETS_DEBUG, &naddr.ip4);
}
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
sock_set_errno(sock, 0);
@ -401,10 +446,18 @@ int
lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock;
ip_addr_t local_addr;
union {
ip_addr_t ip4;
#if LWIP_IPV6
ip6_addr_t ip6;
#endif /* LWIP_IPV6 */
} local_addr;
u16_t local_port;
err_t err;
const struct sockaddr_in *name_in;
#if LWIP_IPV6
const struct sockaddr_in6 *name_in6;
#endif /* LWIP_IPV6 */
sock = get_socket(s);
if (!sock) {
@ -413,18 +466,33 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
/* check size, familiy and alignment of 'name' */
LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
SOCK_ADDR_MATCH(name, sock) &&
((((mem_ptr_t)name) % 4) == 0)),
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
name_in = (const struct sockaddr_in *)(void*)name;
inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
local_port = name_in->sin_port;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
#if LWIP_IPV6
if ((name->sa_family) == AF_INET6) {
name_in6 = (const struct sockaddr_in6 *)(void*)name;
inet6_addr_to_ip6addr(&local_addr.ip6, &name_in6->sin6_addr);
ip6_addr_debug_print(SOCKETS_DEBUG, &local_addr.ip6);
local_port = name_in6->sin6_port;
}
else
#endif /* LWIP_IPV6 */
{
name_in = (const struct sockaddr_in *)(void*)name;
inet_addr_to_ipaddr(&local_addr.ip4, &name_in->sin_addr);
ip_addr_debug_print(SOCKETS_DEBUG, &local_addr.ip4);
local_port = name_in->sin_port;
}
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
err = netconn_bind(sock->conn, &local_addr.ip4, ntohs(local_port));
if (err != ERR_OK) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
@ -451,7 +519,7 @@ lwip_close(int s)
}
if(sock->conn != NULL) {
is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
} else {
LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
}
@ -468,7 +536,6 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
struct lwip_sock *sock;
err_t err;
const struct sockaddr_in *name_in;
sock = get_socket(s);
if (!sock) {
@ -477,17 +544,38 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
/* check size, familiy and alignment of 'name' */
LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
SOCK_ADDR_MATCH(name, sock) &&
((((mem_ptr_t)name) % 4) == 0)),
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
name_in = (const struct sockaddr_in *)(void*)name;
if (name_in->sin_family == AF_UNSPEC) {
if (name->sa_family == AF_UNSPEC) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
err = netconn_disconnect(sock->conn);
} else {
}
#if LWIP_IPV6
else if (name->sa_family == AF_INET6) {
const struct sockaddr_in6 *name_in6;
ip6_addr_t remote_addr;
u16_t remote_port;
name_in6 = (const struct sockaddr_in6 *)(void*)name;
inet6_addr_to_ip6addr(&remote_addr, &name_in6->sin6_addr);
remote_port = name_in6->sin6_port;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
ip6_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
err = netconn_connect(sock->conn, (ip_addr_t *)&remote_addr, ntohs(remote_port));
}
#endif /* LWIP_IPV6 */
else {
const struct sockaddr_in *name_in;
ip_addr_t remote_addr;
u16_t remote_port;
name_in = (const struct sockaddr_in *)(void*)name;
inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
remote_port = name_in->sin_port;
@ -554,7 +642,6 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
struct pbuf *p;
u16_t buflen, copylen;
int off = 0;
ip_addr_t *addr;
u16_t port;
u8_t done = 0;
err_t err;
@ -588,7 +675,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
/* No data was left from the previous operation, so we try to get
some from the network. */
if (netconn_type(sock->conn) == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
} else {
err = netconn_recv(sock->conn, (struct netbuf **)&buf);
@ -618,7 +705,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
sock->lastdata = buf;
}
if (netconn_type(sock->conn) == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
p = (struct pbuf *)buf;
} else {
p = ((struct netbuf *)buf)->p;
@ -641,7 +728,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
off += copylen;
if (netconn_type(sock->conn) == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
len -= copylen;
if ( (len <= 0) ||
@ -656,47 +743,69 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
/* Check to see from where the data was.*/
if (done) {
ip_addr_t fromaddr;
if (from && fromlen) {
struct sockaddr_in sin;
if (netconn_type(sock->conn) == NETCONN_TCP) {
addr = &fromaddr;
netconn_getaddr(sock->conn, addr, &port, 0);
} else {
addr = netbuf_fromaddr((struct netbuf *)buf);
port = netbuf_fromport((struct netbuf *)buf);
}
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_addr_from_ipaddr(&sin.sin_addr, addr);
if (*fromlen > sizeof(sin)) {
*fromlen = sizeof(sin);
}
MEMCPY(from, &sin, *fromlen);
#if !SOCKETS_DEBUG
if (from && fromlen)
#endif /* !SOCKETS_DEBUG */
{
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
} else {
#if SOCKETS_DEBUG
if (netconn_type(sock->conn) == NETCONN_TCP) {
addr = &fromaddr;
netconn_getaddr(sock->conn, addr, &port, 0);
} else {
addr = netbuf_fromaddr((struct netbuf *)buf);
port = netbuf_fromport((struct netbuf *)buf);
}
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn))) {
ip6_addr_t *fromaddr6;
ip6_addr_t tmpaddr6;
struct sockaddr_in6 sin6;
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
/* @todo: implement netconn_getaddr() for IPv6 addresses */
ip6_addr_set_any(&tmpaddr6);
fromaddr6 = &tmpaddr6;
port = 0;
} else {
fromaddr6 = netbuf_fromaddr_ip6((struct netbuf *)buf);
port = netbuf_fromport((struct netbuf *)buf);
}
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(port);
inet6_addr_from_ip6addr(&sin6.sin6_addr, fromaddr6);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, addr);
if (from && fromlen) {
if (*fromlen > sizeof(sin6)) {
*fromlen = sizeof(sin6);
}
MEMCPY(from, &sin6, *fromlen);
}
ip6_addr_debug_print(SOCKETS_DEBUG, fromaddr6);
} else
#endif /* LWIP_IPV6 */
{
ip_addr_t *fromaddr4;
ip_addr_t tmpaddr4;
struct sockaddr_in sin;
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
fromaddr4 = &tmpaddr4;
netconn_getaddr(sock->conn, fromaddr4, &port, 0);
} else {
fromaddr4 = netbuf_fromaddr((struct netbuf *)buf);
port = netbuf_fromport((struct netbuf *)buf);
}
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_addr_from_ipaddr(&sin.sin_addr, fromaddr4);
if (from && fromlen) {
if (*fromlen > sizeof(sin)) {
*fromlen = sizeof(sin);
}
MEMCPY(from, &sin, *fromlen);
}
ip_addr_debug_print(SOCKETS_DEBUG, &fromaddr4);
}
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
#endif /* SOCKETS_DEBUG */
}
}
@ -705,7 +814,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
/* If this is a TCP socket, check if there is data left in the
buffer. If so, it should be saved in the sock structure for next
time around. */
if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
sock->lastdata = buf;
sock->lastoffset += copylen;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
@ -713,7 +822,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
sock->lastdata = NULL;
sock->lastoffset = 0;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
if (netconn_type(sock->conn) == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
pbuf_free((struct pbuf *)buf);
} else {
netbuf_delete((struct netbuf *)buf);
@ -757,7 +866,7 @@ lwip_send(int s, const void *data, size_t size, int flags)
return -1;
}
if (sock->conn->type != NETCONN_TCP) {
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
#if (LWIP_UDP || LWIP_RAW)
return lwip_sendto(s, data, size, flags, NULL, 0);
#else /* (LWIP_UDP || LWIP_RAW) */
@ -791,7 +900,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
struct lwip_sock *sock;
err_t err;
u16_t short_size;
const struct sockaddr_in *to_in;
u16_t remote_port;
#if !LWIP_TCPIP_CORE_LOCKING
struct netbuf buf;
@ -802,7 +910,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
return -1;
}
if (sock->conn->type == NETCONN_TCP) {
if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) {
#if LWIP_TCP
return lwip_send(s, data, size, flags);
#else /* LWIP_TCP */
@ -817,22 +925,25 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
short_size = (u16_t)size;
LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
((tolen == sizeof(struct sockaddr_in)) &&
((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
SOCK_ADDR_MATCH(to, sock) &&
((((mem_ptr_t)to) % 4) == 0))),
sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
to_in = (const struct sockaddr_in *)(void*)to;
#if LWIP_TCPIP_CORE_LOCKING
/* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
{
struct pbuf* p;
ip_addr_t *remote_addr;
#if LWIP_IPV6
ip6_addr_t *remote_addr6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_TX_SINGLE_PBUF
p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
if (p != NULL) {
#if LWIP_CHECKSUM_ON_COPY
u16_t chksum = 0;
if (sock->conn->type != NETCONN_RAW) {
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) {
chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
} else
#endif /* LWIP_CHECKSUM_ON_COPY */
@ -843,20 +954,39 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
p->payload = (void*)data;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (to_in != NULL) {
inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
remote_port = ntohs(to_in->sin_port);
if (to != NULL) {
#if LWIP_IPV6
if (to->sa_family == AF_INET6) {
const struct sockaddr_in6 *to_in6;
to_in6 = (const struct sockaddr_in6 *)(void*)to;
inet6_addr_to_ip6addr_p(remote_addr6, &to_in6->sin6_addr);
remote_addr = (ip_addr_t *)remote_addr6;
remote_port = ntohs(to_in6->sin6_port);
}
else
#endif /* LWIP_IPV6 */
{
const struct sockaddr_in *to_in;
to_in = (const struct sockaddr_in *)(void*)to;
inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
remote_port = ntohs(to_in->sin_port);
}
} else {
remote_addr = &sock->conn->pcb.raw->remote_ip;
if (sock->conn->type == NETCONN_RAW) {
remote_port = 0;
} else {
remote_port = sock->conn->pcb.udp->remote_port;
remote_addr = IP_ADDR_ANY;
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
remote_addr6 = IP6_ADDR_ANY;
remote_addr = (ip_addr_t *)remote_addr6;
}
else
#endif /* LWIP_IPV6 */
{
remote_addr = IP_ADDR_ANY;
}
}
LOCK_TCPIP_CORE();
if (sock->conn->type == NETCONN_RAW) {
if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
} else {
#if LWIP_UDP
@ -885,18 +1015,48 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
buf.flags = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
if (to) {
inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
remote_port = ntohs(to_in->sin_port);
#if LWIP_IPV6
if ((to->sa_family) == AF_INET6) {
const struct sockaddr_in6 *to_in6;
to_in6 = (const struct sockaddr_in6 *)(void*)to;
inet6_addr_to_ip6addr(&buf.addr.ip6, &to_in6->sin6_addr);
remote_port = ntohs(to_in6->sin6_port);
}
else
#endif /* LWIP_IPV6 */
{
const struct sockaddr_in *to_in;
to_in = (const struct sockaddr_in *)(void*)to;
inet_addr_to_ipaddr(&buf.addr.ip4, &to_in->sin_addr);
remote_port = ntohs(to_in->sin_port);
}
netbuf_fromport(&buf) = remote_port;
} else {
remote_port = 0;
ip_addr_set_any(&buf.addr);
remote_port = 0;
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
ip6_addr_set_any(&buf.addr.ip6);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set_any(&buf.addr.ip4);
}
netbuf_fromport(&buf) = 0;
}
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
s, data, short_size, flags));
ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
ip6_addr_debug_print(SOCKETS_DEBUG, &buf.addr.ip6);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr.ip4);
}
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
/* make the buffer point to the data that should be sent */
@ -906,7 +1066,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
err = ERR_MEM;
} else {
#if LWIP_CHECKSUM_ON_COPY
if (sock->conn->type != NETCONN_RAW) {
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) {
u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
netbuf_set_chksum(&buf, chksum);
err = ERR_OK;
@ -937,23 +1097,41 @@ lwip_socket(int domain, int type, int protocol)
struct netconn *conn;
int i;
#if !LWIP_IPV6
LWIP_UNUSED_ARG(domain);
#endif /* LWIP_IPV6 */
/* create a netconn */
switch (type) {
case SOCK_RAW:
#if LWIP_IPV6
conn = netconn_new_with_proto_and_callback((domain == AF_INET) ? NETCONN_RAW : NETCONN_RAW_IPV6,
(u8_t)protocol, event_callback);
#else /* LWIP_IPV6 */
conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
#endif /* LWIP_IPV6 */
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
break;
case SOCK_DGRAM:
#if LWIP_IPV6
conn = netconn_new_with_callback((domain == AF_INET) ?
((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP) :
((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE_IPV6 : NETCONN_UDP_IPV6) ,
event_callback);
#else /* LWIP_IPV6 */
conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
NETCONN_UDPLITE : NETCONN_UDP, event_callback);
#endif /* LWIP_IPV6 */
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
break;
case SOCK_STREAM:
#if LWIP_IPV6
conn = netconn_new_with_callback((domain == AF_INET) ? NETCONN_TCP : NETCONN_TCP_IPV6, event_callback);
#else /* LWIP_IPV6 */
conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
#endif /* LWIP_IPV6 */
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
if (conn != NULL) {
@ -1365,7 +1543,7 @@ lwip_shutdown(int s, int how)
}
if (sock->conn != NULL) {
if (netconn_type(sock->conn) != NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
sock_set_errno(sock, EOPNOTSUPP);
return EOPNOTSUPP;
}
@ -1395,33 +1573,63 @@ static int
lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
{
struct lwip_sock *sock;
struct sockaddr_in sin;
ip_addr_t naddr;
sock = get_socket(s);
if (!sock) {
return -1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
#if LWIP_IPV6
if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
struct sockaddr_in6 sin6;
ip6_addr_t naddr6;
/* get the IP address and port */
netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
/* get the IP address and port */
netconn_getaddr(sock->conn, (ip_addr_t *)&naddr6, &sin6.sin6_port, local);
sin.sin_port = htons(sin.sin_port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
ip6_addr_debug_print(SOCKETS_DEBUG, &naddr6);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin6.sin6_port));
if (*namelen > sizeof(sin)) {
*namelen = sizeof(sin);
sin6.sin6_port = htons(sin6.sin6_port);
inet6_addr_from_ip6addr(&sin6.sin6_addr, &naddr6);
if (*namelen > sizeof(sin6)) {
*namelen = sizeof(sin6);
}
MEMCPY(name, &sin6, *namelen);
}
else
#endif /* LWIP_IPV6 */
{
struct sockaddr_in sin;
ip_addr_t naddr;
MEMCPY(name, &sin, *namelen);
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
/* get the IP address and port */
netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
sin.sin_port = htons(sin.sin_port);
inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
if (*namelen > sizeof(sin)) {
*namelen = sizeof(sin);
}
MEMCPY(name, &sin, *namelen);
}
sock_set_errno(sock, 0);
return 0;
}
@ -1495,7 +1703,12 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
err = EINVAL;
}
#if LWIP_UDP
if ((sock->conn->type != NETCONN_UDP) ||
if (
#if LWIP_IPV6
((sock->conn->type != NETCONN_UDP) && (sock->conn->type != NETCONN_UDP_IPV6)) ||
#else /* LWIP_IPV6 */
(sock->conn->type != NETCONN_UDP) ||
#endif /* LWIP_IPV6 */
((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
/* this flag is only available for UDP, not for UDP lite */
err = EAFNOSUPPORT;
@ -1559,7 +1772,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
}
/* If this is no TCP socket, ignore any options. */
if (sock->conn->type != NETCONN_TCP)
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP)
return 0;
switch (optname) {
@ -1588,7 +1801,11 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
}
/* If this is no UDP lite socket, ignore any options. */
#if LWIP_IPV6
if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6)) {
#else /* LWIP_IPV6 */
if (sock->conn->type != NETCONN_UDPLITE) {
#endif /* LWIP_IPV6 */
return 0;
}
@ -1892,7 +2109,12 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
err = EINVAL;
}
#if LWIP_UDP
if ((sock->conn->type != NETCONN_UDP) ||
if (
#if LWIP_IPV6
((sock->conn->type != NETCONN_UDP) && (sock->conn->type != NETCONN_UDP_IPV6)) ||
#else /* LWIP_IPV6 */
(sock->conn->type != NETCONN_UDP) ||
#endif /* LWIP_IPV6 */
((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
/* this flag is only available for UDP, not for UDP lite */
err = EAFNOSUPPORT;
@ -1969,7 +2191,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
}
/* If this is no TCP socket, ignore any options. */
if (sock->conn->type != NETCONN_TCP)
if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP)
return 0;
switch (optname) {
@ -1998,7 +2220,11 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
}
/* If this is no UDP lite socket, ignore any options. */
#if LWIP_IPV6
if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6))
#else /* LWIP_IPV6 */
if (sock->conn->type != NETCONN_UDPLITE)
#endif /* LWIP_IPV6 */
return 0;
switch (optname) {
@ -2281,7 +2507,7 @@ lwip_ioctl(int s, long cmd, void *argp)
/* Check if there is data left from the last recv operation. /maq 041215 */
if (sock->lastdata) {
struct pbuf *p = (struct pbuf *)sock->lastdata;
if (netconn_type(sock->conn) != NETCONN_TCP) {
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
p = ((struct netbuf *)p)->p;
}
buflen = p->tot_len;

View File

@ -56,6 +56,9 @@
#include "lwip/dns.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "lwip/ip6.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
@ -299,6 +302,13 @@ lwip_init(void)
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if LWIP_IPV6
ip6_init();
nd6_init();
#if LWIP_IPV6_MLD
mld6_init();
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if LWIP_TIMERS
sys_timeouts_init();

View File

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

View File

@ -382,14 +382,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 +396,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 +404,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 */

View File

@ -60,6 +60,7 @@
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 2
# endif
u16_t lwip_standard_chksum(void *dataptr, int len);
#endif
/* If none set: */
#ifndef LWIP_CHKSUM_ALGORITHM
@ -77,7 +78,7 @@
* @note accumulator size limits summable length to 64k
* @note host endianess is irrelevant (p3 RFC1071)
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, u16_t len)
{
u32_t acc;
@ -131,7 +132,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
* @return host order (!) lwip checksum (non-inverted Internet sum)
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;
@ -187,7 +188,7 @@ lwip_standard_chksum(void *dataptr, int len)
* by Curt McDowell, Broadcom Corp. December 8th, 2005
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;

View File

@ -496,23 +496,27 @@ ip_input(struct pbuf *p, struct netif *inp)
case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
snmp_inc_ipindelivers();
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
udp_input(p, inp);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case IP_PROTO_TCP:
snmp_inc_ipindelivers();
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
tcp_input(p, inp);
break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
case IP_PROTO_ICMP:
snmp_inc_ipindelivers();
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
icmp_input(p, inp);
break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
case IP_PROTO_IGMP:
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
igmp_input(p, inp, &current_iphdr_dest);
break;
#endif /* LWIP_IGMP */

View File

@ -1,5 +1,11 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* 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,
@ -26,154 +32,272 @@
*
* 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>
*/
/* Some ICMP messages should be passed to the transport protocols. This
is not implemented. */
#include "lwip/opt.h"
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip6_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 type, u8_t code, u32_t data);
/**
* 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
icmp_input(struct pbuf *p, struct netif *inp)
icmp6_input(struct pbuf *p, struct netif *inp)
{
u8_t type;
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
struct icmp6_hdr *icmp6hdr;
struct pbuf * r;
ip6_addr_t * reply_src;
ICMP_STATS_INC(icmp.recv);
ICMP6_STATS_INC(icmp6.recv);
/* TODO: check length before accessing payload! */
/* 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;
}
type = ((u8_t *)p->payload)[0];
icmp6hdr = (struct icmp6_hdr *)p->payload;
switch (type) {
case ICMP6_ECHO:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
#if LWIP_ICMP6_CHECKSUM_CHECK
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
IP6_NEXTH_ICMP6, p->tot_len) != 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);
ICMP_STATS_INC(icmp.lenerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
iecho = p->payload;
iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
ICMP_STATS_INC(icmp.chkerr);
/* return;*/
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
ip_addr_set(&tmpaddr, &(iphdr->src));
ip_addr_set(&(iphdr->src), &(iphdr->dest));
ip_addr_set(&(iphdr->dest), &tmpaddr);
iecho->type = ICMP6_ER;
/* adjust the checksum */
if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
} else {
iecho->chksum += htons(ICMP6_ECHO << 8);
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
ICMP_STATS_INC(icmp.xmit);
#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. */
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;
}
/* 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,
reply_src, ip6_current_src_addr(),
IP6_NEXTH_ICMP6, r->tot_len);
/* 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);
/* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
ip_output_if (p, &(iphdr->src), IP_HDRINCL,
iphdr->hoplim, IP_PROTO_ICMP, inp);
break;
default:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
ICMP_STATS_INC(icmp.proterr);
ICMP_STATS_INC(icmp.drop);
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
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
pbuf_free(p);
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (8 + IP_HLEN + 8)));
iphdr = p->payload;
idur = q->payload;
idur->type = (u8_t)ICMP6_DUR;
idur->icode = (u8_t)t;
SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
/* calculate checksum */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
ICMP_STATS_INC(icmp.xmit);
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
pbuf_free(q);
icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0);
}
/**
* 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
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
{
icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu);
}
/**
* 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, ICMP6_TYPE_TE, c, 0);
}
/**
* 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, ICMP6_TYPE_PP, c, pointer);
}
/**
* 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 type Type of the ICMPv6 header
* @param code Code of the ICMPv6 header
* @param data Additional 32-bit parameter in the ICMPv6 header
*/
static void
icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
struct icmp6_hdr *icmp6hdr;
ip6_addr_t * reply_src;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
/* 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_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
pbuf_free(p);
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 message",
(q->len >= (8 + IP_HLEN + 8)));
LWIP_ASSERT("check that first pbuf can hold icmp 6message",
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
iphdr = p->payload;
tehdr = q->payload;
tehdr->type = (u8_t)ICMP6_TE;
tehdr->icode = (u8_t)t;
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 + 8, (u8_t *)p->payload, IP_HLEN + 8);
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
IP6_HLEN + LWIP_ICMP6_DATASIZE);
/* Select an address to use as source. */
reply_src = ip6_select_source_address(current_netif, ip6_current_src_addr());
if (reply_src == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
/* calculate checksum */
tehdr->chksum = 0;
tehdr->chksum = inet_chksum(tehdr, q->len);
ICMP_STATS_INC(icmp.xmit);
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
icmp6hdr->chksum = 0;
icmp6hdr->chksum = ip6_chksum_pseudo(q, reply_src, ip6_current_src_addr(),
IP6_NEXTH_ICMP6, q->tot_len);
ICMP6_STATS_INC(icmp6.xmit);
ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6);
pbuf_free(q);
}
#endif /* LWIP_ICMP */
#endif /* LWIP_ICMP6 && LWIP_IPV6 */

View File

@ -1,12 +1,11 @@
/**
* @file
* Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
* byte order functions.
*
* INET v6 addresses.
*/
/*
* 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,
@ -33,131 +32,20 @@
*
* 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"
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/inet.h"
#include "lwip/inet6.h"
/* chksum:
*
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
* This function is used by the other checksum functions.
*
* For now, this is not optimized. Must be optimized for the particular processor
* arcitecture on which it is to run. Preferebly coded in assembler.
*/
/** @see ip6_addr.c for implementation of functions. */
static u32_t
chksum(void *dataptr, u16_t len)
{
u16_t *sdataptr = dataptr;
u32_t acc;
for(acc = 0; len > 1; len -= 2) {
acc += *sdataptr++;
}
/* add up any odd byte */
if (len == 1) {
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
}
return acc;
}
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u32_t proto_len)
{
u32_t acc;
struct pbuf *q;
u8_t swapped, i;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
for(i = 0; i < 8; i++) {
acc += ((u16_t *)src->addr)[i] & 0xffff;
acc += ((u16_t *)dest->addr)[i] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
}
acc += (u16_t)htons((u16_t)proto);
acc += ((u16_t *)&proto_len)[0] & 0xffff;
acc += ((u16_t *)&proto_len)[1] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
return ~(acc & 0xffff);
}
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
* and ICMP.
*/
u16_t
inet_chksum(void *dataptr, u16_t len)
{
u32_t acc, sum;
acc = chksum(dataptr, len);
sum = (acc & 0xffff) + (acc >> 16);
sum += (sum >> 16);
return ~(sum & 0xffff);
}
u16_t
inet_chksum_pbuf(struct pbuf *p)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
return ~(acc & 0xffff);
}
#endif /* LWIP_IPV6 */

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,11 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* 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,
@ -26,47 +32,210 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* 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"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
u8_t
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask)
#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)
{
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
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 (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 {
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 (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. */
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;
}
u8_t
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
/**
* 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)
{
return(addr1->addr[0] == addr2->addr[0] &&
addr1->addr[1] == addr2->addr[1] &&
addr1->addr[2] == addr2->addr[2] &&
addr1->addr[3] == addr2->addr[3]);
static char str[40];
return ip6addr_ntoa_r(addr, str, 40);
}
void
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
/**
* 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)
{
SMEMCPY(dest, src, sizeof(struct ip_addr));
/* dest->addr[0] = src->addr[0];
dest->addr[1] = src->addr[1];
dest->addr[2] = src->addr[2];
dest->addr[3] = src->addr[3];*/
}
u32_t current_block_index, current_block_value;
s32_t zero_flag, i;
u8_t
ip_addr_isany(struct ip_addr *addr)
{
if (addr == NULL) return 1;
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
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));
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
if (i >= buflen) return NULL;
}
buf[i++] = xchar((current_block_value & 0xf));
if (i >= buflen) return NULL;
zero_flag = 0;
}
}
buf[i] = 0;
return buf;
}
#endif /* LWIP_IPV6 */

View File

@ -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>

View File

@ -40,6 +40,7 @@
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
@ -59,6 +60,12 @@
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif /* LWIP_DHCP */
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_IPV6_MLD
#include "lwip/mld6.h"
#endif /* LWIP_IPV6_MLD */
#if LWIP_NETIF_STATUS_CALLBACK
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
@ -138,6 +145,9 @@ 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 +155,12 @@ 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);
}
#endif /* LWIP_IPV6 */
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
@ -154,6 +170,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 +190,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;
@ -245,6 +275,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);
@ -331,10 +365,10 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
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(&(pcb->local_ip.ip4), &(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(&(pcb->local_ip.ip4))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
@ -348,11 +382,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(&(lpcb->local_ip.ip4)))) &&
(ip_addr_cmp(&(lpcb->local_ip.ip4), &(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(&(lpcb->local_ip.ip4), ipaddr);
}
}
}
@ -471,6 +505,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 */
}
}
}
@ -541,6 +585,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 +798,62 @@ 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 */
}
#endif /* LWIP_IPV6 */

View File

@ -49,6 +49,8 @@
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include <string.h>
@ -79,11 +81,24 @@ 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;
@ -91,17 +106,38 @@ raw_input(struct pbuf *p, struct netif *inp)
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if ((pcb->protocol == proto) &&
(ip_addr_isany(&pcb->local_ip) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
#if LWIP_IPV6
((pcb->isipv6 &&
(ip6_addr_isany(&pcb->local_ip.ip6) ||
ip6_addr_cmp(&pcb->local_ip.ip6, ip6_current_dest_addr()))) ||
(!pcb->isipv6 &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
(ip_addr_isany(&pcb->local_ip.ip4) ||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr()))))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
#if LWIP_IPV6
&& !pcb->isipv6
#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) {
#if LWIP_IPV6
if (pcb->isipv6) {
eaten = pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr());
}
else
#endif /* LWIP_IPV6 */
{
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 +177,15 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&pcb->local_ip.ip4, ipaddr);
}
return ERR_OK;
}
@ -161,7 +205,15 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&pcb->remote_ip.ip4, ipaddr);
}
return ERR_OK;
}
@ -183,7 +235,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;
}
@ -209,6 +261,33 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
#if LWIP_IPV6
/* TODO lots of v4 and v6 code duplication, optimize! Or will compiler optimize? */
if (pcb->isipv6) {
/* not enough space to add an IPv6 header to first pbuf in given p chain? */
if (pbuf_header(p, IP6_HLEN)) {
/* allocate header in new pbuf */
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
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);
/* { 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, -IP6_HLEN)) {
LWIP_ASSERT("Can't restore header we just removed!", 0);
return ERR_MEM;
}
}
}
else
#endif /* LWIP_IPV6 */
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, IP_HLEN)) {
/* allocate header in new pbuf */
@ -233,6 +312,19 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
}
}
#if LWIP_IPV6
if (pcb->isipv6) {
if ((netif = ip6_route(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to IPv6 destionation\n"));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
}
else
#endif /* LWIP_IPV6 */
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)));
@ -244,29 +336,62 @@ 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
if (!netif->isipv6) {
#endif /* LWIP_IPV6 */
/* 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);
}
return ERR_VAL;
}
return ERR_VAL;
#if LWIP_IPV6
}
#endif /* LWIP_IPV6 */
#endif /* IP_SOF_BROADCAST */
if (ip_addr_isany(&pcb->local_ip)) {
#if LWIP_IPV6
if (pcb->isipv6) {
if (ip6_addr_isany(&pcb->local_ip.ip6)) {
/* select an IPv6 address from the netif as source address */
src_ip = (ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)ipaddr);
if (src_ip == NULL) {
/* No suitable source address was found. */
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
} else {
/* use RAW PCB local IPv6 address as source address */
src_ip = (ip_addr_t *)&(pcb->local_ip.ip6);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&pcb->local_ip.ip4)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* use RAW PCB local IP address as source address */
src_ip = &(pcb->local_ip);
src_ip = &(pcb->local_ip.ip4);
}
#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_IPV6
if (pcb->isipv6) {
err = ip6_output_if(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
}
else
#endif /* LWIP_IPV6 */
{
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*/
@ -289,7 +414,13 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
/* TODO is this necessary, or ar ip4 and ip6 pointers the same (think union)? */
return raw_sendto(pcb, p, (ip_addr_t *)&pcb->remote_ip.ip6);
}
#endif /* LWIP_IPV6 */
return raw_sendto(pcb, p, &pcb->remote_ip.ip4);
}
/**
@ -351,4 +482,28 @@ 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);
if (pcb != NULL) {
pcb->isipv6 = 1;
}
return pcb;
}
#endif /* LWIP_IPV6 */
#endif /* LWIP_RAW */

View File

@ -52,6 +52,9 @@
#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>
@ -147,8 +150,17 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
pcb->local_port, pcb->remote_port);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
pcb->local_port, pcb->remote_port);
}
tcp_pcb_purge(pcb);
@ -318,8 +330,8 @@ 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;
/*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 */
@ -337,10 +349,10 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
} else {
seqno = pcb->snd_nxt;
ackno = pcb->rcv_nxt;
ip_addr_copy(local_ip, pcb->local_ip);
ip_addr_copy(remote_ip, pcb->remote_ip);
/*ip_addr_copy(local_ip, pcb->local_ip.ip4);
ip_addr_copy(remote_ip, pcb->remote_ip.ip4);
local_port = pcb->local_port;
remote_port = pcb->remote_port;
remote_port = pcb->remote_port;*/
#if LWIP_CALLBACK_API
errf = pcb->errf;
#endif /* LWIP_CALLBACK_API */
@ -357,12 +369,20 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
tcp_segs_free(pcb->ooseq);
}
#endif /* TCP_QUEUE_OOSEQ */
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);
#if LWIP_IPV6
if (pcb->isipv6) {
tcp_rst_ip6(seqno, ackno, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->local_port, pcb->remote_port);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(seqno, ackno, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->local_port, pcb->remote_port);
}
}
memp_free(MEMP_TCP_PCB, pcb);
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
}
}
@ -432,18 +452,40 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
((cpcb->so_options & SOF_REUSEADDR) == 0))
#endif /* SO_REUSE */
{
if (ip_addr_isany(&(cpcb->local_ip)) ||
if (
#if LWIP_IPV6
!pcb->isipv6 &&
!cpcb->isipv6 &&
#endif /* LWIP_IPV6 */
(ip_addr_isany(&(cpcb->local_ip.ip4)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
ip_addr_cmp(&(cpcb->local_ip.ip4), ipaddr))) {
return ERR_USE;
}
#if LWIP_IPV6
if (pcb->isipv6 &&
cpcb->isipv6 &&
(ip6_addr_isany(&(cpcb->local_ip.ip6)) ||
ip6_addr_isany((ip6_addr_t *)ipaddr) ||
ip6_addr_cmp(&(cpcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) {
return ERR_USE;
}
#endif /* LWIP_IPV6 */
}
}
}
}
#if LWIP_IPV6
if (pcb->isipv6) {
if (!ip6_addr_isany((ip6_addr_t *)ipaddr)) {
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
}
}
else
#endif /* LWIP_IPV6 */
if (!ip_addr_isany(ipaddr)) {
pcb->local_ip = *ipaddr;
pcb->local_ip.ip4 = *ipaddr;
}
pcb->local_port = port;
TCP_REG(&tcp_bound_pcbs, pcb);
@ -498,7 +540,15 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
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 ((
#if LWIP_IPV6
pcb->isipv6 &&
lpcb->isipv6 &&
ip6_addr_cmp(&lpcb->local_ip.ip6, &pcb->local_ip.ip6)) ||
(!pcb->isipv6 &&
!lpcb->isipv6 &&
#endif /* LWIP_IPV6 */
ip_addr_cmp(&lpcb->local_ip.ip4, &pcb->local_ip.ip4))) {
/* this address/port is already used */
return NULL;
}
@ -518,7 +568,16 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
lpcb->so_options |= SOF_ACCEPTCONN;
lpcb->ttl = pcb->ttl;
lpcb->tos = pcb->tos;
ip_addr_copy(lpcb->local_ip, pcb->local_ip);
#if LWIP_IPV6
lpcb->isipv6 = pcb->isipv6;
if (lpcb->isipv6) {
ip6_addr_copy(lpcb->local_ip.ip6, pcb->local_ip.ip6);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_copy(lpcb->local_ip.ip4, pcb->local_ip.ip4);
}
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
@ -657,23 +716,55 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
if (ipaddr != NULL) {
pcb->remote_ip = *ipaddr;
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
}
else
#endif /* LWIP_IPV6 */
{
pcb->remote_ip.ip4 = *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 LWIP_IPV6
if (pcb->isipv6) {
if (ip6_addr_isany(&(pcb->local_ip.ip6))) {
/* no local IPv6 address set, yet. */
ip6_addr_t * local_addr6;
struct netif *netif = ip6_route(&(pcb->remote_ip.ip6), &(pcb->remote_ip.ip6));
if (netif == NULL) {
/* Don't even try to send a SYN packet if we have no route
since that will fail. */
return ERR_RTE;
}
/* Select and IPv6 address from the netif. */
local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6));
if (local_addr6 == NULL) {
/* Don't even try to send a SYN packet if we have no suitable
source address. */
return ERR_RTE;
}
ip6_addr_set(&pcb->local_ip.ip6, local_addr6);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&(pcb->local_ip.ip4))) {
/* no local IP address set, yet. */
struct netif *netif = ip_route(&(pcb->remote_ip));
struct netif *netif = ip_route(&(pcb->remote_ip.ip4));
if (netif == 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);
ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr);
}
old_local_port = pcb->local_port;
@ -691,8 +782,18 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
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)) {
#if LWIP_IPV6
((cpcb->isipv6 &&
pcb->isipv6 &&
ip6_addr_cmp(&cpcb->local_ip.ip6, &pcb->local_ip.ip6) &&
ip6_addr_cmp(&cpcb->remote_ip.ip6, (ip6_addr_t *)ipaddr)) ||
(!cpcb->isipv6 &&
!pcb->isipv6 &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
ip_addr_cmp(&cpcb->local_ip.ip4, &pcb->local_ip.ip4) &&
ip_addr_cmp(&cpcb->remote_ip.ip4, ipaddr)))) {
/* linux returns EISCONN here, but ERR_USE should be OK for us */
return ERR_USE;
}
@ -713,7 +814,15 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &pcb->local_ip.ip6, &pcb->remote_ip.ip6);
}
else
#endif /* LWIP_IPV6 */
{
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->remote_ip.ip4);
}
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
pcb->cwnd = 1;
pcb->ssthresh = pcb->mss * 10;
@ -852,9 +961,13 @@ tcp_slowtmr(void)
(pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
#endif /* LWIP_TCP_KEEPALIVE */
{
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 "));
if (!pcb->isipv6) {
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
} else {
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
}
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
++pcb_remove;
++pcb_reset;
@ -919,8 +1032,17 @@ tcp_slowtmr(void)
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);
#if LWIP_IPV6
if (pcb->isipv6) {
tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
pcb->local_port, pcb->remote_port);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
pcb->local_port, pcb->remote_port);
}
}
pcb2 = pcb;
@ -1266,6 +1388,27 @@ 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);
/* could allocate TCP PCB? */
if (pcb != NULL) {
pcb->isipv6 = 1;
}
return pcb;
}
#endif /* LWIP_IPV6 */
/**
* Used to specify the argument that should be passed callback
* functions.
@ -1376,8 +1519,18 @@ 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))) {
#if LWIP_IPV6
((lpcb->isipv6 &&
pcb->isipv6 &&
(ip6_addr_isany(&lpcb->local_ip.ip6) ||
ip6_addr_cmp(&pcb->local_ip.ip6, &lpcb->local_ip.ip6))) ||
(!lpcb->isipv6 &&
!pcb->isipv6 &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
(ip_addr_isany(&lpcb->local_ip.ip4) ||
ip_addr_cmp(&pcb->local_ip.ip4, &lpcb->local_ip.ip4))))) {
/* 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);
@ -1492,6 +1645,35 @@ tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
}
return sendmss;
}
#if LWIP_IPV6
/**
* Calculates the effective send mss that can be used for a specific IPv6
* address by using ip6_route to determine the netif used to send to the
* address and calculating the minimum of TCP_MSS and that netif's mtu (if set).
*/
u16_t
tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest)
{
u16_t mss_s;
struct netif *outif;
s16_t mtu;
/* First look in destination cache, to see if there is a PAth MTU. */
outif = ip6_route(src, dest);
mtu = nd6_get_destination_mtu(dest, outif);
if (mtu != 0) {
mss_s = mtu - IP6_HLEN - TCP_HLEN;
/* 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().
*/
sendmss = LWIP_MIN(sendmss, mss_s);
}
return sendmss;
}
#endif /* LWIP_IPV6 */
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
const char*

View File

@ -55,13 +55,18 @@
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "arch/perf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip6_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
@ -105,15 +110,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
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);
@ -124,8 +128,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
/* Don't even process incoming broadcasts/multicasts. */
if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
ip_addr_ismulticast(&current_iphdr_dest)) {
if ((
#if LWIP_IPV6
(ip6_current_header() != NULL) &&
ip6_addr_ismulticast(ip6_current_dest_addr())) ||
((ip_current_header() != NULL) &&
#endif /* LWIP_IPV6 */
(ip_addr_isbroadcast(ip_current_dest_addr(), inp) ||
ip_addr_ismulticast(ip_current_dest_addr())))) {
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
@ -134,6 +144,25 @@ tcp_input(struct pbuf *p, struct netif *inp)
}
#if CHECKSUM_CHECK_TCP
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
IP6_NEXTH_TCP, p->tot_len) != 0) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
IP6_NEXTH_TCP, p->tot_len)));
#if TCP_DEBUG
tcp_debug_print(tcphdr);
#endif /* TCP_DEBUG */
TCP_STATS_INC(tcp.chkerr);
TCP_STATS_INC(tcp.drop);
snmp_inc_tcpinerrs();
pbuf_free(p);
return;
}
}
else
#endif /* LWIP_IPV6 */
/* Verify TCP checksum. */
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
IP_PROTO_TCP, p->tot_len) != 0) {
@ -149,7 +178,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
pbuf_free(p);
return;
}
#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. */
@ -184,9 +213,18 @@ tcp_input(struct pbuf *p, struct netif *inp)
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
pcb->local_port == tcphdr->dest &&
((
#if LWIP_IPV6
pcb->isipv6 &&
(ip6_current_header() != NULL) &&
ip6_addr_cmp(&(pcb->remote_ip.ip6), ip6_current_src_addr()) &&
ip6_addr_cmp(&(pcb->local_ip.ip6), ip6_current_dest_addr())) ||
(!pcb->isipv6 &&
(ip_current_header() != NULL) &&
#endif /* LWIP_IPV6 */
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr()) &&
ip_addr_cmp(&(pcb->local_ip.ip4), ip_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
@ -209,9 +247,18 @@ tcp_input(struct pbuf *p, struct netif *inp)
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
pcb->local_port == tcphdr->dest &&
((
#if LWIP_IPV6
pcb->isipv6 &&
(ip6_current_header() != NULL) &&
ip6_addr_cmp(&(pcb->remote_ip.ip6), ip6_current_src_addr()) &&
ip6_addr_cmp(&(pcb->local_ip.ip6), ip6_current_dest_addr())) ||
(!pcb->isipv6 &&
(ip_current_header() != NULL) &&
#endif /* LWIP_IPV6 */
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr()) &&
ip_addr_cmp(&(pcb->local_ip.ip4), ip_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. */
@ -228,19 +275,50 @@ tcp_input(struct pbuf *p, struct netif *inp)
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if (lpcb->local_port == tcphdr->dest) {
#if SO_REUSE
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
/* found an exact match */
break;
} else if(ip_addr_isany(&(lpcb->local_ip))) {
/* found an ANY-match */
lpcb_any = lpcb;
lpcb_prev = prev;
#if LWIP_IPV6
if (lpcb->isipv6 &&
(ip6_current_header() != NULL)) {
if (ip6_addr_cmp(&(lpcb->local_ip.ip6), ip6_current_dest_addr())) {
/* found an exact match */
break;
} else if(ip6_addr_isany(&(lpcb->local_ip.ip6))) {
/* found an ANY-match */
lpcb_any = lpcb;
lpcb_prev = prev;
}
}
else if (!lpcb->isipv6 &&
(ip_current_header() != NULL))
#endif /* LWIP_IPV6 */
{
if (ip_addr_cmp(&(lpcb->local_ip.ip4), ip_current_dest_addr())) {
/* found an exact match */
break;
} else if(ip_addr_isany(&(lpcb->local_ip.ip4))) {
/* found an ANY-match */
lpcb_any = lpcb;
lpcb_prev = prev;
}
}
#else /* SO_REUSE */
if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
ip_addr_isany(&(lpcb->local_ip))) {
/* found a match */
break;
#if LWIP_IPV6
if (lpcb->isipv6 &&
(ip6_current_header() != NULL)) {
if (ip6_addr_cmp(&(lpcb->local_ip.ip6), ip6_current_dest_addr()) ||
ip6_addr_isany(&(lpcb->local_ip.ip6))) {
/* found an exact match */
break;
}
}
else if (!lpcb->isipv6 &&
(ip_current_header() != NULL))
#endif /* LWIP_IPV6 */
{
if (ip_addr_cmp(&(lpcb->local_ip.ip4), ip_current_dest_addr()) ||
ip_addr_isany(&(lpcb->local_ip.ip4))) {
/* found a match */
break;
}
}
#endif /* SO_REUSE */
}
@ -415,9 +493,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);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
tcp_rst_ip6(ackno, seqno + tcplen,
ip6_current_dest_addr(), ip6_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(ackno, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
}
pbuf_free(p);
}
@ -450,9 +538,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
/* 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);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
tcp_rst_ip6(ackno + 1, seqno + tcplen,
ip6_current_dest_addr(), ip6_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(ackno + 1, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
} 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
@ -474,9 +572,19 @@ 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
npcb->isipv6 = pcb->isipv6;
if (npcb->isipv6) {
ip6_addr_copy(npcb->local_ip.ip6, *ip6_current_dest_addr());
ip6_addr_copy(npcb->remote_ip.ip6, *ip6_current_src_addr());
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_copy(npcb->local_ip.ip4, *ip_current_dest_addr());
ip_addr_copy(npcb->remote_ip.ip4, *ip_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;
@ -497,7 +605,15 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
/* 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));
#if LWIP_IPV6
if (npcb->isipv6) {
npcb->mss = tcp_eff_send_mss_ip6(npcb->mss, &(npcb->local_ip.ip6), &(npcb->remote_ip.ip6));
}
else
#endif /* LWIP_IPV6 */
{
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip.ip4));
}
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
snmp_inc_tcppassiveopens();
@ -539,8 +655,17 @@ 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);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
return ERR_OK;
}
} else if (flags & TCP_FIN) {
@ -637,7 +762,15 @@ tcp_process(struct tcp_pcb *pcb)
pcb->state = ESTABLISHED;
#if TCP_CALCULATE_EFF_SEND_MSS
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
#if LWIP_IPV6
if (pcb->isipv6) {
pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6));
}
else
#endif /* LWIP_IPV6 */
{
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip.ip4));
}
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
/* Set ssthresh again after changing pcb->mss (already set in tcp_connect
@ -673,8 +806,17 @@ 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);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
}
break;
case SYN_RCVD:
@ -716,8 +858,17 @@ 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);
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
else
#endif /* LWIP_IPV6 */
{
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
}
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
@ -1019,6 +1170,13 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->rtime = 0;
pcb->polltmr = 0;
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
if (pcb->isipv6) {
/* 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;
@ -1336,6 +1494,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) {
/* 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);

View File

@ -52,6 +52,9 @@
#include "lwip/inet_chksum.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip6_chksum.h"
#include <string.h>
@ -865,17 +868,34 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
}
#endif
#if LWIP_IPV6
if (pcb->isipv6) {
/* Chksum is mandatory over IPv6 */
tcphdr->chksum = ip6_chksum_pseudo(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6),
IP6_NEXTH_TCP, p->tot_len);
#if LWIP_NETIF_HWADDRHINT
ip6_output_hinted(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
IP6_NEXTH_TCP, &(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip6_output(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
IP6_NEXTH_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
else
#endif /* LWIP_IPV6 */
{
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
IP_PROTO_TCP, p->tot_len);
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4),
IP_PROTO_TCP, p->tot_len);
#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));
ip_output_hinted(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), 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,
IP_PROTO_TCP);
ip_output(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
pbuf_free(p);
return ERR_OK;
@ -1086,12 +1106,30 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
/* 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 LWIP_IPV6
if (pcb->isipv6) {
if (ip6_addr_isany(&(pcb->local_ip.ip6))) {
ip6_addr_t * local_addr6;
netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->remote_ip.ip6));
if (netif == NULL) {
return;
}
/* Select and IPv6 address from the netif. */
local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6));
if (local_addr6 == NULL) {
return;
}
ip6_addr_set(&pcb->local_ip.ip6, local_addr6);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&(pcb->local_ip.ip4))) {
netif = ip_route(&(pcb->remote_ip.ip4));
if (netif == NULL) {
return;
}
ip_addr_copy(pcb->local_ip, netif->ip_addr);
ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr);
}
if (pcb->rttest == 0) {
@ -1112,14 +1150,24 @@ 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;
#if LWIP_IPV6
if (pcb->isipv6) {
chksum_slow = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6),
&(pcb->remote_ip.ip6),
IP6_NEXTH_TCP, seg->p->tot_len);
}
else
#endif /* LWIP_IPV6 */
{
chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4),
&(pcb->remote_ip.ip4),
IP_PROTO_TCP, seg->p->tot_len);
}
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
LWIP_ASSERT("data included but not checksummed",
@ -1127,9 +1175,19 @@ 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);
#if LWIP_IPV6
if (pcb->isipv6) {
acc = ip6_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip6),
&(pcb->remote_ip.ip6),
IP6_NEXTH_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
}
else
#endif /* LWIP_IPV6 */
{
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip4),
&(pcb->remote_ip.ip4),
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
}
/* add payload checksum */
if (seg->chksum_swapped) {
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
@ -1147,20 +1205,46 @@ 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 LWIP_IPV6
if (pcb->isipv6) {
/* Chksum is mandatory in IPv6 */
seg->tcphdr->chksum = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6),
&(pcb->remote_ip.ip6),
IP6_NEXTH_TCP, seg->p->tot_len);
}
else
#endif /* LWIP_IPV6 */
{
#if CHECKSUM_GEN_TCP
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4),
&(pcb->remote_ip.ip4),
IP_PROTO_TCP, seg->p->tot_len);
#endif /* CHECKSUM_GEN_TCP */
}
#endif /* TCP_CHECKSUM_ON_COPY */
TCP_STATS_INC(tcp.xmit);
#if LWIP_IPV6
if (pcb->isipv6) {
#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));
ip6_output_hinted(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
IP6_NEXTH_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);
ip6_output(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
IP6_NEXTH_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
else
#endif /* LWIP_IPV6 */
{
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
IP_PROTO_TCP, &(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
}
/**
@ -1220,6 +1304,65 @@ tcp_rst(u32_t seqno, u32_t ackno,
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
}
#if LWIP_IPV6
/**
* Send a TCP RESET packet (empty segment with RST flag set) over IPv6,
* either to abort a connection or to show that there is no matching local
* connection for a received segment.
*
* Called by tcp_abort() (to abort a local connection), tcp_input() (if no
* matching local pcb was found), tcp_listen_input() (if incoming segment
* has ACK flag set) and tcp_process() (received segment in the wrong state)
*
* Since a RST segment is in most cases not sent for an active connection,
* tcp_rst() has a number of arguments that are taken from a tcp_pcb for
* most other segment output functions.
*
* @param seqno the sequence number to use for the outgoing segment
* @param ackno the acknowledge number to use for the outgoing segment
* @param local_ip6 the local IPv6 address to send the segment from
* @param remote_ip6 the remote IPv6 address to send the segment to
* @param local_port the local TCP port to send the segment from
* @param remote_port the remote TCP port to send the segment to
*/
void
tcp_rst_ip6(u32_t seqno, u32_t ackno,
ip6_addr_t *local_ip6, ip6_addr_t *remote_ip6,
u16_t local_port, u16_t remote_port)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = (struct tcp_hdr *)p->payload;
tcphdr->src = htons(local_port);
tcphdr->dest = htons(remote_port);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
tcphdr->wnd = PP_HTONS(TCP_WND);
tcphdr->chksum = 0;
tcphdr->urgp = 0;
/* chksum us mandatory over IPv6. */
tcphdr->chksum = ip6_chksum_pseudo(p, local_ip6, remote_ip6,
IP6_NEXTH_TCP, p->tot_len);
TCP_STATS_INC(tcp.xmit);
snmp_inc_tcpoutrsts();
/* Send output with hardcoded HL since we have no access to the pcb */
ip6_output(p, local_ip6, remote_ip6, TCP_TTL, 0, IP6_NEXTH_TCP);
pbuf_free(p);
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
}
#endif /* LWIP_IPV6 */
/**
* Requeue all unacked segments for retransmission
*
@ -1351,9 +1494,13 @@ 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 "));
if (!pcb->isipv6) {
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
} else {
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
}
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));
@ -1366,19 +1513,41 @@ tcp_keepalive(struct tcp_pcb *pcb)
}
tcphdr = (struct tcp_hdr *)p->payload;
#if LWIP_IPV6
if (pcb->isipv6) {
tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
IP6_NEXTH_TCP, p->tot_len);
}
else
#endif /* LWIP_IPV6 */
{
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
IP_PROTO_TCP, p->tot_len);
#endif
}
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_IPV6
if (pcb->isipv6) {
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP,
&(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
else
#endif /* LWIP_IPV6 */
{
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
pbuf_free(p);
@ -1404,11 +1573,13 @@ 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 "));
if (!pcb->isipv6) {
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
} else {
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
}
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: tcp_ticks %"U32_F
@ -1445,19 +1616,41 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
}
#if LWIP_IPV6
if (pcb->isipv6) {
tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
IP6_NEXTH_TCP, p->tot_len);
}
else
#endif /* LWIP_IPV6 */
{
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
IP_PROTO_TCP, p->tot_len);
#endif
}
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_IPV6
if (pcb->isipv6) {
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP,
&(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
else
#endif /* LWIP_IPV6 */
{
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP,
&(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
pbuf_free(p);

View File

@ -56,7 +56,9 @@
#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"
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
@ -217,6 +219,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 +289,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 */

View File

@ -55,8 +55,12 @@
#include "lwip/memp.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/ip6_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"
@ -76,7 +80,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,7 +90,6 @@ 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;
@ -95,11 +98,8 @@ udp_input(struct pbuf *p, struct netif *inp)
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 +113,11 @@ udp_input(struct pbuf *p, struct netif *inp)
udphdr = (struct udp_hdr *)p->payload;
/* is broadcast packet ? */
broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);
#if LWIP_IPV6
broadcast = (ip_current_header() != NULL) && 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 +128,19 @@ 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 ("));
if (ip_current_header() != NULL) {
ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr());
} else {
ip6_addr_debug_print(UDP_DEBUG, ip6_current_dest_addr());
}
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
if (ip_current_header() != NULL) {
ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr());
} else {
ip6_addr_debug_print(UDP_DEBUG, ip6_current_src_addr());
}
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
#if LWIP_DHCP
pcb = NULL;
@ -143,8 +153,12 @@ udp_input(struct pbuf *p, struct netif *inp)
/* accept the packe if
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- inp->dhcp->pcb->remote == ANY or iphdr->src */
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {
if (
#if LWIP_IPV6
!pcb->isipv6 &&
#endif /* LWIP_IPV6 */
((ip_addr_isany(&inp->dhcp->pcb->remote_ip.ip4) ||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip.ip4), ip_current_src_addr())))) {
pcb = inp->dhcp->pcb;
}
}
@ -162,25 +176,44 @@ 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 ("));
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip4);
} else {
ip6_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip6);
}
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip4);
} else {
ip6_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip6);
}
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));
/* compare PCB local addr+port to UDP destination addr+port */
if ((pcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IPV6
((pcb->isipv6 &&
(ip6_current_header() != NULL) &&
(ip6_addr_isany(&pcb->local_ip.ip6) ||
#if LWIP_IPV6_MLD
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6_MLD */
ip6_addr_cmp(&pcb->local_ip.ip6, ip6_current_dest_addr()))) ||
(!pcb->isipv6 &&
(ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ip_addr_isany(&pcb->local_ip.ip4)) ||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(&current_iphdr_dest) ||
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
(broadcast && (pcb->so_options & SOF_BROADCAST)))))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))) {
(broadcast))))) {
#endif /* IP_SOF_BROADCAST_RECV */
local_match = 1;
if ((uncon_pcb == NULL) &&
@ -192,8 +225,18 @@ udp_input(struct pbuf *p, struct netif *inp)
/* compare PCB remote addr+port to UDP source addr+port */
if ((local_match != 0) &&
(pcb->remote_port == src) &&
(ip_addr_isany(&pcb->remote_ip) ||
ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {
#if LWIP_IPV6
((pcb->isipv6 &&
(ip6_current_header() != NULL) &&
(ip6_addr_isany(&pcb->remote_ip.ip6) ||
ip6_addr_cmp(&pcb->remote_ip.ip6, ip6_current_src_addr()))) ||
(!pcb->isipv6 &&
(ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((ip_addr_isany(&pcb->remote_ip.ip4) ||
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr())))))) {
/* the first fully matching PCB */
if (prev != NULL) {
/* move the pcb to the front of udp_pcbs so that is
@ -215,10 +258,26 @@ udp_input(struct pbuf *p, struct netif *inp)
}
/* Check checksum if this is a match or if it was directed at us. */
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {
if ((pcb != NULL) ||
#if LWIP_IPV6
((ip6_current_header() != NULL) &&
netif_matches_ip6_addr(inp, ip6_current_dest_addr())) ||
((ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
(
#endif /* LWIP_IPV6 */
ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()))) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
#if LWIP_UDPLITE
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
if (
#if LWIP_IPV6
((ip6_current_header() != NULL) &&
(IP6H_NEXTH(ip6_current_header()) == IP_PROTO_UDPLITE)) ||
((ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
(
#endif /* LWIP_IPV6 */
(IPH_PROTO(iphdr) == IP_PROTO_UDPLITE))) {
/* Do the UDP Lite checksum */
#if CHECKSUM_CHECK_UDP
u16_t chklen = ntohs(udphdr->len);
@ -237,7 +296,22 @@ udp_input(struct pbuf *p, struct netif *inp)
goto end;
}
}
if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
if (ip6_chksum_pseudo_partial(p, ip6_current_src_addr(), ip6_current_dest_addr(),
IP6_NEXTH_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;
}
}
else
#endif /* LWIP_IPV6 */
if (inet_chksum_pseudo_partial(p, ip_current_src_addr(), ip_current_dest_addr(),
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"));
@ -253,6 +327,21 @@ udp_input(struct pbuf *p, struct netif *inp)
{
#if CHECKSUM_CHECK_UDP
if (udphdr->chksum != 0) {
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
IP6_NEXTH_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;
}
}
else
#endif /* LWIP_IPV6 */
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,
@ -277,32 +366,53 @@ udp_input(struct pbuf *p, struct netif *inp)
if (pcb != NULL) {
snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&
if ((broadcast ||
#if LWIP_IPV6
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6 */
ip_addr_ismulticast(ip_current_dest_addr())) &&
((pcb->so_options & SOF_REUSEADDR) != 0)) {
/* 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;
#if LWIP_IPV6
if (ip6_current_header() != NULL) {
hdrs_len = (s16_t)(ip6_current_header_tot_len() + UDP_HLEN);
} else
#endif /* LWIP_IPV6 */
{
hdrs_len = (s16_t)((IPH_HL(ip_current_header()) * 4) + UDP_HLEN);
}
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
if (mpcb != pcb) {
/* compare PCB local addr+port to UDP destination addr+port */
if ((mpcb->local_port == dest) &&
((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IPV6
((mpcb->isipv6 &&
(ip6_addr_ismulticast(ip6_current_dest_addr()) ||
ip6_addr_cmp(&mpcb->local_ip.ip6, ip6_current_dest_addr()))) ||
(!mpcb->isipv6 &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ip_addr_isany(&mpcb->local_ip.ip4)) ||
ip_addr_cmp(&(mpcb->local_ip.ip4), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(&current_iphdr_dest) ||
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
(broadcast && (mpcb->so_options & 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 +420,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 (mpcb->isipv6) {
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 +438,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->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 +462,33 @@ udp_input(struct pbuf *p, struct netif *inp)
} else {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
#if LWIP_ICMP
#if LWIP_ICMP || LWIP_ICMP6
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!broadcast &&
!ip_addr_ismulticast(&current_iphdr_dest)) {
/* 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);
}
#if LWIP_IPV6
!ip6_addr_ismulticast(ip6_current_dest_addr()) &&
#endif /* LWIP_IPV6 */
!ip_addr_ismulticast(ip_current_dest_addr())) {
#if LWIP_IPV6 && LWIP_ICMP6
if (ip6_current_header() != NULL) {
/* move payload pointer back to ip header */
pbuf_header(p, ip6_current_header_tot_len() + UDP_HLEN);
LWIP_ASSERT("p->payload == ip6_current_header()", (p->payload == ip6_current_header()));
icmp6_dest_unreach(p, ICMP6_DUR_PORT);
}
else
#endif /* LWIP_IPV6 && LWIP_ICMP6 */
{
#if LWIP_ICMP
/* move payload pointer back to ip header */
pbuf_header(p, (IPH_HL(ip_current_header()) * 4) + UDP_HLEN);
LWIP_ASSERT("p->payload == ip_current_header()", (p->payload == ip_current_header()));
icmp_dest_unreach(p, ICMP_DUR_PORT);
#endif /* LWIP_ICMP */
}
}
#endif /* LWIP_ICMP || LWIP_ICMP6 */
UDP_STATS_INC(udp.proterr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpnoports();
@ -381,7 +523,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, &pcb->remote_ip.ip4, pcb->remote_port);
}
#if LWIP_CHECKSUM_ON_COPY
@ -392,7 +534,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, &pcb->remote_ip.ip4, pcb->remote_port,
have_chksum, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
@ -433,16 +575,35 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
/* find the outgoing network interface for this packet */
#if LWIP_IPV6
if (pcb->isipv6) {
if (ip6_addr_ismulticast((ip6_addr_t *)dst_ip)) {
/* For multicast, find a netif based on source address. */
netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->local_ip.ip6));
}
else {
netif = ip6_route(&(pcb->local_ip.ip6), (ip6_addr_t *)dst_ip);
}
}
else
#endif /* LWIP_IPV6 */
{
#if LWIP_IGMP
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
#else
netif = ip_route(dst_ip);
netif = ip_route(dst_ip);
#endif /* LWIP_IGMP */
}
/* 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 "));
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip);
} else {
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (ip6_addr_t *)dst_ip);
}
LWIP_DEBUGF(UDP_DEBUG, ("\n"));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
@ -494,7 +655,11 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
#if IP_SOF_BROADCAST
/* broadcast filter? */
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
if ( ((pcb->so_options & SOF_BROADCAST) == 0) &&
#if LWIP_IPV6
!pcb->isipv6 &&
#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 +669,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, &pcb->local_ip.ip4, 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;
@ -544,20 +709,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 &&
ip6_addr_ismulticast((ip6_addr_t*)dst_ip)) ||
#endif /* LWIP_IPV6_MLD */
(!pcb->isipv6 &&
#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) {
if (ip6_addr_isany(&pcb->local_ip.ip6)) {
src_ip =(ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)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, &(pcb->local_ip.ip6)) < 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 = (ip_addr_t *)&(pcb->local_ip.ip6);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(&pcb->local_ip.ip4)) {
/* 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(&(pcb->local_ip.ip4), &(netif->ip_addr))) {
/* local_ip doesn't match, drop the packet */
if (q != p) {
/* free the header pbuf */
@ -568,7 +773,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 = &(pcb->local_ip.ip4);
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
@ -595,31 +800,64 @@ 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 (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#endif /* !LWIP_CHECKSUM_ON_COPY */
#if LWIP_IPV6
/* Checksum is mandatory for IPv6. */
if (pcb->isipv6) {
udphdr->chksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)dst_ip,
IP6_NEXTH_UDPLITE, q->tot_len,
#if !LWIP_CHECKSUM_ON_COPY
chklen);
#else /* !LWIP_CHECKSUM_ON_COPY */
(have_chksum ? UDP_HLEN : chklen));
if (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#endif /* !LWIP_CHECKSUM_ON_COPY */
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) {
udphdr->chksum = 0xffff;
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) {
udphdr->chksum = 0xffff;
}
}
else
#endif /* LWIP_IPV6 */
{
#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 (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#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_IPV6
if (pcb->isipv6) {
err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDPLITE, netif);
}
else
#endif /* LWIP_IPV6 */
{
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*/
@ -629,20 +867,21 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
udphdr->len = htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
#if LWIP_IPV6
/* Checksum is mandatory over IPv6. */
if (pcb->isipv6) {
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,
udpchksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP,
q->tot_len, UDP_HLEN);
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 = ip6_chksum_pseudo(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, q->tot_len);
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
@ -651,14 +890,48 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
}
udphdr->chksum = udpchksum;
}
else
#endif /* LWIP_IPV6 */
{
#if CHECKSUM_GEN_UDP
if ((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);
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);
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udpchksum == 0x0000) {
udpchksum = 0xffff;
}
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_IPV6
if (pcb->isipv6) {
err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDP, netif);
}
else
#endif /* LWIP_IPV6 */
{
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*/
@ -704,7 +977,11 @@ 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);
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr);
} else {
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, (ip6_addr_t *)ipaddr);
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
rebind = 0;
@ -730,9 +1007,20 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
#endif /* SO_REUSE */
if ((ipcb->local_port == port) &&
/* 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))) {
#if LWIP_IPV6
((pcb->isipv6 &&
ipcb->isipv6 &&
(ip6_addr_isany(&(ipcb->local_ip.ip6)) ||
ip6_addr_isany((ip6_addr_t *)ipaddr) ||
ip6_addr_cmp(&(ipcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) ||
(!pcb->isipv6 &&
!ipcb->isipv6 &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
(ip_addr_isany(&(ipcb->local_ip.ip4)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(ipcb->local_ip.ip4), 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));
@ -741,7 +1029,15 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
}
}
ip_addr_set(&pcb->local_ip, ipaddr);
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&pcb->local_ip.ip4, ipaddr);
}
/* no port specified? */
if (port == 0) {
@ -778,11 +1074,13 @@ 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 "));
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip4);
} else {
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip6);
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
return ERR_OK;
}
/**
@ -808,39 +1106,54 @@ 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, &pcb->local_ip.ip4, pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
ip_addr_set(&pcb->remote_ip, ipaddr);
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set(&pcb->remote_ip.ip4, 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)
#endif /* LWIP_IPV6 */
{
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(&pcb->local_ip.ip4) && !ip_addr_isany(&pcb->remote_ip.ip4)) {
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(&(pcb->remote_ip.ip4))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.ip4.addr));
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! */
pcb->local_ip.ip4 = netif->ip_addr;
} else if (ip_addr_isany(&pcb->remote_ip.ip4)) {
pcb->local_ip.ip4.addr = 0;
}
/** 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->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_connect: connected to "));
if (!pcb->isipv6) {
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip4);
} else {
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip6);
}
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) {
@ -864,7 +1177,15 @@ void
udp_disconnect(struct udp_pcb *pcb)
{
/* reset remote address association */
ip_addr_set_any(&pcb->remote_ip);
#if LWIP_IPV6
if (pcb->isipv6) {
ip6_addr_set_any(&pcb->remote_ip.ip6);
}
else
#endif /* LWIP_IPV6 */
{
ip_addr_set_any(&pcb->remote_ip.ip4);
}
pcb->remote_port = 0;
/* mark PCB as unconnected */
pcb->flags &= ~UDP_FLAGS_CONNECTED;
@ -883,7 +1204,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;
}
@ -943,6 +1264,28 @@ 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();
/* could allocate UDP PCB? */
if (pcb != NULL) {
pcb->isipv6 = 1;
}
return pcb;
}
#endif /* LWIP_IPV6 */
#if UDP_DEBUG
/**
* Print UDP header information for debug purposes.

View File

@ -37,6 +37,7 @@
#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"
@ -69,14 +70,29 @@ extern "C" {
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
#if LWIP_IPV6
#define IP_PCB_ISIPV6 u8_t isipv6;
#define IP_PCB_IP6 ip6_addr_t ip6;
#else
#define IP_PCB_ISIPV6
#define IP_PCB_IP6
#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 \
/* ip addresses in network byte order */ \
ip_addr_t local_ip; \
ip_addr_t remote_ip; \
union { \
ip_addr_t ip4; \
IP_PCB_IP6 \
} local_ip; \
union { \
ip_addr_t ip4; \
IP_PCB_IP6 \
} remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \

View File

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

View File

@ -76,20 +76,35 @@ extern "C" {
/* 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)
#define NETCONNTYPE_ISIPV6(t) ((t)&0x08)
#define NETCONNTYPE_ISUDPLITE(t)(((t)&0xF7) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t)(((t)&0xF7) == NETCONN_UDPNOCHKSUM)
/** Protocol family and type of the netconn */
enum netconn_type {
NETCONN_INVALID = 0,
/* NETCONN_TCP Group */
NETCONN_TCP = 0x10,
#if LWIP_IPV6
NETCONN_TCP_IPV6 = 0x18,
#endif /* LWIP_IPV6 */
/* NETCONN_UDP Group */
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM= 0x22,
#if LWIP_IPV6
NETCONN_UDP_IPV6 = 0x28,
NETCONN_UDPLITE_IPV6 = 0x29,
NETCONN_UDPNOCHKSUM_IPV6= 0x2a,
#endif /* LWIP_IPV6 */
/* NETCONN_RAW Group */
NETCONN_RAW = 0x40
#if LWIP_IPV6
,
NETCONN_RAW_IPV6 = 0x48
#endif /* LWIP_IPV6 */
};
/** Current state of the netconn. Non-TCP netconns are always
@ -111,13 +126,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;
@ -235,13 +250,25 @@ err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
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) \
netconn_bind(conn, (ip_addr_t*) ip6addr, port)
#define netconn_connect_ip6(conn, ip6addr, port) \
netconn_connect(conn, (ip_addr_t*) ip6addr, port)
#define netconn_sendto_ip6(conn, buf, ip6addr, port) \
netconn_sendto(conn, buf, (ip_addr_t*) ip6addr, port)
#if LWIP_IPV6_MLD
#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) \
netconn_join_leave_group(conn, (ip_addr_t*)multiaddr, (ip_addr_t*)srcaddr, join_or_leave)
#endif /* LWIP_IPV6_MLD*/
#endif /* LWIP_IPV6 */
#define netconn_err(conn) ((conn)->last_err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)

View File

@ -98,14 +98,14 @@ struct api_msg_msg {
struct {
u8_t shut;
} sd;
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** used for do_join_leave_group */
struct {
ip_addr_t *multiaddr;
ip_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;
@ -154,9 +154,9 @@ 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
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
void do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
void do_gethostbyname(void *arg);

View File

@ -47,7 +47,7 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg),
#if IP_REASSEMBLY
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
#endif /* IP_REASSEMBLY */
#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG
LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
@ -91,6 +91,19 @@ LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE,
LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
#if LWIP_IPV6 && LWIP_ND6_QUEUEING
LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE")
#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */
#if LWIP_IPV6 && LWIP_IPV6_REASS
LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA")
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_MLD
LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP")
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/*
* A list of pools of pbuf's used by LWIP.
*

View File

@ -35,6 +35,7 @@
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -45,9 +46,18 @@ extern "C" {
/** This netbuf includes a checksum */
#define NETBUF_FLAG_CHKSUM 0x02
#if LWIP_IPV6
#define NETBUF_IP6 ip6_addr_t ip6;
#else
#define NETBUF_IP6
#endif /* LWIP_IPV6 */
struct netbuf {
struct pbuf *p, *ptr;
ip_addr_t addr;
union {
ip_addr_t ip4;
NETBUF_IP6
} addr;
u16_t port;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
@ -55,7 +65,10 @@ struct netbuf {
#endif /* LWIP_CHECKSUM_ON_COPY */
u16_t toport_chksum;
#if LWIP_NETBUF_RECVINFO
ip_addr_t toaddr;
union {
ip_addr_t ip4;
NETBUF_IP6
} toaddr;
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
};
@ -81,12 +94,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) (&((buf)->addr.ip4))
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr.ip4), 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) (&((buf)->toaddr.ip4))
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->toaddr.ip4), 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 +107,13 @@ 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) (&((buf)->addr.ip6))
#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set((&(buf)->addr.ip6), fromaddr)
#define netbuf_destaddr_ip6(buf) (&((buf)->toaddr.ip6))
#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set((&(buf)->toaddr.ip6), destaddr)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}
#endif

View File

@ -39,6 +39,7 @@
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
@ -48,6 +49,9 @@ struct dhcp;
#if LWIP_AUTOIP
struct autoip;
#endif
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#ifdef __cplusplus
extern "C" {
@ -117,6 +121,18 @@ typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
*/
typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr);
#if LWIP_IPV6
/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet
* shall be sent. For ethernet netif, set this to 'nd_output' and set
* 'linkoutput'.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (p->payload points to IP header)
* @param ipaddr The IPv6 address to which the packet shall be sent
*/
typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p,
ip6_addr_t *ipaddr);
#endif /* LWIP_IPV6 */
/** Function prototype for netif->linkoutput functions. Only used for ethernet
* netifs. This function is called by ARP when a packet shall be sent.
*
@ -129,6 +145,11 @@ typedef void (*netif_status_callback_fn)(struct netif *netif);
/** Function prototype for netif igmp_mac_filter functions */
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
ip_addr_t *group, u8_t action);
#if LWIP_IPV6 && LWIP_IPV6_MLD
/** Function prototype for netif mld_mac_filter functions */
typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif,
ip6_addr_t *group, u8_t action);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
@ -142,6 +163,13 @@ struct netif {
ip_addr_t netmask;
ip_addr_t gw;
#if LWIP_IPV6
/** Array of IPv6 addresses for this netif. */
ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
/** The state of each IPv6 address (Tentative, Preferred, etc).
* @see ip6_addr.h */
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6 */
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
netif_input_fn input;
@ -153,6 +181,12 @@ struct netif {
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
netif_linkoutput_fn linkoutput;
#if LWIP_IPV6
/** This function is called by the IPv6 module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
netif_output_ip6_fn output_ip6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
/** This function is called when the netif state is set to up or down
*/
@ -174,6 +208,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 +254,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 */
@ -308,6 +359,15 @@ 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 */
#ifdef __cplusplus
}
#endif

View File

@ -1544,6 +1544,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
@ -1557,6 +1592,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 */
@ -1779,6 +1819,231 @@
#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
/*
---------------------------------------
---------- Debugging options ----------
@ -2040,4 +2305,11 @@
#define DNS_DEBUG LWIP_DBG_OFF
#endif
/**
* IP6_DEBUG: Enable debugging for IPv6.
*/
#ifndef IP6_DEBUG
#define IP6_DEBUG LWIP_DBG_ON
#endif
#endif /* __LWIP_OPT_H__ */

View File

@ -45,7 +45,11 @@ extern "C" {
#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
#define PBUF_TRANSPORT_HLEN 20
#if LWIP_IPV6
#define PBUF_IP_HLEN 40
#else
#define PBUF_IP_HLEN 20
#endif
typedef enum {
PBUF_TRANSPORT,

View File

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

View File

@ -42,6 +42,7 @@
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/inet6.h"
#ifdef __cplusplus
extern "C" {
@ -56,10 +57,24 @@ struct sockaddr_in {
char sin_zero[8];
};
#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;
char 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
@ -118,7 +133,13 @@ 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

View File

@ -144,6 +144,21 @@ struct stats_ {
#if SYS_STATS
struct stats_sys sys;
#endif
#if IP6_STATS
struct stats_proto ip6;
#endif
#if ICMP6_STATS
struct stats_proto icmp6;
#endif
#if IP6_FRAG_STATS
struct stats_proto ip6_frag;
#endif
#if MLD6_STATS
struct stats_igmp mld6;
#endif
#if ND6_STATS
struct stats_proto nd6;
#endif
};
extern struct stats_ lwip_stats;
@ -268,6 +283,46 @@ 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_proto(&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);

View File

@ -42,6 +42,8 @@
#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" {
@ -367,6 +369,14 @@ 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, (ip_addr_t *)ip6addr, port)
#define tcp_connect_ip6(pcb, ip6addr, port, connected) \
udp_connect(pcb, (ip_addr_t *)ip6addr, port, connected)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}

View File

@ -43,6 +43,8 @@
#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" {
@ -429,6 +431,11 @@ 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);
#if LWIP_IPV6
void tcp_rst_ip6(u32_t seqno, u32_t ackno,
ip6_addr_t *local_ip6, ip6_addr_t *remote_ip6,
u16_t local_port, u16_t remote_port);
#endif /* LWIP_IPV6 */
u32_t tcp_next_iss(void);
@ -437,6 +444,9 @@ 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);
#if LWIP_IPV6
u16_t tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest);
#endif /* LWIP_IPV6 */
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
#if LWIP_CALLBACK_API

View File

@ -40,6 +40,7 @@
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
@ -87,6 +88,26 @@ struct udp_pcb;
typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip_addr_t *addr, u16_t port);
#if LWIP_IPV6
/** Function prototype for udp pcb IPv6 receive callback functions
* The callback is responsible for freeing the pbuf
* if it's not used any more.
*
* @param arg user supplied argument (udp_pcb.recv_arg)
* @param pcb the udp_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IPv6 address from which the packet was received
* @param port the remote port from which the packet was received
*/
typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ip6_addr_t *addr, u16_t port);
#endif /* LWIP_IPV6 */
#if LWIP_IPV6
#define UDP_PCB_RECV_IP6 udp_recv_ip6_fn ip6;
#else
#define UDP_PCB_RECV_IP6
#endif /* LWIP_IPV6 */
struct udp_pcb {
/* Common members of all PCB types */
@ -111,7 +132,10 @@ struct udp_pcb {
#endif /* LWIP_UDPLITE */
/** receive callback function */
udp_recv_fn recv;
union {
udp_recv_fn ip4;
UDP_PCB_RECV_IP6
}recv;
/** user-supplied argument for the recv callback */
void *recv_arg;
};
@ -156,6 +180,26 @@ void udp_input (struct pbuf *p, struct netif *inp);
#define udp_init() /* Compatibility define, not init needed. */
#if LWIP_IPV6
struct udp_pcb * udp_new_ip6(void);
#define udp_bind_ip6(pcb, ip6addr, port) \
udp_bind(pcb, (ip_addr_t *)ip6addr, port)
#define udp_connect_ip6(pcb, ip6addr, port) \
udp_connect(pcb, (ip_addr_t *)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, (ip_addr_t *)ip6addr, port)
#define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \
udp_sendto_if(pcb, pbuf, (ip_addr_t *)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, (ip_addr_t *)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, (ip_addr_t *)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);
#else

View File

@ -137,6 +137,7 @@ PACK_STRUCT_END
#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 */

View File

@ -55,6 +55,7 @@
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "netif/etharp.h"
#include "lwip/ip6.h"
#if PPPOE_SUPPORT
#include "netif/ppp_oe.h"
@ -1301,6 +1302,19 @@ ethernet_input(struct pbuf *p, struct netif *netif)
break;
#endif /* PPPOE_SUPPORT */
#if LWIP_IPV6
case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
/* skip Ethernet header */
if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
LWIP_ASSERT("Can't move over header in packet", 0);
goto free_and_return;
} else {
/* pass to IPv6 layer */
ip6_input(p, netif);
}
break;
#endif /* LWIP_IPV6 */
default:
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);

View File

@ -51,8 +51,9 @@
#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 +240,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 +307,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]);