++ 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
#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
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);
}
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 */
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;
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. */
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);
}
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;
}
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.
*
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
#include "lwip/tcpip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
+#include "lwip/mld6.h"
#include <string.h>
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;
} 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 */
#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 */
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;
#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);
#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;
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() */
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);
(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",
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);
} 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);
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;
{
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);
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 */
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)) {
/* @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;
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
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)
}
TCPIP_APIMSG_ACK(msg);
}
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
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
#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;
#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 */
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;
{
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);
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);
*/
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);
-
- if (*addrlen > sizeof(sin))
- *addrlen = sizeof(sin);
+ memset(&tempaddr, 0, sizeof(tempaddr));
+
+#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);
+
+ 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, &sin, *addrlen);
+ MEMCPY(addr, &tempaddr, *addrlen);
}
newsock = alloc_socket(newconn, 1);
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);
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) {
/* 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));
}
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);
}
{
struct lwip_sock *sock;
err_t err;
- const struct sockaddr_in *name_in;
sock = get_socket(s);
if (!sock) {
/* 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;
struct pbuf *p;
u16_t buflen, copylen;
int off = 0;
- ip_addr_t *addr;
u16_t port;
u8_t done = 0;
err_t err;
/* 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);
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;
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) ||
/* 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);
+
+ 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, ("lwip_recvfrom(%d): addr=", s));
- ip_addr_debug_print(SOCKETS_DEBUG, addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
-#endif /* SOCKETS_DEBUG */
}
}
/* 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));
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);
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) */
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;
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 */
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 */
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
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 */
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;
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) {
}
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;
}
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;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
- /* get the IP address and port */
- netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
+ /* get the IP address and port */
+ netconn_getaddr(sock->conn, (ip_addr_t *)&naddr6, &sin6.sin6_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));
+ 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));
- sin.sin_port = htons(sin.sin_port);
- inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
+ sin6.sin6_port = htons(sin6.sin6_port);
+ inet6_addr_from_ip6addr(&sin6.sin6_addr, &naddr6);
- if (*namelen > sizeof(sin)) {
- *namelen = sizeof(sin);
+ 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;
}
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;
}
/* 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) {
}
/* 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;
}
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;
}
/* 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) {
}
/* 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) {
/* 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;
#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.
#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();
* 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
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;
}
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
- if (ip_addr_ismulticast(¤t_iphdr_dest)) {
+ if (ip_addr_ismulticast(ip_current_dest_addr())) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
- if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
+ if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */
/**
* 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;
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"));
}
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 */
# 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
* @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;
* @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;
* 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;
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, ¤t_iphdr_dest);
break;
#endif /* LWIP_IGMP */
+/**
+ * @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,
*
* 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 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 */
- if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
+ switch (icmp6hdr->type) {
+ case ICMP6_TYPE_NA: /* Neighbor advertisement */
+ case ICMP6_TYPE_NS: /* Neighbor solicitation */
+ case ICMP6_TYPE_RA: /* Router advertisement */
+ case ICMP6_TYPE_RD: /* Redirect */
+ case ICMP6_TYPE_PTB: /* Packet too big */
+ nd6_input(p, inp);
+ return;
+ break;
+ case ICMP6_TYPE_RS:
+#if LWIP_IPV6_FORWARD
+ /* TODO implement router functionality */
+#endif
+ break;
+#if LWIP_IPV6_MLD
+ case ICMP6_TYPE_MLQ:
+ case ICMP6_TYPE_MLR:
+ case ICMP6_TYPE_MLD:
+ mld6_input(p, inp);
+ return;
+ break;
+#endif
+ case ICMP6_TYPE_EREQ:
+#if !LWIP_MULTICAST_PING
+ /* multicast destination address? */
+ if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
+ /* drop */
+ pbuf_free(p);
+ ICMP6_STATS_INC(icmp6.drop);
+ return;
+ }
+#endif /* LWIP_MULTICAST_PING */
+ /* Allocate reply. */
+ r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
+ if (r == NULL) {
+ /* drop */
pbuf_free(p);
- ICMP_STATS_INC(icmp.lenerr);
+ ICMP6_STATS_INC(icmp6.memerr);
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;*/
+
+ /* Copy echo request. */
+ if (pbuf_copy(r, p) != ERR_OK) {
+ /* drop */
+ pbuf_free(p);
+ pbuf_free(r);
+ ICMP6_STATS_INC(icmp6.err);
+ 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);
+
+ /* 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;
}
- 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);
- /* 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);
+ /* 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);
+
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);
+ icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0);
+}
- /* calculate checksum */
- idur->chksum = 0;
- idur->chksum = inet_chksum(idur, q->len);
- ICMP_STATS_INC(icmp.xmit);
+/**
+ * Send an icmpv6 'packet too big' packet.
+ *
+ * @param p the input packet for which the 'packet too big' should be sent,
+ * p->payload pointing to the IPv6 header
+ * @param mtu the maximum mtu that we can accept
+ */
+void
+icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
+{
+ icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu);
+}
- ip_output(q, NULL,
- (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
- pbuf_free(q);
+/**
+ * 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
-icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
+icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
{
- struct pbuf *q;
- struct ip_hdr *iphdr;
- struct icmp_te_hdr *tehdr;
+ icmp6_send_response(p, ICMP6_TYPE_PP, c, pointer);
+}
- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
+/**
+ * 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 icmp6_hdr *icmp6hdr;
+ ip6_addr_t * reply_src;
- /* @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 */
/**
* @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,
*
* This file is part of the lwIP TCP/IP stack.
*
- * Author: Adam Dunkels <adam@sics.se>
+ * Author: Ivan Delamer <delamer@inicotech.com>
*
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/inet.h"
-
-/* chksum:
*
- * Sums up all 16 bit words in a memory portion. Also includes any odd byte.
- * This function is used by the other checksum functions.
- *
- * For now, this is not optimized. Must be optimized for the particular processor
- * arcitecture on which it is to run. Preferebly coded in assembler.
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
*/
-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;
+#include "lwip/opt.h"
- while (acc >> 16) {
- acc = (acc & 0xffff) + (acc >> 16);
- }
- return ~(acc & 0xffff);
-}
+#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
-/* 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;
+#include "lwip/def.h"
+#include "lwip/inet6.h"
- acc = chksum(dataptr, len);
- sum = (acc & 0xffff) + (acc >> 16);
- sum += (sum >> 16);
- return ~(sum & 0xffff);
-}
+/** @see ip6_addr.c for implementation of functions. */
-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
+ *
+ * IPv6 layer.
+ */
+
/*
- * 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,
*
* This file is part of the lwIP TCP/IP stack.
*
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-
-
-/* ip.c
+ * Author: Ivan Delamer <delamer@inicotech.com>
*
- * This is the code for the IP layer for IPv6.
*
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
*/
#include "lwip/opt.h"
+#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
+
#include "lwip/def.h"
#include "lwip/mem.h"
-#include "lwip/ip.h"
-#include "lwip/inet.h"
#include "lwip/netif.h"
-#include "lwip/icmp.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/ip6_frag.h"
+#include "lwip/icmp6.h"
+#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp_impl.h"
-
+#include "lwip/dhcp6.h"
+#include "lwip/nd6.h"
+#include "lwip/mld6.h"
+#include "lwip/debug.h"
#include "lwip/stats.h"
-#include "arch/perf.h"
-/* ip_init:
+/** Header of the input IPv6 packet currently being processed. */
+const struct ip6_hdr *current_ip6_header;
+/** Total header length of current_ip6_header (i.e. after this, the UDP/TCP header starts) */
+u16_t current_ip6_header_tot_len;
+/** Source IPv6 address of current_header */
+ip6_addr_t current_ip6hdr_src;
+/** Destination IPv6 address of current_header */
+ip6_addr_t current_ip6hdr_dest;
+
+
+
+/**
+ * Finds the appropriate network interface for a given IPv6 address. It tries to select
+ * a netif following a sequence of heuristics:
+ * 1) if there is only 1 netif, return it
+ * 2) if the destination is a link-local address, try to match the src address to a netif.
+ * this is a tricky case because with multiple netifs, link-local addresses only have
+ * meaning within a particular subnet/link.
+ * 3) tries to match the destination subnet to a configured address
+ * 4) tries to find a router
+ * 5) tries to match the source address to the netif
+ * 6) returns the default netif, if configured
*
- * Initializes the IP layer.
+ * @param src the source IPv6 address, if known
+ * @param dest the destination IPv6 address for which to find the route
+ * @return the netif on which to send to reach dest
*/
-
-void
-ip_init(void)
-{
-}
-
-/* ip_route:
- *
- * Finds the appropriate network interface for a given IP address. It searches the
- * list of network interfaces linearly. A match is found if the masked IP address of
- * the network interface equals the masked IP address given to the function.
- */
-
struct netif *
-ip_route(struct ip_addr *dest)
+ip6_route(struct ip6_addr *src, struct ip6_addr *dest)
{
struct netif *netif;
+ s8_t i;
+
+ /* If single netif configuration, fast return. */
+ if ((netif_list != NULL) && (netif_list->next == NULL)) {
+ return netif_list;
+ }
+
+ /* Special processing for link-local addresses. */
+ if (ip6_addr_islinklocal(dest)) {
+ if (ip6_addr_isany(src)) {
+ /* Use default netif. */
+ return netif_default;
+ }
+
+ /* Try to find the netif for the source address. */
+ for(netif = netif_list; netif != NULL; netif = netif->next) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
+ return netif;
+ }
+ }
+ }
+ /* netif not found, use default netif */
+ return netif_default;
+ }
+
+ /* See if the destination subnet matches a configured address. */
for(netif = netif_list; netif != NULL; netif = netif->next) {
- if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
- return netif;
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+ return netif;
+ }
+ }
+ }
+
+ /* Get the netif for a suitable router. */
+ i = nd6_select_router(dest, NULL);
+ if (i >= 0) {
+ if (default_router_list[i].neighbor_entry != NULL) {
+ if (default_router_list[i].neighbor_entry->netif != NULL) {
+ return default_router_list[i].neighbor_entry->netif;
+ }
}
}
+ /* try with the netif that matches the source address. */
+ if (!ip6_addr_isany(src)) {
+ for(netif = netif_list; netif != NULL; netif = netif->next) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
+ return netif;
+ }
+ }
+ }
+ }
+
+ /* no matching netif found, use default netif */
return netif_default;
}
-/* ip_forward:
+/**
+ * Select the best IPv6 source address for a given destination
+ * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior
+ * is assumed.
*
- * Forwards an IP packet. It finds an appropriate route for the packet, decrements
- * the TTL value of the packet, adjusts the checksum and outputs the packet on the
- * appropriate interface.
+ * @param netif the netif on which to send a packet
+ * @param dest the destination we are trying to reach
+ * @return the most suitable source address to use, or NULL if no suitable
+ * source address is found
*/
+ip6_addr_t *
+ip6_select_source_address(struct netif *netif, ip6_addr_t * dest)
+{
+ ip6_addr_t * src = NULL;
+ u8_t i;
+
+ /* If dest is link-local, choose a link-local source. */
+ if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
+ return netif_ip6_addr(netif, i);
+ }
+ }
+ }
+
+ /* Choose a site-local with matching prefix. */
+ if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_issitelocal(netif_ip6_addr(netif, i)) &&
+ ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+ return netif_ip6_addr(netif, i);
+ }
+ }
+ }
+ /* Choose a unique-local with matching prefix. */
+ if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) &&
+ ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+ return netif_ip6_addr(netif, i);
+ }
+ }
+ }
+
+ /* Choose a global with best matching prefix. */
+ if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) {
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_isglobal(netif_ip6_addr(netif, i))) {
+ if (src == NULL) {
+ src = netif_ip6_addr(netif, i);
+ }
+ else {
+ /* Replace src only if we find a prefix match. */
+ /* TODO find longest matching prefix. */
+ if ((!(ip6_addr_netcmp(src, dest))) &&
+ ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) {
+ src = netif_ip6_addr(netif, i);
+ }
+ }
+ }
+ }
+ if (src != NULL) {
+ return src;
+ }
+ }
+
+ return NULL;
+}
+
+#if LWIP_IPV6_FORWARD
+/**
+ * Forwards an IPv6 packet. It finds an appropriate route for the
+ * packet, decrements the HL value of the packet, and outputs
+ * the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IPv6 header of the input packet
+ * @param inp the netif on which this packet was received
+ */
static void
-ip_forward(struct pbuf *p, struct ip_hdr *iphdr)
+ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
- PERF_START;
-
- if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {
-
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));
-#if IP_DEBUG
- ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-#endif /* IP_DEBUG */
- LWIP_DEBUGF(IP_DEBUG, ("\n"));
- pbuf_free(p);
+ /* do not forward link-local addresses */
+ if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
+ IP6_STATS_INC(ip6.rterr);
+ IP6_STATS_INC(ip6.drop);
return;
}
- /* Decrement TTL and send ICMP if ttl == 0. */
- if (--iphdr->hoplim == 0) {
-#if LWIP_ICMP
+
+ /* Find network interface where to forward this IP packet to. */
+ netif = ip6_route(IP6_ADDR_ANY, ip6_current_dest_addr());
+ if (netif == NULL) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+ IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
+#if LWIP_ICMP6
/* Don't send ICMP messages in response to ICMP messages */
- if (iphdr->nexthdr != IP_PROTO_ICMP) {
- icmp_time_exceeded(p, ICMP_TE_TTL);
+ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
+ icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
}
-#endif /* LWIP_ICMP */
- pbuf_free(p);
+#endif /* LWIP_ICMP6 */
+ IP6_STATS_INC(ip6.rterr);
+ IP6_STATS_INC(ip6.drop);
+ return;
+ }
+ /* Do not forward packets onto the same network interface on which
+ * they arrived. */
+ if (netif == inp) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n"));
+ IP6_STATS_INC(ip6.rterr);
+ IP6_STATS_INC(ip6.drop);
return;
}
- /* Incremental update of the IP checksum. */
- /* if (iphdr->chksum >= htons(0xffff - 0x100)) {
- iphdr->chksum += htons(0x100) + 1;
- } else {
- iphdr->chksum += htons(0x100);
- }*/
-
-
- LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));
-#if IP_DEBUG
- ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-#endif /* IP_DEBUG */
- LWIP_DEBUGF(IP_DEBUG, ("\n"));
-
- IP_STATS_INC(ip.fw);
- IP_STATS_INC(ip.xmit);
-
- PERF_STOP("ip_forward");
+ /* decrement HL */
+ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1);
+ /* send ICMP6 if HL == 0 */
+ if (IP6H_HOPLIM(iphdr) == 0) {
+#if LWIP_ICMP6
+ /* Don't send ICMP messages in response to ICMP messages */
+ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
+ icmp6_time_exceeded(p, ICMP6_TE_HL);
+ }
+#endif /* LWIP_ICMP6 */
+ IP6_STATS_INC(ip6.drop);
+ return;
+ }
- netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+ IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
+ IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
+
+ /* transmit pbuf on chosen interface */
+ netif->output_ip6(netif, p, ip6_current_dest_addr());
+ IP6_STATS_INC(ip6.fw);
+ IP6_STATS_INC(ip6.xmit);
+ return;
}
+#endif /* LWIP_IPV6_FORWARD */
-/* ip_input:
- *
- * This function is called by the network interface device driver when an IP packet is
- * received. The function does the basic checks of the IP header such as packet size
- * being at least larger than the header size etc. If the packet was not destined for
- * us, the packet is forwarded (using ip_forward). The IP checksum is always checked.
+
+/**
+ * This function is called by the network interface device driver when
+ * an IPv6 packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip6_forward).
*
* Finally, the packet is sent to the upper layer protocol input function.
+ *
+ * @param p the received IPv6 packet (p->payload points to IPv6 header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ * processed, but currently always returns ERR_OK)
*/
-
-void
-ip_input(struct pbuf *p, struct netif *inp) {
- struct ip_hdr *iphdr;
+err_t
+ip6_input(struct pbuf *p, struct netif *inp)
+{
+ struct ip6_hdr *ip6hdr;
struct netif *netif;
+ u8_t nexth;
+ u16_t hlen; /* the current header length */
+ u8_t i;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+ int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
-
- PERF_START;
-
-#if IP_DEBUG
- ip_debug_print(p);
-#endif /* IP_DEBUG */
-
-
- IP_STATS_INC(ip.recv);
+ IP6_STATS_INC(ip6.recv);
/* identify the IP header */
- iphdr = p->payload;
-
+ ip6hdr = (struct ip6_hdr *)p->payload;
+ if (IP6H_V(ip6hdr) != 6) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U16_F"\n",
+ IP6H_V(ip6hdr)));
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.err);
+ IP6_STATS_INC(ip6.drop);
+ return ERR_OK;
+ }
- if (iphdr->v != 6) {
- LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
-#if IP_DEBUG
- ip_debug_print(p);
-#endif /* IP_DEBUG */
+ /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+ if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) {
+ if (IP6_HLEN > p->len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+ IP6_HLEN, p->len));
+ }
+ if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+ IP6H_PLEN(ip6hdr) + IP6_HLEN, p->tot_len));
+ }
+ /* free (drop) packet pbufs */
pbuf_free(p);
- IP_STATS_INC(ip.err);
- IP_STATS_INC(ip.drop);
- return;
+ IP6_STATS_INC(ip6.lenerr);
+ IP6_STATS_INC(ip6.drop);
+ return ERR_OK;
}
- /* is this packet for us? */
- for(netif = netif_list; netif != NULL; netif = netif->next) {
-#if IP_DEBUG
- LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
- ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
- LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));
- ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
- LWIP_DEBUGF(IP_DEBUG, ("\n"));
-#endif /* IP_DEBUG */
- if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {
- break;
+ /* Trim pbuf. This should have been done at the netif layer,
+ * but we'll do it anyway just to be sure that its done. */
+ pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr));
+
+ /* copy IP addresses to aligned ip6_addr_t */
+ ip6_addr_copy(current_ip6hdr_dest, ip6hdr->dest);
+ ip6_addr_copy(current_ip6hdr_src, ip6hdr->src);
+
+ /* current header pointer. */
+ current_ip6_header = ip6hdr;
+
+ /* match packet against an interface, i.e. is this packet for us? */
+ if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
+ /* Always joined to multicast if-local and link-local all-nodes group. */
+ if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) ||
+ ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) {
+ netif = inp;
+ }
+#if LWIP_IPV6_MLD
+ else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) {
+ netif = inp;
+ }
+#else /* LWIP_IPV6_MLD */
+ else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) {
+ /* Accept all solicited node packets when MLD is not enabled
+ * (for Neighbor discovery). */
+ netif = inp;
+ }
+#endif /* LWIP_IPV6_MLD */
+ else {
+ netif = NULL;
}
}
+ else {
+ /* start trying with inp. if that's not acceptable, start walking the
+ list of configured netifs.
+ 'first' is used as a boolean to mark whether we started walking the list */
+ int first = 1;
+ netif = inp;
+ do {
+ /* interface is up? */
+ if (netif_is_up(netif)) {
+ /* unicast to this interface address? address configured? */
+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+ ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) {
+ /* exit outer loop */
+ goto netif_found;
+ }
+ }
+ }
+ if (first) {
+ first = 0;
+ netif = netif_list;
+ } else {
+ netif = netif->next;
+ }
+ if (netif == inp) {
+ netif = netif->next;
+ }
+ } while(netif != NULL);
+netif_found:
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n",
+ netif->name[0], netif->name[1]));
+ }
+ /* "::" packet source address? (used in duplicate address detection) */
+ if (ip6_addr_isany(ip6_current_src_addr()) &&
+ (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) {
+ /* packet source is not valid */
+ /* free (drop) packet pbufs */
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n"));
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.drop);
+ goto ip6_input_cleanup;
+ }
+ /* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
-#if IP_FORWARD
- ip_forward(p, iphdr);
-#endif
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n"));
+#if LWIP_IPV6_FORWARD
+ /* non-multicast packet? */
+ if (!ip6_addr_ismulticast(ip6_current_dest_addr())) {
+ /* try to forward IP packet on (other) interfaces */
+ ip6_forward(p, ip6hdr, inp);
+ }
+#endif /* LWIP_IPV6_FORWARD */
pbuf_free(p);
- return;
+ goto ip6_input_cleanup;
}
- pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));
+ /* current netif pointer. */
+ current_netif = inp;
+
+ /* Save next header type. */
+ nexth = IP6H_NEXTH(ip6hdr);
+
+ /* Init header length. */
+ hlen = current_ip6_header_tot_len = IP6_HLEN;
+
+ /* Move to payload. */
+ pbuf_header(p, -IP6_HLEN);
+
+ /* Process known option extension headers, if present. */
+ while (nexth != IP6_NEXTH_NONE)
+ {
+ switch (nexth) {
+ case IP6_NEXTH_HOPBYHOP:
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n"));
+ /* Get next header type. */
+ nexth = *((u8_t *)p->payload);
+
+ /* Get the header length. */
+ hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+ current_ip6_header_tot_len += hlen;
+
+ /* Skip over this header. */
+ if (hlen > p->len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+ hlen, p->len));
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.lenerr);
+ IP6_STATS_INC(ip6.drop);
+ goto ip6_input_cleanup;
+ }
+
+ pbuf_header(p, -hlen);
+ break;
+ case IP6_NEXTH_DESTOPTS:
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n"));
+ /* Get next header type. */
+ nexth = *((u8_t *)p->payload);
+
+ /* Get the header length. */
+ hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+ current_ip6_header_tot_len += hlen;
+
+ /* Skip over this header. */
+ if (hlen > p->len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+ hlen, p->len));
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.lenerr);
+ IP6_STATS_INC(ip6.drop);
+ goto ip6_input_cleanup;
+ }
+
+ pbuf_header(p, -hlen);
+ break;
+ case IP6_NEXTH_ROUTING:
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n"));
+ /* Get next header type. */
+ nexth = *((u8_t *)p->payload);
+
+ /* Get the header length. */
+ hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+ current_ip6_header_tot_len += hlen;
+
+ /* Skip over this header. */
+ if (hlen > p->len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+ hlen, p->len));
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.lenerr);
+ IP6_STATS_INC(ip6.drop);
+ goto ip6_input_cleanup;
+ }
+
+ pbuf_header(p, -hlen);
+ break;
- /* send to upper layers */
-#if IP_DEBUG
- /* LWIP_DEBUGF("ip_input: \n");
- ip_debug_print(p);
- LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
-#endif /* IP_DEBUG */
-
- if(pbuf_header(p, -IP_HLEN)) {
- LWIP_ASSERT("Can't move over header in packet", 0);
- return;
+ case IP6_NEXTH_FRAGMENT:
+ {
+ struct ip6_frag_hdr * frag_hdr;
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n"));
+
+ frag_hdr = (struct ip6_frag_hdr *)p->payload;
+
+ /* Get next header type. */
+ nexth = frag_hdr->_nexth;
+
+ /* Fragment Header length. */
+ hlen = 8;
+ current_ip6_header_tot_len += hlen;
+
+ /* Make sure this header fits in current pbuf. */
+ if (hlen > p->len) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+ ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+ hlen, p->len));
+ /* free (drop) packet pbufs */
+ pbuf_free(p);
+ IP6_FRAG_STATS_INC(ip6_frag.lenerr);
+ IP6_FRAG_STATS_INC(ip6_frag.drop);
+ goto ip6_input_cleanup;
+ }
+
+ /* Offset == 0 and more_fragments == 0? */
+ if (((frag_hdr->_fragment_offset & IP6_FRAG_OFFSET_MASK) == 0) &&
+ ((frag_hdr->_fragment_offset & IP6_FRAG_MORE_FLAG) == 0)) {
+
+ /* This is a 1-fragment packet, usually a packet that we have
+ * already reassembled. Skip this header anc continue. */
+ pbuf_header(p, -hlen);
+ }
+ else {
+#if LWIP_IPV6_REASS
+
+ /* reassemble the packet */
+ p = ip6_reass(p);
+ /* packet not fully reassembled yet? */
+ if (p == NULL) {
+ goto ip6_input_cleanup;
+ }
+
+ /* Returned p point to IPv6 header.
+ * Update all our variables and pointers and continue. */
+ ip6hdr = (struct ip6_hdr *)p->payload;
+ nexth = IP6H_NEXTH(ip6hdr);
+ hlen = current_ip6_header_tot_len = IP6_HLEN;
+ pbuf_header(p, -IP6_HLEN);
+
+#else /* LWIP_IPV6_REASS */
+ /* free (drop) packet pbufs */
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n"));
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.opterr);
+ IP6_STATS_INC(ip6.drop);
+ goto ip6_input_cleanup;
+#endif /* LWIP_IPV6_REASS */
+ }
+ break;
+ }
+ default:
+ goto options_done;
+ break;
+ }
}
+options_done:
+
+ /* p points to IPv6 header again. */
+ pbuf_header(p, current_ip6_header_tot_len);
- switch (iphdr->nexthdr) {
- case IP_PROTO_UDP:
- udp_input(p, inp);
- break;
- case IP_PROTO_TCP:
- tcp_input(p, inp);
- break;
-#if LWIP_ICMP
- case IP_PROTO_ICMP:
- icmp_input(p, inp);
- break;
+ /* send to upper layers */
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));
+ ip6_debug_print(p);
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+#if LWIP_RAW
+ /* raw input did not eat the packet? */
+ if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+ {
+ switch (nexth) {
+ case IP6_NEXTH_NONE:
+ pbuf_free(p);
+ break;
+#if LWIP_UDP
+ case IP6_NEXTH_UDP:
+#if LWIP_UDPLITE
+ case IP6_NEXTH_UDPLITE:
+#endif /* LWIP_UDPLITE */
+ /* Point to payload. */
+ pbuf_header(p, -current_ip6_header_tot_len);
+ udp_input(p, inp);
+ break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+ case IP6_NEXTH_TCP:
+ /* Point to payload. */
+ pbuf_header(p, -current_ip6_header_tot_len);
+ tcp_input(p, inp);
+ break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP6
+ case IP6_NEXTH_ICMP6:
+ /* Point to payload. */
+ pbuf_header(p, -current_ip6_header_tot_len);
+ icmp6_input(p, inp);
+ break;
#endif /* LWIP_ICMP */
- default:
-#if LWIP_ICMP
- /* send ICMP destination protocol unreachable */
- icmp_dest_unreach(p, ICMP_DUR_PROTO);
+ default:
+#if LWIP_ICMP6
+ /* send ICMP parameter problem unless it was a multicast or ICMPv6 */
+ if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) &&
+ (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) {
+ icmp6_param_problem(p, ICMP6_PP_HEADER, current_ip6_header_tot_len - hlen);
+ }
#endif /* LWIP_ICMP */
- pbuf_free(p);
- LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n",
- iphdr->nexthdr));
-
- IP_STATS_INC(ip.proterr);
- IP_STATS_INC(ip.drop);
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr)));
+ pbuf_free(p);
+ IP6_STATS_INC(ip6.proterr);
+ IP6_STATS_INC(ip6.drop);
+ break;
+ }
}
- PERF_STOP("ip_input");
+
+ip6_input_cleanup:
+ current_netif = NULL;
+ current_ip6_header = NULL;
+ current_ip6_header_tot_len = 0;
+ ip6_addr_set_any(¤t_ip6hdr_src);
+ ip6_addr_set_any(¤t_ip6hdr_dest);
+
+ return ERR_OK;
}
-/* ip_output_if:
+/**
+ * Sends an IPv6 packet on a network interface. This function constructs
+ * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is
+ * used as source (usually during network startup). If the source IPv6 address it
+ * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network
+ * interface is filled in as source address. If the destination IPv6 address is
+ * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points
+ * to it instead of the data.
*
- * Sends an IP packet on a network interface. This function constructs the IP header
- * and calculates the IP header checksum. If the source IP address is NULL,
- * the IP address of the outgoing network interface is filled in as source address.
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an
+ IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ * IP address of the netif is selected and used as source address.
+ * if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ * ERR_BUF if p doesn't have enough space for IPv6/LINK headers
+ * returns errors returned by netif->output
*/
-
err_t
-ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
- u8_t ttl,
- u8_t proto, struct netif *netif)
+ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+ u8_t hl, u8_t tc,
+ u8_t nexth, struct netif *netif)
{
- struct ip_hdr *iphdr;
-
- PERF_START;
-
- LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));
- if (pbuf_header(p, IP_HLEN)) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
- IP_STATS_INC(ip.err);
-
- return ERR_BUF;
- }
- LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));
+ struct ip6_hdr *ip6hdr;
+ ip6_addr_t dest_addr;
+
+ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ /* Should the IPv6 header be generated or is it already included in p? */
+ if (dest != IP6_HDRINCL) {
+ /* generate IPv6 header */
+ if (pbuf_header(p, IP6_HLEN)) {
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n"));
+ IP6_STATS_INC(ip6.err);
+ return ERR_BUF;
+ }
- iphdr = p->payload;
+ ip6hdr = (struct ip6_hdr *)p->payload;
+ LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr",
+ (p->len >= sizeof(struct ip6_hdr)));
+ IP6H_HOPLIM_SET(ip6hdr, hl);
+ IP6H_NEXTH_SET(ip6hdr, nexth);
- if (dest != IP_HDRINCL) {
- LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n"));
- iphdr->hoplim = ttl;
- iphdr->nexthdr = proto;
- iphdr->len = htons(p->tot_len - IP_HLEN);
- ip_addr_set(&(iphdr->dest), dest);
+ /* dest cannot be NULL here */
+ ip6_addr_copy(ip6hdr->dest, *dest);
- iphdr->v = 6;
+ IP6H_VTCFL_SET(ip6hdr, 6, tc, 0);
+ IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN);
- if (ip_addr_isany(src)) {
- ip_addr_set(&(iphdr->src), &(netif->ip_addr));
- } else {
- ip_addr_set(&(iphdr->src), src);
+ if (src == NULL) {
+ src = IP6_ADDR_ANY;
+ }
+ else if (ip6_addr_isany(src)) {
+ src = ip6_select_source_address(netif, dest);
+ if ((src == NULL) || ip6_addr_isany(src)) {
+ /* No appropriate source address was found for this packet. */
+ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n"));
+ IP6_STATS_INC(ip6.rterr);
+ return ERR_RTE;
+ }
}
+ /* src cannot be NULL here */
+ ip6_addr_copy(ip6hdr->src, *src);
} else {
- dest = &(iphdr->dest);
+ /* IP header already included in p */
+ ip6hdr = (struct ip6_hdr *)p->payload;
+ ip6_addr_copy(dest_addr, ip6hdr->dest);
+ dest = &dest_addr;
}
- IP_STATS_INC(ip.xmit);
-
- LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len));
-#if IP_DEBUG
- ip_debug_print(p);
-#endif /* IP_DEBUG */
+ IP6_STATS_INC(ip6.xmit);
+
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+ ip6_debug_print(p);
+
+#if ENABLE_LOOPBACK
+ /* TODO implement loopback for v6
+ if (ip6_addr_cmp(dest, netif_ip6_addr(0))) {
+ return netif_loop_output(netif, p, dest);
+ }*/
+#endif /* ENABLE_LOOPBACK */
+#if LWIP_IPV6_FRAG
+ /* don't fragment if interface has mtu set to 0 [loopif] */
+ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) {
+ return ip6_frag(p, netif, dest);
+ }
+#endif /* LWIP_IPV6_FRAG */
- PERF_STOP("ip_output_if");
- return netif->output(netif, p, dest);
+ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()"));
+ return netif->output_ip6(netif, p, dest);
}
-/* ip_output:
+/**
+ * Simple interface to ip6_output_if. It finds the outgoing network
+ * interface and calls upon ip6_output_if to do the actual work.
*
- * Simple interface to ip_output_if. It finds the outgoing network interface and
- * calls upon ip_output_if to do the actual work.
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an
+ IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ * IP address of the netif is selected and used as source address.
+ * if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
+ *
+ * @return ERR_RTE if no route is found
+ * see ip_output_if() for more return values
*/
-
err_t
-ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
- u8_t ttl, u8_t proto)
+ip6_output(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+ u8_t hl, u8_t tc, u8_t nexth)
{
struct netif *netif;
- if ((netif = ip_route(dest)) == NULL) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
- IP_STATS_INC(ip.rterr);
+
+ /* pbufs passed to IPv6 must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ if ((netif = ip6_route(src, dest)) == NULL) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+ IP6_ADDR_BLOCK1(dest),
+ IP6_ADDR_BLOCK2(dest),
+ IP6_ADDR_BLOCK3(dest),
+ IP6_ADDR_BLOCK4(dest),
+ IP6_ADDR_BLOCK5(dest),
+ IP6_ADDR_BLOCK6(dest),
+ IP6_ADDR_BLOCK7(dest),
+ IP6_ADDR_BLOCK8(dest)));
+ IP6_STATS_INC(ip6.rterr);
return ERR_RTE;
}
- return ip_output_if (p, src, dest, ttl, proto, netif);
+ return ip6_output_if(p, src, dest, hl, tc, nexth, netif);
}
+
#if LWIP_NETIF_HWADDRHINT
+/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ * before calling ip6_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+ protocol header; if dest == IP_HDRINCL, p already includes an
+ IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ * IP address of the netif is selected and used as source address.
+ * if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ * calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ * see ip_output_if() for more return values
+ */
err_t
-ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
- u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+ u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint)
{
struct netif *netif;
err_t err;
- if ((netif = ip_route(dest)) == NULL) {
- LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
- IP_STATS_INC(ip.rterr);
+ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+ gets altered as the packet is passed down the stack */
+ LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+ if ((netif = ip6_route(src, dest)) == NULL) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+ IP6_ADDR_BLOCK1(dest),
+ IP6_ADDR_BLOCK2(dest),
+ IP6_ADDR_BLOCK3(dest),
+ IP6_ADDR_BLOCK4(dest),
+ IP6_ADDR_BLOCK5(dest),
+ IP6_ADDR_BLOCK6(dest),
+ IP6_ADDR_BLOCK7(dest),
+ IP6_ADDR_BLOCK8(dest)));
+ IP6_STATS_INC(ip6.rterr);
return ERR_RTE;
}
netif->addr_hint = addr_hint;
- err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
+ err = ip6_output_if(p, src, dest, hl, tc, nexth, netif);
netif->addr_hint = NULL;
return err;
}
#endif /* LWIP_NETIF_HWADDRHINT*/
-#if IP_DEBUG
+#if LWIP_IPV6_MLD
+/**
+ * Add a hop-by-hop options header with a router alert option and padding.
+ *
+ * Used by MLD when sending a Multicast listener report/done message.
+ *
+ * @param p the packet to which we will prepend the options header
+ * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6)
+ * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD)
+ * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise
+ */
+err_t
+ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value)
+{
+ struct ip6_hbh_hdr * hbh_hdr;
+
+ /* Move pointer to make room for hop-by-hop options header. */
+ if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) {
+ LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n"));
+ IP6_STATS_INC(ip6.err);
+ return ERR_BUF;
+ }
+
+ hbh_hdr = (struct ip6_hbh_hdr *)p->payload;
+
+ /* Set fields. */
+ hbh_hdr->_nexth = nexth;
+ hbh_hdr->_hlen = 0;
+ hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION;
+ hbh_hdr->_ra_opt_dlen = 2;
+ hbh_hdr->_ra_opt_data = value;
+ hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION;
+ hbh_hdr->_padn_opt_dlen = 0;
+
+ return ERR_OK;
+}
+#endif /* LWIP_IPV6_MLD */
+
+#if IP6_DEBUG
+/* Print an IPv6 header by using LWIP_DEBUGF
+ * @param p an IPv6 packet, p->payload pointing to the IPv6 header
+ */
void
-ip_debug_print(struct pbuf *p)
+ip6_debug_print(struct pbuf *p)
{
- struct ip_hdr *iphdr = p->payload;
-
- LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" | %"X16_F"%"X16_F" | %"X16_F"%"X16_F" | (v, traffic class, flow label)\n",
- iphdr->v,
- iphdr->tclass1, iphdr->tclass2,
- iphdr->flow1, iphdr->flow2));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" | %2"U16_F" | %2"U16_F" | (len, nexthdr, hoplim)\n",
- ntohs(iphdr->len),
- iphdr->nexthdr,
- iphdr->hoplim));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n",
- (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff,
- ntohl(iphdr->src.addr[0]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n",
- (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff,
- ntohl(iphdr->src.addr[1]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n",
- (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff,
- ntohl(iphdr->src.addr[2]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n",
- (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff,
- ntohl(iphdr->src.addr[3]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n",
- (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff,
- ntohl(iphdr->dest.addr[0]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n",
- (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff,
- ntohl(iphdr->dest.addr[1]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n",
- (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff,
- ntohl(iphdr->dest.addr[2]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n",
- (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff,
- ntohl(iphdr->dest.addr[3]) & 0xffff));
- LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
+
+ LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n"));
+ LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n",
+ IP6H_V(ip6hdr),
+ IP6H_TC(ip6hdr),
+ IP6H_FL(ip6hdr)));
+ LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n",
+ ntohs(IP6H_PLEN(ip6hdr)),
+ ntohs(IP6H_NEXTH(ip6hdr)),
+ ntohs(IP6H_HOPLIM(ip6hdr))));
+ LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n",
+ IP6_ADDR_BLOCK1(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK2(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK3(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK4(&(ip6hdr->src))));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n",
+ IP6_ADDR_BLOCK5(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK6(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK7(&(ip6hdr->src)),
+ IP6_ADDR_BLOCK8(&(ip6hdr->src))));
+ LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n",
+ IP6_ADDR_BLOCK1(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK2(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK3(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK4(&(ip6hdr->dest))));
+ LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n",
+ IP6_ADDR_BLOCK5(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK6(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK7(&(ip6hdr->dest)),
+ IP6_ADDR_BLOCK8(&(ip6hdr->dest))));
+ LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
}
-#endif /* IP_DEBUG */
+#endif /* IP6_DEBUG */
+
+#endif /* LWIP_IPV6 */
+/**
+ * @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,
*
* 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)
-{
- 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]));
-
-}
+#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 } };
-u8_t
-ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
+#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] == addr2->addr[0] &&
- addr1->addr[1] == addr2->addr[1] &&
- addr1->addr[2] == addr2->addr[2] &&
- addr1->addr[3] == addr2->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;
+
}
-void
-ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
+/**
+ * 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)
{
- 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];*/
+ static char str[40];
+ return ip6addr_ntoa_r(addr, str, 40);
}
-u8_t
-ip_addr_isany(struct ip_addr *addr)
+/**
+ * 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)
{
- if (addr == NULL) return 1;
- return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
+ u32_t current_block_index, current_block_value;
+ s32_t zero_flag, i;
+
+ i = 0;
+ zero_flag = 0; /* used to indicate a zero chain for "::' */
+
+ for (current_block_index = 0; current_block_index < 8; current_block_index++) {
+ /* get the current 16-bit block */
+ current_block_value = htonl(addr->addr[current_block_index >> 1]);
+ if ((current_block_index & 0x1) == 0) {
+ current_block_value = current_block_value >> 16;
+ }
+ current_block_value &= 0xffff;
+
+ if (current_block_value == 0) {
+ /* generate empty block "::" */
+ if (!zero_flag) {
+ if (current_block_index > 0) {
+ zero_flag = 1;
+ buf[i++] = ':';
+ if (i >= buflen) return NULL;
+ }
+ }
+ }
+ else {
+ if (current_block_index > 0) {
+ buf[i++] = ':';
+ if (i >= buflen) return NULL;
+ }
+
+ if ((current_block_value & 0xf000) == 0) {
+ zero_flag = 1;
+ }
+ else {
+ buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
+ 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 */
#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>
#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"
#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)
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);
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 */
/* 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 */
#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;
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);
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 */
}
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);
}
}
}
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 */
+
}
}
}
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);
}
}
#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 */
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
#include <string.h>
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;
/* 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), ¤t_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(¤t_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;
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;
}
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;
}
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;
}
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 */
}
}
+#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)));
}
#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*/
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);
}
/**
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 */
#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>
/* 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);
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 */
} 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 */
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);
}
}
((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);
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;
}
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);
}
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;
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;
}
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;
(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;
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;
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.
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);
}
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*
#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;
* 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
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);
}
/* Don't even process incoming broadcasts/multicasts. */
- if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) ||
- ip_addr_ismulticast(¤t_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();
}
#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) {
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. */
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
if (pcb->remote_port == tcphdr->src &&
- pcb->local_port == tcphdr->dest &&
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
+ pcb->local_port == tcphdr->dest &&
+ ((
+#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
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
if (pcb->remote_port == tcphdr->src &&
- pcb->local_port == tcphdr->dest &&
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
- ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
+ pcb->local_port == tcphdr->dest &&
+ ((
+#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. */
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if (lpcb->local_port == tcphdr->dest) {
#if SO_REUSE
- if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) {
- /* found an exact match */
- break;
- } else if(ip_addr_isany(&(lpcb->local_ip))) {
- /* 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), ¤t_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 */
}
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);
}
/* 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
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;
/* 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();
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) {
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
/* 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:
}
} 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 */
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;
/* 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);
#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>
}
#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;
/* 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) {
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",
}
/* 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);
#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*/
+ }
}
/**
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
*
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));
}
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);
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
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);
#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;
}
#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)
{
#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 */
#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"
* 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.
*
*/
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;
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));
udphdr = (struct udp_hdr *)p->payload;
/* is broadcast packet ? */
- broadcast = ip_addr_isbroadcast(¤t_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));
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;
/* accept the packe if
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- inp->dhcp->pcb->remote == ANY or iphdr->src */
- if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
- ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) {
+ 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;
}
}
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), ¤t_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(¤t_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) &&
/* compare PCB remote addr+port to UDP source addr+port */
if ((local_match != 0) &&
(pcb->remote_port == src) &&
- (ip_addr_isany(&pcb->remote_ip) ||
- ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) {
+#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
}
/* Check checksum if this is a match or if it was directed at us. */
- if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) {
+ if ((pcb != NULL) ||
+#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);
goto end;
}
}
- if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_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"));
{
#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,
if (pcb != NULL) {
snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
- if ((broadcast || ip_addr_ismulticast(¤t_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), ¤t_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(¤t_iphdr_dest) ||
+ ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
- (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
+ (broadcast && (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);
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);
+ }
}
}
}
}
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);
} else {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
-#if LWIP_ICMP
+#if LWIP_ICMP || LWIP_ICMP6
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!broadcast &&
- !ip_addr_ismulticast(¤t_iphdr_dest)) {
- /* 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();
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
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 */
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;
}
#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;
/* 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;
/* 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 */
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));
}
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*/
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' */
}
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*/
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;
#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));
}
}
- 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) {
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;
}
/**
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 ((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 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.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) {
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;
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;
}
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.
#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"
#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 */ \
/** 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);
/* 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
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;
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)
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;
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);
#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 */
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.
*
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
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
#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 */
};
#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
(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
#include "lwip/err.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#if LWIP_AUTOIP
struct autoip;
#endif
+#if LWIP_IPV6_DHCP6
+#include "lwip/dhcp6.h"
+#endif /* LWIP_IPV6_DHCP6 */
#ifdef __cplusplus
extern "C" {
*/
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.
*
/** 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
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;
* 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
*/
/** 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;
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 */
#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
#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
#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 */
#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 ----------
#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__ */
#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,
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
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;
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;
};
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. */
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
+#include "lwip/inet6.h"
#ifdef __cplusplus
extern "C" {
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
#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
#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;
#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);
#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" {
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
}
#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" {
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);
#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
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
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 */
#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;
};
#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
#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 */
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "netif/etharp.h"
+#include "lwip/ip6.h"
#if PPPOE_SUPPORT
#include "netif/ppp_oe.h"
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);
#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"
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
+ case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
* 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]);