From 4bfbe7ebeb807d7d1029df4952576474951ccf43 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 17 May 2011 19:35:14 +0000 Subject: [PATCH 001/151] ... and finally, we got a first working version of a dual-stack lwIP runnin IPv4 and IPv6 in parallel - big thanks to Ivan Delamer! (this is work in progress, so please beware, test a lot and report problems!) --- CHANGELOG | 4 + src/api/api_lib.c | 30 +- src/api/api_msg.c | 175 ++++- src/api/netbuf.c | 12 +- src/api/sockets.c | 454 +++++++++---- src/core/init.c | 10 + src/core/ipv4/icmp.c | 11 +- src/core/ipv4/igmp.c | 10 +- src/core/ipv4/inet_chksum.c | 7 +- src/core/ipv4/ip.c | 4 + src/core/ipv6/icmp6.c | 338 +++++++--- src/core/ipv6/inet6.c | 134 +--- src/core/ipv6/ip6.c | 1105 +++++++++++++++++++++++-------- src/core/ipv6/ip6_addr.c | 231 ++++++- src/core/memp.c | 3 + src/core/netif.c | 117 +++- src/core/raw.c | 195 +++++- src/core/tcp.c | 240 ++++++- src/core/tcp_in.c | 249 +++++-- src/core/tcp_out.c | 277 ++++++-- src/core/timers.c | 61 +- src/core/udp.c | 583 ++++++++++++---- src/include/ipv4/lwip/ip.h | 20 +- src/include/ipv4/lwip/ip_frag.h | 3 + src/include/lwip/api.h | 39 +- src/include/lwip/api_msg.h | 8 +- src/include/lwip/memp_std.h | 15 +- src/include/lwip/netbuf.h | 32 +- src/include/lwip/netif.h | 62 +- src/include/lwip/opt.h | 272 ++++++++ src/include/lwip/pbuf.h | 4 + src/include/lwip/raw.h | 35 +- src/include/lwip/sockets.h | 23 +- src/include/lwip/stats.h | 55 ++ src/include/lwip/tcp.h | 10 + src/include/lwip/tcp_impl.h | 10 + src/include/lwip/udp.h | 46 +- src/include/netif/etharp.h | 1 + src/netif/etharp.c | 14 + src/netif/ethernetif.c | 9 +- 40 files changed, 3930 insertions(+), 978 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 29518303..f23128ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) + * nearly the whole stack: Finally, we got decent IPv6 support, big thanks to + Ivan! (this is work in progress: we're just post release anyway :-) + 2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage) * tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static memory message diff --git a/src/api/api_lib.c b/src/api/api_lib.c index b1a9e525..bc7507b7 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -372,7 +372,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_SO_RCVTIMEO*/ #if LWIP_TCP - if (conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { if (!netconn_get_noautorecved(conn) || (buf == NULL)) { /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here @@ -434,7 +434,7 @@ err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) { LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && - netconn_type(conn) == NETCONN_TCP, return ERR_ARG;); + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); return netconn_recv_data(conn, (void **)new_buf); } @@ -461,7 +461,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); #if LWIP_TCP - if (conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { struct pbuf *p = NULL; /* This is not a listening netconn, since recvmbox is set */ @@ -481,7 +481,11 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) buf->p = p; buf->ptr = p; buf->port = 0; - ip_addr_set_any(&buf->addr); +#if LWIP_IPV6 + ip6_addr_set_any(&buf->addr.ip6); +#else /* LWIP_IPV6 */ + ip_addr_set_any(&buf->addr.ip4); +#endif /* LWIP_IPV6 */ *new_buf = buf; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; @@ -508,7 +512,7 @@ void netconn_recved(struct netconn *conn, u32_t length) { #if LWIP_TCP - if ((conn != NULL) && (conn->type == NETCONN_TCP) && + if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (netconn_get_noautorecved(conn))) { struct api_msg msg; /* Let the stack know that we have taken the data. */ @@ -540,7 +544,15 @@ err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) { if (buf != NULL) { - ip_addr_set(&buf->addr, addr); +#if LWIP_IPV6 + if (conn->pcb.ip->isipv6) { + ip6_addr_set(&buf->addr.ip6, (ip6_addr_t *)addr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&buf->addr.ip4, addr); + } buf->port = port; return netconn_send(conn, buf); } @@ -591,7 +603,7 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl err_t err; LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); - LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); + LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); if (size == 0) { return ERR_OK; } @@ -664,7 +676,7 @@ netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); } -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** * Join multicast groups for UDP netconns. * @@ -696,7 +708,7 @@ netconn_join_leave_group(struct netconn *conn, NETCONN_SET_SAFE_ERR(conn, err); return err; } -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 448f96dd..6f6ffc4d 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -51,6 +51,7 @@ #include "lwip/tcpip.h" #include "lwip/igmp.h" #include "lwip/dns.h" +#include "lwip/mld6.h" #include @@ -112,7 +113,15 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->p = q; buf->ptr = q; - ip_addr_copy(buf->addr, *ip_current_src_addr()); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_copy(buf->addr.ip6, *ip6_current_src_addr()); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_copy(buf->addr.ip4, *ip_current_src_addr()); + } buf->port = pcb->protocol; len = q->tot_len; @@ -175,9 +184,30 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, } else { buf->p = p; buf->ptr = p; - ip_addr_set(&buf->addr, addr); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + ip6_addr_set(&buf->addr.ip6, (ip6_addr_t *)addr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&buf->addr.ip4, addr); + } buf->port = port; #if LWIP_NETBUF_RECVINFO +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + /* get the UDP header - always in the first pbuf, ensured by udp_input */ + const struct udp_hdr* udphdr = (void*)(((char*)ip6_current_header()) + + ip6_current_header_tot_len()); +#if LWIP_CHECKSUM_ON_COPY + buf->flags = NETBUF_FLAG_DESTADDR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + ip6_addr_set(&buf->toaddr.ip6, ip6_current_dest_addr()); + buf->toport_chksum = udphdr->dest; + } + else +#endif /* LWIP_IPV6 */ { const struct ip_hdr* iphdr = ip_current_header(); /* get the UDP header - always in the first pbuf, ensured by udp_input */ @@ -185,7 +215,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, #if LWIP_CHECKSUM_ON_COPY buf->flags = NETBUF_FLAG_DESTADDR; #endif /* LWIP_CHECKSUM_ON_COPY */ - ip_addr_set(&buf->toaddr, ip_current_dest_addr()); + ip_addr_set(&buf->toaddr.ip4, ip_current_dest_addr()); buf->toport_chksum = udphdr->dest; } #endif /* LWIP_NETBUF_RECVINFO */ @@ -487,7 +517,15 @@ pcb_new(struct api_msg_msg *msg) switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + msg->conn->pcb.raw = raw_new_ip6(msg->msg.n.proto); + } + else +#endif /* LWIP_IPV6 */ + { + msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + } if(msg->conn->pcb.raw == NULL) { msg->err = ERR_MEM; break; @@ -497,17 +535,25 @@ pcb_new(struct api_msg_msg *msg) #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + msg->conn->pcb.udp = udp_new_ip6(); + } + else +#endif /* LWIP_IPV6 */ + { + msg->conn->pcb.udp = udp_new(); + } if(msg->conn->pcb.udp == NULL) { msg->err = ERR_MEM; break; } #if LWIP_UDPLITE - if (msg->conn->type==NETCONN_UDPLITE) { + if (NETCONNTYPE_ISUDPLITE((msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); } #endif /* LWIP_UDPLITE */ - if (msg->conn->type==NETCONN_UDPNOCHKSUM) { + if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); } udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); @@ -515,7 +561,15 @@ pcb_new(struct api_msg_msg *msg) #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + msg->conn->pcb.tcp = tcp_new_ip6(); + } + else +#endif /* LWIP_IPV6 */ + { + msg->conn->pcb.tcp = tcp_new(); + } if(msg->conn->pcb.tcp == NULL) { msg->err = ERR_MEM; break; @@ -680,7 +734,7 @@ netconn_drain(struct netconn *conn) if (sys_mbox_valid(&conn->recvmbox)) { while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { #if LWIP_TCP - if (conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { if(mem != NULL) { p = (struct pbuf*)mem; /* pcb might be set to NULL already by err_tcp() */ @@ -738,7 +792,7 @@ do_close_internal(struct netconn *conn) u8_t shut, shut_rx, shut_tx, close; LWIP_ASSERT("invalid conn", (conn != NULL)); - LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); + LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); @@ -824,7 +878,7 @@ do_delconn(struct api_msg_msg *msg) (msg->conn->state != NETCONN_LISTEN) && (msg->conn->state != NETCONN_CONNECT)) { /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else { LWIP_ASSERT("blocking connect in progress", @@ -942,7 +996,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err) if (conn->current_msg != NULL) { conn->current_msg->err = err; } - if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { + if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { setup_tcp(conn); } was_blocking = !IN_NONBLOCKING_CONNECT(conn); @@ -1056,7 +1110,7 @@ do_listen(struct api_msg_msg *msg) } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { if (msg->conn->state == NETCONN_NONE) { #if TCP_LISTEN_BACKLOG struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); @@ -1113,29 +1167,62 @@ do_send(struct api_msg_msg *msg) switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - if (ip_addr_isany(&msg->msg.b->addr)) { +#if LWIP_IPV6 + if (msg->conn->pcb.ip->isipv6) { + if (ip6_addr_isany(&msg->msg.b->addr.ip6)) { + msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); + } else { + msg->err = raw_sendto_ip6(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr.ip6); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&msg->msg.b->addr.ip4)) { msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { - msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); + msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr.ip4); } break; #endif #if LWIP_UDP case NETCONN_UDP: #if LWIP_CHECKSUM_ON_COPY - if (ip_addr_isany(&msg->msg.b->addr)) { +#if LWIP_IPV6 + if (msg->conn->pcb.ip->isipv6) { + if (ip6_addr_isany(&msg->msg.b->addr.ip6)) { + msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } else { + msg->err = udp_sendto_chksum_ip6(msg->conn->pcb.udp, msg->msg.b->p, + &msg->msg.b->addr.ip6, msg->msg.b->port, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&msg->msg.b->addr.ip4)) { msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } else { msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, - &msg->msg.b->addr, msg->msg.b->port, + &msg->msg.b->addr.ip4, msg->msg.b->port, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } #else /* LWIP_CHECKSUM_ON_COPY */ - if (ip_addr_isany(&msg->msg.b->addr)) { +#if LWIP_IPV6 + if (msg->conn->pcb.ip->isipv6) { + if (ip6_addr_isany(&msg->msg.b->addr.ip6)) { + msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); + } else { + msg->err = udp_sendto_ip6(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr.ip6, msg->msg.b->port); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&msg->msg.b->addr.ip4)) { msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); } else { - msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); + msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr.ip4, msg->msg.b->port); } #endif /* LWIP_CHECKSUM_ON_COPY */ break; @@ -1160,7 +1247,7 @@ do_recv(struct api_msg_msg *msg) { msg->err = ERR_OK; if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { #if TCP_LISTEN_BACKLOG if (msg->conn->pcb.tcp->state == LISTEN) { tcp_accepted(msg->conn->pcb.tcp); @@ -1315,7 +1402,7 @@ do_write(struct api_msg_msg *msg) if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { - if (msg->conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { #if LWIP_TCP if (msg->conn->state != NETCONN_NONE) { /* netconn is connecting, closing or in blocking write */ @@ -1368,8 +1455,20 @@ void do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { - *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : - msg->conn->pcb.ip->remote_ip); +#if LWIP_IPV6 + if (msg->conn->pcb.ip->isipv6) { + if (msg->msg.ad.local) { + ip6_addr_set((ip6_addr_t *)msg->msg.ad.ipaddr, &(msg->conn->pcb.ip->local_ip.ip6)); + } else { + ip6_addr_set((ip6_addr_t *)msg->msg.ad.ipaddr, &(msg->conn->pcb.ip->remote_ip.ip6)); + } + } + else +#endif /* LWIP_IPV6 */ + { + *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip.ip4 : + msg->conn->pcb.ip->remote_ip.ip4); + } msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { @@ -1424,9 +1523,9 @@ do_close(struct api_msg_msg *msg) /* @todo: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; - } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { + } else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) { if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { /* LISTEN doesn't support half shutdown */ msg->err = ERR_CONN; @@ -1451,7 +1550,7 @@ do_close(struct api_msg_msg *msg) sys_sem_signal(&msg->conn->op_completed); } -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** * Join multicast groups for UDP netconns. * Called from netconn_join_leave_group @@ -1467,10 +1566,24 @@ do_join_leave_group(struct api_msg_msg *msg) if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP - if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); - } else { - msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); +#if LWIP_IPV6 && LWIP_IPV6_MLD + if (msg->conn->pcb.udp->isipv6) { + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = mld6_joingroup((ip6_addr_t *)msg->msg.jl.netif_addr, (ip6_addr_t *)msg->msg.jl.multiaddr); + } else { + msg->err = mld6_leavegroup((ip6_addr_t *)msg->msg.jl.netif_addr, (ip6_addr_t *)msg->msg.jl.multiaddr); + } + } + else +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + { +#if LWIP_IGMP + if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { + msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); + } else { + msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); + } +#endif /* LWIP_IGMP */ } #endif /* LWIP_UDP */ #if (LWIP_TCP || LWIP_RAW) @@ -1484,7 +1597,7 @@ do_join_leave_group(struct api_msg_msg *msg) } TCPIP_APIMSG_ACK(msg); } -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** diff --git a/src/api/netbuf.c b/src/api/netbuf.c index 9390c9ee..0aded3af 100644 --- a/src/api/netbuf.c +++ b/src/api/netbuf.c @@ -61,7 +61,11 @@ netbuf *netbuf_new(void) if (buf != NULL) { buf->p = NULL; buf->ptr = NULL; - ip_addr_set_any(&buf->addr); +#if LWIP_IPV6 + ip6_addr_set_any(&buf->addr.ip6); +#else /* LWIP_IPV6 */ + ip_addr_set_any(&buf->addr.ip4); +#endif /* LWIP_IPV6 */ buf->port = 0; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY @@ -69,7 +73,11 @@ netbuf *netbuf_new(void) #endif /* LWIP_CHECKSUM_ON_COPY */ buf->toport_chksum = 0; #if LWIP_NETBUF_RECVINFO - ip_addr_set_any(&buf->toaddr); +#if LWIP_IPV6 + ip6_addr_set_any(&buf->toaddr.ip6); +#else /* LWIP_IPV6 */ + ip_addr_set_any(&buf->toaddr.ip4); +#endif /* LWIP_IPV6 */ #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ return buf; diff --git a/src/api/sockets.c b/src/api/sockets.c index e36012ce..ba035de5 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -58,6 +58,16 @@ #include +/* Check that the family member of a struct sockaddr matches the socket's IP version */ +#if LWIP_IPV6 +#define SOCK_ADDR_MATCH(name, sock) \ + ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ + (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) +#else /* LWIP_IPV6 */ +#define SOCK_ADDR_MATCH(name, sock) (((name)->sa_family) == AF_INET) +#endif /* LWIP_IPV6 */ + + #define NUM_SOCKETS MEMP_NUM_NETCONN /** Contains all internal pointers and states used for a socket */ @@ -259,7 +269,7 @@ alloc_socket(struct netconn *newconn, int accepted) sockets[i].rcvevent = 0; /* TCP sendbuf is empty, but the socket is not yet writable until connected * (unless it has been created by accept()). */ - sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); + sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); sockets[i].errevent = 0; sockets[i].err = 0; sockets[i].select_waiting = 0; @@ -313,10 +323,19 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct lwip_sock *sock, *nsock; struct netconn *newconn; - ip_addr_t naddr; + union { + ip_addr_t ip4; +#if LWIP_IPV6 + ip6_addr_t ip6; +#endif /* LWIP_IPV6 */ + } naddr; u16_t port; int newsock; - struct sockaddr_in sin; + struct sockaddr tempaddr; + struct sockaddr_in * sin; +#if LWIP_IPV6 + struct sockaddr_in6 * sin6; +#endif /* LWIP_IPV6 */ err_t err; SYS_ARCH_DECL_PROTECT(lev); @@ -344,7 +363,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) netconn_set_noautorecved(newconn, 1); /* get the IP address and port of the remote host */ - err = netconn_peer(newconn, &naddr, &port); + err = netconn_peer(newconn, &naddr.ip4, &port); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); netconn_delete(newconn); @@ -357,16 +376,34 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) */ if (NULL != addr) { LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + memset(&tempaddr, 0, sizeof(tempaddr)); - if (*addrlen > sizeof(sin)) - *addrlen = sizeof(sin); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(newconn->type)) { + sin6 = (struct sockaddr_in6 *)&tempaddr; + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + sin6->sin6_flowinfo = 0; + inet6_addr_from_ip6addr(&sin6->sin6_addr, &naddr.ip6); - MEMCPY(addr, &sin, *addrlen); + if (*addrlen > sin6->sin6_len) + *addrlen = sin6->sin6_len; + } + else +#endif /* LWIP_IPV6 */ + { + sin = (struct sockaddr_in *)&tempaddr; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + inet_addr_from_ipaddr(&sin->sin_addr, &naddr.ip4); + + if (*addrlen > sin->sin_len) + *addrlen = sin->sin_len; + } + + MEMCPY(addr, &tempaddr, *addrlen); } newsock = alloc_socket(newconn, 1); @@ -390,7 +427,15 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) SYS_ARCH_UNPROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); - ip_addr_debug_print(SOCKETS_DEBUG, &naddr); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(newconn->type)) { + ip6_addr_debug_print(SOCKETS_DEBUG, &naddr.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_debug_print(SOCKETS_DEBUG, &naddr.ip4); + } LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); sock_set_errno(sock, 0); @@ -401,10 +446,18 @@ int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_sock *sock; - ip_addr_t local_addr; + union { + ip_addr_t ip4; +#if LWIP_IPV6 + ip6_addr_t ip6; +#endif /* LWIP_IPV6 */ + } local_addr; u16_t local_port; err_t err; const struct sockaddr_in *name_in; +#if LWIP_IPV6 + const struct sockaddr_in6 *name_in6; +#endif /* LWIP_IPV6 */ sock = get_socket(s); if (!sock) { @@ -413,18 +466,33 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + SOCK_ADDR_MATCH(name, sock) && + ((((mem_ptr_t)name) % 4) == 0)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - name_in = (const struct sockaddr_in *)(void*)name; - - inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); - local_port = name_in->sin_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); +#if LWIP_IPV6 + if ((name->sa_family) == AF_INET6) { + name_in6 = (const struct sockaddr_in6 *)(void*)name; + + inet6_addr_to_ip6addr(&local_addr.ip6, &name_in6->sin6_addr); + ip6_addr_debug_print(SOCKETS_DEBUG, &local_addr.ip6); + + local_port = name_in6->sin6_port; + } + else +#endif /* LWIP_IPV6 */ + { + name_in = (const struct sockaddr_in *)(void*)name; + + inet_addr_to_ipaddr(&local_addr.ip4, &name_in->sin_addr); + ip_addr_debug_print(SOCKETS_DEBUG, &local_addr.ip4); + + local_port = name_in->sin_port; + } LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); - err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); + err = netconn_bind(sock->conn, &local_addr.ip4, ntohs(local_port)); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); @@ -451,7 +519,7 @@ lwip_close(int s) } if(sock->conn != NULL) { - is_tcp = netconn_type(sock->conn) == NETCONN_TCP; + is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; } else { LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); } @@ -468,7 +536,6 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_sock *sock; err_t err; - const struct sockaddr_in *name_in; sock = get_socket(s); if (!sock) { @@ -477,17 +544,38 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), + SOCK_ADDR_MATCH(name, sock) && + ((((mem_ptr_t)name) % 4) == 0)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - name_in = (const struct sockaddr_in *)(void*)name; - - if (name_in->sin_family == AF_UNSPEC) { + if (name->sa_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); - } else { + } +#if LWIP_IPV6 + else if (name->sa_family == AF_INET6) { + const struct sockaddr_in6 *name_in6; + ip6_addr_t remote_addr; + u16_t remote_port; + + name_in6 = (const struct sockaddr_in6 *)(void*)name; + + inet6_addr_to_ip6addr(&remote_addr, &name_in6->sin6_addr); + remote_port = name_in6->sin6_port; + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); + ip6_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); + + err = netconn_connect(sock->conn, (ip_addr_t *)&remote_addr, ntohs(remote_port)); + } +#endif /* LWIP_IPV6 */ + else { + const struct sockaddr_in *name_in; ip_addr_t remote_addr; u16_t remote_port; + name_in = (const struct sockaddr_in *)(void*)name; + inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); remote_port = name_in->sin_port; @@ -554,7 +642,6 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, struct pbuf *p; u16_t buflen, copylen; int off = 0; - ip_addr_t *addr; u16_t port; u8_t done = 0; err_t err; @@ -588,7 +675,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, /* No data was left from the previous operation, so we try to get some from the network. */ - if (netconn_type(sock->conn) == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); } else { err = netconn_recv(sock->conn, (struct netbuf **)&buf); @@ -618,7 +705,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, sock->lastdata = buf; } - if (netconn_type(sock->conn) == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { p = (struct pbuf *)buf; } else { p = ((struct netbuf *)buf)->p; @@ -641,7 +728,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, off += copylen; - if (netconn_type(sock->conn) == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); len -= copylen; if ( (len <= 0) || @@ -656,47 +743,69 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, /* Check to see from where the data was.*/ if (done) { - ip_addr_t fromaddr; - if (from && fromlen) { - struct sockaddr_in sin; - - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = &fromaddr; - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr((struct netbuf *)buf); - port = netbuf_fromport((struct netbuf *)buf); - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - inet_addr_from_ipaddr(&sin.sin_addr, addr); - - if (*fromlen > sizeof(sin)) { - *fromlen = sizeof(sin); - } - - MEMCPY(from, &sin, *fromlen); - +#if !SOCKETS_DEBUG + if (from && fromlen) +#endif /* !SOCKETS_DEBUG */ + { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); - } else { -#if SOCKETS_DEBUG - if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = &fromaddr; - netconn_getaddr(sock->conn, addr, &port, 0); - } else { - addr = netbuf_fromaddr((struct netbuf *)buf); - port = netbuf_fromport((struct netbuf *)buf); - } +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn))) { + ip6_addr_t *fromaddr6; + ip6_addr_t tmpaddr6; + struct sockaddr_in6 sin6; + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + /* @todo: implement netconn_getaddr() for IPv6 addresses */ + ip6_addr_set_any(&tmpaddr6); + fromaddr6 = &tmpaddr6; + port = 0; + } else { + fromaddr6 = netbuf_fromaddr_ip6((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); + } + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); + inet6_addr_from_ip6addr(&sin6.sin6_addr, fromaddr6); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, addr); + if (from && fromlen) { + if (*fromlen > sizeof(sin6)) { + *fromlen = sizeof(sin6); + } + MEMCPY(from, &sin6, *fromlen); + } + + ip6_addr_debug_print(SOCKETS_DEBUG, fromaddr6); + } else +#endif /* LWIP_IPV6 */ + { + ip_addr_t *fromaddr4; + ip_addr_t tmpaddr4; + struct sockaddr_in sin; + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + fromaddr4 = &tmpaddr4; + netconn_getaddr(sock->conn, fromaddr4, &port, 0); + } else { + fromaddr4 = netbuf_fromaddr((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + inet_addr_from_ipaddr(&sin.sin_addr, fromaddr4); + + if (from && fromlen) { + if (*fromlen > sizeof(sin)) { + *fromlen = sizeof(sin); + } + MEMCPY(from, &sin, *fromlen); + } + + ip_addr_debug_print(SOCKETS_DEBUG, &fromaddr4); + } LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); -#endif /* SOCKETS_DEBUG */ } } @@ -705,7 +814,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, /* If this is a TCP socket, check if there is data left in the buffer. If so, it should be saved in the sock structure for next time around. */ - if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { + if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { sock->lastdata = buf; sock->lastoffset += copylen; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); @@ -713,7 +822,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, sock->lastdata = NULL; sock->lastoffset = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); - if (netconn_type(sock->conn) == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { pbuf_free((struct pbuf *)buf); } else { netbuf_delete((struct netbuf *)buf); @@ -757,7 +866,7 @@ lwip_send(int s, const void *data, size_t size, int flags) return -1; } - if (sock->conn->type != NETCONN_TCP) { + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) return lwip_sendto(s, data, size, flags, NULL, 0); #else /* (LWIP_UDP || LWIP_RAW) */ @@ -791,7 +900,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags, struct lwip_sock *sock; err_t err; u16_t short_size; - const struct sockaddr_in *to_in; u16_t remote_port; #if !LWIP_TCPIP_CORE_LOCKING struct netbuf buf; @@ -802,7 +910,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, return -1; } - if (sock->conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) { #if LWIP_TCP return lwip_send(s, data, size, flags); #else /* LWIP_TCP */ @@ -817,22 +925,25 @@ lwip_sendto(int s, const void *data, size_t size, int flags, short_size = (u16_t)size; LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || ((tolen == sizeof(struct sockaddr_in)) && - ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), + SOCK_ADDR_MATCH(to, sock) && + ((((mem_ptr_t)to) % 4) == 0))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); - to_in = (const struct sockaddr_in *)(void*)to; #if LWIP_TCPIP_CORE_LOCKING /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ { struct pbuf* p; ip_addr_t *remote_addr; +#if LWIP_IPV6 + ip6_addr_t *remote_addr6; +#endif /* LWIP_IPV6 */ #if LWIP_NETIF_TX_SINGLE_PBUF p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); if (p != NULL) { #if LWIP_CHECKSUM_ON_COPY u16_t chksum = 0; - if (sock->conn->type != NETCONN_RAW) { + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) { chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); } else #endif /* LWIP_CHECKSUM_ON_COPY */ @@ -843,20 +954,39 @@ lwip_sendto(int s, const void *data, size_t size, int flags, p->payload = (void*)data; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - if (to_in != NULL) { - inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); - remote_port = ntohs(to_in->sin_port); + if (to != NULL) { +#if LWIP_IPV6 + if (to->sa_family == AF_INET6) { + const struct sockaddr_in6 *to_in6; + to_in6 = (const struct sockaddr_in6 *)(void*)to; + inet6_addr_to_ip6addr_p(remote_addr6, &to_in6->sin6_addr); + remote_addr = (ip_addr_t *)remote_addr6; + remote_port = ntohs(to_in6->sin6_port); + } + else +#endif /* LWIP_IPV6 */ + { + const struct sockaddr_in *to_in; + to_in = (const struct sockaddr_in *)(void*)to; + inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + } } else { - remote_addr = &sock->conn->pcb.raw->remote_ip; - if (sock->conn->type == NETCONN_RAW) { - remote_port = 0; - } else { - remote_port = sock->conn->pcb.udp->remote_port; + remote_addr = IP_ADDR_ANY; +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(sock->conn->type)) { + remote_addr6 = IP6_ADDR_ANY; + remote_addr = (ip_addr_t *)remote_addr6; + } + else +#endif /* LWIP_IPV6 */ + { + remote_addr = IP_ADDR_ANY; } } LOCK_TCPIP_CORE(); - if (sock->conn->type == NETCONN_RAW) { + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) { err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); } else { #if LWIP_UDP @@ -885,18 +1015,48 @@ lwip_sendto(int s, const void *data, size_t size, int flags, buf.flags = 0; #endif /* LWIP_CHECKSUM_ON_COPY */ if (to) { - inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); - remote_port = ntohs(to_in->sin_port); +#if LWIP_IPV6 + if ((to->sa_family) == AF_INET6) { + const struct sockaddr_in6 *to_in6; + to_in6 = (const struct sockaddr_in6 *)(void*)to; + inet6_addr_to_ip6addr(&buf.addr.ip6, &to_in6->sin6_addr); + remote_port = ntohs(to_in6->sin6_port); + } + else +#endif /* LWIP_IPV6 */ + { + const struct sockaddr_in *to_in; + to_in = (const struct sockaddr_in *)(void*)to; + inet_addr_to_ipaddr(&buf.addr.ip4, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + } netbuf_fromport(&buf) = remote_port; } else { - remote_port = 0; - ip_addr_set_any(&buf.addr); + remote_port = 0; +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(sock->conn->type)) { + ip6_addr_set_any(&buf.addr.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set_any(&buf.addr.ip4); + } netbuf_fromport(&buf) = 0; } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", s, data, short_size, flags)); - ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(sock->conn->type)) { + ip6_addr_debug_print(SOCKETS_DEBUG, &buf.addr.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr.ip4); + } LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); /* make the buffer point to the data that should be sent */ @@ -906,7 +1066,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, err = ERR_MEM; } else { #if LWIP_CHECKSUM_ON_COPY - if (sock->conn->type != NETCONN_RAW) { + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) { u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); netbuf_set_chksum(&buf, chksum); err = ERR_OK; @@ -937,23 +1097,41 @@ lwip_socket(int domain, int type, int protocol) struct netconn *conn; int i; +#if !LWIP_IPV6 LWIP_UNUSED_ARG(domain); +#endif /* LWIP_IPV6 */ /* create a netconn */ switch (type) { case SOCK_RAW: +#if LWIP_IPV6 + conn = netconn_new_with_proto_and_callback((domain == AF_INET) ? NETCONN_RAW : NETCONN_RAW_IPV6, + (u8_t)protocol, event_callback); +#else /* LWIP_IPV6 */ conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); +#endif /* LWIP_IPV6 */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_DGRAM: +#if LWIP_IPV6 + conn = netconn_new_with_callback((domain == AF_INET) ? + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP) : + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE_IPV6 : NETCONN_UDP_IPV6) , + event_callback); +#else /* LWIP_IPV6 */ conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP, event_callback); +#endif /* LWIP_IPV6 */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_STREAM: +#if LWIP_IPV6 + conn = netconn_new_with_callback((domain == AF_INET) ? NETCONN_TCP : NETCONN_TCP_IPV6, event_callback); +#else /* LWIP_IPV6 */ conn = netconn_new_with_callback(NETCONN_TCP, event_callback); +#endif /* LWIP_IPV6 */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); if (conn != NULL) { @@ -1365,7 +1543,7 @@ lwip_shutdown(int s, int how) } if (sock->conn != NULL) { - if (netconn_type(sock->conn) != NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { sock_set_errno(sock, EOPNOTSUPP); return EOPNOTSUPP; } @@ -1395,33 +1573,63 @@ static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; - struct sockaddr_in sin; - ip_addr_t naddr; sock = get_socket(s); if (!sock) { return -1; } - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; +#if LWIP_IPV6 + if (NETCONNTYPE_ISIPV6(sock->conn->type)) { + struct sockaddr_in6 sin6; + ip6_addr_t naddr6; - /* get the IP address and port */ - netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &naddr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); + /* get the IP address and port */ + netconn_getaddr(sock->conn, (ip_addr_t *)&naddr6, &sin6.sin6_port, local); - sin.sin_port = htons(sin.sin_port); - inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip6_addr_debug_print(SOCKETS_DEBUG, &naddr6); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin6.sin6_port)); - if (*namelen > sizeof(sin)) { - *namelen = sizeof(sin); + sin6.sin6_port = htons(sin6.sin6_port); + inet6_addr_from_ip6addr(&sin6.sin6_addr, &naddr6); + + if (*namelen > sizeof(sin6)) { + *namelen = sizeof(sin6); + } + + MEMCPY(name, &sin6, *namelen); } + else +#endif /* LWIP_IPV6 */ + { + struct sockaddr_in sin; + ip_addr_t naddr; - MEMCPY(name, &sin, *namelen); + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + + /* get the IP address and port */ + netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip_addr_debug_print(SOCKETS_DEBUG, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); + + sin.sin_port = htons(sin.sin_port); + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); + + if (*namelen > sizeof(sin)) { + *namelen = sizeof(sin); + } + + MEMCPY(name, &sin, *namelen); + } sock_set_errno(sock, 0); return 0; } @@ -1495,7 +1703,12 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) err = EINVAL; } #if LWIP_UDP - if ((sock->conn->type != NETCONN_UDP) || + if ( +#if LWIP_IPV6 + ((sock->conn->type != NETCONN_UDP) && (sock->conn->type != NETCONN_UDP_IPV6)) || +#else /* LWIP_IPV6 */ + (sock->conn->type != NETCONN_UDP) || +#endif /* LWIP_IPV6 */ ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; @@ -1559,7 +1772,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* If this is no TCP socket, ignore any options. */ - if (sock->conn->type != NETCONN_TCP) + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) return 0; switch (optname) { @@ -1588,7 +1801,11 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* If this is no UDP lite socket, ignore any options. */ +#if LWIP_IPV6 + if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6)) { +#else /* LWIP_IPV6 */ if (sock->conn->type != NETCONN_UDPLITE) { +#endif /* LWIP_IPV6 */ return 0; } @@ -1892,7 +2109,12 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EINVAL; } #if LWIP_UDP - if ((sock->conn->type != NETCONN_UDP) || + if ( +#if LWIP_IPV6 + ((sock->conn->type != NETCONN_UDP) && (sock->conn->type != NETCONN_UDP_IPV6)) || +#else /* LWIP_IPV6 */ + (sock->conn->type != NETCONN_UDP) || +#endif /* LWIP_IPV6 */ ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; @@ -1969,7 +2191,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* If this is no TCP socket, ignore any options. */ - if (sock->conn->type != NETCONN_TCP) + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) return 0; switch (optname) { @@ -1998,7 +2220,11 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* If this is no UDP lite socket, ignore any options. */ +#if LWIP_IPV6 + if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6)) +#else /* LWIP_IPV6 */ if (sock->conn->type != NETCONN_UDPLITE) +#endif /* LWIP_IPV6 */ return 0; switch (optname) { @@ -2281,7 +2507,7 @@ lwip_ioctl(int s, long cmd, void *argp) /* Check if there is data left from the last recv operation. /maq 041215 */ if (sock->lastdata) { struct pbuf *p = (struct pbuf *)sock->lastdata; - if (netconn_type(sock->conn) != NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { p = ((struct netbuf *)p)->p; } buflen = p->tot_len; diff --git a/src/core/init.c b/src/core/init.c index bf5c79da..30f09845 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -56,6 +56,9 @@ #include "lwip/dns.h" #include "lwip/timers.h" #include "netif/etharp.h" +#include "lwip/ip6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" /* Compile-time sanity checks for configuration errors. * These can be done independently of LWIP_DEBUG, without penalty. @@ -299,6 +302,13 @@ lwip_init(void) #if LWIP_DNS dns_init(); #endif /* LWIP_DNS */ +#if LWIP_IPV6 + ip6_init(); + nd6_init(); +#if LWIP_IPV6_MLD + mld6_init(); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ #if LWIP_TIMERS sys_timeouts_init(); diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index 32902a52..ca59acfc 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -70,7 +70,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); * Currently only processes icmp echo requests and sends * out the echo response. * - * @param p the icmp echo request packet, p->payload pointing to the ip header + * @param p the icmp echo request packet, p->payload pointing to the icmp header * @param inp the netif on which this packet was received */ void @@ -87,10 +87,9 @@ icmp_input(struct pbuf *p, struct netif *inp) ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); - - iphdr = (struct ip_hdr *)p->payload; + iphdr = (struct ip_hdr *)ip_current_header(); hlen = IPH_HL(iphdr) * 4; - if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { + if (p->len < sizeof(u16_t)*2) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); goto lenerr; } @@ -110,13 +109,13 @@ icmp_input(struct pbuf *p, struct netif *inp) int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ - if (ip_addr_ismulticast(¤t_iphdr_dest)) { + if (ip_addr_ismulticast(ip_current_dest_addr())) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ - if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { + if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 4e4405e1..cf2e8ce1 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -382,14 +382,13 @@ igmp_remove_group(struct igmp_group *group) /** * Called from ip_input() if a new IGMP packet is received. * - * @param p received igmp packet, p->payload pointing to the ip header + * @param p received igmp packet, p->payload pointing to the igmp header * @param inp network interface on which the packet was received * @param dest destination ip address of the igmp packet */ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) { - struct ip_hdr * iphdr; struct igmp_msg* igmp; struct igmp_group* group; struct igmp_group* groupref; @@ -397,8 +396,7 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) IGMP_STATS_INC(igmp.recv); /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ - iphdr = (struct ip_hdr *)p->payload; - if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { + if (p->len < IGMP_MINLEN) { pbuf_free(p); IGMP_STATS_INC(igmp.lenerr); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); @@ -406,9 +404,9 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); + ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); + ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); /* Now calculate and check the checksum */ diff --git a/src/core/ipv4/inet_chksum.c b/src/core/ipv4/inet_chksum.c index 960252f6..b95f7f28 100644 --- a/src/core/ipv4/inet_chksum.c +++ b/src/core/ipv4/inet_chksum.c @@ -60,6 +60,7 @@ # ifndef LWIP_CHKSUM_ALGORITHM # define LWIP_CHKSUM_ALGORITHM 2 # endif +u16_t lwip_standard_chksum(void *dataptr, int len); #endif /* If none set: */ #ifndef LWIP_CHKSUM_ALGORITHM @@ -77,7 +78,7 @@ * @note accumulator size limits summable length to 64k * @note host endianess is irrelevant (p3 RFC1071) */ -static u16_t +u16_t lwip_standard_chksum(void *dataptr, u16_t len) { u32_t acc; @@ -131,7 +132,7 @@ lwip_standard_chksum(void *dataptr, u16_t len) * @return host order (!) lwip checksum (non-inverted Internet sum) */ -static u16_t +u16_t lwip_standard_chksum(void *dataptr, int len) { u8_t *pb = (u8_t *)dataptr; @@ -187,7 +188,7 @@ lwip_standard_chksum(void *dataptr, int len) * by Curt McDowell, Broadcom Corp. December 8th, 2005 */ -static u16_t +u16_t lwip_standard_chksum(void *dataptr, int len) { u8_t *pb = (u8_t *)dataptr; diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 6f248716..5e9a387d 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -496,23 +496,27 @@ ip_input(struct pbuf *p, struct netif *inp) case IP_PROTO_UDPLITE: #endif /* LWIP_UDPLITE */ snmp_inc_ipindelivers(); + pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP_PROTO_TCP: snmp_inc_ipindelivers(); + pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP case IP_PROTO_ICMP: snmp_inc_ipindelivers(); + pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ icmp_input(p, inp); break; #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: + pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ igmp_input(p, inp, ¤t_iphdr_dest); break; #endif /* LWIP_IGMP */ diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index 4fcc8955..c92235e1 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -1,5 +1,11 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + /* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -26,154 +32,272 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Adam Dunkels + * Author: Ivan Delamer * + * + * Please coordinate changes and requests with Ivan Delamer + * */ -/* 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 + +#ifndef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE 8 +#endif +#if LWIP_ICMP6_DATASIZE == 0 +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/* Forward declarations */ +static void icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data); + + +/** + * Process an input ICMPv6 message. Called by ip6_input. + * + * Will generate a reply for echo requests. Other messages are forwarded + * to nd6_input, or mld6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ void -icmp_input(struct pbuf *p, struct netif *inp) +icmp6_input(struct pbuf *p, struct netif *inp) { - u8_t type; - struct icmp_echo_hdr *iecho; - struct ip_hdr *iphdr; - struct ip_addr tmpaddr; + struct icmp6_hdr *icmp6hdr; + struct pbuf * r; + ip6_addr_t * reply_src; - ICMP_STATS_INC(icmp.recv); + ICMP6_STATS_INC(icmp6.recv); - /* TODO: check length before accessing payload! */ + /* Check that ICMPv6 header fits in payload */ + if (p->len < sizeof(struct icmp6_hdr)) { + /* drop short packets */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.lenerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } - type = ((u8_t *)p->payload)[0]; + icmp6hdr = (struct icmp6_hdr *)p->payload; - switch (type) { - case ICMP6_ECHO: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); - - if (p->tot_len < sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); +#if LWIP_ICMP6_CHECKSUM_CHECK + if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(), + IP6_NEXTH_ICMP6, p->tot_len) != 0) { + /* Checksum failed */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.chkerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } +#endif /* LWIP_ICMP6_CHECKSUM_CHECK */ + switch (icmp6hdr->type) { + case ICMP6_TYPE_NA: /* Neighbor advertisement */ + case ICMP6_TYPE_NS: /* Neighbor solicitation */ + case ICMP6_TYPE_RA: /* Router advertisement */ + case ICMP6_TYPE_RD: /* Redirect */ + case ICMP6_TYPE_PTB: /* Packet too big */ + nd6_input(p, inp); + return; + break; + case ICMP6_TYPE_RS: +#if LWIP_IPV6_FORWARD + /* TODO implement router functionality */ +#endif + break; +#if LWIP_IPV6_MLD + case ICMP6_TYPE_MLQ: + case ICMP6_TYPE_MLR: + case ICMP6_TYPE_MLD: + mld6_input(p, inp); + return; + break; +#endif + case ICMP6_TYPE_EREQ: +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* drop */ pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); + ICMP6_STATS_INC(icmp6.drop); return; } - iecho = p->payload; - iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN); - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.chkerr); - /* return;*/ - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len)); - ip_addr_set(&tmpaddr, &(iphdr->src)); - ip_addr_set(&(iphdr->src), &(iphdr->dest)); - ip_addr_set(&(iphdr->dest), &tmpaddr); - iecho->type = ICMP6_ER; - /* adjust the checksum */ - if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) { - iecho->chksum += htons(ICMP6_ECHO << 8) + 1; - } else { - iecho->chksum += htons(ICMP6_ECHO << 8); - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.xmit); +#endif /* LWIP_MULTICAST_PING */ + + /* Allocate reply. */ + r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); + if (r == NULL) { + /* drop */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.memerr); + return; + } + + /* Copy echo request. */ + if (pbuf_copy(r, p) != ERR_OK) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.err); + return; + } + + /* Determine reply source IPv6 address. */ + reply_src = ip6_select_source_address(inp, ip6_current_src_addr()); + if (reply_src == NULL) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + + /* Set fields in reply. */ + ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + reply_src, ip6_current_src_addr(), + IP6_NEXTH_ICMP6, r->tot_len); + + /* Send reply. */ + ICMP6_STATS_INC(icmp6.xmit); + ip6_output_if(r, reply_src, ip6_current_src_addr(), + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); + pbuf_free(r); - /* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ - ip_output_if (p, &(iphdr->src), IP_HDRINCL, - iphdr->hoplim, IP_PROTO_ICMP, inp); break; default: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type)); - ICMP_STATS_INC(icmp.proterr); - ICMP_STATS_INC(icmp.drop); + ICMP6_STATS_INC(icmp6.proterr); + ICMP6_STATS_INC(icmp6.drop); + break; } pbuf_free(p); } + +/** + * Send an icmpv6 'destination unreachable' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the unreachable type + */ void -icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) { - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_dur_hdr *idur; - - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (8 + IP_HLEN + 8))); - - iphdr = p->payload; - - idur = q->payload; - idur->type = (u8_t)ICMP6_DUR; - idur->icode = (u8_t)t; - - SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8); - - /* calculate checksum */ - idur->chksum = 0; - idur->chksum = inet_chksum(idur, q->len); - ICMP_STATS_INC(icmp.xmit); - - ip_output(q, NULL, - (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); - pbuf_free(q); + icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0); } +/** + * Send an icmpv6 'packet too big' packet. + * + * @param p the input packet for which the 'packet too big' should be sent, + * p->payload pointing to the IPv6 header + * @param mtu the maximum mtu that we can accept + */ void -icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +icmp6_packet_too_big(struct pbuf *p, u32_t mtu) +{ + icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu); +} + +/** + * Send an icmpv6 'time exceeded' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the time exceeded type + */ +void +icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) +{ + icmp6_send_response(p, ICMP6_TYPE_TE, c, 0); +} + +/** + * Send an icmpv6 'parameter problem' packet. + * + * @param p the input packet for which the 'param problem' should be sent, + * p->payload pointing to the IP header + * @param c ICMPv6 code for the param problem type + * @param pointer the pointer to the byte where the parameter is found + */ +void +icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) +{ + icmp6_send_response(p, ICMP6_TYPE_PP, c, pointer); +} + +/** + * Send an ICMPv6 packet in response to an incoming packet. + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param type Type of the ICMPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + */ +static void +icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data) { struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_te_hdr *tehdr; + struct icmp6_hdr *icmp6hdr; + ip6_addr_t * reply_src; - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); - - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ + /* ICMPv6 header + IPv6 header + data */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, + PBUF_RAM); if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); + ICMP6_STATS_INC(icmp6.memerr); return; } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (8 + IP_HLEN + 8))); + LWIP_ASSERT("check that first pbuf can hold icmp 6message", + (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); - iphdr = p->payload; - - tehdr = q->payload; - tehdr->type = (u8_t)ICMP6_TE; - tehdr->icode = (u8_t)t; + icmp6hdr = (struct icmp6_hdr *)q->payload; + icmp6hdr->type = type; + icmp6hdr->code = code; + icmp6hdr->data = data; /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8); + SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, + IP6_HLEN + LWIP_ICMP6_DATASIZE); + + /* Select an address to use as source. */ + reply_src = ip6_select_source_address(current_netif, ip6_current_src_addr()); + if (reply_src == NULL) { + /* drop */ + pbuf_free(q); + ICMP6_STATS_INC(icmp6.rterr); + return; + } /* calculate checksum */ - tehdr->chksum = 0; - tehdr->chksum = inet_chksum(tehdr, q->len); - ICMP_STATS_INC(icmp.xmit); - ip_output(q, NULL, - (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); + icmp6hdr->chksum = 0; + icmp6hdr->chksum = ip6_chksum_pseudo(q, reply_src, ip6_current_src_addr(), + IP6_NEXTH_ICMP6, q->tot_len); + + ICMP6_STATS_INC(icmp6.xmit); + ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6); pbuf_free(q); } -#endif /* LWIP_ICMP */ + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ diff --git a/src/core/ipv6/inet6.c b/src/core/ipv6/inet6.c index c3de85c0..bdf4ff4f 100644 --- a/src/core/ipv6/inet6.c +++ b/src/core/ipv6/inet6.c @@ -1,12 +1,11 @@ /** * @file - * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the - * byte order functions. * + * INET v6 addresses. */ /* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -33,131 +32,20 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Adam Dunkels + * Author: Ivan Delamer * + * + * Please coordinate changes and requests with Ivan Delamer + * */ #include "lwip/opt.h" +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + #include "lwip/def.h" -#include "lwip/inet.h" +#include "lwip/inet6.h" -/* chksum: - * - * Sums up all 16 bit words in a memory portion. Also includes any odd byte. - * This function is used by the other checksum functions. - * - * For now, this is not optimized. Must be optimized for the particular processor - * arcitecture on which it is to run. Preferebly coded in assembler. - */ +/** @see ip6_addr.c for implementation of functions. */ -static u32_t -chksum(void *dataptr, u16_t len) -{ - u16_t *sdataptr = dataptr; - u32_t acc; - - - for(acc = 0; len > 1; len -= 2) { - acc += *sdataptr++; - } - - /* add up any odd byte */ - if (len == 1) { - acc += htons((u16_t)(*(u8_t *)dataptr) << 8); - } - - return acc; - -} - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - */ - -u16_t -inet_chksum_pseudo(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, - u8_t proto, u32_t proto_len) -{ - u32_t acc; - struct pbuf *q; - u8_t swapped, i; - - acc = 0; - swapped = 0; - for(q = p; q != NULL; q = q->next) { - acc += chksum(q->payload, q->len); - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - } - - if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - - for(i = 0; i < 8; i++) { - acc += ((u16_t *)src->addr)[i] & 0xffff; - acc += ((u16_t *)dest->addr)[i] & 0xffff; - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - } - acc += (u16_t)htons((u16_t)proto); - acc += ((u16_t *)&proto_len)[0] & 0xffff; - acc += ((u16_t *)&proto_len)[1] & 0xffff; - - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - return ~(acc & 0xffff); -} - -/* inet_chksum: - * - * Calculates the Internet checksum over a portion of memory. Used primarely for IP - * and ICMP. - */ - -u16_t -inet_chksum(void *dataptr, u16_t len) -{ - u32_t acc, sum; - - acc = chksum(dataptr, len); - sum = (acc & 0xffff) + (acc >> 16); - sum += (sum >> 16); - return ~(sum & 0xffff); -} - -u16_t -inet_chksum_pbuf(struct pbuf *p) -{ - u32_t acc; - struct pbuf *q; - u8_t swapped; - - acc = 0; - swapped = 0; - for(q = p; q != NULL; q = q->next) { - acc += chksum(q->payload, q->len); - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8); - } - } - - if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - return ~(acc & 0xffff); -} +#endif /* LWIP_IPV6 */ diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index b945fc5d..5c58f05c 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -1,5 +1,11 @@ +/** + * @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, @@ -26,372 +32,947 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Adam Dunkels + * Author: Ivan Delamer * - */ - - - -/* ip.c - * - * This is the code for the IP layer for IPv6. * + * Please coordinate changes and requests with Ivan Delamer + * */ #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); - }*/ + /* 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; + } + 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()))); - 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"); - - netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); + /* 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; - - - 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 */ + 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); - IP_STATS_INC(ip.err); - IP_STATS_INC(ip.drop); - return; + IP6_STATS_INC(ip6.err); + 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))) { + /* 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); + IP6_STATS_INC(ip6.lenerr); + IP6_STATS_INC(ip6.drop); + return ERR_OK; + } + + /* Trim pbuf. This should have been done at the netif layer, + * but we'll do it anyway just to be sure that its done. */ + pbuf_realloc(p, 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 */ + 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); + goto ip6_input_cleanup; + } + + /* 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; + + 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); + + /* 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_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 */ + 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; } } +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); - if (netif == NULL) { - /* packet not for us, route or discard */ -#if IP_FORWARD - ip_forward(p, iphdr); -#endif - pbuf_free(p); - return; - } - - pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len)); - - /* send to upper layers */ -#if IP_DEBUG - /* 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; - } - - 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; -#endif /* LWIP_ICMP */ - default: -#if LWIP_ICMP - /* send ICMP destination protocol unreachable */ - icmp_dest_unreach(p, ICMP_DUR_PROTO); -#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); - } - PERF_STOP("ip_input"); + 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; + struct ip6_hdr *ip6hdr; + ip6_addr_t dest_addr; - PERF_START; + /* 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); - 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)); - - iphdr = p->payload; - - - 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); - - iphdr->v = 6; - - if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); - } else { - ip_addr_set(&(iphdr->src), src); + /* 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; } + 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); + + /* dest cannot be NULL here */ + ip6_addr_copy(ip6hdr->dest, *dest); + + IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); + IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); + + 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); + IP6_STATS_INC(ip6.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 */ + LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); + ip6_debug_print(p); - PERF_STOP("ip_output_if"); - return netif->output(netif, p, dest); +#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 */ + + 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 -void -ip_debug_print(struct pbuf *p) +#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 ip_hdr *iphdr = p->payload; + struct ip6_hbh_hdr * hbh_hdr; - 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")); + /* 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 /* IP_DEBUG */ +#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 +ip6_debug_print(struct pbuf *p) +{ + 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 /* IP6_DEBUG */ + +#endif /* LWIP_IPV6 */ diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 2da6cea4..3b682051 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -1,5 +1,11 @@ +/** + * @file + * + * IPv6 addresses. + */ + /* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -26,47 +32,210 @@ * * This file is part of the lwIP TCP/IP stack. * - * Author: Adam Dunkels + * Author: Ivan Delamer * + * Functions for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * */ #include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/inet.h" -u8_t -ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, - struct ip_addr *mask) +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + +/* used by IP6_ADDR_ANY in ip6_addr.h */ +const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } }; + +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) +#endif + +/** + * Check whether "cp" is a valid ascii representation + * of an IPv6 address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * + * @param cp IPv6 address in ascii represenation (e.g. "FF01::1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip6addr_aton(const char *cp, ip6_addr_t *addr) { - return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) && - (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) && - (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) && - (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3])); - + u32_t addr_index, zero_blocks, current_block_index, current_block_value; + const char * s; + + /* Count the number of colons, to count the number of blocks in a "::" sequence + zero_blocks may be 1 even if there are no :: sequences */ + zero_blocks = 8; + for (s = cp; *s != 0; s++) { + if (*s == ':') + zero_blocks--; + else if (!isxdigit(*s)) + break; + } + + /* parse each block */ + addr_index = 0; + current_block_index = 0; + current_block_value = 0; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + current_block_index++; + current_block_value = 0; + if (current_block_index > 7) { + /* address too long! */ + return 0; + } if (s[1] == ':') { + s++; + /* "::" found, set zeros */ + while (zero_blocks-- > 0) { + if (current_block_index & 0x1) { + addr_index++; + } + else { + addr->addr[addr_index] = 0; + } + current_block_index++; + } + } + } else if (isxdigit(*s)) { + /* add current digit */ + current_block_value = (current_block_value << 4) + + (isdigit(*s) ? *s - '0' : + 10 + (islower(*s) ? *s - 'a' : *s - 'A')); + } else { + /* unexpected digit, space? CRLF? */ + break; + } + } + + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + + /* convert to network byte order. */ + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = htonl(addr->addr[addr_index]); + } + + if (current_block_index != 7) { + return 0; + } + + return 1; + } -u8_t -ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2) +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * represenation of addr + */ +char * +ip6addr_ntoa(const ip6_addr_t *addr) { - return(addr1->addr[0] == addr2->addr[0] && - addr1->addr[1] == addr2->addr[1] && - addr1->addr[2] == addr2->addr[2] && - addr1->addr[3] == addr2->addr[3]); + static char str[40]; + return ip6addr_ntoa_r(addr, str, 40); } -void -ip_addr_set(struct ip_addr *dest, struct ip_addr *src) +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip6 address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) { - SMEMCPY(dest, src, sizeof(struct ip_addr)); - /* dest->addr[0] = src->addr[0]; - dest->addr[1] = src->addr[1]; - dest->addr[2] = src->addr[2]; - dest->addr[3] = src->addr[3];*/ -} + u32_t current_block_index, current_block_value; + s32_t zero_flag, i; -u8_t -ip_addr_isany(struct ip_addr *addr) -{ - if (addr == NULL) return 1; - return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0); + i = 0; + zero_flag = 0; /* used to indicate a zero chain for "::' */ + + for (current_block_index = 0; current_block_index < 8; current_block_index++) { + /* get the current 16-bit block */ + current_block_value = htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + if (current_block_value == 0) { + /* generate empty block "::" */ + if (!zero_flag) { + if (current_block_index > 0) { + zero_flag = 1; + buf[i++] = ':'; + if (i >= buflen) return NULL; + } + } + } + else { + if (current_block_index > 0) { + buf[i++] = ':'; + if (i >= buflen) return NULL; + } + + if ((current_block_value & 0xf000) == 0) { + zero_flag = 1; + } + else { + buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); + if (i >= buflen) return NULL; + } + + if (((current_block_value & 0xf00) == 0) && (zero_flag)) { + /* do nothing */ + } + else { + buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); + if (i >= buflen) return NULL; + } + + if (((current_block_value & 0xf0) == 0) && (zero_flag)) { + /* do nothing */ + } + else { + buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); + if (i >= buflen) return NULL; + } + + buf[i++] = xchar((current_block_value & 0xf)); + if (i >= buflen) return NULL; + + zero_flag = 0; + } + } + + buf[i] = 0; + + return buf; } +#endif /* LWIP_IPV6 */ diff --git a/src/core/memp.c b/src/core/memp.c index 4da879a5..bfe6ee60 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -58,6 +58,9 @@ #include "lwip/snmp_msg.h" #include "lwip/dns.h" #include "netif/ppp_oe.h" +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" #include diff --git a/src/core/netif.c b/src/core/netif.c index f190b1f2..e93762af 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -40,6 +40,7 @@ #include "lwip/def.h" #include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" #include "lwip/netif.h" #include "lwip/tcp_impl.h" #include "lwip/snmp.h" @@ -59,6 +60,12 @@ #if LWIP_DHCP #include "lwip/dhcp.h" #endif /* LWIP_DHCP */ +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ #if LWIP_NETIF_STATUS_CALLBACK #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) @@ -138,6 +145,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { static u8_t netifnum = 0; +#if LWIP_IPV6 + u32_t i; +#endif LWIP_ASSERT("No init function given", init != NULL); @@ -145,6 +155,12 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_set_zero(&netif->ip_addr); ip_addr_set_zero(&netif->netmask); ip_addr_set_zero(&netif->gw); +#if LWIP_IPV6 + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + ip6_addr_set_zero(&netif->ip6_addr[i]); + netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); + } +#endif /* LWIP_IPV6 */ netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ @@ -154,6 +170,17 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ +#if LWIP_IPV6_AUTOCONFIG + /* IPv6 address autoconfiguration not enabled by default */ + netif->ip6_autoconfig_enabled = 0; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_IPV6_DHCP6 + /* netif not under DHCPv6 control by default */ + netif->dhcp6 = NULL; +#endif /* LWIP_IPV6_DHCP6 */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ @@ -163,6 +190,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->mld_mac_filter = NULL; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if ENABLE_LOOPBACK netif->loop_first = NULL; netif->loop_last = NULL; @@ -245,6 +275,10 @@ netif_remove(struct netif *netif) igmp_stop(netif); } #endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* stop MLD processing */ + mld6_stop(netif); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ if (netif_is_up(netif)) { /* set netif down before removing (call callback function) */ netif_set_down(netif); @@ -331,10 +365,10 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) pcb = tcp_active_pcbs; while (pcb != NULL) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) + if (ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr)) #if LWIP_AUTOIP /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && !ip_addr_islinklocal(&(pcb->local_ip)) + && !ip_addr_islinklocal(&(pcb->local_ip.ip4)) #endif /* LWIP_AUTOIP */ ) { /* this connection must be aborted */ @@ -348,11 +382,11 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) } for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { /* PCB bound to current local interface address? */ - if ((!(ip_addr_isany(&(lpcb->local_ip)))) && - (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { + if ((!(ip_addr_isany(&(lpcb->local_ip.ip4)))) && + (ip_addr_cmp(&(lpcb->local_ip.ip4), &(netif->ip_addr)))) { /* The PCB is listening to the old ipaddr and * is set to listen to the new one instead */ - ip_addr_set(&(lpcb->local_ip), ipaddr); + ip_addr_set(&(lpcb->local_ip.ip4), ipaddr); } } } @@ -471,6 +505,16 @@ void netif_set_up(struct netif *netif) igmp_report_groups( netif); } #endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups( netif); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send Router Solicitation messages. */ + netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + } } } @@ -541,6 +585,10 @@ void netif_set_link_up(struct netif *netif ) igmp_report_groups( netif); } #endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* send mld memberships */ + mld6_report_groups( netif); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ } NETIF_LINK_CALLBACK(netif); } @@ -750,3 +798,62 @@ netif_poll_all(void) } #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ + +#if LWIP_IPV6 +s8_t +netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) { + return i; + } + } + return -1; +} + +void +netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit) +{ + u8_t i, addr_index; + + /* Link-local prefix. */ + netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul); + netif->ip6_addr[0].addr[1] = 0; + + /* Generate interface ID. */ + if (from_mac_48bit) { + /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ + netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | + ((u32_t)(netif->hwaddr[1]) << 16) | + ((u32_t)(netif->hwaddr[2]) << 8) | + (0xff)); + netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) | + ((u32_t)(netif->hwaddr[3]) << 16) | + ((u32_t)(netif->hwaddr[4]) << 8) | + (netif->hwaddr[5])); + } + else { + /* Use hwaddr directly as interface ID. */ + netif->ip6_addr[0].addr[2] = 0; + netif->ip6_addr[0].addr[3] = 0; + + addr_index = 3; + for (i = 0; i < 8; i++) { + if (i == 4) { + addr_index--; + } + netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)); + } + } + + /* Set address state. */ +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* Will perform duplicate address detection (DAD). */ + netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE; +#else + /* Consider address valid. */ + netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED; +#endif /* LWIP_IPV6_AUTOCONFIG */ +} +#endif /* LWIP_IPV6 */ diff --git a/src/core/raw.c b/src/core/raw.c index 9fcb1003..8a0ce762 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -49,6 +49,8 @@ #include "lwip/raw.h" #include "lwip/stats.h" #include "arch/perf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" #include @@ -79,11 +81,24 @@ raw_input(struct pbuf *p, struct netif *inp) struct ip_hdr *iphdr; s16_t proto; u8_t eaten = 0; +#if LWIP_IPV6 + struct ip6_hdr *ip6hdr; +#endif /* LWIP_IPV6 */ + LWIP_UNUSED_ARG(inp); iphdr = (struct ip_hdr *)p->payload; - proto = IPH_PROTO(iphdr); +#if LWIP_IPV6 + if (IPH_V(iphdr) == 6) { + ip6hdr = (struct ip6_hdr *)p->payload; + proto = IP6H_NEXTH(ip6hdr); + } + else +#endif /* LWIP_IPV6 */ + { + proto = IPH_PROTO(iphdr); + } prev = NULL; pcb = raw_pcbs; @@ -91,17 +106,38 @@ raw_input(struct pbuf *p, struct netif *inp) /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if ((pcb->protocol == proto) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&(pcb->local_ip), ¤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; @@ -141,7 +177,15 @@ raw_input(struct pbuf *p, struct netif *inp) err_t raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) { - ip_addr_set(&pcb->local_ip, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&pcb->local_ip.ip4, ipaddr); + } return ERR_OK; } @@ -161,7 +205,15 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) err_t raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) { - ip_addr_set(&pcb->remote_ip, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&pcb->remote_ip.ip4, ipaddr); + } return ERR_OK; } @@ -183,7 +235,7 @@ void raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ - pcb->recv = recv; + pcb->recv.ip4 = recv; pcb->recv_arg = recv_arg; } @@ -209,6 +261,33 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); +#if LWIP_IPV6 + /* TODO lots of v4 and v6 code duplication, optimize! Or will compiler optimize? */ + if (pcb->isipv6) { + /* not enough space to add an IPv6 header to first pbuf in given p chain? */ + if (pbuf_header(p, IP6_HLEN)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); + return ERR_MEM; + } + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + if(pbuf_header(q, -IP6_HLEN)) { + LWIP_ASSERT("Can't restore header we just removed!", 0); + return ERR_MEM; + } + } + } + else +#endif /* LWIP_IPV6 */ /* not enough space to add an IP header to first pbuf in given p chain? */ if (pbuf_header(p, IP_HLEN)) { /* allocate header in new pbuf */ @@ -233,6 +312,19 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } } +#if LWIP_IPV6 + if (pcb->isipv6) { + if ((netif = ip6_route(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr)) == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to IPv6 destionation\n")); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + } + else +#endif /* LWIP_IPV6 */ if ((netif = ip_route(ipaddr)) == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); @@ -244,29 +336,62 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } #if IP_SOF_BROADCAST - /* broadcast filter? */ - if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); +#if LWIP_IPV6 + if (!netif->isipv6) { +#endif /* LWIP_IPV6 */ + /* broadcast filter? */ + if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); + /* free any temporary header pbuf allocated by pbuf_header() */ + if (q != p) { + pbuf_free(q); + } + return ERR_VAL; } - return ERR_VAL; +#if LWIP_IPV6 } +#endif /* LWIP_IPV6 */ #endif /* IP_SOF_BROADCAST */ - if (ip_addr_isany(&pcb->local_ip)) { +#if LWIP_IPV6 + if (pcb->isipv6) { + if (ip6_addr_isany(&pcb->local_ip.ip6)) { + /* select an IPv6 address from the netif as source address */ + src_ip = (ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)ipaddr); + if (src_ip == NULL) { + /* No suitable source address was found. */ + if (q != p) { + pbuf_free(q); + } + return ERR_RTE; + } + } else { + /* use RAW PCB local IPv6 address as source address */ + src_ip = (ip_addr_t *)&(pcb->local_ip.ip6); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&pcb->local_ip.ip4)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* use RAW PCB local IP address as source address */ - src_ip = &(pcb->local_ip); + src_ip = &(pcb->local_ip.ip4); } #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); +#if LWIP_IPV6 + if (pcb->isipv6) { + err = ip6_output_if(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); + } + else +#endif /* LWIP_IPV6 */ + { + err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); + } #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -289,7 +414,13 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) err_t raw_send(struct raw_pcb *pcb, struct pbuf *p) { - return raw_sendto(pcb, p, &pcb->remote_ip); +#if LWIP_IPV6 + if (pcb->isipv6) { + /* TODO is this necessary, or ar ip4 and ip6 pointers the same (think union)? */ + return raw_sendto(pcb, p, (ip_addr_t *)&pcb->remote_ip.ip6); + } +#endif /* LWIP_IPV6 */ + return raw_sendto(pcb, p, &pcb->remote_ip.ip4); } /** @@ -351,4 +482,28 @@ raw_new(u8_t proto) return pcb; } +#if LWIP_IPV6 +/** + * Create a RAW PCB for IPv6. + * + * @return The RAW PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @param proto the protocol number (next header) of the IPv6 packet payload + * (e.g. IP6_NEXTH_ICMP6) + * + * @see raw_remove() + */ +struct raw_pcb * +raw_new_ip6(u8_t proto) +{ + struct raw_pcb *pcb; + pcb = raw_new(proto); + if (pcb != NULL) { + pcb->isipv6 = 1; + } + return pcb; +} +#endif /* LWIP_IPV6 */ + #endif /* LWIP_RAW */ diff --git a/src/core/tcp.c b/src/core/tcp.c index c629bc4e..1d62def6 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -52,6 +52,9 @@ #include "lwip/tcp_impl.h" #include "lwip/debug.h" #include "lwip/stats.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/nd6.h" #include @@ -147,8 +150,17 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) /* don't call tcp_abort here: we must not deallocate the pcb since that might not be expected when calling tcp_close */ - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); +#if LWIP_IPV6 + if (pcb->isipv6) { + tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, + pcb->local_port, pcb->remote_port); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, + pcb->local_port, pcb->remote_port); + } tcp_pcb_purge(pcb); @@ -318,8 +330,8 @@ void tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno; - u16_t remote_port, local_port; - ip_addr_t remote_ip, local_ip; + /*u16_t remote_port, local_port; + ip_addr_t remote_ip, local_ip; */ #if LWIP_CALLBACK_API tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ @@ -337,10 +349,10 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) } else { seqno = pcb->snd_nxt; ackno = pcb->rcv_nxt; - ip_addr_copy(local_ip, pcb->local_ip); - ip_addr_copy(remote_ip, pcb->remote_ip); + /*ip_addr_copy(local_ip, pcb->local_ip.ip4); + ip_addr_copy(remote_ip, pcb->remote_ip.ip4); local_port = pcb->local_port; - remote_port = pcb->remote_port; + remote_port = pcb->remote_port;*/ #if LWIP_CALLBACK_API errf = pcb->errf; #endif /* LWIP_CALLBACK_API */ @@ -357,12 +369,20 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) tcp_segs_free(pcb->ooseq); } #endif /* TCP_QUEUE_OOSEQ */ - memp_free(MEMP_TCP_PCB, pcb); - TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); if (reset) { LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); +#if LWIP_IPV6 + if (pcb->isipv6) { + tcp_rst_ip6(seqno, ackno, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->local_port, pcb->remote_port); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(seqno, ackno, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->local_port, pcb->remote_port); + } } + memp_free(MEMP_TCP_PCB, pcb); + TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); } } @@ -432,18 +452,40 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) ((cpcb->so_options & SOF_REUSEADDR) == 0)) #endif /* SO_REUSE */ { - if (ip_addr_isany(&(cpcb->local_ip)) || + if ( +#if LWIP_IPV6 + !pcb->isipv6 && + !cpcb->isipv6 && +#endif /* LWIP_IPV6 */ + (ip_addr_isany(&(cpcb->local_ip.ip4)) || ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + ip_addr_cmp(&(cpcb->local_ip.ip4), ipaddr))) { return ERR_USE; } +#if LWIP_IPV6 + if (pcb->isipv6 && + cpcb->isipv6 && + (ip6_addr_isany(&(cpcb->local_ip.ip6)) || + ip6_addr_isany((ip6_addr_t *)ipaddr) || + ip6_addr_cmp(&(cpcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) { + return ERR_USE; + } +#endif /* LWIP_IPV6 */ } } } } +#if LWIP_IPV6 + if (pcb->isipv6) { + if (!ip6_addr_isany((ip6_addr_t *)ipaddr)) { + ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr); + } + } + else +#endif /* LWIP_IPV6 */ if (!ip_addr_isany(ipaddr)) { - pcb->local_ip = *ipaddr; + pcb->local_ip.ip4 = *ipaddr; } pcb->local_port = port; TCP_REG(&tcp_bound_pcbs, pcb); @@ -498,7 +540,15 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) this port is only used once for every local IP. */ for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if (lpcb->local_port == pcb->local_port) { - if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + if (( +#if LWIP_IPV6 + pcb->isipv6 && + lpcb->isipv6 && + ip6_addr_cmp(&lpcb->local_ip.ip6, &pcb->local_ip.ip6)) || + (!pcb->isipv6 && + !lpcb->isipv6 && +#endif /* LWIP_IPV6 */ + ip_addr_cmp(&lpcb->local_ip.ip4, &pcb->local_ip.ip4))) { /* this address/port is already used */ return NULL; } @@ -518,7 +568,16 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) lpcb->so_options |= SOF_ACCEPTCONN; lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; - ip_addr_copy(lpcb->local_ip, pcb->local_ip); +#if LWIP_IPV6 + lpcb->isipv6 = pcb->isipv6; + if (lpcb->isipv6) { + ip6_addr_copy(lpcb->local_ip.ip6, pcb->local_ip.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_copy(lpcb->local_ip.ip4, pcb->local_ip.ip4); + } if (pcb->local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } @@ -657,23 +716,55 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { - pcb->remote_ip = *ipaddr; +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->remote_ip.ip4 = *ipaddr; + } } else { return ERR_VAL; } pcb->remote_port = port; /* check if we have a route to the remote host */ - if (ip_addr_isany(&(pcb->local_ip))) { +#if LWIP_IPV6 + if (pcb->isipv6) { + if (ip6_addr_isany(&(pcb->local_ip.ip6))) { + /* no local IPv6 address set, yet. */ + ip6_addr_t * local_addr6; + struct netif *netif = ip6_route(&(pcb->remote_ip.ip6), &(pcb->remote_ip.ip6)); + if (netif == NULL) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } + /* Select and IPv6 address from the netif. */ + local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6)); + if (local_addr6 == NULL) { + /* Don't even try to send a SYN packet if we have no suitable + source address. */ + return ERR_RTE; + } + + ip6_addr_set(&pcb->local_ip.ip6, local_addr6); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&(pcb->local_ip.ip4))) { /* no local IP address set, yet. */ - struct netif *netif = ip_route(&(pcb->remote_ip)); + struct netif *netif = ip_route(&(pcb->remote_ip.ip4)); if (netif == NULL) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ return ERR_RTE; } /* Use the netif's IP address as local address. */ - ip_addr_copy(pcb->local_ip, netif->ip_addr); + ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr); } old_local_port = pcb->local_port; @@ -691,8 +782,18 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if ((cpcb->local_port == pcb->local_port) && (cpcb->remote_port == port) && - ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && - ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { +#if LWIP_IPV6 + ((cpcb->isipv6 && + pcb->isipv6 && + ip6_addr_cmp(&cpcb->local_ip.ip6, &pcb->local_ip.ip6) && + ip6_addr_cmp(&cpcb->remote_ip.ip6, (ip6_addr_t *)ipaddr)) || + (!cpcb->isipv6 && + !pcb->isipv6 && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + ip_addr_cmp(&cpcb->local_ip.ip4, &pcb->local_ip.ip4) && + ip_addr_cmp(&cpcb->remote_ip.ip4, ipaddr)))) { /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } @@ -713,7 +814,15 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &pcb->local_ip.ip6, &pcb->remote_ip.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->remote_ip.ip4); + } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; @@ -852,9 +961,13 @@ tcp_slowtmr(void) (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) #endif /* LWIP_TCP_KEEPALIVE */ { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4); + } else { + ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); ++pcb_remove; ++pcb_reset; @@ -919,8 +1032,17 @@ tcp_slowtmr(void) TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); if (pcb_reset) { - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); +#if LWIP_IPV6 + if (pcb->isipv6) { + tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, + pcb->local_port, pcb->remote_port); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, + pcb->local_port, pcb->remote_port); + } } pcb2 = pcb; @@ -1266,6 +1388,27 @@ tcp_new(void) return tcp_alloc(TCP_PRIO_NORMAL); } +#if LWIP_IPV6 +/** + * Creates a new TCP-over-IPv6 protocol control block but doesn't + * place it on any of the TCP PCB lists. + * The pcb is not put on any list until binding using tcp_bind(). + * + * @return a new tcp_pcb that initially is in state CLOSED + */ +struct tcp_pcb * +tcp_new_ip6(void) +{ + struct tcp_pcb * pcb; + pcb = tcp_alloc(TCP_PRIO_NORMAL); + /* could allocate TCP PCB? */ + if (pcb != NULL) { + pcb->isipv6 = 1; + } + return pcb; +} +#endif /* LWIP_IPV6 */ + /** * Used to specify the argument that should be passed callback * functions. @@ -1376,8 +1519,18 @@ tcp_pcb_purge(struct tcp_pcb *pcb) tcp_listen_pcbs.listen_pcbs != NULL); for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && - (ip_addr_isany(&lpcb->local_ip) || - ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { +#if LWIP_IPV6 + ((lpcb->isipv6 && + pcb->isipv6 && + (ip6_addr_isany(&lpcb->local_ip.ip6) || + ip6_addr_cmp(&pcb->local_ip.ip6, &lpcb->local_ip.ip6))) || + (!lpcb->isipv6 && + !pcb->isipv6 && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + (ip_addr_isany(&lpcb->local_ip.ip4) || + ip_addr_cmp(&pcb->local_ip.ip4, &lpcb->local_ip.ip4))))) { /* port and address of the listen pcb match the timed-out pcb */ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", lpcb->accepts_pending > 0); @@ -1492,6 +1645,35 @@ tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) } return sendmss; } + +#if LWIP_IPV6 +/** + * Calculates the effective send mss that can be used for a specific IPv6 + * address by using ip6_route to determine the netif used to send to the + * address and calculating the minimum of TCP_MSS and that netif's mtu (if set). + */ +u16_t +tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest) +{ + u16_t mss_s; + struct netif *outif; + s16_t mtu; + + /* First look in destination cache, to see if there is a PAth MTU. */ + outif = ip6_route(src, dest); + mtu = nd6_get_destination_mtu(dest, outif); + + if (mtu != 0) { + mss_s = mtu - IP6_HLEN - TCP_HLEN; + /* RFC 1122, chap 4.2.2.6: + * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize + * We correct for TCP options in tcp_write(). + */ + sendmss = LWIP_MIN(sendmss, mss_s); + } + return sendmss; +} +#endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ const char* diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 90952648..86bb93e7 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -55,13 +55,18 @@ #include "lwip/stats.h" #include "lwip/snmp.h" #include "arch/perf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" +#if LWIP_ND6_TCP_REACHABILITY_HINTS +#include "lwip/nd6.h" +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ /* These variables are global to all functions involved in the input processing of TCP segments. They are set by the tcp_input() function. */ static struct tcp_seg inseg; static struct tcp_hdr *tcphdr; -static struct ip_hdr *iphdr; static u32_t seqno, ackno; static u8_t flags; static u16_t tcplen; @@ -85,7 +90,7 @@ static err_t tcp_timewait_input(struct tcp_pcb *pcb); * the TCP finite state machine. This function is called by the IP layer (in * ip_input()). * - * @param p received TCP segment to process (p->payload pointing to the IP header) + * @param p received TCP segment to process (p->payload pointing to the TCP header) * @param inp network interface on which this segment was received */ void @@ -105,15 +110,14 @@ tcp_input(struct pbuf *p, struct netif *inp) TCP_STATS_INC(tcp.recv); snmp_inc_tcpinsegs(); - iphdr = (struct ip_hdr *)p->payload; - tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); + tcphdr = (struct tcp_hdr *)p->payload; #if TCP_INPUT_DEBUG tcp_debug_print(tcphdr); #endif - /* remove header from payload */ - if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { + /* Check that TCP header fits in payload */ + if (p->len < sizeof(struct tcp_hdr)) { /* drop short packets */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); TCP_STATS_INC(tcp.lenerr); @@ -124,8 +128,14 @@ tcp_input(struct pbuf *p, struct netif *inp) } /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(¤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(); @@ -134,6 +144,25 @@ tcp_input(struct pbuf *p, struct netif *inp) } #if CHECKSUM_CHECK_TCP +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(), + IP6_NEXTH_TCP, p->tot_len) != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(), + IP6_NEXTH_TCP, p->tot_len))); + #if TCP_DEBUG + tcp_debug_print(tcphdr); + #endif /* TCP_DEBUG */ + TCP_STATS_INC(tcp.chkerr); + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } + } + else +#endif /* LWIP_IPV6 */ /* Verify TCP checksum. */ if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_TCP, p->tot_len) != 0) { @@ -149,7 +178,7 @@ tcp_input(struct pbuf *p, struct netif *inp) pbuf_free(p); return; } -#endif +#endif /* CHECKSUM_CHECK_TCP */ /* Move the payload pointer in the pbuf so that it points to the TCP data instead of the TCP header. */ @@ -184,9 +213,18 @@ tcp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤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 @@ -209,9 +247,18 @@ tcp_input(struct pbuf *p, struct netif *inp) for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤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. */ @@ -228,19 +275,50 @@ tcp_input(struct pbuf *p, struct netif *inp) for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if (lpcb->local_port == tcphdr->dest) { #if SO_REUSE - if (ip_addr_cmp(&(lpcb->local_ip), ¤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 */ } @@ -415,9 +493,19 @@ aborted: if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); - tcp_rst(ackno, seqno + tcplen, - ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + tcp_rst_ip6(ackno, seqno + tcplen, + ip6_current_dest_addr(), ip6_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(ackno, seqno + tcplen, + ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } } pbuf_free(p); } @@ -450,9 +538,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno + 1, seqno + tcplen, - ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + tcp_rst_ip6(ackno + 1, seqno + tcplen, + ip6_current_dest_addr(), ip6_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(ackno + 1, seqno + tcplen, + ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG @@ -474,9 +572,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ - ip_addr_copy(npcb->local_ip, current_iphdr_dest); +#if LWIP_IPV6 + npcb->isipv6 = pcb->isipv6; + if (npcb->isipv6) { + ip6_addr_copy(npcb->local_ip.ip6, *ip6_current_dest_addr()); + ip6_addr_copy(npcb->remote_ip.ip6, *ip6_current_src_addr()); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_copy(npcb->local_ip.ip4, *ip_current_dest_addr()); + ip_addr_copy(npcb->remote_ip.ip4, *ip_current_src_addr()); + } npcb->local_port = pcb->local_port; - ip_addr_copy(npcb->remote_ip, current_iphdr_src); npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; @@ -497,7 +605,15 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) /* Parse any options in the SYN. */ tcp_parseopt(npcb); #if TCP_CALCULATE_EFF_SEND_MSS - npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); +#if LWIP_IPV6 + if (npcb->isipv6) { + npcb->mss = tcp_eff_send_mss_ip6(npcb->mss, &(npcb->local_ip.ip6), &(npcb->remote_ip.ip6)); + } + else +#endif /* LWIP_IPV6 */ + { + npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip.ip4)); + } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); @@ -539,8 +655,17 @@ tcp_timewait_input(struct tcp_pcb *pcb) should be sent in reply */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { /* If the SYN is in the window it is an error, send a reset */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } return ERR_OK; } } else if (flags & TCP_FIN) { @@ -637,7 +762,15 @@ tcp_process(struct tcp_pcb *pcb) pcb->state = ESTABLISHED; #if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); +#if LWIP_IPV6 + if (pcb->isipv6) { + pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6)); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip.ip4)); + } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect @@ -673,8 +806,17 @@ tcp_process(struct tcp_pcb *pcb) /* received ACK? possibly a half-open connection */ else if (flags & TCP_ACK) { /* send a RST to bring the other side in a non-synchronized state. */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } } break; case SYN_RCVD: @@ -716,8 +858,17 @@ tcp_process(struct tcp_pcb *pcb) } } else { /* incorrect ACK number, send RST */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(), + tcphdr->dest, tcphdr->src); + } + else +#endif /* LWIP_IPV6 */ + { + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), + tcphdr->dest, tcphdr->src); + } } } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { /* Looks like another copy of the SYN - retransmit our SYN-ACK */ @@ -1019,6 +1170,13 @@ tcp_receive(struct tcp_pcb *pcb) pcb->rtime = 0; pcb->polltmr = 0; + +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (pcb->isipv6) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ } else { /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ pcb->acked = 0; @@ -1336,6 +1494,13 @@ tcp_receive(struct tcp_pcb *pcb) /* Acknowledge the segment(s). */ tcp_ack(pcb); +#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS + if (pcb->isipv6) { + /* Inform neighbor reachability of forward progress. */ + nd6_reachability_hint(ip6_current_src_addr()); + } +#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ + } else { /* We get here if the incoming segment is out-of-sequence. */ tcp_send_empty_ack(pcb); diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 86e09195..308b8273 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -52,6 +52,9 @@ #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/snmp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" #include @@ -865,17 +868,34 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) } #endif +#if LWIP_IPV6 + if (pcb->isipv6) { + /* Chksum is mandatory over IPv6 */ + tcphdr->chksum = ip6_chksum_pseudo(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), + IP6_NEXTH_TCP, p->tot_len); +#if LWIP_NETIF_HWADDRHINT + ip6_output_hinted(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, + IP6_NEXTH_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip6_output(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, + IP6_NEXTH_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + } + else +#endif /* LWIP_IPV6 */ + { #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), + IP_PROTO_TCP, p->tot_len); #endif #if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); + ip_output_hinted(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, + IP_PROTO_TCP, &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); + ip_output(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, + IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ + } pbuf_free(p); return ERR_OK; @@ -1086,12 +1106,30 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* If we don't have a local IP address, we get one by calling ip_route(). */ - if (ip_addr_isany(&(pcb->local_ip))) { - netif = ip_route(&(pcb->remote_ip)); +#if LWIP_IPV6 + if (pcb->isipv6) { + if (ip6_addr_isany(&(pcb->local_ip.ip6))) { + ip6_addr_t * local_addr6; + netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->remote_ip.ip6)); + if (netif == NULL) { + return; + } + /* Select and IPv6 address from the netif. */ + local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6)); + if (local_addr6 == NULL) { + return; + } + ip6_addr_set(&pcb->local_ip.ip6, local_addr6); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&(pcb->local_ip.ip4))) { + netif = ip_route(&(pcb->remote_ip.ip4)); if (netif == NULL) { return; } - ip_addr_copy(pcb->local_ip, netif->ip_addr); + ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr); } if (pcb->rttest == 0) { @@ -1112,14 +1150,24 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) seg->p->payload = seg->tcphdr; seg->tcphdr->chksum = 0; -#if CHECKSUM_GEN_TCP #if TCP_CHECKSUM_ON_COPY { u32_t acc; #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); + u16_t chksum_slow; +#if LWIP_IPV6 + if (pcb->isipv6) { + chksum_slow = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6), + &(pcb->remote_ip.ip6), + IP6_NEXTH_TCP, seg->p->tot_len); + } + else +#endif /* LWIP_IPV6 */ + { + chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4), + &(pcb->remote_ip.ip4), + IP_PROTO_TCP, seg->p->tot_len); + } #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { LWIP_ASSERT("data included but not checksummed", @@ -1127,9 +1175,19 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) } /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ - acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); +#if LWIP_IPV6 + if (pcb->isipv6) { + acc = ip6_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip6), + &(pcb->remote_ip.ip6), + IP6_NEXTH_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); + } + else +#endif /* LWIP_IPV6 */ + { + acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip4), + &(pcb->remote_ip.ip4), + IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); + } /* add payload checksum */ if (seg->chksum_swapped) { seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); @@ -1147,20 +1205,46 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ } #else /* TCP_CHECKSUM_ON_COPY */ - seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif /* TCP_CHECKSUM_ON_COPY */ +#if LWIP_IPV6 + if (pcb->isipv6) { + /* Chksum is mandatory in IPv6 */ + seg->tcphdr->chksum = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6), + &(pcb->remote_ip.ip6), + IP6_NEXTH_TCP, seg->p->tot_len); + } + else +#endif /* LWIP_IPV6 */ + { +#if CHECKSUM_GEN_TCP + seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4), + &(pcb->remote_ip.ip4), + IP_PROTO_TCP, seg->p->tot_len); #endif /* CHECKSUM_GEN_TCP */ + } +#endif /* TCP_CHECKSUM_ON_COPY */ TCP_STATS_INC(tcp.xmit); +#if LWIP_IPV6 + if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); + ip6_output_hinted(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, + IP6_NEXTH_TCP, &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); + ip6_output(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, + IP6_NEXTH_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ + } + else +#endif /* LWIP_IPV6 */ + { +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, + IP_PROTO_TCP, &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, + IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + } } /** @@ -1220,6 +1304,65 @@ tcp_rst(u32_t seqno, u32_t ackno, LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); } +#if LWIP_IPV6 +/** + * Send a TCP RESET packet (empty segment with RST flag set) over IPv6, + * either to abort a connection or to show that there is no matching local + * connection for a received segment. + * + * Called by tcp_abort() (to abort a local connection), tcp_input() (if no + * matching local pcb was found), tcp_listen_input() (if incoming segment + * has ACK flag set) and tcp_process() (received segment in the wrong state) + * + * Since a RST segment is in most cases not sent for an active connection, + * tcp_rst() has a number of arguments that are taken from a tcp_pcb for + * most other segment output functions. + * + * @param seqno the sequence number to use for the outgoing segment + * @param ackno the acknowledge number to use for the outgoing segment + * @param local_ip6 the local IPv6 address to send the segment from + * @param remote_ip6 the remote IPv6 address to send the segment to + * @param local_port the local TCP port to send the segment from + * @param remote_port the remote TCP port to send the segment to + */ +void +tcp_rst_ip6(u32_t seqno, u32_t ackno, + ip6_addr_t *local_ip6, ip6_addr_t *remote_ip6, + u16_t local_port, u16_t remote_port) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + if (p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); + return; + } + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= sizeof(struct tcp_hdr))); + + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = htons(local_port); + tcphdr->dest = htons(remote_port); + tcphdr->seqno = htonl(seqno); + tcphdr->ackno = htonl(ackno); + TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); + tcphdr->wnd = PP_HTONS(TCP_WND); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + + /* chksum us mandatory over IPv6. */ + tcphdr->chksum = ip6_chksum_pseudo(p, local_ip6, remote_ip6, + IP6_NEXTH_TCP, p->tot_len); + + TCP_STATS_INC(tcp.xmit); + snmp_inc_tcpoutrsts(); + /* Send output with hardcoded HL since we have no access to the pcb */ + ip6_output(p, local_ip6, remote_ip6, TCP_TTL, 0, IP6_NEXTH_TCP); + pbuf_free(p); + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); +} +#endif /* LWIP_IPV6 */ + /** * Requeue all unacked segments for retransmission * @@ -1351,9 +1494,13 @@ tcp_keepalive(struct tcp_pcb *pcb) struct pbuf *p; struct tcp_hdr *tcphdr; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4); + } else { + ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); @@ -1366,19 +1513,41 @@ tcp_keepalive(struct tcp_pcb *pcb) } tcphdr = (struct tcp_hdr *)p->payload; +#if LWIP_IPV6 + if (pcb->isipv6) { + tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, + IP6_NEXTH_TCP, p->tot_len); + } + else +#endif /* LWIP_IPV6 */ + { #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, + IP_PROTO_TCP, p->tot_len); #endif + } TCP_STATS_INC(tcp.xmit); /* Send output to IP */ +#if LWIP_IPV6 + if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); + ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP, + &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); + ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ + } + else +#endif /* LWIP_IPV6 */ + { +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + } pbuf_free(p); @@ -1404,11 +1573,13 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) u16_t len; u8_t is_fin; - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" - U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); + LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4); + } else { + ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6); + } + LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: tcp_ticks %"U32_F @@ -1445,19 +1616,41 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); } +#if LWIP_IPV6 + if (pcb->isipv6) { + tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, + IP6_NEXTH_TCP, p->tot_len); + } + else +#endif /* LWIP_IPV6 */ + { #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, + IP_PROTO_TCP, p->tot_len); #endif + } TCP_STATS_INC(tcp.xmit); /* Send output to IP */ +#if LWIP_IPV6 + if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); + ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP, + &(pcb->addr_hint)); #else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); + ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ + } + else +#endif /* LWIP_IPV6 */ + { +#if LWIP_NETIF_HWADDRHINT + ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP, + &(pcb->addr_hint)); +#else /* LWIP_NETIF_HWADDRHINT*/ + ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP); +#endif /* LWIP_NETIF_HWADDRHINT*/ + } pbuf_free(p); diff --git a/src/core/timers.c b/src/core/timers.c index f0e92cce..da6278f0 100644 --- a/src/core/timers.c +++ b/src/core/timers.c @@ -56,7 +56,9 @@ #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" - +#include "lwip/nd6.h" +#include "lwip/ip6_frag.h" +#include "lwip/mld6.h" /** The one and only timeout list */ static struct sys_timeo *next_timeout; @@ -217,6 +219,54 @@ dns_timer(void *arg) } #endif /* LWIP_DNS */ +#if LWIP_IPV6 +/** + * Timer callback function that calls nd6_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +nd6_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n")); + nd6_tmr(); + sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); +} + +#if LWIP_IPV6_REASS +/** + * Timer callback function that calls ip6_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +ip6_reass_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n")); + ip6_reass_tmr(); + sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); +} +#endif /* LWIP_IPV6_REASS */ + +#if LWIP_IPV6_MLD +/** + * Timer callback function that calls mld6_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +mld6_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n")); + mld6_tmr(); + sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); +} +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ + /** Initialize this module */ void sys_timeouts_init(void) { @@ -239,6 +289,15 @@ void sys_timeouts_init(void) #if LWIP_DNS sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); #endif /* LWIP_DNS */ +#if LWIP_IPV6 + sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); +#if LWIP_IPV6_REASS + sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); +#endif /* LWIP_IPV6_REASS */ +#if LWIP_IPV6_MLD + sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); +#endif /* LWIP_IPV6_MLD */ +#endif /* LWIP_IPV6 */ #if NO_SYS /* Initialise timestamp for sys_check_timeouts */ diff --git a/src/core/udp.c b/src/core/udp.c index 4596ba2b..2594657c 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -55,8 +55,12 @@ #include "lwip/memp.h" #include "lwip/inet_chksum.h" #include "lwip/ip_addr.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" +#include "lwip/icmp6.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "arch/perf.h" @@ -76,7 +80,7 @@ struct udp_pcb *udp_pcbs; * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * - * @param p pbuf to be demultiplexed to a UDP PCB. + * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) * @param inp network interface on which the datagram was received. * */ @@ -86,7 +90,6 @@ udp_input(struct pbuf *p, struct netif *inp) struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; - struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; u8_t broadcast; @@ -95,11 +98,8 @@ udp_input(struct pbuf *p, struct netif *inp) UDP_STATS_INC(udp.recv); - iphdr = (struct ip_hdr *)p->payload; - - /* Check minimum length (IP header + UDP header) - * and move payload pointer to UDP header */ - if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { + /* Check minimum length (UDP header) */ + if (p->len < UDP_HLEN) { /* drop short packets */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); @@ -113,7 +113,11 @@ udp_input(struct pbuf *p, struct netif *inp) udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(¤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)); @@ -124,13 +128,19 @@ udp_input(struct pbuf *p, struct netif *inp) udp_debug_print(udphdr); /* print the UDP source and destination */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), - ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); + LWIP_DEBUGF(UDP_DEBUG, ("udp (")); + if (ip_current_header() != NULL) { + ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr()); + } else { + ip6_addr_debug_print(UDP_DEBUG, ip6_current_dest_addr()); + } + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest))); + if (ip_current_header() != NULL) { + ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr()); + } else { + ip6_addr_debug_print(UDP_DEBUG, ip6_current_src_addr()); + } + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; @@ -143,8 +153,12 @@ udp_input(struct pbuf *p, struct netif *inp) /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src */ - if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || - ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤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; } } @@ -162,25 +176,44 @@ udp_input(struct pbuf *p, struct netif *inp) for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; /* print the PCB local and remote address */ - LWIP_DEBUGF(UDP_DEBUG, - ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); + LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip4); + } else { + ip6_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip6); + } + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip4); + } else { + ip6_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip6); + } + LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && - ((!broadcast && ip_addr_isany(&pcb->local_ip)) || - ip_addr_cmp(&(pcb->local_ip), ¤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) && @@ -192,8 +225,18 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && - (ip_addr_isany(&pcb->remote_ip) || - ip_addr_cmp(&(pcb->remote_ip), ¤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 @@ -215,10 +258,26 @@ udp_input(struct pbuf *p, struct netif *inp) } /* Check checksum if this is a match or if it was directed at us. */ - if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤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); @@ -237,7 +296,22 @@ udp_input(struct pbuf *p, struct netif *inp) 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")); @@ -253,6 +327,21 @@ udp_input(struct pbuf *p, struct netif *inp) { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { +#if LWIP_IPV6 + if (ip6_current_header() != NULL) { + if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(), + IP6_NEXTH_UDP, p->tot_len) != 0) { + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + goto end; + } + } + else +#endif /* LWIP_IPV6 */ if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_UDP, p->tot_len) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, @@ -277,32 +366,53 @@ udp_input(struct pbuf *p, struct netif *inp) if (pcb != NULL) { snmp_inc_udpindatagrams(); #if SO_REUSE && SO_REUSE_RXTOALL - if ((broadcast || ip_addr_ismulticast(¤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); @@ -310,8 +420,16 @@ udp_input(struct pbuf *p, struct netif *inp) err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ - pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + pbuf_header(q, -hdrs_len); +#if LWIP_IPV6 + if (mpcb->isipv6) { + mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src); + } + else +#endif /* LWIP_IPV6 */ + { + mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + } } } } @@ -320,14 +438,22 @@ udp_input(struct pbuf *p, struct netif *inp) } if (p_header_changed) { /* and move payload to UDP data again */ - pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + pbuf_header(p, -hdrs_len); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ - if (pcb->recv != NULL) { + if (pcb->recv.ip4 != NULL) { /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); +#if LWIP_IPV6 + if (pcb->isipv6) { + pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); + } } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); @@ -336,17 +462,33 @@ udp_input(struct pbuf *p, struct netif *inp) } else { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); -#if LWIP_ICMP +#if LWIP_ICMP || LWIP_ICMP6 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && - !ip_addr_ismulticast(¤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(); @@ -381,7 +523,7 @@ err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); + return udp_sendto(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port); } #if LWIP_CHECKSUM_ON_COPY @@ -392,7 +534,7 @@ udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum) { /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + return udp_sendto_chksum(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port, have_chksum, chksum); } #endif /* LWIP_CHECKSUM_ON_COPY */ @@ -433,16 +575,35 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); /* find the outgoing network interface for this packet */ +#if LWIP_IPV6 + if (pcb->isipv6) { + if (ip6_addr_ismulticast((ip6_addr_t *)dst_ip)) { + /* For multicast, find a netif based on source address. */ + netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->local_ip.ip6)); + } + else { + netif = ip6_route(&(pcb->local_ip.ip6), (ip6_addr_t *)dst_ip); + } + } + else +#endif /* LWIP_IPV6 */ + { #if LWIP_IGMP - netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); + netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); #else - netif = ip_route(dst_ip); + netif = ip_route(dst_ip); #endif /* LWIP_IGMP */ + } /* no outgoing network interface could be found? */ if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip); + } else { + ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (ip6_addr_t *)dst_ip); + } + LWIP_DEBUGF(UDP_DEBUG, ("\n")); UDP_STATS_INC(udp.rterr); return ERR_RTE; } @@ -494,7 +655,11 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, #if IP_SOF_BROADCAST /* broadcast filter? */ - if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { + if ( ((pcb->so_options & SOF_BROADCAST) == 0) && +#if LWIP_IPV6 + !pcb->isipv6 && +#endif /* LWIP_IPV6 */ + ip_addr_isbroadcast(dst_ip, netif) ) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); return ERR_VAL; @@ -504,7 +669,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); - err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port); if (err != ERR_OK) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); return err; @@ -544,20 +709,60 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* Multicast Loop? */ #if LWIP_IGMP - if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { + if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && +#if LWIP_IPV6 + ( +#if LWIP_IPV6_MLD + (pcb->isipv6 && + ip6_addr_ismulticast((ip6_addr_t*)dst_ip)) || +#endif /* LWIP_IPV6_MLD */ + (!pcb->isipv6 && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + ip_addr_ismulticast(dst_ip)))) { q->flags |= PBUF_FLAG_MCASTLOOP; } #endif /* LWIP_IGMP */ /* PCB local address is IP_ANY_ADDR? */ - if (ip_addr_isany(&pcb->local_ip)) { +#if LWIP_IPV6 + if (pcb->isipv6) { + if (ip6_addr_isany(&pcb->local_ip.ip6)) { + src_ip =(ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)dst_ip); + if (src_ip == NULL) { + /* No suitable source address was found. */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + /* p is still referenced by the caller, and will live on */ + } + return ERR_RTE; + } + } else { + /* use UDP PCB local IPv6 address as source address, if still valid. */ + if (netif_matches_ip6_addr(netif, &(pcb->local_ip.ip6)) < 0) { + /* Address isn't valid anymore. */ + if (q != p) { + /* free the header pbuf */ + pbuf_free(q); + /* p is still referenced by the caller, and will live on */ + } + return ERR_RTE; + } + src_ip = (ip_addr_t *)&(pcb->local_ip.ip6); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(&pcb->local_ip.ip4)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ - if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { + if (!ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr))) { /* local_ip doesn't match, drop the packet */ if (q != p) { /* free the header pbuf */ @@ -568,7 +773,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, return ERR_VAL; } /* use UDP PCB local IP address as source address */ - src_ip = &(pcb->local_ip); + src_ip = &(pcb->local_ip.ip4); } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); @@ -595,31 +800,64 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } udphdr->len = htons(chklen_hdr); /* calculate checksum */ -#if CHECKSUM_GEN_UDP - udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, -#if !LWIP_CHECKSUM_ON_COPY - chklen); -#else /* !LWIP_CHECKSUM_ON_COPY */ - (have_chksum ? UDP_HLEN : chklen)); - if (have_chksum) { - u32_t acc; - acc = udphdr->chksum + (u16_t)~(chksum); - udphdr->chksum = FOLD_U32T(acc); - } -#endif /* !LWIP_CHECKSUM_ON_COPY */ +#if LWIP_IPV6 + /* Checksum is mandatory for IPv6. */ + if (pcb->isipv6) { + udphdr->chksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)dst_ip, + IP6_NEXTH_UDPLITE, q->tot_len, + #if !LWIP_CHECKSUM_ON_COPY + chklen); + #else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } + #endif /* !LWIP_CHECKSUM_ON_COPY */ - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } } + else +#endif /* LWIP_IPV6 */ + { +#if CHECKSUM_GEN_UDP + udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, + IP_PROTO_UDPLITE, q->tot_len, + #if !LWIP_CHECKSUM_ON_COPY + chklen); + #else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } + #endif /* !LWIP_CHECKSUM_ON_COPY */ + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } #endif /* CHECKSUM_GEN_UDP */ + } /* output to IP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); +#if LWIP_IPV6 + if (pcb->isipv6) { + err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDPLITE, netif); + } + else +#endif /* LWIP_IPV6 */ + { + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); + } #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -629,20 +867,21 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); udphdr->len = htons(q->tot_len); /* calculate checksum */ -#if CHECKSUM_GEN_UDP - if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { +#if LWIP_IPV6 + /* Checksum is mandatory over IPv6. */ + if (pcb->isipv6) { u16_t udpchksum; #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { u32_t acc; - udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + udpchksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, q->tot_len, UDP_HLEN); acc = udpchksum + (u16_t)~(chksum); udpchksum = FOLD_U32T(acc); } else #endif /* LWIP_CHECKSUM_ON_COPY */ { - udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); + udpchksum = ip6_chksum_pseudo(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, q->tot_len); } /* chksum zero must become 0xffff, as zero means 'no checksum' */ @@ -651,14 +890,48 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } udphdr->chksum = udpchksum; } + else +#endif /* LWIP_IPV6 */ + { +#if CHECKSUM_GEN_UDP + if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + q->tot_len, UDP_HLEN); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); + } + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; + } #endif /* CHECKSUM_GEN_UDP */ + } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); /* output to IP */ #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); +#if LWIP_IPV6 + if (pcb->isipv6) { + err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDP, netif); + } + else +#endif /* LWIP_IPV6 */ + { + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); + } #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ @@ -704,7 +977,11 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) u8_t rebind; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - ip_addr_debug_print(UDP_DEBUG, ipaddr); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr); + } else { + ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, (ip6_addr_t *)ipaddr); + } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); rebind = 0; @@ -730,9 +1007,20 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) #endif /* SO_REUSE */ if ((ipcb->local_port == port) && /* IP address matches, or one is IP_ADDR_ANY? */ - (ip_addr_isany(&(ipcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { +#if LWIP_IPV6 + ((pcb->isipv6 && + ipcb->isipv6 && + (ip6_addr_isany(&(ipcb->local_ip.ip6)) || + ip6_addr_isany((ip6_addr_t *)ipaddr) || + ip6_addr_cmp(&(ipcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) || + (!pcb->isipv6 && + !ipcb->isipv6 && +#else /* LWIP_IPV6 */ + (( +#endif /* LWIP_IPV6 */ + (ip_addr_isany(&(ipcb->local_ip.ip4)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(ipcb->local_ip.ip4), ipaddr))))) { /* other PCB already binds to this local IP and port */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); @@ -741,7 +1029,15 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } } - ip_addr_set(&pcb->local_ip, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&pcb->local_ip.ip4, ipaddr); + } /* no port specified? */ if (port == 0) { @@ -778,11 +1074,13 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) pcb->next = udp_pcbs; udp_pcbs = pcb; } - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip4); + } else { + ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip6); + } + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); return ERR_OK; } /** @@ -808,39 +1106,54 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) struct udp_pcb *ipcb; if (pcb->local_port == 0) { - err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + err_t err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port); if (err != ERR_OK) { return err; } } - ip_addr_set(&pcb->remote_ip, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&pcb->remote_ip.ip4, ipaddr); + } pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; /** TODO: this functionality belongs in upper layers */ #ifdef LWIP_UDP_TODO - /* Nail down local IP for netconn_addr()/getsockname() */ - if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { - struct netif *netif; +#if LWIP_IPV6 + if (!pcb->isipv6) +#endif /* LWIP_IPV6 */ + { + /* Nail down local IP for netconn_addr()/getsockname() */ + if (ip_addr_isany(&pcb->local_ip.ip4) && !ip_addr_isany(&pcb->remote_ip.ip4)) { + struct netif *netif; - if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; + if ((netif = ip_route(&(pcb->remote_ip.ip4))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.ip4.addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + /** TODO: this will bind the udp pcb locally, to the interface which + is used to route output packets to the remote address. However, we + might want to accept incoming packets on any interface! */ + pcb->local_ip.ip4 = netif->ip_addr; + } else if (ip_addr_isany(&pcb->remote_ip.ip4)) { + pcb->local_ip.ip4.addr = 0; } - /** TODO: this will bind the udp pcb locally, to the interface which - is used to route output packets to the remote address. However, we - might want to accept incoming packets on any interface! */ - pcb->local_ip = netif->ip_addr; - } else if (ip_addr_isany(&pcb->remote_ip)) { - pcb->local_ip.addr = 0; } #endif - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); + if (!pcb->isipv6) { + ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip4); + } else { + ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip6); + } + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { @@ -864,7 +1177,15 @@ void udp_disconnect(struct udp_pcb *pcb) { /* reset remote address association */ - ip_addr_set_any(&pcb->remote_ip); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set_any(&pcb->remote_ip.ip6); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set_any(&pcb->remote_ip.ip4); + } pcb->remote_port = 0; /* mark PCB as unconnected */ pcb->flags &= ~UDP_FLAGS_CONNECTED; @@ -883,7 +1204,7 @@ void udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ - pcb->recv = recv; + pcb->recv.ip4 = recv; pcb->recv_arg = recv_arg; } @@ -943,6 +1264,28 @@ udp_new(void) return pcb; } +#if LWIP_IPV6 +/** + * Create a UDP PCB for IPv6. + * + * @return The UDP PCB which was created. NULL if the PCB data structure + * could not be allocated. + * + * @see udp_remove() + */ +struct udp_pcb * +udp_new_ip6(void) +{ + struct udp_pcb *pcb; + pcb = udp_new(); + /* could allocate UDP PCB? */ + if (pcb != NULL) { + pcb->isipv6 = 1; + } + return pcb; +} +#endif /* LWIP_IPV6 */ + #if UDP_DEBUG /** * Print UDP header information for debug purposes. diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h index 74f501d1..18a2abb8 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip.h @@ -37,6 +37,7 @@ #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" #include "lwip/err.h" #include "lwip/netif.h" @@ -69,14 +70,29 @@ extern "C" { #define IP_PCB_ADDRHINT #endif /* LWIP_NETIF_HWADDRHINT */ +#if LWIP_IPV6 +#define IP_PCB_ISIPV6 u8_t isipv6; +#define IP_PCB_IP6 ip6_addr_t ip6; +#else +#define IP_PCB_ISIPV6 +#define IP_PCB_IP6 +#endif /* LWIP_IPV6 */ + /* This is the common part of all PCB types. It needs to be at the beginning of a PCB type definition. It is located here so that changes to this common part are made in one location instead of having to change all PCB structs. */ #define IP_PCB \ + IP_PCB_ISIPV6 \ /* ip addresses in network byte order */ \ - ip_addr_t local_ip; \ - ip_addr_t remote_ip; \ + union { \ + ip_addr_t ip4; \ + IP_PCB_IP6 \ + } local_ip; \ + union { \ + ip_addr_t ip4; \ + IP_PCB_IP6 \ + } remote_ip; \ /* Socket options */ \ u8_t so_options; \ /* Type Of Service */ \ diff --git a/src/include/ipv4/lwip/ip_frag.h b/src/include/ipv4/lwip/ip_frag.h index 77b5eb1e..47eca9f4 100644 --- a/src/include/ipv4/lwip/ip_frag.h +++ b/src/include/ipv4/lwip/ip_frag.h @@ -70,12 +70,15 @@ struct pbuf * ip_reass(struct pbuf *p); /** A custom pbuf that holds a reference to another pbuf, which is freed * when this custom pbuf is freed. This is used to create a custom PBUF_REF * that points into the original pbuf. */ +#ifndef __LWIP_PBUF_CUSTOM_REF__ +#define __LWIP_PBUF_CUSTOM_REF__ struct pbuf_custom_ref { /** 'base class' */ struct pbuf_custom pc; /** pointer to the original pbuf that is referenced */ struct pbuf *original; }; +#endif /* __LWIP_PBUF_CUSTOM_REF__ */ #endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest); diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 91b9e5d2..f85a2dc9 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -76,20 +76,35 @@ extern "C" { /* Helpers to process several netconn_types by the same code */ -#define NETCONNTYPE_GROUP(t) (t&0xF0) -#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#define NETCONNTYPE_ISIPV6(t) ((t)&0x08) +#define NETCONNTYPE_ISUDPLITE(t)(((t)&0xF7) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t)(((t)&0xF7) == NETCONN_UDPNOCHKSUM) /** Protocol family and type of the netconn */ enum netconn_type { NETCONN_INVALID = 0, /* NETCONN_TCP Group */ NETCONN_TCP = 0x10, +#if LWIP_IPV6 + NETCONN_TCP_IPV6 = 0x18, +#endif /* LWIP_IPV6 */ /* NETCONN_UDP Group */ NETCONN_UDP = 0x20, NETCONN_UDPLITE = 0x21, NETCONN_UDPNOCHKSUM= 0x22, +#if LWIP_IPV6 + NETCONN_UDP_IPV6 = 0x28, + NETCONN_UDPLITE_IPV6 = 0x29, + NETCONN_UDPNOCHKSUM_IPV6= 0x2a, +#endif /* LWIP_IPV6 */ /* NETCONN_RAW Group */ NETCONN_RAW = 0x40 +#if LWIP_IPV6 + , + NETCONN_RAW_IPV6 = 0x48 +#endif /* LWIP_IPV6 */ }; /** Current state of the netconn. Non-TCP netconns are always @@ -111,13 +126,13 @@ enum netconn_evt { NETCONN_EVT_ERROR }; -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** Used for netconn_join_leave_group() */ enum netconn_igmp { NETCONN_JOIN, NETCONN_LEAVE }; -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ /* forward-declare some structs to avoid to include their headers */ struct ip_pcb; @@ -235,13 +250,25 @@ err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, err_t netconn_close(struct netconn *conn); err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); #endif /* LWIP_DNS */ +#if LWIP_IPV6 +#define netconn_bind_ip6(conn, ip6addr, port) \ + netconn_bind(conn, (ip_addr_t*) ip6addr, port) +#define netconn_connect_ip6(conn, ip6addr, port) \ + netconn_connect(conn, (ip_addr_t*) ip6addr, port) +#define netconn_sendto_ip6(conn, buf, ip6addr, port) \ + netconn_sendto(conn, buf, (ip_addr_t*) ip6addr, port) +#if LWIP_IPV6_MLD +#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) \ + netconn_join_leave_group(conn, (ip_addr_t*)multiaddr, (ip_addr_t*)srcaddr, join_or_leave) +#endif /* LWIP_IPV6_MLD*/ +#endif /* LWIP_IPV6 */ #define netconn_err(conn) ((conn)->last_err) #define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index f99d8c3b..2541e641 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -98,14 +98,14 @@ struct api_msg_msg { struct { u8_t shut; } sd; -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** used for do_join_leave_group */ struct { ip_addr_t *multiaddr; ip_addr_t *netif_addr; enum netconn_igmp join_or_leave; } jl; -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if TCP_LISTEN_BACKLOG struct { u8_t backlog; @@ -154,9 +154,9 @@ void do_write ( struct api_msg_msg *msg); void do_getaddr ( struct api_msg_msg *msg); void do_close ( struct api_msg_msg *msg); void do_shutdown ( struct api_msg_msg *msg); -#if LWIP_IGMP +#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) void do_join_leave_group( struct api_msg_msg *msg); -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS void do_gethostbyname(void *arg); diff --git a/src/include/lwip/memp_std.h b/src/include/lwip/memp_std.h index 6ce408fb..e7b90f29 100644 --- a/src/include/lwip/memp_std.h +++ b/src/include/lwip/memp_std.h @@ -47,7 +47,7 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), #if IP_REASSEMBLY LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") #endif /* IP_REASSEMBLY */ -#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") #endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ @@ -91,6 +91,19 @@ LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") #endif /* PPP_SUPPORT && PPPOE_SUPPORT */ +#if LWIP_IPV6 && LWIP_ND6_QUEUEING +LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") +#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ + +#if LWIP_IPV6 && LWIP_IPV6_REASS +LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ + +#if LWIP_IPV6 && LWIP_IPV6_MLD +LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + /* * A list of pools of pbuf's used by LWIP. * diff --git a/src/include/lwip/netbuf.h b/src/include/lwip/netbuf.h index 7d247d71..82d3d701 100644 --- a/src/include/lwip/netbuf.h +++ b/src/include/lwip/netbuf.h @@ -35,6 +35,7 @@ #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { @@ -45,9 +46,18 @@ extern "C" { /** This netbuf includes a checksum */ #define NETBUF_FLAG_CHKSUM 0x02 +#if LWIP_IPV6 +#define NETBUF_IP6 ip6_addr_t ip6; +#else +#define NETBUF_IP6 +#endif /* LWIP_IPV6 */ + struct netbuf { struct pbuf *p, *ptr; - ip_addr_t addr; + union { + ip_addr_t ip4; + NETBUF_IP6 + } addr; u16_t port; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY @@ -55,7 +65,10 @@ struct netbuf { #endif /* LWIP_CHECKSUM_ON_COPY */ u16_t toport_chksum; #if LWIP_NETBUF_RECVINFO - ip_addr_t toaddr; + union { + ip_addr_t ip4; + NETBUF_IP6 + } toaddr; #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ }; @@ -81,12 +94,12 @@ void netbuf_first (struct netbuf *buf); #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) #define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) #define netbuf_len(buf) ((buf)->p->tot_len) -#define netbuf_fromaddr(buf) (&((buf)->addr)) -#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) +#define netbuf_fromaddr(buf) (&((buf)->addr.ip4)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr.ip4), fromaddr) #define netbuf_fromport(buf) ((buf)->port) #if LWIP_NETBUF_RECVINFO -#define netbuf_destaddr(buf) (&((buf)->toaddr)) -#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) +#define netbuf_destaddr(buf) (&((buf)->toaddr.ip4)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->toaddr.ip4), destaddr) #define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) #endif /* LWIP_NETBUF_RECVINFO */ #if LWIP_CHECKSUM_ON_COPY @@ -94,6 +107,13 @@ void netbuf_first (struct netbuf *buf); (buf)->toport_chksum = chksum; } while(0) #endif /* LWIP_CHECKSUM_ON_COPY */ +#if LWIP_IPV6 +#define netbuf_fromaddr_ip6(buf) (&((buf)->addr.ip6)) +#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set((&(buf)->addr.ip6), fromaddr) +#define netbuf_destaddr_ip6(buf) (&((buf)->toaddr.ip6)) +#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set((&(buf)->toaddr.ip6), destaddr) +#endif /* LWIP_IPV6 */ + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index a8790b5f..a8527f88 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -39,6 +39,7 @@ #include "lwip/err.h" #include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" #include "lwip/def.h" #include "lwip/pbuf.h" @@ -48,6 +49,9 @@ struct dhcp; #if LWIP_AUTOIP struct autoip; #endif +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif /* LWIP_IPV6_DHCP6 */ #ifdef __cplusplus extern "C" { @@ -117,6 +121,18 @@ typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); */ typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr); +#if LWIP_IPV6 +/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'nd_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IPv6 address to which the packet shall be sent + */ +typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, + ip6_addr_t *ipaddr); +#endif /* LWIP_IPV6 */ /** Function prototype for netif->linkoutput functions. Only used for ethernet * netifs. This function is called by ARP when a packet shall be sent. * @@ -129,6 +145,11 @@ typedef void (*netif_status_callback_fn)(struct netif *netif); /** Function prototype for netif igmp_mac_filter functions */ typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, ip_addr_t *group, u8_t action); +#if LWIP_IPV6 && LWIP_IPV6_MLD +/** Function prototype for netif mld_mac_filter functions */ +typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, + ip6_addr_t *group, u8_t action); +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ /** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization @@ -142,6 +163,13 @@ struct netif { ip_addr_t netmask; ip_addr_t gw; +#if LWIP_IPV6 + /** Array of IPv6 addresses for this netif. */ + ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; + /** The state of each IPv6 address (Tentative, Preferred, etc). + * @see ip6_addr.h */ + u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; +#endif /* LWIP_IPV6 */ /** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ netif_input_fn input; @@ -153,6 +181,12 @@ struct netif { * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ netif_linkoutput_fn linkoutput; +#if LWIP_IPV6 + /** This function is called by the IPv6 module when it wants + * to send a packet on the interface. This function typically + * first resolves the hardware address, then sends the packet. */ + netif_output_ip6_fn output_ip6; +#endif /* LWIP_IPV6 */ #if LWIP_NETIF_STATUS_CALLBACK /** This function is called when the netif state is set to up or down */ @@ -174,6 +208,18 @@ struct netif { /** the AutoIP client state information for this netif */ struct autoip *autoip; #endif +#if LWIP_IPV6_AUTOCONFIG + /** is this netif enabled for IPv6 autoconfiguration */ + u8_t ip6_autoconfig_enabled; +#endif /* LWIP_IPV6_AUTOCONFIG */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /** Number of Router Solicitation messages that remain to be sent. */ + u8_t rs_count; +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ +#if LWIP_IPV6_DHCP6 + /** the DHCPv6 client state information for this netif */ + struct dhcp6 *dhcp6; +#endif /* LWIP_IPV6_DHCP6 */ #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ char* hostname; @@ -208,10 +254,15 @@ struct netif { u32_t ifoutdiscards; #endif /* LWIP_SNMP */ #if LWIP_IGMP - /** This function could be called to add or delete a entry in the multicast + /** This function could be called to add or delete an entry in the multicast filter table of the ethernet MAC.*/ netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IGMP */ +#if LWIP_IPV6 && LWIP_IPV6_MLD + /** This function could be called to add or delete an entry in the IPv6 multicast + filter table of the ethernet MAC. */ + netif_mld_mac_filter_fn mld_mac_filter; +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ @@ -308,6 +359,15 @@ void netif_poll_all(void); #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ +#if LWIP_IPV6 +#define netif_ip6_addr(netif, i) (&(netif->ip6_addr[(i)])) +#define netif_ip6_addr_state(netif, i) (netif->ip6_addr_state[(i)]) +#define netif_ip6_addr_set_state(netif, i, state) (netif->ip6_addr_state[(i)] = (state)) +s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr); +void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit); +#endif /* LWIP_IPV6 */ + + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index a1b87658..e5b5eed8 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1544,6 +1544,41 @@ #define SYS_STATS (NO_SYS == 0) #endif +/** + * IP6_STATS==1: Enable IPv6 stats. + */ +#ifndef IP6_STATS +#define IP6_STATS (LWIP_IPV6) +#endif + +/** + * ICMP6_STATS==1: Enable ICMP for IPv6 stats. + */ +#ifndef ICMP6_STATS +#define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) +#endif + +/** + * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. + */ +#ifndef IP6_FRAG_STATS +#define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) +#endif + +/** + * MLD6_STATS==1: Enable MLD for IPv6 stats. + */ +#ifndef MLD6_STATS +#define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) +#endif + +/** + * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. + */ +#ifndef ND6_STATS +#define ND6_STATS (LWIP_IPV6) +#endif + #else #define LINK_STATS 0 @@ -1557,6 +1592,11 @@ #define MEMP_STATS 0 #define SYS_STATS 0 #define LWIP_STATS_DISPLAY 0 +#define IP6_STATS 0 +#define ICMP6_STATS 0 +#define IP6_FRAG_STATS 0 +#define MLD6_STATS 0 +#define ND6_STATS 0 #endif /* LWIP_STATS */ @@ -1779,6 +1819,231 @@ #define LWIP_CHECKSUM_ON_COPY 0 #endif +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#ifndef LWIP_IPV6 +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#ifndef LWIP_IPV6_NUM_ADDRESSES +#define LWIP_IPV6_NUM_ADDRESSES 3 +#endif + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#ifndef LWIP_IPV6_FORWARD +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#ifndef LWIP_ICMP6 +#define LWIP_ICMP6 (LWIP_IPV6) +#endif + +/** + * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in + * ICMPv6 error messages. + */ +#ifndef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE 8 +#endif + +/** + * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages + */ +#ifndef LWIP_ICMP6_HL +#define LWIP_ICMP6_HL 255 +#endif + +/** + * LWIP_ICMP6_CHECKSUM_CHECK==1: verify checksum on ICMPv6 packets + */ +#ifndef LWIP_ICMP6_CHECKSUM_CHECK +#define LWIP_ICMP6_CHECKSUM_CHECK 1 +#endif + +/** + * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. + */ +#ifndef LWIP_IPV6_MLD +#define LWIP_IPV6_MLD (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined. + */ +#ifndef MEMP_NUM_MLD6_GROUP +#define MEMP_NUM_MLD6_GROUP 4 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. + */ +#ifndef LWIP_IPV6_FRAG +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented + */ +#ifndef LWIP_IPV6_REASS +#define LWIP_IPV6_REASS (LWIP_IPV6) +#endif + +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#ifndef LWIP_ND6_QUEUEING +#define LWIP_ND6_QUEUEING (LWIP_IPV6) +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#ifndef MEMP_NUM_ND6_QUEUE +#define MEMP_NUM_ND6_QUEUE 20 +#endif + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#ifndef LWIP_ND6_NUM_NEIGHBORS +#define LWIP_ND6_NUM_NEIGHBORS 10 +#endif + +/** + * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache + */ +#ifndef LWIP_ND6_NUM_DESTINATIONS +#define LWIP_ND6_NUM_DESTINATIONS 10 +#endif + +/** + * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache + */ +#ifndef LWIP_ND6_NUM_PREFIXES +#define LWIP_ND6_NUM_PREFIXES 5 +#endif + +/** + * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache + */ +#ifndef LWIP_ND6_NUM_ROUTERS +#define LWIP_ND6_NUM_ROUTERS 3 +#endif + +/** + * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send + * (neighbor solicit and router solicit) + */ +#ifndef LWIP_ND6_MAX_MULTICAST_SOLICIT +#define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 +#endif + +/** + * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages + * to send during neighbor reachability detection. + */ +#ifndef LWIP_ND6_MAX_UNICAST_SOLICIT +#define LWIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif + +/** + * Unused: See ND RFC (time in milliseconds). + */ +#ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 +#endif + +/** + * Unused: See ND RFC + */ +#ifndef LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT +#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 +#endif + +/** + * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). + * May be updated by router advertisement messages. + */ +#ifndef LWIP_ND6_REACHABLE_TIME +#define LWIP_ND6_REACHABLE_TIME 30000 +#endif + +/** + * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages + */ +#ifndef LWIP_ND6_RETRANS_TIMER +#define LWIP_ND6_RETRANS_TIMER 1000 +#endif + +/** + * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation + * message is sent, during neighbor reachability detection. + */ +#ifndef LWIP_ND6_DELAY_FIRST_PROBE_TIME +#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 +#endif + +/** + * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers, and netif MTU. + */ +#ifndef LWIP_ND6_ALLOW_RA_UPDATES +#define LWIP_ND6_ALLOW_RA_UPDATES 1 +#endif + +/** + * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during + * network startup. + */ +#ifndef LWIP_IPV6_SEND_ROUTER_SOLICIT +#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 +#endif + +/** + * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery + * with reachability hints for connected destinations. This helps avoid sending + * unicast neighbor solicitation messages. + */ +#ifndef LWIP_ND6_TCP_REACHABILITY_HINTS +#define LWIP_ND6_TCP_REACHABILITY_HINTS 1 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#ifndef LWIP_IPV6_AUTOCONFIG +#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) +#endif + +/** + * LWIP_IPV6_DUP_DETECT_ATTEMPTS: Number of duplicate address detection attempts. + */ +#ifndef LWIP_IPV6_DUP_DETECT_ATTEMPTS +#define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 +#endif + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. + */ +#ifndef LWIP_IPV6_DHCP6 +#define LWIP_IPV6_DHCP6 0 +#endif + /* --------------------------------------- ---------- Debugging options ---------- @@ -2040,4 +2305,11 @@ #define DNS_DEBUG LWIP_DBG_OFF #endif +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#ifndef IP6_DEBUG +#define IP6_DEBUG LWIP_DBG_ON +#endif + #endif /* __LWIP_OPT_H__ */ diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 3b1d608b..59eec8c5 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -45,7 +45,11 @@ extern "C" { #define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) #define PBUF_TRANSPORT_HLEN 20 +#if LWIP_IPV6 +#define PBUF_IP_HLEN 40 +#else #define PBUF_IP_HLEN 20 +#endif typedef enum { PBUF_TRANSPORT, diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index 17d0a1c5..a3751f81 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -40,6 +40,7 @@ #include "lwip/def.h" #include "lwip/ip.h" #include "lwip/ip_addr.h" +#include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { @@ -60,6 +61,27 @@ struct raw_pcb; typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr); +#if LWIP_IPV6 +/** Function prototype for raw pcb IPv6 receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IPv6 address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip6_addr_t *addr); +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV6 +#define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6; +#else +#define RAW_PCB_RECV_IP6 +#endif /* LWIP_IPV6 */ + struct raw_pcb { /* Common members of all PCB types */ IP_PCB; @@ -69,7 +91,10 @@ struct raw_pcb { u8_t protocol; /** receive callback function */ - raw_recv_fn recv; + union { + raw_recv_fn ip4; + RAW_PCB_RECV_IP6 + } recv; /* user-supplied argument for the recv callback */ void *recv_arg; }; @@ -85,6 +110,14 @@ void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *re err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr); err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); +#if LWIP_IPV6 +struct raw_pcb * raw_new_ip6 (u8_t proto); +#define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, (ip_addr_t *)ip6addr) +#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, (ip_addr_t *)ip6addr) +#define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg) +#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, (ip_addr_t *)ip6addr) +#endif /* LWIP_IPV6 */ + /* The following functions are the lower layer interface to RAW. */ u8_t raw_input (struct pbuf *p, struct netif *inp); #define raw_init() /* Compatibility define, not init needed. */ diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 3c8fed24..09842b67 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -42,6 +42,7 @@ #include "lwip/ip_addr.h" #include "lwip/inet.h" +#include "lwip/inet6.h" #ifdef __cplusplus extern "C" { @@ -56,10 +57,24 @@ struct sockaddr_in { char sin_zero[8]; }; +#if LWIP_IPV6 +struct sockaddr_in6 { + u8_t sin6_len; /* length of this structure */ + u8_t sin6_family; /* AF_INET6 */ + u16_t sin6_port; /* Transport layer port # */ + u32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ +}; +#endif /* LWIP_IPV6 */ + struct sockaddr { u8_t sa_len; u8_t sa_family; - char sa_data[14]; +#if LWIP_IPV6 + u8_t sa_data[22]; +#else /* LWIP_IPV6 */ + u8_t sa_data[14]; +#endif /* LWIP_IPV6 */ }; #ifndef socklen_t @@ -118,7 +133,13 @@ struct linger { #define AF_UNSPEC 0 #define AF_INET 2 +#if LWIP_IPV6 +#define AF_INET6 10 +#else /* LWIP_IPV6 */ +#define AF_INET6 AF_UNSPEC +#endif /* LWIP_IPV6 */ #define PF_INET AF_INET +#define PF_INET6 AF_INET6 #define PF_UNSPEC AF_UNSPEC #define IPPROTO_IP 0 diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h index 015b7ce7..3ca6ed22 100644 --- a/src/include/lwip/stats.h +++ b/src/include/lwip/stats.h @@ -144,6 +144,21 @@ struct stats_ { #if SYS_STATS struct stats_sys sys; #endif +#if IP6_STATS + struct stats_proto ip6; +#endif +#if ICMP6_STATS + struct stats_proto icmp6; +#endif +#if IP6_FRAG_STATS + struct stats_proto ip6_frag; +#endif +#if MLD6_STATS + struct stats_igmp mld6; +#endif +#if ND6_STATS + struct stats_proto nd6; +#endif }; extern struct stats_ lwip_stats; @@ -268,6 +283,46 @@ void stats_init(void); #define SYS_STATS_DISPLAY() #endif +#if IP6_STATS +#define IP6_STATS_INC(x) STATS_INC(x) +#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") +#else +#define IP6_STATS_INC(x) +#define IP6_STATS_DISPLAY() +#endif + +#if ICMP6_STATS +#define ICMP6_STATS_INC(x) STATS_INC(x) +#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") +#else +#define ICMP6_STATS_INC(x) +#define ICMP6_STATS_DISPLAY() +#endif + +#if IP6_FRAG_STATS +#define IP6_FRAG_STATS_INC(x) STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") +#else +#define IP6_FRAG_STATS_INC(x) +#define IP6_FRAG_STATS_DISPLAY() +#endif + +#if MLD6_STATS +#define MLD6_STATS_INC(x) STATS_INC(x) +#define MLD6_STATS_DISPLAY() stats_display_proto(&lwip_stats.mld6, "MLDv1") +#else +#define MLD6_STATS_INC(x) +#define MLD6_STATS_DISPLAY() +#endif + +#if ND6_STATS +#define ND6_STATS_INC(x) STATS_INC(x) +#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") +#else +#define ND6_STATS_INC(x) +#define ND6_STATS_DISPLAY() +#endif + /* Display of statistics */ #if LWIP_STATS_DISPLAY void stats_display(void); diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 07dcd10e..53bc5320 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -42,6 +42,8 @@ #include "lwip/ip.h" #include "lwip/icmp.h" #include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { @@ -367,6 +369,14 @@ err_t tcp_output (struct tcp_pcb *pcb); const char* tcp_debug_state_str(enum tcp_state s); +#if LWIP_IPV6 +struct tcp_pcb * tcp_new_ip6 (void); +#define tcp_bind_ip6(pcb, ip6addr, port) \ + tcp_bind(pcb, (ip_addr_t *)ip6addr, port) +#define tcp_connect_ip6(pcb, ip6addr, port, connected) \ + udp_connect(pcb, (ip_addr_t *)ip6addr, port, connected) +#endif /* LWIP_IPV6 */ + #ifdef __cplusplus } diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index b4feec0d..126e8eb0 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -43,6 +43,8 @@ #include "lwip/ip.h" #include "lwip/icmp.h" #include "lwip/err.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { @@ -429,6 +431,11 @@ void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); void tcp_rst(u32_t seqno, u32_t ackno, ip_addr_t *local_ip, ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port); +#if LWIP_IPV6 +void tcp_rst_ip6(u32_t seqno, u32_t ackno, + ip6_addr_t *local_ip6, ip6_addr_t *remote_ip6, + u16_t local_port, u16_t remote_port); +#endif /* LWIP_IPV6 */ u32_t tcp_next_iss(void); @@ -437,6 +444,9 @@ void tcp_zero_window_probe(struct tcp_pcb *pcb); #if TCP_CALCULATE_EFF_SEND_MSS u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr); +#if LWIP_IPV6 +u16_t tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest); +#endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if LWIP_CALLBACK_API diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index c98c1b3e..68b7b4e1 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -40,6 +40,7 @@ #include "lwip/netif.h" #include "lwip/ip_addr.h" #include "lwip/ip.h" +#include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { @@ -87,6 +88,26 @@ struct udp_pcb; typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); +#if LWIP_IPV6 +/** Function prototype for udp pcb IPv6 receive callback functions + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IPv6 address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip6_addr_t *addr, u16_t port); +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV6 +#define UDP_PCB_RECV_IP6 udp_recv_ip6_fn ip6; +#else +#define UDP_PCB_RECV_IP6 +#endif /* LWIP_IPV6 */ struct udp_pcb { /* Common members of all PCB types */ @@ -111,7 +132,10 @@ struct udp_pcb { #endif /* LWIP_UDPLITE */ /** receive callback function */ - udp_recv_fn recv; + union { + udp_recv_fn ip4; + UDP_PCB_RECV_IP6 + }recv; /** user-supplied argument for the recv callback */ void *recv_arg; }; @@ -156,6 +180,26 @@ void udp_input (struct pbuf *p, struct netif *inp); #define udp_init() /* Compatibility define, not init needed. */ +#if LWIP_IPV6 +struct udp_pcb * udp_new_ip6(void); +#define udp_bind_ip6(pcb, ip6addr, port) \ + udp_bind(pcb, (ip_addr_t *)ip6addr, port) +#define udp_connect_ip6(pcb, ip6addr, port) \ + udp_connect(pcb, (ip_addr_t *)ip6addr, port) +#define udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \ + udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg) +#define udp_sendto_ip6(pcb, pbuf, ip6addr, port) \ + udp_sendto(pcb, pbuf, (ip_addr_t *)ip6addr, port) +#define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \ + udp_sendto_if(pcb, pbuf, (ip_addr_t *)ip6addr, port, netif) +#if LWIP_CHECKSUM_ON_COPY +#define udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \ + udp_sendto_chksum(pcb, pbuf, (ip_addr_t *)ip6addr, port, have_chk, chksum) +#define udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \ + udp_sendto_if_chksum(pcb, pbuf, (ip_addr_t *)ip6addr, port, netif, have_chk, chksum) +#endif /*LWIP_CHECKSUM_ON_COPY */ +#endif /* LWIP_IPV6 */ + #if UDP_DEBUG void udp_debug_print(struct udp_hdr *udphdr); #else diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h index 691575fa..2eda1488 100644 --- a/src/include/netif/etharp.h +++ b/src/include/netif/etharp.h @@ -137,6 +137,7 @@ PACK_STRUCT_END #define ETHTYPE_ARP 0x0806U #define ETHTYPE_IP 0x0800U #define ETHTYPE_VLAN 0x8100U +#define ETHTYPE_IPV6 0x86DDU #define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ #define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */ diff --git a/src/netif/etharp.c b/src/netif/etharp.c index b60dadd0..99ae853a 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -55,6 +55,7 @@ #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "netif/etharp.h" +#include "lwip/ip6.h" #if PPPOE_SUPPORT #include "netif/ppp_oe.h" @@ -1301,6 +1302,19 @@ ethernet_input(struct pbuf *p, struct netif *netif) break; #endif /* PPPOE_SUPPORT */ +#if LWIP_IPV6 + case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ + /* skip Ethernet header */ + if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) { + LWIP_ASSERT("Can't move over header in packet", 0); + goto free_and_return; + } else { + /* pass to IPv6 layer */ + ip6_input(p, netif); + } + break; +#endif /* LWIP_IPV6 */ + default: ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); diff --git a/src/netif/ethernetif.c b/src/netif/ethernetif.c index a5b7d990..c22731ec 100644 --- a/src/netif/ethernetif.c +++ b/src/netif/ethernetif.c @@ -51,8 +51,9 @@ #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/sys.h" -#include -#include +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" #include "netif/etharp.h" #include "netif/ppp_oe.h" @@ -239,6 +240,7 @@ ethernetif_input(struct netif *netif) switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: + case ETHTYPE_IPV6: case ETHTYPE_ARP: #if PPPOE_SUPPORT /* PPPoE packet? */ @@ -305,6 +307,9 @@ ethernetif_init(struct netif *netif) * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ netif->linkoutput = low_level_output; ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); From 90a03a77ad3e484950c78dee911bc74d9d60eb86 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 17 May 2011 19:54:40 +0000 Subject: [PATCH 002/151] Added new files for IPv6 --- src/core/ipv6/dhcp6.c | 50 + src/core/ipv6/ethip6.c | 197 ++++ src/core/ipv6/ip6_chksum.c | 176 +++ src/core/ipv6/ip6_frag.c | 689 +++++++++++ src/core/ipv6/mld6.c | 578 ++++++++++ src/core/ipv6/nd6.c | 1728 ++++++++++++++++++++++++++++ src/include/ipv6/lwip/dhcp6.h | 58 + src/include/ipv6/lwip/ethip6.h | 68 ++ src/include/ipv6/lwip/icmp6.h | 152 +++ src/include/ipv6/lwip/inet6.h | 89 ++ src/include/ipv6/lwip/ip6.h | 225 ++++ src/include/ipv6/lwip/ip6_addr.h | 282 +++++ src/include/ipv6/lwip/ip6_chksum.h | 70 ++ src/include/ipv6/lwip/ip6_frag.h | 102 ++ src/include/ipv6/lwip/mld6.h | 118 ++ src/include/ipv6/lwip/nd6.h | 368 ++++++ 16 files changed, 4950 insertions(+) create mode 100644 src/core/ipv6/dhcp6.c create mode 100644 src/core/ipv6/ethip6.c create mode 100644 src/core/ipv6/ip6_chksum.c create mode 100644 src/core/ipv6/ip6_frag.c create mode 100644 src/core/ipv6/mld6.c create mode 100644 src/core/ipv6/nd6.c create mode 100644 src/include/ipv6/lwip/dhcp6.h create mode 100644 src/include/ipv6/lwip/ethip6.h create mode 100644 src/include/ipv6/lwip/icmp6.h create mode 100644 src/include/ipv6/lwip/inet6.h create mode 100644 src/include/ipv6/lwip/ip6.h create mode 100644 src/include/ipv6/lwip/ip6_addr.h create mode 100644 src/include/ipv6/lwip/ip6_chksum.h create mode 100644 src/include/ipv6/lwip/ip6_frag.h create mode 100644 src/include/ipv6/lwip/mld6.h create mode 100644 src/include/ipv6/lwip/nd6.h diff --git a/src/core/ipv6/dhcp6.c b/src/core/ipv6/dhcp6.c new file mode 100644 index 00000000..9656c3b2 --- /dev/null +++ b/src/core/ipv6/dhcp6.c @@ -0,0 +1,50 @@ +/** + * @file + * + * DHCPv6. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + + +#endif /* LWIP_IPV6_DHCP6 */ diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c new file mode 100644 index 00000000..1a6001e3 --- /dev/null +++ b/src/core/ipv6/ethip6.c @@ -0,0 +1,197 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET + +#include "lwip/ethip6.h" +#include "lwip/nd6.h" +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" + +#include + +#define ETHTYPE_IPV6 0x86dd + +/** The ethernet address */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { + PACK_STRUCT_FIELD(u8_t addr[6]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Ethernet header */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_hdr { +#if ETH_PAD_SIZE + PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif + PACK_STRUCT_FIELD(struct eth_addr dest); + PACK_STRUCT_FIELD(struct eth_addr src); + PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) + +static err_t ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst); + +/** + * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. + * + * For IPv6 multicast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, ... + * + * @TODO anycast addresses + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ip6addr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t +ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr) +{ + struct eth_addr dest; + s8_t i; + + /* make room for Ethernet header - should not fail */ + if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { + /* bail out */ + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("etharp_output: could not allocate room for header.\n")); + return ERR_BUF; + } + + /* multicast destination IP address? */ + if (ip6_addr_ismulticast(ip6addr)) { + /* Hash IP multicast address to MAC address.*/ + dest.addr[0] = 0x33; + dest.addr[1] = 0x33; + dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0]; + dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1]; + dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2]; + dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3]; + + /* Send out. */ + return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); + } + + /* We have a unicast destination IP address */ + /* TODO anycast? */ + /* Get next hop record. */ + i = nd6_get_next_hop_entry(ip6addr, netif); + if (i < 0) { + /* failed to get a next hop neighbor record. */ + return ERR_MEM; + } + + /* Now that we have a destination record, send or queue the packet. */ + if (neighbor_cache[i].state == ND6_STALE) { + /* Switch to delay state. */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */ + if ((neighbor_cache[i].state == ND6_REACHABLE) || + (neighbor_cache[i].state == ND6_DELAY) || + (neighbor_cache[i].state == ND6_PROBE)) { + + /* Send out. */ + SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); + return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); + } + + /* We should queue packet on this interface. */ + pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); + nd6_queue_packet(i, q); + + return ERR_OK; +} + +/** + * Send an IPv6 packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; + + LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", + (netif->hwaddr_len == 6)); + SMEMCPY(ðhdr->dest, dst, 6); + SMEMCPY(ðhdr->src, src, 6); + ethhdr->type = PP_HTONS(ETHTYPE_IPV6); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); + /* send the packet */ + return netif->linkoutput(netif, p); +} + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/src/core/ipv6/ip6_chksum.c b/src/core/ipv6/ip6_chksum.c new file mode 100644 index 00000000..311a166d --- /dev/null +++ b/src/core/ipv6/ip6_chksum.c @@ -0,0 +1,176 @@ +/** + * @file + * + * IPv6 Checksum helper functions. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" +#include "lwip/def.h" + +#ifndef LWIP_CHKSUM +# define LWIP_CHKSUM lwip_standard_chksum +extern u16_t lwip_standard_chksum(void *dataptr, u16_t len); +#endif + + +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo(struct pbuf *p, + ip6_addr_t *src, ip6_addr_t *dest, + u8_t proto, u16_t proto_len) +{ + u32_t acc; + u32_t addr; + struct pbuf *q; + u8_t swapped; + + acc = 0; + swapped = 0; + /* iterate through all pbuf in chain */ + for(q = p; q != NULL; q = q->next) { + acc += LWIP_CHKSUM(q->payload, q->len); + /* fold the upper bit down */ + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + } + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + for (swapped = 0; swapped < 4; swapped++) { + addr = src->addr[swapped]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[swapped]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("ip6_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. Will only compute for a + * portion of the payload. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param chksum_len number of payload bytes used to compute chksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo_partial(struct pbuf *p, + ip6_addr_t *src, ip6_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len) +{ + u32_t acc; + u32_t addr; + struct pbuf *q; + u8_t swapped; + u16_t chklen; + + acc = 0; + swapped = 0; + /* iterate through all pbuf in chain */ + for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { + chklen = q->len; + if (chklen > chksum_len) { + chklen = chksum_len; + } + acc += LWIP_CHKSUM(q->payload, chklen); + chksum_len -= chklen; + acc = FOLD_U32T(acc); + if (q->len % 2 != 0) { + swapped = 1 - swapped; + acc = SWAP_BYTES_IN_WORD(acc); + } + } + if (swapped) { + acc = SWAP_BYTES_IN_WORD(acc); + } + + for (swapped = 0; swapped < 4; swapped++) { + addr = src->addr[swapped]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[swapped]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + acc += (u32_t)htons((u16_t)proto); + acc += (u32_t)htons(proto_len); + + /* Fold 32-bit sum to 16 bits + calling this twice is propably faster than if statements... */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); + LWIP_DEBUGF(INET_DEBUG, ("ip6_chksum_pseudo_partial(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); + return (u16_t)~(acc & 0xffffUL); +} + +#endif /* LWIP_IPV6 */ diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c new file mode 100644 index 00000000..d6f7ee1d --- /dev/null +++ b/src/core/ipv6/ip6_frag.c @@ -0,0 +1,689 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" +#include "lwip/ip6_frag.h" +#include "lwip/ip6.h" +#include "lwip/icmp6.h" +#include "lwip/nd6.h" + +#include "lwip/pbuf.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + +#if LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + + +/** Setting this to 0, you can turn off checking the fragments for overlapping + * regions. The code gets a little smaller. Only use this if you know that + * overlapping won't occur on your network! */ +#ifndef IP_REASS_CHECK_OVERLAP +#define IP_REASS_CHECK_OVERLAP 1 +#endif /* IP_REASS_CHECK_OVERLAP */ + +/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is + * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. + * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA + * is set to 1, so one datagram can be reassembled at a time, only. */ +#ifndef IP_REASS_FREE_OLDEST +#define IP_REASS_FREE_OLDEST 1 +#endif /* IP_REASS_FREE_OLDEST */ + +#define IP_REASS_FLAG_LASTFRAG 0x01 + +/** This is a helper struct which holds the starting + * offset and the ending offset of this fragment to + * easily chain the fragments. + * It has the same packing requirements as the IPv6 header, since it replaces + * the Fragment Header in memory in incoming fragments to keep + * track of the various fragments. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_reass_helper { + PACK_STRUCT_FIELD(struct pbuf *next_pbuf); + PACK_STRUCT_FIELD(u16_t start); + PACK_STRUCT_FIELD(u16_t end); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* static variables */ +static struct ip6_reassdata *reassdatagrams; +static u16_t ip6_reass_pbufcount; + +/* Forward declarations. */ +static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr); +#if IP_REASS_FREE_OLDEST +static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed); +#endif /* IP_REASS_FREE_OLDEST */ + +void +ip6_reass_tmr(void) +{ + struct ip6_reassdata *r, *tmp; + + r = reassdatagrams; + while (r != NULL) { + /* Decrement the timer. Once it reaches 0, + * clean up the incomplete fragment assembly */ + if (r->timer > 0) { + r->timer--; + r = r->next; + } else { + /* reassembly timed out */ + tmp = r; + /* get the next pointer before freeing */ + r = r->next; + /* free the helper struct and all enqueued pbufs */ + ip6_reass_free_complete_datagram(tmp); + } + } +} + +/** + * Free a datagram (struct ip6_reassdata) and all its pbufs. + * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), + * sends an ICMP time exceeded packet. + * + * @param ipr datagram to free + */ +static void +ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) +{ + struct ip6_reassdata *prev; + u16_t pbufs_freed = 0; + u8_t clen; + struct pbuf *p; + struct ip6_reass_helper *iprh; + +#if LWIP_ICMP6 + iprh = (struct ip6_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, move back to the original header (we are now pointing to Fragment header). */ + pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr); + icmp6_time_exceeded(p, ICMP6_TE_FRAG); + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(p); + } +#endif /* LWIP_ICMP6 */ + + /* First, free all received pbufs. The individual pbufs need to be released + separately as they have not yet been chained */ + p = ipr->p; + while (p != NULL) { + struct pbuf *pcur; + iprh = (struct ip6_reass_helper *)p->payload; + pcur = p; + /* get the next pointer before freeing */ + p = iprh->next_pbuf; + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(pcur); + } + + /* Then, unchain the struct ip6_reassdata from the list and free it. */ + if (ipr == reassdatagrams) { + reassdatagrams = ipr->next; + } else { + prev = reassdatagrams; + while (prev != NULL) { + if (prev->next == ipr) { + break; + } + prev = prev->next; + } + if (prev != NULL) { + prev->next = ipr->next; + } + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* Finally, update number of pbufs in reassembly queue */ + LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); + ip6_reass_pbufcount -= pbufs_freed; +} + +#if IP_REASS_FREE_OLDEST +/** + * Free the oldest datagram to make room for enqueueing new fragments. + * The datagram ipr is not freed! + * + * @param ipr ip6_reassdata for the current fragment + * @param pbufs_needed number of pbufs needed to enqueue + * (used for freeing other datagrams if not enough space) + */ +static void +ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) +{ + struct ip6_reassdata *r, *oldest; + + /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, + * but don't free the current datagram! */ + do { + r = oldest = reassdatagrams; + while (r != NULL) { + if (r != ipr) { + if (r->timer <= oldest->timer) { + /* older than the previous oldest */ + oldest = r; + } + } + r = r->next; + } + if (oldest != NULL) { + ip6_reass_free_complete_datagram(oldest); + } + } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); +} +#endif /* IP_REASS_FREE_OLDEST */ + +/** + * Reassembles incoming IPv6 fragments into an IPv6 datagram. + * + * @param p points to the IPv6 Fragment Header + * @param len the length of the payload (after Fragment Header) + * @return NULL if reassembly is incomplete, pbuf pointing to + * IPv6 Header if reassembly is complete + */ +struct pbuf * +ip6_reass(struct pbuf *p) +{ + struct ip6_reassdata *ipr, *ipr_prev; + struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; + struct ip6_frag_hdr * frag_hdr; + u16_t offset, len; + u8_t clen, valid = 1; + struct pbuf *q; + + IP6_FRAG_STATS_INC(ip6_frag.recv); + + frag_hdr = (struct ip6_frag_hdr *) p->payload; + + clen = pbuf_clen(p); + + offset = ntohs(frag_hdr->_fragment_offset); + + /* Calculate fragment length from IPv6 payload length. + * Adjust for headers before Fragment Header. + * And finally adjust by Fragment Header length. */ + len = ntohs(ip6_current_header()->_plen); + len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN; + len -= IP6_FRAG_HLEN; + + /* Look for the datagram the fragment belongs to in the current datagram queue, + * remembering the previous in the queue for later dequeueing. */ + for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) { + /* Check if the incoming fragment matches the one currently present + in the reassembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if ((frag_hdr->_identification == ipr->identification) && + ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) && + ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) { + IP6_FRAG_STATS_INC(ip6_frag.cachehit); + break; + } + ipr_prev = ipr; + } + + if (ipr == NULL) { + /* Enqueue a new datagram into the datagram queue */ + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST + /* Make room and try again. */ + ip6_reass_remove_oldest_datagram(ipr, clen); + ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); + if (ipr == NULL) +#endif /* IP_REASS_FREE_OLDEST */ + { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } + + memset(ipr, 0, sizeof(struct ip6_reassdata)); + ipr->timer = IP_REASS_MAXAGE; + + /* enqueue the new structure to the front of the list */ + ipr->next = reassdatagrams; + reassdatagrams = ipr; + + /* Use the current IPv6 header for src/dest address reference. + * Eventually, we will replace it when we get the first fragment + * (it might be this one, in any case, it is done later). */ + ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); + + /* copy the fragmented packet id. */ + ipr->identification = frag_hdr->_identification; + + /* copy the nexth field */ + ipr->nexth = frag_hdr->_nexth; + } + + /* Check if we are allowed to enqueue more datagrams. */ + if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { +#if IP_REASS_FREE_OLDEST + ip6_reass_remove_oldest_datagram(ipr, clen); + if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) +#endif /* IP_REASS_FREE_OLDEST */ + { + /* @todo: send ICMPv6 time exceeded here? */ + /* drop this pbuf */ + IP6_FRAG_STATS_INC(ip6_frag.memerr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } + + /* Overwrite Fragment Header with our own helper struct. */ + iprh = (struct ip6_reass_helper *)p->payload; + iprh->next_pbuf = NULL; + iprh->start = (offset & IP6_FRAG_OFFSET_MASK); + iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; + + /* find the right place to insert this pbuf */ + /* Iterate through until we either get to the end of the list (append), + * or we find on with a larger offset (insert). */ + for (q = ipr->p; q != NULL;) { + iprh_tmp = (struct ip6_reass_helper*)q->payload; + if (iprh->start < iprh_tmp->start) { +#if IP_REASS_CHECK_OVERLAP + if (iprh->end > iprh_tmp->start) { + /* fragment overlaps with following, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + if (iprh_prev != NULL) { + if (iprh->start < iprh_prev->end) { + /* fragment overlaps with previous, throw away */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; + } + } +#endif /* IP_REASS_CHECK_OVERLAP */ + /* the new pbuf should be inserted before this */ + iprh->next_pbuf = q; + if (iprh_prev != NULL) { + /* not the fragment with the lowest offset */ + iprh_prev->next_pbuf = p; + } else { + /* fragment with the lowest offset */ + ipr->p = p; + } + break; + } else if(iprh->start == iprh_tmp->start) { + /* received the same datagram twice: no need to keep the datagram */ + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; +#if IP_REASS_CHECK_OVERLAP + } else if(iprh->start < iprh_tmp->end) { + /* overlap: no need to keep the new datagram */ + IP6_FRAG_STATS_INC(ip6_frag.proterr); + IP6_FRAG_STATS_INC(ip6_frag.drop); + goto nullreturn; +#endif /* IP_REASS_CHECK_OVERLAP */ + } else { + /* Check if the fragments received so far have no gaps. */ + if (iprh_prev != NULL) { + if (iprh_prev->end != iprh_tmp->start) { + /* There is a fragment missing between the current + * and the previous fragment */ + valid = 0; + } + } + } + q = iprh_tmp->next_pbuf; + iprh_prev = iprh_tmp; + } + + /* If q is NULL, then we made it to the end of the list. Determine what to do now */ + if (q == NULL) { + if (iprh_prev != NULL) { + /* this is (for now), the fragment with the highest offset: + * chain it to the last fragment */ +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); +#endif /* IP_REASS_CHECK_OVERLAP */ + iprh_prev->next_pbuf = p; + if (iprh_prev->end != iprh->start) { + valid = 0; + } + } else { +#if IP_REASS_CHECK_OVERLAP + LWIP_ASSERT("no previous fragment, this must be the first fragment!", + ipr->p == NULL); +#endif /* IP_REASS_CHECK_OVERLAP */ + /* this is the first fragment we ever received for this ip datagram */ + ipr->p = p; + } + } + + /* Track the current number of pbufs current 'in-flight', in order to limit + the number of fragments that may be enqueued at any one time */ + ip6_reass_pbufcount += clen; + + /* Remember IPv6 header if this is the first fragment. */ + if (iprh->start == 0) { + ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); + } + + /* If this is the last fragment, calculate total packet length. */ + if ((offset & IP6_FRAG_MORE_FLAG) == 0) { + ipr->datagram_len = iprh->end; + } + + /* Additional validity tests: we have received first and last fragment. */ + iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; + if (iprh_tmp->start != 0) { + valid = 0; + } + if (ipr->datagram_len == 0) { + valid = 0; + } + + /* Final validity test: no gaps between current and last fragment. */ + iprh_prev = iprh; + q = iprh->next_pbuf; + while (q != NULL) { + iprh = (struct ip6_reass_helper*)q->payload; + if (iprh_prev->end != iprh->start) { + valid = 0; + break; + } + iprh_prev = iprh; + q = iprh->next_pbuf; + } + + if (valid) { + /* All fragments have been received */ + + /* chain together the pbufs contained within the ip6_reassdata list. */ + iprh = (struct ip6_reass_helper*) ipr->p->payload; + while(iprh != NULL) { + + if (iprh->next_pbuf != NULL) { + /* Save next helper struct (will be hidden in next step). */ + iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload; + + /* hide the fragment header for every succeding fragment */ + pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN); + pbuf_cat(ipr->p, iprh->next_pbuf); + } + else { + iprh_tmp = NULL; + } + + iprh = iprh_tmp; + } + + /* Adjust datagram length by adding header lengths. */ + ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr) + + IP6_FRAG_HLEN + - IP6_HLEN ; + + /* Set payload length in ip header. */ + ipr->iphdr->_plen = htons(ipr->datagram_len); + + /* Get the furst pbuf. */ + p = ipr->p; + + /* Restore Fragment Header in first pbuf. Mark as "single fragment" + * packet. Restore nexth. */ + frag_hdr = (struct ip6_frag_hdr *) p->payload; + frag_hdr->_nexth = ipr->nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = 0; + frag_hdr->_identification = 0; + + /* Move pbuf back to IPv6 header. */ + pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr); + + /* release the sources allocate for the fragment queue entry */ + if (reassdatagrams == ipr) { + /* it was the first in the list */ + reassdatagrams = ipr->next; + } else { + /* it wasn't the first, so it must have a valid 'prev' */ + LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); + ipr_prev->next = ipr->next; + } + memp_free(MEMP_IP6_REASSDATA, ipr); + + /* and adjust the number of pbufs currently queued for reassembly. */ + ip6_reass_pbufcount -= pbuf_clen(p); + + /* Return the pbuf chain */ + return p; + } + /* the datagram is not (yet?) reassembled completely */ + return NULL; + +nullreturn: + pbuf_free(p); + return NULL; +} + +#endif /* LWIP_IPV6_REASS */ + +#if LWIP_IPV6_FRAG + +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip6_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ip6_frag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip6_frag_free_pbuf_custom_ref(pcr); +} + +/** + * Fragment an IPv6 datagram if too large for the netif or path MTU. + * + * Chop the datagram in MTU sized chunks and send them in order + * by pointing PBUF_REFs into p + * + * @param p ipv6 packet to send + * @param netif the netif on which to send + * @param dest destination ipv6 address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise + */ +err_t +ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest) +{ + struct ip6_hdr *original_ip6hdr; + struct ip6_hdr *ip6hdr; + struct ip6_frag_hdr * frag_hdr; + struct pbuf *rambuf; + struct pbuf *newpbuf; + static u32_t identification; + u16_t nfb; + u16_t left, cop; + u16_t mtu; + u16_t fragment_offset = 0; + u16_t last; + u16_t poff = IP6_HLEN; + u16_t newpbuflen = 0; + u16_t left_to_copy; + + identification++; + + original_ip6hdr = (struct ip6_hdr *)p->payload; + + mtu = nd6_get_destination_mtu(dest, netif); + + /* TODO we assume there are no options in the unfragmentable part (IPv6 header). */ + left = p->tot_len - IP6_HLEN; + + nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; + + while (left) { + last = (left <= nfb); + + /* Fill this fragment */ + cop = last ? left : nfb; + + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); + if (rambuf == NULL) { + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (p->len >= (IP6_HLEN + IP6_FRAG_HLEN))); + SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); + ip6hdr = (struct ip6_hdr *)rambuf->payload; + frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len -= poff; + p->tot_len -= poff; + + left_to_copy = cop; + while (left_to_copy) { + struct pbuf_custom_ref *pcr; + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + pcr = ip6_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip6_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + IP6_FRAG_STATS_INC(ip6_frag.memerr); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; + + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) { + p = p->next; + } + } + poff = newpbuflen; + + /* Set headers */ + frag_hdr->_nexth = original_ip6hdr->_nexth; + frag_hdr->reserved = 0; + frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); + frag_hdr->_identification = htonl(identification); + + IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); + IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); + + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + IP6_FRAG_STATS_INC(ip6_frag.xmit); + netif->output_ip6(netif, rambuf, dest); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); + left -= cop; + fragment_offset += cop; + } + return ERR_OK; +} + +#endif /* LWIP_IPV6_FRAG */ diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c new file mode 100644 index 00000000..2e9213b9 --- /dev/null +++ b/src/core/ipv6/mld6.c @@ -0,0 +1,578 @@ +/** + * @file + * + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +/* Based on igmp.c implementation of igmp v2 protocol */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/mld6.h" +#include "lwip/icmp6.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/memp.h" +#include "lwip/stats.h" + +#include + + +/* + * MLD constants + */ +#define MLD6_HL 1 +#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) + +#define MLD6_GROUP_NON_MEMBER 0 +#define MLD6_GROUP_DELAYING_MEMBER 1 +#define MLD6_GROUP_IDLE_MEMBER 2 + + +/* The list of joined groups. */ +static struct mld_group* mld_group_list; + + +/* Forward declarations. */ +static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr); +static err_t mld6_free_group(struct mld_group *group); +static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); +static void mld6_send(struct mld_group *group, u8_t type); + + +/** + * Stop MLD processing on interface + * + * @param netif network interface on which stop MLD processing + */ +err_t +mld6_stop(struct netif *netif) +{ + struct mld_group *group = mld_group_list; + struct mld_group *prev = NULL; + struct mld_group *next; + + /* look for groups joined on this interface further down the list */ + while (group != NULL) { + next = group->next; + /* is it a group joined on this interface? */ + if (group->netif == netif) { + /* is it the first group of the list? */ + if (group == mld_group_list) { + mld_group_list = next; + } + /* is there a "previous" group defined? */ + if (prev != NULL) { + prev->next = next; + } + /* disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER); + } + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + } else { + /* change the "previous" */ + prev = group; + } + /* move to "next" */ + group = next; + } + return ERR_OK; +} + +/** + * Report MLD memberships for this interface + * + * @param netif network interface on which report MLD memberships + */ +void +mld6_report_groups(struct netif *netif) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if (group->netif == netif) { + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + group = group->next; + } +} + +/** + * Search for a group that is joined on a netif + * + * @param ifp the network interface for which to look + * @param addr the group ipv6 address to search for + * @return a struct mld_group* if the group has been found, + * NULL if the group wasn't found. + */ +struct mld_group * +mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) { + return group; + } + group = group->next; + } + + return NULL; +} + + +/** + * create a new group + * + * @param ifp the network interface for which to create + * @param addr the new group ipv6 + * @return a struct mld_group*, + * NULL on memory error. + */ +static struct mld_group * +mld6_new_group(struct netif *ifp, ip6_addr_t *addr) +{ + struct mld_group *group; + + group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); + if (group != NULL) { + group->netif = ifp; + ip6_addr_set(&(group->group_address), addr); + group->timer = 0; /* Not running */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + group->use = 0; + group->next = mld_group_list; + + mld_group_list = group; + } + + return group; +} + +/** + * Remove a group in the mld_group_list and free + * + * @param group the group to remove + * @return ERR_OK if group was removed from the list, an err_t otherwise + */ +static err_t +mld6_free_group(struct mld_group *group) +{ + err_t err = ERR_OK; + + /* Is it the first group? */ + if (mld_group_list == group) { + mld_group_list = group->next; + } else { + /* look for group further down the list */ + struct mld_group *tmpGroup; + for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { + if (tmpGroup->next == group) { + tmpGroup->next = group->next; + break; + } + } + /* Group not find group */ + if (tmpGroup == NULL) + err = ERR_ARG; + } + /* free group */ + memp_free(MEMP_MLD6_GROUP, group); + + return err; +} + + +/** + * Process an input MLD message. Called by icmp6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +mld6_input(struct pbuf *p, struct netif *inp) +{ + struct mld_header * mld_hdr; + struct mld_group* group; + + MLD6_STATS_INC(mld6.recv); + + /* Check that mld header fits in packet. */ + if (p->len < sizeof(struct mld_header)) { + /* TODO debug message */ + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + MLD6_STATS_INC(mld6.drop); + return; + } + + mld_hdr = (struct mld_header *)p->payload; + + switch (mld_hdr->type) { + case ICMP6_TYPE_MLQ: /* Multicast listener query. */ + { + /* Is it a general query? */ + if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && + ip6_addr_isany(&(mld_hdr->multicast_address))) { + MLD6_STATS_INC(mld6.rx_general); + /* Report all groups, except all nodes group, and if-local groups. */ + group = mld_group_list; + while (group != NULL) { + if ((group->netif == inp) && + (!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && + (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + group = group->next; + } + } + else { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_group); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* Schedule a report. */ + mld6_delayed_report(group, mld_hdr->max_resp_delay); + } + } + break; /* ICMP6_TYPE_MLQ */ + } + case ICMP6_TYPE_MLR: /* Multicast listener report. */ + { + /* Have we joined this group? + * We use IP6 destination address to have a memory aligned copy. + * mld_hdr->multicast_address should be the same. */ + MLD6_STATS_INC(mld6.rx_report); + group = mld6_lookfor_group(inp, ip6_current_dest_addr()); + if (group != NULL) { + /* If we are waiting to report, cancel it. */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + group->timer = 0; /* stopped */ + group->group_state = MLD6_GROUP_IDLE_MEMBER; + group->last_reporter_flag = 0; + } + } + break; /* ICMP6_TYPE_MLR */ + } + case ICMP6_TYPE_MLD: /* Multicast listener done. */ + { + /* Do nothing, router will query us. */ + break; /* ICMP6_TYPE_MLD */ + } + default: + MLD6_STATS_INC(mld6.proterr); + MLD6_STATS_INC(mld6.drop); + break; + } + + pbuf_free(p); +} + +/** + * Join a group on a network interface. + * + * @param srcaddr ipv6 address of the network interface which should + * join a new group. If IP6_ADDR_ANY, join on all netifs + * @param groupaddr the ipv6 address of the group to join + * @return ERR_OK if group was joined on the netif(s), an err_t otherwise + */ +err_t +mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct mld_group *group; + struct netif *netif; + u8_t match; + u8_t i; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we join this interface ? */ + match = 0; + if (ip6_addr_isany(srcaddr)) { + match = 1; + } + else { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { + match = 1; + break; + } + } + } + if (match) { + /* find group or create a new one if not found */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group == NULL) { + /* Joining a new group. Create a new group entry. */ + group = mld6_new_group(netif, groupaddr); + if (group == NULL) { + return ERR_MEM; + } + + /* Activate this address on the MAC layer. */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER); + } + + /* Report our membership. */ + MLD6_STATS_INC(mld6.tx_report); + mld6_send(group, ICMP6_TYPE_MLR); + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); + } + + /* Increment group use */ + group->use++; + err = ERR_OK; + } + + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + +/** + * Leave a group on a network interface. + * + * @param srcaddr ipv6 address of the network interface which should + * leave the group. If IP6_ISANY, leave on all netifs + * @param groupaddr the ipv6 address of the group to leave + * @return ERR_OK if group was left on the netif(s), an err_t otherwise + */ +err_t +mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) +{ + err_t err = ERR_VAL; /* no matching interface */ + struct mld_group *group; + struct netif *netif; + u8_t match; + u8_t i; + + /* loop through netif's */ + netif = netif_list; + while (netif != NULL) { + /* Should we leave this interface ? */ + match = 0; + if (ip6_addr_isany(srcaddr)) { + match = 1; + } + else { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { + match = 1; + break; + } + } + } + if (match) { + /* find group */ + group = mld6_lookfor_group(netif, groupaddr); + + if (group != NULL) { + /* Leave if there is no other use of the group */ + if (group->use <= 1) { + /* If we are the last reporter for this group */ + if (group->last_reporter_flag) { + MLD6_STATS_INC(mld6.tx_leave); + mld6_send(group, ICMP6_TYPE_MLD); + } + + /* Disable the group at the MAC level */ + if (netif->mld_mac_filter != NULL) { + netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER); + } + + /* Free the group */ + mld6_free_group(group); + } else { + /* Decrement group use */ + group->use--; + } + /* Leave on this interface */ + err = ERR_OK; + } + } + /* proceed to next network interface */ + netif = netif->next; + } + + return err; +} + + +/** + * Periodic timer for mld processing. Must be called every + * MLD6_TMR_INTERVAL milliseconds (100). + * + * When a delaying member expires, a membership report is sent. + */ +void +mld6_tmr(void) +{ + struct mld_group *group = mld_group_list; + + while (group != NULL) { + if (group->timer > 0) { + group->timer--; + if (group->timer == 0) { + /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ + if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { + MLD6_STATS_INC(mld6.tx_report); + mld6_send(group, ICMP6_TYPE_MLR); + group->group_state = MLD6_GROUP_IDLE_MEMBER; + } + } + } + group = group->next; + } +} + +/** + * Schedule a delayed membership report for a group + * + * @param group the mld_group for which "delaying" membership report + * should be sent + * @param maxresp the max resp delay provided in the query + */ +static void +mld6_delayed_report(struct mld_group *group, u16_t maxresp) +{ + /* Convert maxresp from milliseconds to tmr ticks */ + maxresp = maxresp / MLD6_TMR_INTERVAL; + if (maxresp == 0) { + maxresp = 1; + } + + /* Randomize maxresp. */ + maxresp = (LWIP_RAND() % (maxresp - 1)) + 1; + + /* Apply timer value if no report has been scheduled already. */ + if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || + ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + group->timer = maxresp; + group->group_state = MLD6_GROUP_DELAYING_MEMBER; + } +} + +/** + * Send a MLD message (report or done). + * + * An IPv6 hop-by-hop options header with a router alert option + * is prepended. + * + * @param group the group to report or quit + * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) + */ +static void +mld6_send(struct mld_group *group, u8_t type) +{ + struct mld_header * mld_hdr; + struct pbuf * p; + ip6_addr_t * src_addr; + + /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); + if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) { + /* We couldn't allocate a suitable pbuf. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + MLD6_STATS_INC(mld6.memerr); + return; + } + + /* Move to make room for Hop-by-hop options header. */ + if (pbuf_header(p, -IP6_HBH_HLEN)) { + pbuf_free(p); + MLD6_STATS_INC(mld6.lenerr); + return; + } + + /* Select our source address. */ + if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) { + /* This is a special case, when we are performing duplicate address detection. + * We must join the multicast group, but we don't have a valid address yet. */ + src_addr = IP6_ADDR_ANY; + } else { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(group->netif, 0); + } + + /* MLD message header pointer. */ + mld_hdr = (struct mld_header *)p->payload; + + /* Set fields. */ + mld_hdr->type = type; + mld_hdr->code = 0; + mld_hdr->chksum = 0; + mld_hdr->max_resp_delay = 0; + mld_hdr->reserved = 0; + ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); + + mld_hdr->chksum = ip6_chksum_pseudo(p, src_addr, &(group->group_address), + IP6_NEXTH_ICMP6, p->len); + + /* Add hop-by-hop headers options: router alert with MLD value. */ + ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); + + /* Send the packet out. */ + MLD6_STATS_INC(mld6.xmit); + ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), + MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif); + pbuf_free(p); +} + + + +#endif /* LWIP_IPV6 */ diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c new file mode 100644 index 00000000..7a80e653 --- /dev/null +++ b/src/core/ipv6/nd6.c @@ -0,0 +1,1728 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/nd6.h" +#include "lwip/pbuf.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/ip6_chksum.h" +#include "lwip/netif.h" +#include "lwip/icmp6.h" +#include "lwip/mld6.h" +#include "lwip/stats.h" + +#include + + +/* Router tables. */ +struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; +struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; +struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; +struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; + +/* Default values, can be updated by a RA message. */ +u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; +u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* TODO implement this value in timer */ + +/* Index for cache entries. */ +static u8_t nd6_cached_neighbor_index; +static u8_t nd6_cached_destination_index; + +/* Multicast address holder. */ +static ip6_addr_t multicast_address; + +/* Forward declarations. */ +static s8_t nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr); +static s8_t nd6_new_neighbor_cache_entry(void); +static void nd6_free_neighbor_cache_entry(s8_t i); +static s8_t nd6_find_destination_cache_entry(ip6_addr_t * ip6addr); +static s8_t nd6_new_destination_cache_entry(void); +static s8_t nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif); +static s8_t nd6_get_router(ip6_addr_t * router_addr, struct netif * netif); +static s8_t nd6_new_router(ip6_addr_t * router_addr, struct netif * netif); +static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); +static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); + +#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 +#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 +static void nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); +static void nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +static void nd6_send_rs(struct netif * netif); +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +#if LWIP_ND6_QUEUEING +static void nd6_free_q(struct nd6_q_entry *q); +static void nd6_send_q(s8_t i); +#endif /* LWIP_ND6_QUEUEING */ + + +/** + * Process an incoming neighbor discovery message + * + * @param p the nd packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +nd6_input(struct pbuf *p, struct netif *inp) +{ + u8_t msg_type; + s8_t i; + + ND6_STATS_INC(nd6.recv); + + msg_type = *((u8_t *)p->payload); + switch (msg_type) { + case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ + { + struct na_header * na_hdr; + struct lladdr_option * lladdr_opt; + + /* Check that na header and link-layer address option fit in packet. */ + if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + + /* Unsolicited NA?*/ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* This is an unsolicited NA. + * link-layer changed? + * part of DAD mechanism? */ + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); + +#if LWIP_IPV6_DUP_DETECT_ATTEMPTS + /* If the target address matches this netif, it is a DAD response. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { + /* We are using a duplicate address. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + +#if LWIP_IPV6_MLD + /* Leave solicited node multicast group. */ + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); + mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address); +#endif /* LWIP_IPV6_MLD */ + + + + +#if LWIP_IPV6_AUTOCONFIG + /* Check to see if this address was autoconfigured. */ + if (!ip6_addr_islinklocal(ip6_current_dest_addr())) { + i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); + if (i >= 0) { + /* Mark this prefix as duplicate, so that we don't use it + * to generate this address again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + + pbuf_free(p); + return; + } + } +#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ + + /* This is an unsolicited NA, most likely there was a LLADDR change. */ + i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); + if (i >= 0) { + if (na_hdr->flags & ND6_FLAG_OVERRIDE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + } + } + else { + /* This is a solicited NA. + * neighbor address resolution response? + * neighbor unreachability detection response? */ + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); + + /* Find the cache entry corresponding to this na. */ + i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); + if (i < 0) { + /* We no longer care about this target address. drop it. */ + pbuf_free(p); + return; + } + + /* Update cache entry. */ + neighbor_cache[i].netif = inp; + neighbor_cache[i].counter.reachable_time = reachable_time; + if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || + (neighbor_cache[i].state == ND6_INCOMPLETE)) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + } + neighbor_cache[i].state = ND6_REACHABLE; + +#if LWIP_ND6_QUEUEING + /* Send queued packets, if any. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } +#endif /* LWIP_ND6_QUEUEING */ + } + + break; /* ICMP6_TYPE_NA */ + } + case ICMP6_TYPE_NS: /* Neighbor solicitation. */ + { + struct ns_header * ns_hdr; + struct lladdr_option * lladdr_opt; + u8_t accepted; + + /* Check that ns header fits in packet. */ + if (p->len < sizeof(struct ns_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ns_hdr = (struct ns_header *)p->payload; + + /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ + lladdr_opt = NULL; + if (p->len >= (sizeof(struct ns_header) + sizeof(struct lladdr_option))) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + } + + /* Check if the target address is configured on the receiving netif. */ + accepted = 0; + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || + (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && + ip6_addr_isany(ip6_current_src_addr()))) && + ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { + accepted = 1; + break; + } + } + + /* NS not for us? */ + if (!accepted) { + pbuf_free(p); + return; + } + + /* Check for ANY address in src (DAD algorithm). */ + if (ip6_addr_isany(ip6_current_src_addr())) { + /* Sender is validating this address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { + /* Send a NA back so that the sender does not use this address. */ + nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); + if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { + /* We shouldn't use this address either. */ + netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); + } + } + } + } + else { + /* Sender is trying to resolve our address. */ + /* Verify that they included their own link-layer address. */ + if (lladdr_opt == NULL) { + /* Not a valid message. */ + pbuf_free(p); + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + return; + } + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if ( i>= 0) { + /* We already have a record for the solicitor. */ + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + + /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + else + { + /* Add their IPv6 address and link-layer address to neighbor cache. + * We will need it at least to send a unicast NA message, but most + * likely we will also be communicating with this node soon. */ + i = nd6_new_neighbor_cache_entry(); + if (i < 0) { + /* We couldn't assign a cache entry for this neighbor. + * we won't be able to reply. drop it. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); + + /* Send back a NA for us. Allocate the reply pbuf. */ + nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); + } + + break; /* ICMP6_TYPE_NS */ + } + case ICMP6_TYPE_RA: /* Router Advertisement. */ + { + struct ra_header * ra_hdr; + u8_t * buffer; /* Used to copy options. */ + s8_t i; + u16_t offset; + + /* Check that RA header fits in packet. */ + if (p->len < sizeof(struct ra_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + ra_hdr = (struct ra_header *)p->payload; + + /* If we are sending RS messages, stop. */ +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + if (inp->rs_count > 0) { + inp->rs_count = 0; + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + + /* Get the matching default router entry. */ + i = nd6_get_router(ip6_current_src_addr(), inp); + if (i < 0) { + /* Create a new router entry. */ + i = nd6_new_router(ip6_current_src_addr(), inp); + } + + if (i < 0) { + /* Could not create a new router entry. */ + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Re-set invalidation timer. */ + default_router_list[i].invalidation_timer = ra_hdr->router_lifetime; + + /* Re-set default timer values. */ +#if LWIP_ND6_ALLOW_RA_UPDATES + if (ra_hdr->retrans_timer > 0) { + retrans_timer = ra_hdr->retrans_timer; + } + if (ra_hdr->reachable_time > 0) { + reachable_time = ra_hdr->reachable_time; + } +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + + /* TODO set default hop limit... */ + /* ra_hdr->current_hop_limit;*/ + + /* Update flags in local entry (incl. preference). */ + default_router_list[i].flags = ra_hdr->flags; + + /* Offset to options. */ + offset = sizeof(struct ra_header); + + /* Allocate buffer to copy options (so we can traverse pbufs). */ + buffer = (u8_t *)mem_malloc(sizeof(struct prefix_option)); /* Size of a prefix option, biggest option. */ + if (buffer == NULL) { + pbuf_free(p); + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Process each option. */ + while ((p->tot_len - offset) > 0) { + pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); + switch (buffer[0]) { + case ND6_OPTION_TYPE_SOURCE_LLADDR: + { + struct lladdr_option * lladdr_opt; + lladdr_opt = (struct lladdr_option *)buffer; + if ((default_router_list[i].neighbor_entry != NULL) && + (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { + SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); + default_router_list[i].neighbor_entry->state = ND6_REACHABLE; + default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; + } + break; + } + case ND6_OPTION_TYPE_MTU: + { + struct mtu_option * mtu_opt; + mtu_opt = (struct mtu_option *)buffer; + if (mtu_opt->mtu >= 1280) { +#if LWIP_ND6_ALLOW_RA_UPDATES + inp->mtu = mtu_opt->mtu; +#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ + } + break; + } + case ND6_OPTION_TYPE_PREFIX_INFO: + { + struct prefix_option * prefix_opt; + prefix_opt = (struct prefix_option *)buffer; + + if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) { + /* Add to on-link prefix list. */ + + /* Get a memory-aligned copy of the prefix. */ + ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix)); + + /* find cache entry for this prefix. */ + i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); + if (i < 0) { + /* Create a new cache entry. */ + i = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp); + } + if (i >= 0) { + prefix_list[i].invalidation_timer = prefix_opt->valid_lifetime; + +#if LWIP_IPV6_AUTOCONFIG + if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { + /* Mark prefix as autonomous, so that address autoconfiguration can take place. + * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + + break; + } + case ND6_OPTION_TYPE_ROUTE_INFO: + { + struct route_option * route_opt; + route_opt = (struct route_option *)buffer; + + /* TODO implement preferred routes. */ + + break; + } + default: + /* Unrecognized option, abort. */ + ND6_STATS_INC(nd6.proterr); + break; + } + offset += 8 * ((u16_t)buffer[1]); + } + + + /* free options buffer. */ + mem_free(buffer); + + break; /* ICMP6_TYPE_RA */ + } + case ICMP6_TYPE_RD: /* Redirect */ + { + struct redirect_header * redir_hdr; + s8_t i; + struct lladdr_option * lladdr_opt; + + /* Check that Redir header fits in packet. */ + if (p->len < sizeof(struct redirect_header)) { + /* TODO debug message */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + redir_hdr = (struct redirect_header *)p->payload; + + lladdr_opt = NULL; + if (p->len >= (sizeof(struct redirect_header) + sizeof(struct lladdr_option))) { + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); + } + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address)); + + /* Find dest address in cache */ + i = nd6_find_destination_cache_entry(ip6_current_src_addr()); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Set the new target address. */ + ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address)); + + /* If Link-layer address of other router is given, try to add to neighbor cache. */ + if (lladdr_opt != NULL) { + if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { + /* Copy target address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address)); + + i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); + if (i < 0) { + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + neighbor_cache[i].netif = inp; + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); + + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + if (i >= 0) { + if (neighbor_cache[i].state == ND6_INCOMPLETE) { + MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); + /* Receiving a message does not prove reachability: only in one direction. + * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ + neighbor_cache[i].state = ND6_DELAY; + neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; + } + } + } + } + break; /* ICMP6_TYPE_RD */ + } + case ICMP6_TYPE_PTB: /* Packet too big */ + { + struct icmp6_hdr *icmp6hdr; /* Packet too big message */ + struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */ + s8_t i; + + /* Check that ICMPv6 header + IPv6 header fit in payload */ + if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { + /* drop short packets */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); + ND6_STATS_INC(nd6.drop); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); + + /* Copy original destination address to current source address, to have an aligned copy. */ + ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest)); + + /* Look for entry in destination cache. */ + i = nd6_find_destination_cache_entry(ip6_current_src_addr()); + if (i < 0) { + /* Destination not in cache, drop packet. */ + pbuf_free(p); + return; + } + + /* Change the Path MTU. */ + destination_cache[i].pmtu = icmp6hdr->data; + + break; /* ICMP6_TYPE_PTB */ + } + + default: + ND6_STATS_INC(nd6.proterr); + ND6_STATS_INC(nd6.drop); + break; /* default */ + } + + pbuf_free(p); +} + + +/** + * Periodic timer for Neighbor discovery functions: + * + * - Update neighbor reachability states + * - Update destination cache entries age + * - Update invalidation timers of default routers and on-link prefixes + * - Perform duplicate address detection (DAD) for our addresses + * - Send router solicitations + */ +void +nd6_tmr(void) +{ + s8_t i, j; + struct netif * netif; + + /* Process neighbor entries. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + switch (neighbor_cache[i].state) { + case ND6_INCOMPLETE: + if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } + else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST); + } + break; + case ND6_REACHABLE: +#if LWIP_ND6_QUEUEING + /* Send queued packets, if any are left. Should have been sent already. */ + if (neighbor_cache[i].q != NULL) { + nd6_send_q(i); + } +#endif /* LWIP_ND6_QUEUEING */ + if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { + /* Change to stale state. */ + neighbor_cache[i].state = ND6_STALE; + neighbor_cache[i].counter.stale_time = 0; + } + else { + neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_STALE: + neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL; + break; + case ND6_DELAY: + if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) { + /* Change to PROBE state. */ + neighbor_cache[i].state = ND6_PROBE; + neighbor_cache[i].counter.probes_sent = 0; + } + else { + neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; + } + break; + case ND6_PROBE: + if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) { + /* Retries exceeded. */ + nd6_free_neighbor_cache_entry(i); + } + else { + /* Send a NS for this entry. */ + neighbor_cache[i].counter.probes_sent++; + nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0); + } + break; + case ND6_NO_ENTRY: + default: + /* Do nothing. */ + break; + } + } + + /* Process destination entries. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + destination_cache[i].age++; + } + + /* Process router entries. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (default_router_list[i].neighbor_entry != NULL) { + /* Active entry. */ + if (default_router_list[i].invalidation_timer > 0) { + default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + /* Less than 1 second remainig. Clear this entry. */ + default_router_list[i].neighbor_entry->isrouter = 0; + default_router_list[i].neighbor_entry = NULL; + default_router_list[i].invalidation_timer = 0; + default_router_list[i].flags = 0; + } + } + } + + /* Process prefix entries. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { + prefix_list[i].invalidation_timer = 0; + } + if ((prefix_list[i].invalidation_timer > 0) && + (prefix_list[i].netif != NULL)) { + prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + +#if LWIP_IPV6_AUTOCONFIG + /* Initiate address autoconfiguration for this prefix, if conditions are met. */ + if (prefix_list[i].netif->ip6_autoconfig_enabled && + (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) && + !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) { + /* Try to get an address on this netif that is invalid. + * Skip 0 index (link-local address) */ + for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { + if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDRESS_STATE_INVALID) { + /* Generate an address using this prefix and interface ID from link-local address. */ + prefix_list[i].netif->ip6_addr[j].addr[0] = prefix_list[i].prefix.addr[0]; + prefix_list[i].netif->ip6_addr[j].addr[1] = prefix_list[i].prefix.addr[1]; + prefix_list[i].netif->ip6_addr[j].addr[2] = prefix_list[i].netif->ip6_addr[0].addr[2]; + prefix_list[i].netif->ip6_addr[j].addr[3] = prefix_list[i].netif->ip6_addr[0].addr[3]; + + /* Mark it as tentative (DAD will be performed if configured). */ + netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); + + /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ + prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; + + /* Exit loop. */ + break; + } + } + } +#endif /* LWIP_IPV6_AUTOCONFIG */ + } + } + + + /* Process our own addresses, if DAD configured. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { + if (ip6_addr_istentative(netif->ip6_addr_state[i])) { + if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { + /* No NA received in response. Mark address as valid. */ + netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED; + /* TODO implement preferred and valid lifetimes. */ + } + else if (netif->flags & NETIF_FLAG_UP) { +#if LWIP_IPV6_MLD + if ((netif->ip6_addr_state[i] & 0x07) == 0) { + /* Join solicited node multicast group. */ + ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); + mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address); + } +#endif /* LWIP_IPV6_MLD */ + /* Send a NS for this address. */ + nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); + (netif->ip6_addr_state[i])++; + /* TODO send max 1 NS per tmr call? enable return*/ + /*return;*/ + } + } + } + } + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT + /* Send router solicitation messages, if necessary. */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP)) { + nd6_send_rs(netif); + netif->rs_count--; + } + } +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +} + +/** + * Send a neighbor solicitation message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) +{ + struct ns_header * ns_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + + if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { + /* Use link-local address as source address. */ + src_addr = netif_ip6_addr(netif, 0); + } else { + src_addr = IP6_ADDR_ANY; + } + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + sizeof(struct lladdr_option), PBUF_RAM); + if ((p == NULL) || (p->len < (sizeof(struct ns_header) + sizeof(struct lladdr_option)))) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + ns_hdr = (struct ns_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + + ns_hdr->type = ICMP6_TYPE_NS; + ns_hdr->code = 0; + ns_hdr->chksum = 0; + ns_hdr->reserved = 0; + ip6_addr_set(&(ns_hdr->target_address), target_addr); + + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + target_addr = &multicast_address; + } + + ns_hdr->chksum = ip6_chksum_pseudo(p, src_addr, target_addr, + IP6_NEXTH_ICMP6, p->len); + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, (src_addr == IP6_ADDR_ANY) ? NULL : src_addr, target_addr, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +/** + * Send a neighbor advertisement message + * + * @param netif the netif on which to send the message + * @param target_addr the IPv6 target address for the ND message + * @param flags one of ND6_SEND_FLAG_* + */ +static void +nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) +{ + struct na_header * na_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + ip6_addr_t * dest_addr; + + /* Use link-local address as source address. */ + src_addr = &(netif->ip6_addr[0]); + + /* Allocate a packet. */ + p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + sizeof(struct lladdr_option), PBUF_RAM); + if ((p == NULL) || (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option)))) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); + + na_hdr->type = ICMP6_TYPE_NA; + na_hdr->code = 0; + na_hdr->chksum = 0; + na_hdr->flags = flags & 0xf0; + na_hdr->reserved[0] = 0; + na_hdr->reserved[1] = 0; + na_hdr->reserved[2] = 0; + ip6_addr_set(&(na_hdr->target_address), target_addr); + + lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; + lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + + /* Generate the solicited node address for the target address. */ + if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { + ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); + dest_addr = &multicast_address; + } + else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { + ip6_addr_set_allnodes_linklocal(&multicast_address); + dest_addr = &multicast_address; + } + else { + dest_addr = ip6_current_src_addr(); + } + + na_hdr->chksum = ip6_chksum_pseudo(p, src_addr, dest_addr, + IP6_NEXTH_ICMP6, p->len); + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, src_addr, dest_addr, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} + +#if LWIP_IPV6_SEND_ROUTER_SOLICIT +/** + * Send a router solicitation message + * + * @param netif the netif on which to send the message + */ +static void +nd6_send_rs(struct netif * netif) +{ + struct rs_header * rs_hdr; + struct lladdr_option * lladdr_opt; + struct pbuf * p; + ip6_addr_t * src_addr; + u16_t packet_len; + + /* Link-local source address, or unspecified address? */ + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { + src_addr = netif_ip6_addr(netif, 0); + } + else { + src_addr = IP6_ADDR_ANY; + } + + /* Generate the all routers target address. */ + ip6_addr_set_allrouters_linklocal(&multicast_address); + + /* Allocate a packet. */ + packet_len = sizeof(struct rs_header); + if (src_addr != IP6_ADDR_ANY) { + packet_len += sizeof(struct lladdr_option); + } + p = pbuf_alloc(PBUF_IP, packet_len, PBUF_RAM); + if ((p == NULL) || (p->len < packet_len)) { + /* We couldn't allocate a suitable pbuf for the ns. drop it. */ + if (p != NULL) { + pbuf_free(p); + } + ND6_STATS_INC(nd6.memerr); + return; + } + + /* Set fields. */ + rs_hdr = (struct rs_header *)p->payload; + + rs_hdr->type = ICMP6_TYPE_RS; + rs_hdr->code = 0; + rs_hdr->chksum = 0; + rs_hdr->reserved = 0; + + if (src_addr != IP6_ADDR_ANY) { + /* Include our hw address. */ + lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); + SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); + } + + rs_hdr->chksum = ip6_chksum_pseudo(p, src_addr, &multicast_address, + IP6_NEXTH_ICMP6, p->len); + + /* Send the packet out. */ + ND6_STATS_INC(nd6.xmit); + ip6_output_if(p, src_addr, &multicast_address, + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); + pbuf_free(p); +} +#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ + +/** + * Search for a neighbor cache entry + * + * @param ip6addr the IPv6 address of the neighbor + * @return The neighbor cache entry index that matched, -1 if no + * entry is found + */ +static s8_t +nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { + return i; + } + } + return -1; +} + +/** + * Create a new neighbor cache entry. + * + * If no unused entry is found, will try to recycle an old entry + * according to ad-hoc "age" heuristic. + * + * @return The neighbor cache entry index that was created, -1 if no + * entry could be created + */ +static s8_t +nd6_new_neighbor_cache_entry(void) +{ + s8_t i; + s8_t j; + u32_t time; + + + /* First, try to find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if (neighbor_cache[i].state == ND6_NO_ENTRY) { + return i; + } + } + + /* We need to recycle an entry. in general, do not recycle if it is a router. */ + + /* Next, try to find a Stale entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_STALE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Probe entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_PROBE) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find a Delayed entry. */ + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_DELAY) && + (!neighbor_cache[i].isrouter)) { + nd6_free_neighbor_cache_entry(i); + return i; + } + } + + /* Next, try to find the oldest reachable entry. */ + time = 0xfffffffful; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_REACHABLE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.reachable_time < time) { + j = i; + time = neighbor_cache[i].counter.reachable_time; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry without queued packets. */ + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ( +#if LWIP_ND6_QUEUEING + (neighbor_cache[i].q == NULL) && +#endif /* LWIP_ND6_QUEUEING */ + (neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } + + /* Next, find oldest incomplete entry with queued packets. */ +#if LWIP_ND6_QUEUEING + time = 0; + j = -1; + for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { + if ((neighbor_cache[i].state == ND6_INCOMPLETE) && + (!neighbor_cache[i].isrouter)) { + if (neighbor_cache[i].counter.probes_sent >= time) { + j = i; + time = neighbor_cache[i].counter.probes_sent; + } + } + } + if (j >= 0) { + nd6_free_neighbor_cache_entry(j); + return j; + } +#endif /* LWIP_ND6_QUEUEING */ + + /* No more entries to try. */ + return -1; +} + +/** + * Will free any resources associated with a neighbor cache + * entry, and will mark it as unused. + * + * @param i the neighbor cache entry index to free + */ +static void +nd6_free_neighbor_cache_entry(s8_t i) +{ +#if LWIP_ND6_QUEUEING + /* Free any queued packets. */ + if (neighbor_cache[i].q != NULL) { + nd6_free_q(neighbor_cache[i].q); + neighbor_cache[i].q = NULL; + } +#endif /* LWIP_ND6_QUEUEING */ + + neighbor_cache[i].state = ND6_NO_ENTRY; + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = NULL; + neighbor_cache[i].counter.reachable_time = 0; + ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); +} + +/** + * Search for a destination cache entry + * + * @param ip6addr the IPv6 address of the destination + * @return The destination cache entry index that matched, -1 if no + * entry is found + */ +static s8_t +nd6_find_destination_cache_entry(ip6_addr_t * ip6addr) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { + return i; + } + } + return -1; +} + +/** + * Create a new destination cache entry. If no unused entry is found, + * will recycle oldest entry. + * + * @return The destination cache entry index that was created, -1 if no + * entry was created + */ +static s8_t +nd6_new_destination_cache_entry(void) +{ + s8_t i, j; + u32_t age; + + /* Find an empty entry. */ + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { + return i; + } + } + + /* Find oldest entry. */ + age = 0; + j = LWIP_ND6_NUM_DESTINATIONS - 1; + for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { + if (destination_cache[i].age > age) { + j = i; + } + } + + return j; +} + +/** + * Determine whether an address matches an on-link prefix. + * + * @param ip6addr the IPv6 address to match + * @return 1 if the address is on-link, 0 otherwise + */ +static s8_t +nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { + if ((prefix_list[i].netif == netif) && + (prefix_list[i].invalidation_timer > 0) && + ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { + return 1; + } + } + return 0; +} + +/** + * Select a default router for a destination. + * + * @param ip6addr the destination address + * @param netif the netif for the outgoing packet, if known + * @return the default router entry index, or -1 if no suitable + * router is found + */ +s8_t +nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + /* last_router is used for round-robin router selection (as recommended + * in RFC). This is more robust in case one router is not reachable, + * we are not stuck trying to resolve it. */ + static s8_t last_router; + (void)ip6addr; /* TODO match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ + + /* TODO: implement default router preference */ + + /* Look for reachable routers. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0) && + (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { + return i; + } + } + + /* Look for router in other reachability states, but still valid according to timer. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if ((default_router_list[i].neighbor_entry != NULL) && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && + (default_router_list[i].invalidation_timer > 0)) { + return i; + } + } + + /* Look for any router for which we have any information at all. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if (++last_router >= LWIP_ND6_NUM_ROUTERS) { + last_router = 0; + } + if (default_router_list[i].neighbor_entry != NULL && + (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { + return i; + } + } + + /* no suitable router found. */ + return -1; +} + +/** + * Find an entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is found, if known + * @return the index of the router entry, or -1 if not found + */ +static s8_t +nd6_get_router(ip6_addr_t * router_addr, struct netif * netif) +{ + s8_t i; + + /* Look for router. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if ((default_router_list[i].neighbor_entry != NULL) && + ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && + ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { + return i; + } + } + + /* router not found. */ + return -1; +} + +/** + * Create a new entry for a default router. + * + * @param router_addr the IPv6 address of the router + * @param netif the netif on which the router is connected, if known + * @return the index on the router table, or -1 if could not be created + */ +static s8_t +nd6_new_router(ip6_addr_t * router_addr, struct netif * netif) +{ + s8_t router_index; + s8_t neighbor_index; + + /* Do we have a neighbor entry for this router? */ + neighbor_index = nd6_find_neighbor_cache_entry(router_addr); + if (neighbor_index < 0) { + /* Create a neighbor entry for this router. */ + neighbor_index = nd6_new_neighbor_cache_entry(); + if (neighbor_index < 0) { + /* Could not create neighbor entry for this router. */ + return -1; + } + ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); + neighbor_cache[neighbor_index].netif = netif; + neighbor_cache[neighbor_index].q = NULL; + neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; + neighbor_cache[neighbor_index].counter.probes_sent = 0; + } + + /* Mark neighbor as router. */ + neighbor_cache[neighbor_index].isrouter = 1; + + /* Look for empty entry. */ + for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { + if (default_router_list[router_index].neighbor_entry == NULL) { + default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); + return router_index; + } + } + + /* Could not create a router entry. */ + + /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ + neighbor_cache[neighbor_index].isrouter = 0; + + /* router not found. */ + return -1; +} + +/** + * Find the cached entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not found + */ +static s8_t +nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) +{ + s8_t i; + + /* Look for prefix in list. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && + (prefix_list[i].netif == netif)) { + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Creates a new entry for an on-link prefix. + * + * @param prefix the IPv6 prefix that is on-link + * @param netif the netif on which the prefix is on-link + * @return the index on the prefix table, or -1 if not created + */ +static s8_t +nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) +{ + s8_t i; + + /* Create new entry. */ + for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { + if ((prefix_list[i].netif == NULL) || + (prefix_list[i].invalidation_timer == 0)) { + /* Found empty prefix entry. */ + prefix_list[i].netif = netif; + ip6_addr_set(&(prefix_list[i].prefix), prefix); + prefix_list[i].flags = 0; + return i; + } + } + + /* Entry not available. */ + return -1; +} + +/** + * Determine the next hop for a destination. Will determine if the + * destination is on-link, else a suitable on-link router is selected. + * + * The last entry index is cached for fast entry search. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the neighbor cache entry for the next hop, ERR_RTE if no + * suitable next hop was found, ERR_MEM if no cache entry + * could be created + */ +s8_t +nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + +#if LWIP_NETIF_HWADDRHINT + /* TODO should addr_hint point to nd6_cached_neighbor_index instead? */ + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + i = *(netif->addr_hint); + if ((i >= 0) && (i < LWIP_ND6_NUM_DESTINATIONS)) { + nd6_cached_destination_index = i; + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look for ip6addr in destination cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + /* the cached entry index is the right one! */ + /* do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + /* Search destination cache. */ + i = nd6_find_destination_cache_entry(ip6addr); + if (i>= 0) { + /* found destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } + else { + /* Not found. Create a new destination entry. */ + i = nd6_new_destination_cache_entry(); + if (i >= 0) { + /* got new destination entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } else { + /* Could not create a destination cache entry. */ + return ERR_MEM; + } + + /* Copy dest address to destination cache. */ + ip6_addr_set(&(destination_cache[i].destination_addr), ip6addr); + + /* Now find the next hop. is it a neighbor? */ + if (ip6_addr_islinklocal(ip6addr) || + nd6_is_prefix_in_netif(ip6addr, netif)) { + /* Destination in local link. */ + destination_cache[i].pmtu = netif->mtu; + ip6_addr_copy(destination_cache[i].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); + } + else { + /* We need to select a router. */ + i = nd6_select_router(ip6addr, netif); + if (i < 0) { + /* No router found. */ + ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); + return ERR_RTE; + } + destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */ + ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); + } + } + } + +#if LWIP_NETIF_HWADDRHINT + /* TODO should addr_hint point to nd6_cached_neighbor_index instead? */ + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + *(netif->addr_hint) = nd6_cached_destination_index; + } +#endif /* LWIP_NETIF_HWADDRHINT */ + + /* Look in neighbor cache for the next-hop address. */ + if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), + &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + /* Cache hit. */ + /* Do nothing. */ + ND6_STATS_INC(nd6.cachehit); + } else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); + if (i >= 0) { + /* Found a matching record, make it new cached entry. */ + nd6_cached_neighbor_index = i; + } + else { + /* Neighbor not in cache. Make a new entry. */ + i = nd6_new_neighbor_cache_entry(); + if (i >= 0) { + /* got new neighbor entry. make it our new cached index. */ + nd6_cached_destination_index = i; + } else { + /* Could not create a neighbor cache entry. */ + return ERR_MEM; + } + + /* Initialize fields. */ + ip6_addr_copy(neighbor_cache[i].next_hop_address, + destination_cache[nd6_cached_destination_index].next_hop_addr); + neighbor_cache[i].isrouter = 0; + neighbor_cache[i].netif = netif; + neighbor_cache[i].state = ND6_INCOMPLETE; + neighbor_cache[i].counter.probes_sent = 0; + } + } + + /* Reset this destination's age. */ + destination_cache[nd6_cached_destination_index].age = 0; + + return nd6_cached_neighbor_index; +} + +#if LWIP_ND6_QUEUEING + +/** + * Queue a packet for a neighbor. + * + * @param neighbor_index the index in the neighbor cache table + * @param q packet to be queued + * @return ERR_OK if succeeded, ERR_MEM if out of memory + */ +err_t +nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) +{ + err_t result = ERR_MEM; + struct pbuf *p; + int copy_needed = 0; + struct nd6_q_entry *new_entry, *r; + + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + if(p->type != PBUF_ROM) { + copy_needed = 1; + break; + } + p = p->next; + } + if(copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + if ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + nd6_free_q(r); + p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); + } + if(p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; + } + } + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet was copied/ref'd? */ + if (p != NULL) { + /* queue packet ... */ + /* allocate a new nd6 queue entry */ + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + /* Free oldest packet (as per RFC recommendation) */ + r = neighbor_cache[neighbor_index].q; + neighbor_cache[neighbor_index].q = r->next; + nd6_free_q(r); + new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); + } + if (new_entry != NULL) { + new_entry->next = NULL; + new_entry->p = p; + if(neighbor_cache[neighbor_index].q != NULL) { + /* queue was already existent, append the new entry to the end */ + r = neighbor_cache[neighbor_index].q; + while (r->next != NULL) { + r = r->next; + } + r->next = new_entry; + } else { + /* queue did not exist, first item in queue */ + neighbor_cache[neighbor_index].q = new_entry; + } + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)q, (s16_t)neighbor_index)); + result = ERR_OK; + } else { + /* the pool MEMP_ND6_QUEUE is empty */ + pbuf_free(p); + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } + } else { + LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); + /* { result == ERR_MEM } through initialization */ + } + + return result; +} + +/** + * Free a complete queue of nd6 q entries + * + * @param q a queue of nd6_q_entry to free + */ +static void +nd6_free_q(struct nd6_q_entry *q) +{ + struct nd6_q_entry *r; + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("q->p != NULL", q->p != NULL); + while (q) { + r = q; + q = q->next; + LWIP_ASSERT("r->p != NULL", (r->p != NULL)); + pbuf_free(r->p); + memp_free(MEMP_ND6_QUEUE, r); + } +} + +/** + * Send queued packets for a neighbor + * + * @param i the neighbor to send packets to + */ +static void +nd6_send_q(s8_t i) +{ + struct ip6_hdr *ip6hdr; + struct nd6_q_entry *q; + + while (neighbor_cache[i].q != NULL) { + /* remember first in queue */ + q = neighbor_cache[i].q; + /* pop first item off the queue */ + neighbor_cache[i].q = q->next; + /* Get ipv6 header. */ + ip6hdr = (struct ip6_hdr *)(q->p->payload); + /* Override ip6_current_dest_addr() so that we have an aligned copy. */ + ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); + /* send the queued IPv6 packet */ + (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr()); + /* free the queued IP packet */ + pbuf_free(q->p); + /* now queue entry can be freed */ + memp_free(MEMP_ND6_QUEUE, q); + } +} + +#endif /* LWIP_ND6_QUEUEING */ + +/** + * Get the Path MTU for a destination. + * + * @param ip6addr the destination address + * @param netif the netif on which the packet will be sent + * @return the Path MTU, if known, or the netif default MTU + */ +u16_t +nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif) +{ + s8_t i; + + i = nd6_find_destination_cache_entry(ip6addr); + if (i >= 0) { + if (destination_cache[i].pmtu > 0) { + return destination_cache[i].pmtu; + } + } + + if (netif != NULL) { + return netif->mtu; + } + + return 1280; /* Minimum MTU */ +} + + +#if LWIP_ND6_TCP_REACHABILITY_HINTS +/** + * Provide the Neighbor discovery process with a hint that a + * destination is reachable. Called by tcp_receive when ACKs are + * received or sent (as per RFC). This is useful to avoid sending + * NS messages every 30 seconds. + * + * @param ip6addr the destination address which is know to be reachable + * by an upper layer protocol (TCP) + */ +void +nd6_reachability_hint(ip6_addr_t * ip6addr) +{ + s8_t i; + + /* Find destination in cache. */ + if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { + i = nd6_cached_destination_index; + ND6_STATS_INC(nd6.cachehit); + } + else { + i = nd6_find_destination_cache_entry(ip6addr); + } + if (i < 0) { + return; + } + + /* Find next hop neighbor in cache. */ + if (ip6_addr_cmp(&(destination_cache[i].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { + i = nd6_cached_neighbor_index; + ND6_STATS_INC(nd6.cachehit); + } + else { + i = nd6_find_neighbor_cache_entry(&(destination_cache[i].next_hop_addr)); + } + if (i < 0) { + return; + } + + /* Set reachability state. */ + neighbor_cache[i].state = ND6_REACHABLE; + neighbor_cache[i].counter.reachable_time = reachable_time; +} +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#endif /* LWIP_IPV6 */ diff --git a/src/include/ipv6/lwip/dhcp6.h b/src/include/ipv6/lwip/dhcp6.h new file mode 100644 index 00000000..e116f5c7 --- /dev/null +++ b/src/include/ipv6/lwip/dhcp6.h @@ -0,0 +1,58 @@ +/** + * @file + * + * IPv6 address autoconfiguration as per RFC 4862. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * IPv6 address autoconfiguration as per RFC 4862. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef __LWIP_IP6_DHCP6_H__ +#define __LWIP_IP6_DHCP6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ + + +struct dhcp6 +{ + TODO: implement DHCP6 +}; + +#endif /* LWIP_IPV6_DHCP6 */ + +#endif /* __LWIP_IP6_DHCP6_H__ */ diff --git a/src/include/ipv6/lwip/ethip6.h b/src/include/ipv6/lwip/ethip6.h new file mode 100644 index 00000000..e7f412b4 --- /dev/null +++ b/src/include/ipv6/lwip/ethip6.h @@ -0,0 +1,68 @@ +/** + * @file + * + * Ethernet output for IPv6. Uses ND tables for link-layer addressing. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef __LWIP_ETHIP6_H__ +#define __LWIP_ETHIP6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 && LWIP_ETHERNET */ + +#endif /* __LWIP_ETHIP6_H__ */ diff --git a/src/include/ipv6/lwip/icmp6.h b/src/include/ipv6/lwip/icmp6.h new file mode 100644 index 00000000..c552e339 --- /dev/null +++ b/src/include/ipv6/lwip/icmp6.h @@ -0,0 +1,152 @@ +/** + * @file + * + * IPv6 version of ICMP, as per RFC 4443. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_ICMP6_H__ +#define __LWIP_ICMP6_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +enum icmp6_type { + ICMP6_TYPE_DUR = 1, /* Destination unreachable */ + ICMP6_TYPE_PTB = 2, /* Packet too big */ + ICMP6_TYPE_TE = 3, /* Time exceeded */ + ICMP6_TYPE_PP = 4, /* Parameter problem */ + ICMP6_TYPE_PE1 = 100, /* Private experimentation */ + ICMP6_TYPE_PE2 = 101, /* Private experimentation */ + ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */ + + ICMP6_TYPE_EREQ = 128, /* Echo request */ + ICMP6_TYPE_EREP = 129, /* Echo reply */ + ICMP6_TYPE_MLQ = 130, /* Multicast listener query */ + ICMP6_TYPE_MLR = 131, /* Multicast listener report */ + ICMP6_TYPE_MLD = 132, /* Multicast listener done */ + ICMP6_TYPE_RS = 133, /* Router solicitation */ + ICMP6_TYPE_RA = 134, /* Router advertisement */ + ICMP6_TYPE_NS = 135, /* Neighbor solicitation */ + ICMP6_TYPE_NA = 136, /* Neighbor advertisement */ + ICMP6_TYPE_RD = 137, /* Redirect */ + ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */ + ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */ + ICMP6_TYPE_MRT = 153, /* Multicast router termination */ + ICMP6_TYPE_PE3 = 200, /* Private experimentation */ + ICMP6_TYPE_PE4 = 201, /* Private experimentation */ + ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */ +}; + +enum icmp6_dur_code { + ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */ + ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */ + ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */ + ICMP6_DUR_ADDRESS = 3, /* Address unreachable */ + ICMP6_DUR_PORT = 4, /* Port unreachable */ + ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */ + ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */ +}; + +enum icmp6_te_code { + ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */ + ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */ +}; + +enum icmp6_pp_code { + ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */ + ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */ + ICMP6_PP_OPTION = 2, /* Unrecognized IPv6 option encountered */ +}; + +/** This is the standard ICMP6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t data); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** This is the ICMP6 header adapted for echo req/resp. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct icmp6_echo_hdr { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +void icmp6_input(struct pbuf *p, struct netif *inp); +void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); +void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); +void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); +void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); + +#endif /* LWIP_ICMP6 && LWIP_IPV6 */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* __LWIP_ICMP6_H__ */ diff --git a/src/include/ipv6/lwip/inet6.h b/src/include/ipv6/lwip/inet6.h new file mode 100644 index 00000000..fbbdcf19 --- /dev/null +++ b/src/include/ipv6/lwip/inet6.h @@ -0,0 +1,89 @@ +/** + * @file + * + * INET v6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_INET6_H__ +#define __LWIP_INET6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** For compatibility with BSD code */ +struct in6_addr { + u32_t s_addr[4]; +}; + +#define IN6ADDR_ANY_INIT {0,0,0,0} +#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)} + + + +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->s_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->s_addr[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->s_addr[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0];} +/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ +#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) + +/* directly map this to the lwip internal functions */ +#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) +#define inet6_ntoa(addr) ip6addr_ntoa((ip6_addr_t*)&(addr)) +#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen) + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_INET6_H__ */ + diff --git a/src/include/ipv6/lwip/ip6.h b/src/include/ipv6/lwip/ip6.h new file mode 100644 index 00000000..b7d53344 --- /dev/null +++ b/src/include/ipv6/lwip/ip6.h @@ -0,0 +1,225 @@ +/** + * @file + * + * IPv6 layer. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_IP6_H__ +#define __LWIP_IP6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip.h" +#include "lwip/ip6_addr.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP6_HLEN 40 + +#define IP6_NEXTH_HOPBYHOP 0 +#define IP6_NEXTH_TCP 6 +#define IP6_NEXTH_UDP 17 +#define IP6_NEXTH_ENCAPS 41 +#define IP6_NEXTH_ROUTING 43 +#define IP6_NEXTH_FRAGMENT 44 +#define IP6_NEXTH_ICMP6 58 +#define IP6_NEXTH_NONE 59 +#define IP6_NEXTH_DESTOPTS 60 +#define IP6_NEXTH_UDPLITE 136 + + +/* This is passed as the destination address to ip6_output_if (not + to ip6_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP6_HDRINCL +#undef IP6_HDRINCL +#endif /* IP6_HDRINCL */ +#define IP6_HDRINCL NULL + + +/* The IPv6 header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hdr { + /* version / traffic class / flow label */ + PACK_STRUCT_FIELD(u32_t _v_tc_fl); + /* payload length */ + PACK_STRUCT_FIELD(u16_t _plen); + /* next header */ + PACK_STRUCT_FIELD(u8_t _nexth); + /* hop limit */ + PACK_STRUCT_FIELD(u8_t _hoplim); + /* source and destination IP addresses */ + PACK_STRUCT_FIELD(ip6_addr_p_t src); + PACK_STRUCT_FIELD(ip6_addr_p_t dest); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Hop-by-hop router alert option. */ +#define IP6_HBH_HLEN 8 +#define IP6_PAD1_OPTION 0 +#define IP6_PADN_ALERT_OPTION 1 +#define IP6_ROUTER_ALERT_OPTION 5 +#define IP6_ROUTER_ALERT_VALUE_MLD 0 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_hbh_hdr { + /* next header */ + PACK_STRUCT_FIELD(u8_t _nexth); + /* header length */ + PACK_STRUCT_FIELD(u8_t _hlen); + /* router alert option type */ + PACK_STRUCT_FIELD(u8_t _ra_opt_type); + /* router alert option data len */ + PACK_STRUCT_FIELD(u8_t _ra_opt_dlen); + /* router alert option data */ + PACK_STRUCT_FIELD(u16_t _ra_opt_data); + /* PadN option type */ + PACK_STRUCT_FIELD(u8_t _padn_opt_type); + /* PadN option data len */ + PACK_STRUCT_FIELD(u8_t _padn_opt_dlen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* Fragment header. */ +#define IP6_FRAG_HLEN 8 +#define IP6_FRAG_OFFSET_MASK 0xfff8 +#define IP6_FRAG_MORE_FLAG 0x0001 +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_frag_hdr { + /* next header */ + PACK_STRUCT_FIELD(u8_t _nexth); + /* reserved */ + PACK_STRUCT_FIELD(u8_t reserved); + /* fragment offset */ + PACK_STRUCT_FIELD(u16_t _fragment_offset); + /* fragmented packet identification */ + PACK_STRUCT_FIELD(u32_t _identification); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) +#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) +#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff) +#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen)) +#define IP6H_NEXTH(hdr) ((hdr)->_nexth) +#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) +#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) + +#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl))) +#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen) +#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) +#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) + + + +/** Header of the input IPv6 packet currently being processed. */ +extern const struct ip6_hdr *current_ip6_header; +/** Total header length of current_ip6_header (i.e. after this, the UDP/TCP header starts) */ +extern u16_t current_ip6_header_tot_len; +/** Source IPv6 address of current_header */ +extern ip6_addr_t current_ip6hdr_src; +/** Destination IPv6 address of current_header */ +extern ip6_addr_t current_ip6hdr_dest; + +#define ip6_init() /* TODO should we init current addresses and header pointer? */ +struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest); +ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest); +err_t ip6_input(struct pbuf *p, struct netif *inp); +err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, + u8_t hl, u8_t tc, u8_t nexth); +err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, + u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); +#if LWIP_NETIF_HWADDRHINT +err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, + u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if LWIP_IPV6_MLD +err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); +#endif /* LWIP_IPV6_MLD */ + + +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() (current_ip6_header) +/** Total header length of current_ip6_header (i.e. after this, the UDP/TCP header starts) */ +#define ip6_current_header_tot_len() (current_ip6_header_tot_len) +/** Source IPv6 address of current_header */ +#define ip6_current_src_addr() (¤t_ip6hdr_src) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (¤t_ip6hdr_dest) + +#if IP6_DEBUG +void ip6_debug_print(struct pbuf *p); +#else +#define ip6_debug_print(p) +#endif /* IP6_DEBUG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_H__ */ diff --git a/src/include/ipv6/lwip/ip6_addr.h b/src/include/ipv6/lwip/ip6_addr.h new file mode 100644 index 00000000..f7e9da10 --- /dev/null +++ b/src/include/ipv6/lwip/ip6_addr.h @@ -0,0 +1,282 @@ +/** + * @file + * + * IPv6 addresses. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * Structs and macros for handling IPv6 addresses. + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_IP6_ADDR_H__ +#define __LWIP_IP6_ADDR_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* This is the aligned version of ip6_addr_t, + used as local variable, on the stack, etc. */ +struct ip6_addr { + u32_t addr[4]; +}; + +/* This is the packed version of ip6_addr_t, + used in network headers that are itself packed */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip6_addr_packed { + PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** ip6_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip6_addr_t as well as on ip6_addr_p_t. */ +typedef struct ip6_addr ip6_addr_t; +typedef struct ip6_addr_packed ip6_addr_p_t; + + +/** IP6_ADDR_ANY can be used as a fixed IPv6 address + * for the wildcard + */ +extern const ip6_addr_t ip6_addr_any; +#define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any) + + + + +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IPv6 partial address given by byte-parts. */ +#define IP6_ADDR(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IPv6 partial address given by byte-parts. +Little-endian version, stored in network order (no htonl). */ +#define IP6_ADDR(ip6addr, index, a,b,c,d) \ + (ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif + +/** Access address in 16-bit block */ +#define IP6_ADDR_BLOCK1(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK2(ip6addr) ((htonl((ip6addr)->addr[0])) & 0xffff) +#define IP6_ADDR_BLOCK3(ip6addr) ((htonl((ip6addr)->addr[1]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK4(ip6addr) ((htonl((ip6addr)->addr[1])) & 0xffff) +#define IP6_ADDR_BLOCK5(ip6addr) ((htonl((ip6addr)->addr[2]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK6(ip6addr) ((htonl((ip6addr)->addr[2])) & 0xffff) +#define IP6_ADDR_BLOCK7(ip6addr) ((htonl((ip6addr)->addr[3]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK8(ip6addr) ((htonl((ip6addr)->addr[3])) & 0xffff) + +/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ +#define ip6_addr_copy(dest, src) {(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];} +/** Safely copy one IPv6 address to another (src may be NULL) */ +#define ip6_addr_set(dest, src) {(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];} + +/** Set complete address to zero */ +#define ip6_addr_set_zero(ip6addr) {(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = 0;} + +/** Set address to ipv6 'any' (no need for htonl()) */ +#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) +/** Set address to ipv6 loopback address */ +#define ip6_addr_set_loopback(ip6addr) {(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);} +/** Safely copy one IPv6 address to another and change byte order + * from host- to network-order. */ +#define ip6_addr_set_hton(dest, src) {(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);} + + + +/** + * Determine if two IPv6 address are on the same network. + * + * @arg addr1 IPv6 address 1 + * @arg addr2 IPv6 address 2 + * @return !0 if the network identifiers of both address match + */ +#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1])) + +#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ + ((addr1)->addr[1] == (addr2)->addr[1]) && \ + ((addr1)->addr[2] == (addr2)->addr[2]) && \ + ((addr1)->addr[3] == (addr2)->addr[3])) + +#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL) + +#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \ + (((ip6addr)->addr[0] == 0) && \ + ((ip6addr)->addr[1] == 0) && \ + ((ip6addr)->addr[2] == 0) && \ + ((ip6addr)->addr[3] == 0))) + + +#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) + +#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) + +#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) + +#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) + +#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) +#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) +#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) +#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) +#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf) +#define IP6_MULTICAST_SCOPE_RESERVED 0x0 +#define IP6_MULTICAST_SCOPE_RESERVED0 0x0 +#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 +#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 +#define IP6_MULTICAST_SCOPE_RESERVED3 0x3 +#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 +#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 +#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 +#define IP6_MULTICAST_SCOPE_GLOBAL 0xe +#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf +#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL)) +#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL)) +#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL)) +#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL)) +#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL)) +#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL)) + +/* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */ +#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) + +#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) +#define ip6_addr_set_allnodes_linklocal(ip6addr) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);} + +#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[1] == 0UL) && \ + ((ip6addr)->addr[2] == 0UL) && \ + ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) +#define ip6_addr_set_allrouters_linklocal(ip6addr) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);} + +#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ + ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ + (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) + +#define ip6_addr_set_solicitednode(ip6addr, if_id) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ + (ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));} + + +/* IPv6 address states. */ +#define IP6_ADDR_INVALID 0x00 +#define IP6_ADDR_TENTATIVE 0x08 +#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ +#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ +#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ +#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ +#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ +#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ +#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ +#define IP6_ADDR_VALID 0x10 +#define IP6_ADDR_PREFERRED 0x30 +#define IP6_ADDR_DEPRECATED 0x50 + +#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) +#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) +#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ +#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) +#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) + +#define ip6_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \ + ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \ + ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) + +int ip6addr_aton(const char *cp, ip6_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ip6addr_ntoa(const ip6_addr_t *addr); +char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); + + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_ADDR_H__ */ diff --git a/src/include/ipv6/lwip/ip6_chksum.h b/src/include/ipv6/lwip/ip6_chksum.h new file mode 100644 index 00000000..600257c7 --- /dev/null +++ b/src/include/ipv6/lwip/ip6_chksum.h @@ -0,0 +1,70 @@ +/** + * @file + * + * IPv6 Checksum helper functions. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_IP6_CHKSUM_H__ +#define __LWIP_IP6_CHKSUM_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/inet_chksum.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t ip6_chksum_pseudo(struct pbuf *p, + ip6_addr_t *src, ip6_addr_t *dest, + u8_t proto, u16_t proto_len); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, + ip6_addr_t *src, ip6_addr_t *dest, + u8_t proto, u16_t proto_len, u16_t chksum_len); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_CHKSUM_H__ */ diff --git a/src/include/ipv6/lwip/ip6_frag.h b/src/include/ipv6/lwip/ip6_frag.h new file mode 100644 index 00000000..12294a97 --- /dev/null +++ b/src/include/ipv6/lwip/ip6_frag.h @@ -0,0 +1,102 @@ +/** + * @file + * + * IPv6 fragmentation and reassembly. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ +#ifndef __LWIP_IP6_FRAG_H__ +#define __LWIP_IP6_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ + +/* The IPv6 reassembly timer interval in milliseconds. */ +#define IP6_REASS_TMR_INTERVAL 1000 + +/* IPv6 reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip6_reassdata { + struct ip6_reassdata *next; + struct pbuf *p; + struct ip6_hdr * iphdr; + u32_t identification; + u16_t datagram_len; + u8_t nexth; + u8_t timer; +}; + +#define ip6_reass_init() /* Compatibility define */ +void ip6_reass_tmr(void); +struct pbuf * ip6_reass(struct pbuf *p); + +#endif /* LWIP_IPV6_REASS */ + +#if LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ + +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +#ifndef __LWIP_PBUF_CUSTOM_REF__ +#define __LWIP_PBUF_CUSTOM_REF__ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* __LWIP_PBUF_CUSTOM_REF__ */ + +err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest); + +#endif /* LWIP_IPV6_FRAG */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP6_FRAG_H__ */ diff --git a/src/include/ipv6/lwip/mld6.h b/src/include/ipv6/lwip/mld6.h new file mode 100644 index 00000000..abd86e55 --- /dev/null +++ b/src/include/ipv6/lwip/mld6.h @@ -0,0 +1,118 @@ +/** + * @file + * + * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. + * No support for MLDv2. + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef __LWIP_MLD6_H__ +#define __LWIP_MLD6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct mld_group { + /** next link */ + struct mld_group *next; + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip6_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ + u8_t group_state; + /** timer for reporting */ + u16_t timer; + /** counter of simultaneous uses */ + u8_t use; +}; + +/** Multicast listener report/query/done message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mld_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t max_resp_delay); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define MLD6_TMR_INTERVAL 100 /* Milliseconds */ + +/* MAC Filter Actions, these are passed to a netif's + * mld_mac_filter callback function. */ +#define MLD6_DEL_MAC_FILTER 0 +#define MLD6_ADD_MAC_FILTER 1 + + +#define mld6_init() /* TODO should we init tables? */ +err_t mld6_stop(struct netif *netif); +void mld6_report_groups(struct netif *netif); +void mld6_tmr(void); +struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr); +void mld6_input(struct pbuf *p, struct netif *inp); +err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); +err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ + +#endif /* __LWIP_MLD6_H__ */ diff --git a/src/include/ipv6/lwip/nd6.h b/src/include/ipv6/lwip/nd6.h new file mode 100644 index 00000000..3009f76c --- /dev/null +++ b/src/include/ipv6/lwip/nd6.h @@ -0,0 +1,368 @@ +/** + * @file + * + * Neighbor discovery and stateless address autoconfiguration for IPv6. + * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 + * (Address autoconfiguration). + */ + +/* + * Copyright (c) 2010 Inico Technologies Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Ivan Delamer + * + * + * Please coordinate changes and requests with Ivan Delamer + * + */ + +#ifndef __LWIP_ND6_H__ +#define __LWIP_ND6_H__ + +#include "lwip/opt.h" + +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip6.h" +#include "lwip/ip6_addr.h" +#include "lwip/netif.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct for tables. */ +struct nd6_neighbor_cache_entry { + ip6_addr_t next_hop_address; + struct netif * netif; + u8_t lladdr[NETIF_MAX_HWADDR_LEN]; + /*u32_t pmtu;*/ +#if LWIP_ND6_QUEUEING + /** Pointer to queue of pending outgoing packets on this entry. */ + struct nd6_q_entry *q; +#endif /* LWIP_ND6_QUEUEING */ + u8_t state; + u8_t isrouter; + union { + u32_t reachable_time; + u32_t delay_time; + u32_t probes_sent; + u32_t stale_time; + } counter; +}; + +struct nd6_destination_cache_entry { + ip6_addr_t destination_addr; + ip6_addr_t next_hop_addr; + u32_t pmtu; + u32_t age; +}; + +struct nd6_prefix_list_entry { + ip6_addr_t prefix; + struct netif * netif; + u32_t invalidation_timer; +#if LWIP_IPV6_AUTOCONFIG + u8_t flags; +#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 +#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 +#endif /* LWIP_IPV6_AUTOCONFIG */ +}; + +struct nd6_router_list_entry { + struct nd6_neighbor_cache_entry * neighbor_entry; + u32_t invalidation_timer; + u8_t flags; +}; + + +enum nd6_neighbor_cache_entry_state { + ND6_NO_ENTRY = 0, + ND6_INCOMPLETE, + ND6_REACHABLE, + ND6_STALE, + ND6_DELAY, + ND6_PROBE +}; + +#if LWIP_ND6_QUEUEING +/** struct for queueing outgoing packets for unknown address + * defined here to be accessed by memp.h + */ +struct nd6_q_entry { + struct nd6_q_entry *next; + struct pbuf *p; +}; +#endif /* LWIP_ND6_QUEUEING */ + +/** Neighbor solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ns_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FIELD(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Neighbor advertisement message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct na_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u8_t flags); + PACK_STRUCT_FIELD(u8_t reserved[3]); + PACK_STRUCT_FIELD(ip6_addr_p_t target_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif +#define ND6_FLAG_ROUTER (0x80) +#define ND6_FLAG_SOLICITED (0x40) +#define ND6_FLAG_OVERRIDE (0x20) + +/** Router solicitation message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct rs_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Router advertisement message header. */ +#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) +#define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40) +#define ND6_RA_FLAG_HOME_AGENT (0x20) +#define ND6_RA_PREFERENCE_MASK (0x18) +#define ND6_RA_PREFERENCE_HIGH (0x08) +#define ND6_RA_PREFERENCE_MEDIUM (0x00) +#define ND6_RA_PREFERENCE_LOW (0x18) +#define ND6_RA_PREFERENCE_DISABLED (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ra_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u8_t current_hop_limit); + PACK_STRUCT_FIELD(u8_t flags); + PACK_STRUCT_FIELD(u16_t router_lifetime); + PACK_STRUCT_FIELD(u32_t reachable_time); + PACK_STRUCT_FIELD(u32_t retrans_timer); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirect message header. */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirect_header { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u32_t reserved); + PACK_STRUCT_FIELD(ip6_addr_p_t target_address); + PACK_STRUCT_FIELD(ip6_addr_p_t destination_address); + /* Options follow. */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Link-layer address option. */ +#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) +#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct lladdr_option { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Prefix information option. */ +#define ND6_OPTION_TYPE_PREFIX_INFO (0x03) +#define ND6_PREFIX_FLAG_ON_LINK (0x80) +#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) +#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) +#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct prefix_option { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t prefix_length); + PACK_STRUCT_FIELD(u8_t flags); + PACK_STRUCT_FIELD(u32_t valid_lifetime); + PACK_STRUCT_FIELD(u32_t preferred_lifetime); + PACK_STRUCT_FIELD(u8_t reserved2[3]); + PACK_STRUCT_FIELD(u8_t site_prefix_length); + PACK_STRUCT_FIELD(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Redirected header option. */ +#define ND6_OPTION_TYPE_REDIR_HDR (0x04) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct redirected_header_option { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t reserved[6]); + /* Portion of redirected packet follows. */ + /* PACK_STRUCT_FIELD(u8_t redirected[8]); */ +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** MTU option. */ +#define ND6_OPTION_TYPE_MTU (0x05) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct mtu_option { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u16_t reserved); + PACK_STRUCT_FIELD(u32_t mtu); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/** Route information option. */ +#define ND6_OPTION_TYPE_ROUTE_INFO (24) +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct route_option { + PACK_STRUCT_FIELD(u8_t type); + PACK_STRUCT_FIELD(u8_t length); + PACK_STRUCT_FIELD(u8_t prefix_length); + PACK_STRUCT_FIELD(u8_t preference); + PACK_STRUCT_FIELD(u32_t route_lifetime); + PACK_STRUCT_FIELD(ip6_addr_p_t prefix); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +/* the possible states of an IP address */ +#define IP6_ADDRESS_STATE_INVALID (0) +#define IP6_ADDRESS_STATE_VALID (0x4) +#define IP6_ADDRESS_STATE_PREFERRED (0x5) /* includes valid */ +#define IP6_ADDRESS_STATE_DEPRECATED (0x6) /* includes valid */ +#define IP6_ADDRESS_STATE_TENTATIV (0x8) + +/** 1 second period */ +#define ND6_TMR_INTERVAL 1000 + +/* Router tables. */ +/* TODO make these static? and entries accessible through API? */ +extern struct nd6_neighbor_cache_entry neighbor_cache[]; +extern struct nd6_destination_cache_entry destination_cache[]; +extern struct nd6_prefix_list_entry prefix_list[]; +extern struct nd6_router_list_entry default_router_list[]; + +/* Default values, can be updated by a RA message. */ +extern u32_t reachable_time; +extern u32_t retrans_timer; + +#define nd6_init() /* TODO should we init tables? */ +void nd6_tmr(void); +void nd6_input(struct pbuf *p, struct netif *inp); +s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif); +s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif); +u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif); +#if LWIP_ND6_QUEUEING +err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p); +#endif /* LWIP_ND6_QUEUEING */ +#if LWIP_ND6_TCP_REACHABILITY_HINTS +void nd6_reachability_hint(ip6_addr_t * ip6addr); +#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_ND6_H__ */ From 58529932438e9deb609b53332f0fc1684228cc0b Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 17 May 2011 19:56:08 +0000 Subject: [PATCH 003/151] Removed files of old IPv6 implementation --- src/include/ipv6/lwip/icmp.h | 100 ------------------------ src/include/ipv6/lwip/inet.h | 68 ----------------- src/include/ipv6/lwip/ip.h | 130 -------------------------------- src/include/ipv6/lwip/ip_addr.h | 97 ------------------------ 4 files changed, 395 deletions(-) delete mode 100644 src/include/ipv6/lwip/icmp.h delete mode 100644 src/include/ipv6/lwip/inet.h delete mode 100644 src/include/ipv6/lwip/ip.h delete mode 100644 src/include/ipv6/lwip/ip_addr.h diff --git a/src/include/ipv6/lwip/icmp.h b/src/include/ipv6/lwip/icmp.h deleted file mode 100644 index 87e9ffd9..00000000 --- a/src/include/ipv6/lwip/icmp.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_ICMP_H__ -#define __LWIP_ICMP_H__ - -#include "lwip/opt.h" - -#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/pbuf.h" -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ICMP6_DUR 1 -#define ICMP6_TE 3 -#define ICMP6_ECHO 128 /* echo */ -#define ICMP6_ER 129 /* echo reply */ - - -enum icmp_dur_type { - ICMP_DUR_NET = 0, /* net unreachable */ - ICMP_DUR_HOST = 1, /* host unreachable */ - ICMP_DUR_PROTO = 2, /* protocol unreachable */ - ICMP_DUR_PORT = 3, /* port unreachable */ - ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ - ICMP_DUR_SR = 5 /* source route failed */ -}; - -enum icmp_te_type { - ICMP_TE_TTL = 0, /* time to live exceeded in transit */ - ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ -}; - -void icmp_input(struct pbuf *p, struct netif *inp); - -void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); -void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); - -struct icmp_echo_hdr { - u8_t type; - u8_t icode; - u16_t chksum; - u16_t id; - u16_t seqno; -}; - -struct icmp_dur_hdr { - u8_t type; - u8_t icode; - u16_t chksum; - u32_t unused; -}; - -struct icmp_te_hdr { - u8_t type; - u8_t icode; - u16_t chksum; - u32_t unused; -}; - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_ICMP */ - -#endif /* __LWIP_ICMP_H__ */ - diff --git a/src/include/ipv6/lwip/inet.h b/src/include/ipv6/lwip/inet.h deleted file mode 100644 index de1a0b63..00000000 --- a/src/include/ipv6/lwip/inet.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_INET_H__ -#define __LWIP_INET_H__ - -#include "lwip/opt.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -u16_t inet_chksum(void *data, u16_t len); -u16_t inet_chksum_pbuf(struct pbuf *p); -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 inet_addr(const char *cp); -s8_t inet_aton(const char *cp, struct in_addr *addr); - -#ifndef _MACHINE_ENDIAN_H_ -#ifndef _NETINET_IN_H -#ifndef _LINUX_BYTEORDER_GENERIC_H -u16_t htons(u16_t n); -u16_t ntohs(u16_t n); -u32_t htonl(u32_t n); -u32_t ntohl(u32_t n); -#endif /* _LINUX_BYTEORDER_GENERIC_H */ -#endif /* _NETINET_IN_H */ -#endif /* _MACHINE_ENDIAN_H_ */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_INET_H__ */ - diff --git a/src/include/ipv6/lwip/ip.h b/src/include/ipv6/lwip/ip.h deleted file mode 100644 index a01cfc65..00000000 --- a/src/include/ipv6/lwip/ip.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_IP_H__ -#define __LWIP_IP_H__ - -#include "lwip/opt.h" -#include "lwip/def.h" -#include "lwip/pbuf.h" -#include "lwip/ip_addr.h" - -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define IP_HLEN 40 - -#define IP_PROTO_ICMP 58 -#define IP_PROTO_UDP 17 -#define IP_PROTO_UDPLITE 136 -#define IP_PROTO_TCP 6 - -/* This is passed as the destination address to ip_output_if (not - to ip_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#ifdef IP_HDRINCL -#undef IP_HDRINCL -#endif /* IP_HDRINCL */ -#define IP_HDRINCL NULL - -#if LWIP_NETIF_HWADDRHINT -#define IP_PCB_ADDRHINT ;u8_t addr_hint -#else -#define IP_PCB_ADDRHINT -#endif /* LWIP_NETIF_HWADDRHINT */ - -/* This is the common part of all PCB types. It needs to be at the - beginning of a PCB type definition. It is located here so that - changes to this common part are made in one location instead of - having to change all PCB structs. */ -#define IP_PCB struct ip_addr local_ip; \ - struct ip_addr remote_ip; \ - /* Socket options */ \ - u16_t so_options; \ - /* Type Of Service */ \ - u8_t tos; \ - /* Time To Live */ \ - u8_t ttl; \ - /* link layer address resolution hint */ \ - IP_PCB_ADDRHINT - - -/* The IPv6 header. */ -struct ip_hdr { -#if BYTE_ORDER == LITTLE_ENDIAN - u8_t tclass1:4, v:4; - u8_t flow1:4, tclass2:4; -#else - u8_t v:4, tclass1:4; - u8_t tclass2:8, flow1:4; -#endif - u16_t flow2; - u16_t len; /* payload length */ - u8_t nexthdr; /* next header */ - u8_t hoplim; /* hop limit (TTL) */ - struct ip_addr src, dest; /* source and destination IP addresses */ -}; - -#define IPH_PROTO(hdr) (iphdr->nexthdr) - -void ip_init(void); - -#include "lwip/netif.h" - -struct netif *ip_route(struct ip_addr *dest); - -void ip_input(struct pbuf *p, struct netif *inp); - -/* source and destination addresses in network byte order, please */ -err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto); - -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); - -#define ip_current_netif() NULL -#define ip_current_header() NULL - -#if IP_DEBUG -void ip_debug_print(struct pbuf *p); -#endif /* IP_DEBUG */ - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_IP_H__ */ - - diff --git a/src/include/ipv6/lwip/ip_addr.h b/src/include/ipv6/lwip/ip_addr.h deleted file mode 100644 index b2d8ae56..00000000 --- a/src/include/ipv6/lwip/ip_addr.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIP_IP_ADDR_H__ -#define __LWIP_IP_ADDR_H__ - -#include "lwip/opt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define IP_ADDR_ANY 0 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN - struct ip_addr { - PACK_STRUCT_FIELD(u32_t addr[4]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -/* - * struct ipaddr2 is used in the definition of the ARP packet format in - * order to support compilers that don't have structure packing. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_addr2 { - PACK_STRUCT_FIELD(u16_t addrw[2]); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \ - (ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \ - (ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \ - (ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0) - -u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, - struct ip_addr *mask); -u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2); -void ip_addr_set(struct ip_addr *dest, struct ip_addr *src); -u8_t ip_addr_isany(struct ip_addr *addr); - -#define ip_addr_debug_print(debug, ipaddr) \ - LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \ - (ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \ - ntohl(ipaddr->addr[0]) & 0xffff, \ - (ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \ - ntohl(ipaddr->addr[1]) & 0xffff, \ - (ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \ - ntohl(ipaddr->addr[2]) & 0xffff, \ - (ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \ - ntohl(ipaddr->addr[3]) & 0xffff)); - -#ifdef __cplusplus -} -#endif - -#endif /* __LWIP_IP_ADDR_H__ */ From 9546e65617b73e6266759ff140b1d23b9660d699 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 21 May 2011 16:01:19 +0000 Subject: [PATCH 004/151] Removed autoip_init() since it does nothing; minor coding style changes --- src/core/ipv4/autoip.c | 32 ++++++++++++-------------------- src/include/ipv4/lwip/autoip.h | 3 +-- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/core/ipv4/autoip.c b/src/core/ipv4/autoip.c index 92bb4591..b122da27 100644 --- a/src/core/ipv4/autoip.c +++ b/src/core/ipv4/autoip.c @@ -122,14 +122,6 @@ static err_t autoip_bind(struct netif *netif); /* start sending probes for llipaddr */ static void autoip_start_probing(struct netif *netif); -/** - * Initialize this module - */ -void -autoip_init(void) -{ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n")); -} /** Set a statically allocated struct autoip to work with. * Using this prevents autoip_start to allocate it using mem_malloc. @@ -170,8 +162,8 @@ autoip_handle_arp_conflict(struct netif *netif) /* Somehow detect if we are defending or retreating */ unsigned char defend = 1; /* tbd */ - if(defend) { - if(netif->autoip->lastconflict > 0) { + if (defend) { + if (netif->autoip->lastconflict > 0) { /* retreat, there was a conflicting ARP in the last * DEFEND_INTERVAL seconds */ @@ -295,7 +287,7 @@ autoip_start(struct netif *netif) struct autoip *autoip = netif->autoip; err_t result = ERR_OK; - if(netif_is_up(netif)) { + if (netif_is_up(netif)) { netif_set_down(netif); } @@ -309,12 +301,12 @@ autoip_start(struct netif *netif) LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - if(autoip == NULL) { + if (autoip == NULL) { /* no AutoIP client attached yet? */ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): starting new AUTOIP client\n")); autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); - if(autoip == NULL) { + if (autoip == NULL) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): could not allocate autoip\n")); return ERR_MEM; @@ -360,7 +352,7 @@ autoip_start_probing(struct netif *netif) * accquiring and probing address * compliant to RFC 3927 Section 2.2.1 */ - if(autoip->tried_llipaddr > MAX_CONFLICTS) { + if (autoip->tried_llipaddr > MAX_CONFLICTS) { autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; } } @@ -404,7 +396,7 @@ autoip_tmr() while (netif != NULL) { /* only act on AutoIP configured interfaces */ if (netif->autoip != NULL) { - if(netif->autoip->lastconflict > 0) { + if (netif->autoip->lastconflict > 0) { netif->autoip->lastconflict--; } @@ -414,10 +406,10 @@ autoip_tmr() switch(netif->autoip->state) { case AUTOIP_STATE_PROBING: - if(netif->autoip->ttw > 0) { + if (netif->autoip->ttw > 0) { netif->autoip->ttw--; } else { - if(netif->autoip->sent_num >= PROBE_NUM) { + if (netif->autoip->sent_num >= PROBE_NUM) { netif->autoip->state = AUTOIP_STATE_ANNOUNCING; netif->autoip->sent_num = 0; netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; @@ -439,10 +431,10 @@ autoip_tmr() break; case AUTOIP_STATE_ANNOUNCING: - if(netif->autoip->ttw > 0) { + if (netif->autoip->ttw > 0) { netif->autoip->ttw--; } else { - if(netif->autoip->sent_num == 0) { + if (netif->autoip->sent_num == 0) { /* We are here the first time, so we waited ANNOUNCE_WAIT seconds * Now we can bind to an IP address and use it. * @@ -458,7 +450,7 @@ autoip_tmr() netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; netif->autoip->sent_num++; - if(netif->autoip->sent_num >= ANNOUNCE_NUM) { + if (netif->autoip->sent_num >= ANNOUNCE_NUM) { netif->autoip->state = AUTOIP_STATE_BOUND; netif->autoip->sent_num = 0; netif->autoip->ttw = 0; diff --git a/src/include/ipv4/lwip/autoip.h b/src/include/ipv4/lwip/autoip.h index 23c264a1..e62b72e8 100644 --- a/src/include/ipv4/lwip/autoip.h +++ b/src/include/ipv4/lwip/autoip.h @@ -89,8 +89,7 @@ struct autoip }; -/** Init srand, has to be called before entering mainloop */ -void autoip_init(void); +#define autoip_init() /* Compatibility define, no init needed. */ /** Set a struct autoip allocated by the application to work with */ void autoip_set_struct(struct netif *netif, struct autoip *autoip); From 6865806b550c4df929af9344c6545e73c45370e9 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 25 May 2011 17:16:35 +0000 Subject: [PATCH 005/151] Combined IPv4 and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP code so that the code is more readable. --- CHANGELOG | 8 +- src/api/api_lib.c | 22 +- src/api/api_msg.c | 193 ++----- src/api/netbuf.c | 12 +- src/api/sockets.c | 503 ++++++------------ src/core/{ipv4 => }/inet_chksum.c | 160 ++++-- src/core/ipv4/inet.c | 42 -- src/core/ipv4/{ip.c => ip4.c} | 81 ++- src/core/ipv4/{ip_addr.c => ip4_addr.c} | 0 src/core/ipv6/ethip6.c | 54 +- src/core/ipv6/icmp6.c | 30 +- src/core/ipv6/ip6.c | 57 +- src/core/ipv6/ip6_chksum.c | 176 ------ src/core/ipv6/mld6.c | 6 +- src/core/ipv6/nd6.c | 24 +- src/core/netif.c | 14 +- src/core/pbuf.c | 24 +- src/core/raw.c | 168 ++---- src/core/snmp/mib2.c | 16 +- src/core/tcp.c | 254 +++------ src/core/tcp_in.c | 263 ++------- src/core/tcp_out.c | 274 ++-------- src/core/udp.c | 476 +++++------------ src/include/ipv4/lwip/icmp.h | 14 + src/include/ipv4/lwip/{ip.h => ip4.h} | 94 +--- .../ipv4/lwip/{ip_addr.h => ip4_addr.h} | 4 +- src/include/ipv6/lwip/ip6.h | 30 -- src/include/ipv6/lwip/ip6_addr.h | 48 +- src/include/ipv6/lwip/ip6_chksum.h | 70 --- src/include/lwip/api.h | 57 +- src/include/lwip/api_msg.h | 6 +- src/include/{ipv4 => }/lwip/inet_chksum.h | 34 +- src/include/lwip/ip.h | 230 ++++++++ src/include/lwip/ip_addr.h | 127 +++++ src/include/lwip/netbuf.h | 35 +- src/include/lwip/netif.h | 5 + src/include/lwip/opt.h | 2 +- src/include/lwip/pbuf.h | 3 + src/include/lwip/sockets.h | 3 +- src/include/lwip/tcp.h | 14 +- src/include/lwip/tcp_impl.h | 28 +- 41 files changed, 1392 insertions(+), 2269 deletions(-) rename src/core/{ipv4 => }/inet_chksum.c (79%) delete mode 100644 src/core/ipv4/inet.c rename src/core/ipv4/{ip.c => ip4.c} (93%) rename src/core/ipv4/{ip_addr.c => ip4_addr.c} (100%) delete mode 100644 src/core/ipv6/ip6_chksum.c rename src/include/ipv4/lwip/{ip.h => ip4.h} (57%) rename src/include/ipv4/lwip/{ip_addr.h => ip4_addr.h} (99%) delete mode 100644 src/include/ipv6/lwip/ip6_chksum.h rename src/include/{ipv4 => }/lwip/inet_chksum.h (70%) create mode 100644 src/include/lwip/ip.h create mode 100644 src/include/lwip/ip_addr.h diff --git a/CHANGELOG b/CHANGELOG index f23128ed..c47b87a6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,7 +6,13 @@ HISTORY ++ New features: - 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) + 2011-05-25: Simon Goldschmidt + * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, + combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 + and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP + code so that the code is more readable. + + 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 :-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index bc7507b7..47767512 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -143,7 +143,7 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) msg.function = do_getaddr; msg.msg.conn = conn; - msg.msg.msg.ad.ipaddr = addr; + msg.msg.msg.ad.ipaddr = ip_2_ipX(addr); msg.msg.msg.ad.port = port; msg.msg.msg.ad.local = local; err = TCPIP_APIMSG(&msg); @@ -481,11 +481,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) buf->p = p; buf->ptr = p; buf->port = 0; -#if LWIP_IPV6 - ip6_addr_set_any(&buf->addr.ip6); -#else /* LWIP_IPV6 */ - ip_addr_set_any(&buf->addr.ip4); -#endif /* LWIP_IPV6 */ + ipX_addr_set_any(LWIP_IPV6, &buf->addr); *new_buf = buf; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; @@ -544,15 +540,7 @@ err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) { if (buf != NULL) { -#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); - } + ipX_addr_set_ipaddr(conn->pcb.ip->isipv6, &buf->addr, addr); buf->port = port; return netconn_send(conn, buf); } @@ -700,8 +688,8 @@ netconn_join_leave_group(struct netconn *conn, msg.function = do_join_leave_group; msg.msg.conn = conn; - msg.msg.msg.jl.multiaddr = multiaddr; - msg.msg.msg.jl.netif_addr = netif_addr; + msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr); + msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr); msg.msg.msg.jl.join_or_leave = join_or_leave; err = TCPIP_APIMSG(&msg); diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 6f6ffc4d..de226a5a 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -113,15 +113,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->p = q; buf->ptr = q; -#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()); - } + ipX_addr_copy(pcb->isipv6, buf->addr, *ipX_current_src_addr()); buf->port = pcb->protocol; len = q->tot_len; @@ -184,38 +176,16 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, } else { buf->p = p; buf->ptr = p; -#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); - } + ipX_addr_set_ipaddr(ip_current_is_v6(), &buf->addr, 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 */ - const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); + const struct udp_hdr* udphdr = ipX_next_header_ptr(); #if LWIP_CHECKSUM_ON_COPY buf->flags = NETBUF_FLAG_DESTADDR; #endif /* LWIP_CHECKSUM_ON_COPY */ - ip_addr_set(&buf->toaddr.ip4, ip_current_dest_addr()); + ipX_addr_set(ip_current_is_v6(), &buf->toaddr, ipX_current_dest_addr()); buf->toport_chksum = udphdr->dest; } #endif /* LWIP_NETBUF_RECVINFO */ @@ -517,71 +487,51 @@ pcb_new(struct api_msg_msg *msg) switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: -#if LWIP_IPV6 - if (NETCONNTYPE_ISIPV6(msg->conn->type)) { - msg->conn->pcb.raw = raw_new_ip6(msg->msg.n.proto); + msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + if(msg->conn->pcb.raw != NULL) { + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); } - 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; - } - raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: -#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; - } + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp != NULL) { #if LWIP_UDPLITE - if (NETCONNTYPE_ISUDPLITE((msg->conn->type)) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); - } + if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } #endif /* LWIP_UDPLITE */ - if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); } - udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: -#if LWIP_IPV6 - if (NETCONNTYPE_ISIPV6(msg->conn->type)) { - msg->conn->pcb.tcp = tcp_new_ip6(); + msg->conn->pcb.tcp = tcp_new(); + if(msg->conn->pcb.tcp != NULL) { + setup_tcp(msg->conn); } - else -#endif /* LWIP_IPV6 */ - { - msg->conn->pcb.tcp = tcp_new(); - } - if(msg->conn->pcb.tcp == NULL) { - msg->err = ERR_MEM; - break; - } - setup_tcp(msg->conn); break; #endif /* LWIP_TCP */ default: /* Unsupported netconn type, e.g. protocol disabled */ msg->err = ERR_VAL; - break; + return; } + if (msg->conn->pcb.ip == NULL) { + msg->err = ERR_MEM; + } +#if LWIP_IPV6 + else { + if (NETCONNTYPE_ISIPV6(msg->conn->type)) { + ip_set_v6(msg->conn->pcb.ip, 1); + } + } +#endif /* LWIP_IPV6 */ } /** @@ -878,7 +828,8 @@ do_delconn(struct api_msg_msg *msg) (msg->conn->state != NETCONN_LISTEN) && (msg->conn->state != NETCONN_CONNECT)) { /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); + LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", + NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else { LWIP_ASSERT("blocking connect in progress", @@ -1167,62 +1118,29 @@ do_send(struct api_msg_msg *msg) switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: -#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)) { + if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { - msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr.ip4); + msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr)); } break; #endif #if LWIP_UDP case NETCONN_UDP: #if LWIP_CHECKSUM_ON_COPY -#if 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)) { + if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } else { msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, - &msg->msg.b->addr.ip4, msg->msg.b->port, + ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } #else /* LWIP_CHECKSUM_ON_COPY */ -#if 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)) { + if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); } else { - msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr.ip4, msg->msg.b->port); + msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port); } #endif /* LWIP_CHECKSUM_ON_COPY */ break; @@ -1455,21 +1373,13 @@ void do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { -#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)); - } + if (msg->msg.ad.local) { + ipX_addr_copy(msg->conn->pcb.ip->isipv6, *(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->local_ip); + } else { + ipX_addr_copy(msg->conn->pcb.ip->isipv6, *(msg->msg.ad.ipaddr), + msg->conn->pcb.ip->remote_ip); } - 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)) { #if LWIP_RAW @@ -1523,7 +1433,8 @@ do_close(struct api_msg_msg *msg) /* @todo: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { /* this only happens for TCP netconns */ - LWIP_ASSERT("msg->conn->type == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); + LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", + NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) { if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { @@ -1569,9 +1480,11 @@ do_join_leave_group(struct api_msg_msg *msg) #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); + msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr), + ipX_2_ip6(msg->msg.jl.multiaddr)); } else { - msg->err = mld6_leavegroup((ip6_addr_t *)msg->msg.jl.netif_addr, (ip6_addr_t *)msg->msg.jl.multiaddr); + msg->err = mld6_leavegroup(ipX_2_ip6(msg->msg.jl.netif_addr), + ipX_2_ip6(msg->msg.jl.multiaddr)); } } else @@ -1579,9 +1492,11 @@ do_join_leave_group(struct api_msg_msg *msg) { #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); + msg->err = igmp_joingroup(ipX_2_ip(msg->msg.jl.netif_addr), + ipX_2_ip(msg->msg.jl.multiaddr)); } else { - msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); + msg->err = igmp_leavegroup(ipX_2_ip(msg->msg.jl.netif_addr), + ipX_2_ip(msg->msg.jl.multiaddr)); } #endif /* LWIP_IGMP */ } diff --git a/src/api/netbuf.c b/src/api/netbuf.c index 0aded3af..0ccd2bce 100644 --- a/src/api/netbuf.c +++ b/src/api/netbuf.c @@ -61,11 +61,7 @@ netbuf *netbuf_new(void) if (buf != NULL) { buf->p = NULL; buf->ptr = NULL; -#if LWIP_IPV6 - ip6_addr_set_any(&buf->addr.ip6); -#else /* LWIP_IPV6 */ - ip_addr_set_any(&buf->addr.ip4); -#endif /* LWIP_IPV6 */ + ipX_addr_set_any(LWIP_IPV6, &buf->addr); buf->port = 0; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY @@ -73,11 +69,7 @@ netbuf *netbuf_new(void) #endif /* LWIP_CHECKSUM_ON_COPY */ buf->toport_chksum = 0; #if LWIP_NETBUF_RECVINFO -#if LWIP_IPV6 - ip6_addr_set_any(&buf->toaddr.ip6); -#else /* LWIP_IPV6 */ - ip_addr_set_any(&buf->toaddr.ip4); -#endif /* LWIP_IPV6 */ + ipX_addr_set_any(LWIP_IPV6, &buf->toaddr); #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ return buf; diff --git a/src/api/sockets.c b/src/api/sockets.c index ba035de5..d897397b 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -58,15 +58,65 @@ #include -/* Check that the family member of a struct sockaddr matches the socket's IP version */ +#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \ + (sin)->sin_len = sizeof(struct sockaddr_in); \ + (sin)->sin_family = AF_INET; \ + (sin)->sin_port = htons((port)); \ + inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \ + memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) +#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \ + inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \ + (port) = (sin)->sin_port; }while(0) + #if LWIP_IPV6 -#define SOCK_ADDR_MATCH(name, sock) \ +#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ + ((namelen) == sizeof(struct sockaddr_in6))) +#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ + ((name)->sa_family == AF_INET6)) +#define SOCK_ADDR_TYPE_MATCH(name, sock) \ ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) +#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \ + (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, ipX_2_ip6(ipXaddr)); }while(0) +#define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \ + if (isipv6) { \ + IP6ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in6*)(sockaddr)), ipXaddr, port); \ + } else { \ + IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)(sockaddr)), ipXaddr, port); \ + } } while(0) +#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \ + inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \ + (port) = (sin6)->sin6_port; }while(0) +#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \ + if (isipv6) { \ + SOCKADDR6_TO_IP6ADDR_PORT(((struct sockaddr_in6*)(sockaddr)), ipXaddr, port); \ + } else { \ + SOCKADDR4_TO_IP4ADDR_PORT(((struct sockaddr_in*)(sockaddr)), ipXaddr, port); \ + } } while(0) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (((domain) == AF_INET) ? \ + (netconn_type) : ((netconn_type) | NETCONN_TYPE_IPV6)) #else /* LWIP_IPV6 */ -#define SOCK_ADDR_MATCH(name, sock) (((name)->sa_family) == AF_INET) +#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) +#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) +#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 +#define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \ + IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)sockaddr), ipXaddr, port) +#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \ + IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)(sockaddr)), ipXaddr, port) +#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) #endif /* LWIP_IPV6 */ +#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ + IS_SOCK_ADDR_TYPE_VALID(name)) +#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ + SOCK_ADDR_TYPE_MATCH(name, sock)) +#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) + + #define NUM_SOCKETS MEMP_NUM_NETCONN @@ -323,19 +373,9 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct lwip_sock *sock, *nsock; struct netconn *newconn; - union { - ip_addr_t ip4; -#if LWIP_IPV6 - ip6_addr_t ip6; -#endif /* LWIP_IPV6 */ - } naddr; + ipX_addr_t naddr; u16_t port; int newsock; - 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); @@ -362,47 +402,25 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) /* Prevent automatic window updates, we do this on our own! */ netconn_set_noautorecved(newconn, 1); - /* get the IP address and port of the remote host */ - 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); - sock_set_errno(sock, err_to_errno(err)); - return -1; - } - /* Note that POSIX only requires us to check addr is non-NULL. addrlen must * not be NULL if addr is valid. */ - if (NULL != addr) { + if (addr != NULL) { + struct sockaddr tempaddr; + /* get the IP address and port of the remote host */ + err = netconn_peer(newconn, ipX_2_ip(&naddr), &port); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); + netconn_delete(newconn); + sock_set_errno(sock, err_to_errno(err)); + return -1; + } LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); - 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; + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port); + if (*addrlen > tempaddr.sa_len) { + *addrlen = tempaddr.sa_len; } - else -#endif /* LWIP_IPV6 */ - { - sin = (struct sockaddr_in *)&tempaddr; - sin->sin_len = sizeof(struct sockaddr_in); - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - inet_addr_from_ipaddr(&sin->sin_addr, &naddr.ip4); - - if (*addrlen > sin->sin_len) - *addrlen = sin->sin_len; - } - MEMCPY(addr, &tempaddr, *addrlen); } @@ -426,17 +444,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) newconn->socket = newsock; SYS_ARCH_UNPROTECT(lev); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); -#if LWIP_IPV6 - if (NETCONNTYPE_ISIPV6(newconn->type)) { - ip6_addr_debug_print(SOCKETS_DEBUG, &naddr.ip6); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); + if (addr != NULL) { + LWIP_DEBUGF(SOCKETS_DEBUG, (" addr=")); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), SOCKETS_DEBUG, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); } - 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); return newsock; @@ -446,53 +459,32 @@ int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_sock *sock; - union { - ip_addr_t ip4; -#if LWIP_IPV6 - ip6_addr_t ip6; -#endif /* LWIP_IPV6 */ - } local_addr; + ipX_addr_t 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) { return -1; } + if (SOCK_ADDR_TYPE_MATCH(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + /* check size, familiy and alignment of 'name' */ - LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - SOCK_ADDR_MATCH(name, sock) && - ((((mem_ptr_t)name) % 4) == 0)), + LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); -#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; - } + ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); - err = netconn_bind(sock->conn, &local_addr.ip4, ntohs(local_port)); + err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), ntohs(local_port)); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); @@ -542,48 +534,28 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) return -1; } + if (SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + /* check size, familiy and alignment of 'name' */ - LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - SOCK_ADDR_MATCH(name, sock) && - ((((mem_ptr_t)name) % 4) == 0)), + LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); if (name->sa_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); - } -#if LWIP_IPV6 - else if (name->sa_family == AF_INET6) { - const struct sockaddr_in6 *name_in6; - ip6_addr_t remote_addr; + } else { + ipX_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; - + SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); - ip6_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + ipX_addr_debug_print(name->sa_family == AF_INET6, 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; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); - ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); - - err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); + err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), ntohs(remote_port)); } if (err != ERR_OK) { @@ -635,14 +607,13 @@ lwip_listen(int s, int backlog) int lwip_recvfrom(int s, void *mem, size_t len, int flags, - struct sockaddr *from, socklen_t *fromlen) + struct sockaddr *from, socklen_t *fromlen) { struct lwip_sock *sock; void *buf = NULL; struct pbuf *p; u16_t buflen, copylen; int off = 0; - u16_t port; u8_t done = 0; err_t err; @@ -747,64 +718,23 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, if (from && fromlen) #endif /* !SOCKETS_DEBUG */ { + u16_t port; + ipX_addr_t tmpaddr; + ipX_addr_t *fromaddr; + struct sockaddr saddr; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); -#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); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { + fromaddr = &tmpaddr; + /* @todo: this does not work for IPv6, yet */ + netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0); + } else { + port = netbuf_fromport((struct netbuf *)buf); + fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf); } + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + &saddr, fromaddr, port); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + SOCKETS_DEBUG, fromaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); } } @@ -866,7 +796,7 @@ lwip_send(int s, const void *data, size_t size, int flags) return -1; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) return lwip_sendto(s, data, size, flags, NULL, 0); #else /* (LWIP_UDP || LWIP_RAW) */ @@ -910,7 +840,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, return -1; } - if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { #if LWIP_TCP return lwip_send(s, data, size, flags); #else /* LWIP_TCP */ @@ -920,13 +850,18 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } + if (SOCK_ADDR_TYPE_MATCH(to, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); + return -1; + } + /* @todo: split into multiple sendto's? */ LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); short_size = (u16_t)size; LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || - ((tolen == sizeof(struct sockaddr_in)) && - SOCK_ADDR_MATCH(to, sock) && - ((((mem_ptr_t)to) % 4) == 0))), + (IS_SOCK_ADDR_LEN_VALID(tolen) && + IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); #if LWIP_TCPIP_CORE_LOCKING @@ -943,7 +878,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, if (p != NULL) { #if LWIP_CHECKSUM_ON_COPY u16_t chksum = 0; - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); } else #endif /* LWIP_CHECKSUM_ON_COPY */ @@ -960,7 +895,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, 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_addr = ip6_2_ip(remote_addr6); remote_port = ntohs(to_in6->sin6_port); } else @@ -974,19 +909,23 @@ lwip_sendto(int s, const void *data, size_t size, int flags, } else { 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; + if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn))) { + remote_addr = ip6_2_ip(IP6_ADDR_ANY); } else #endif /* LWIP_IPV6 */ { remote_addr = IP_ADDR_ANY; } + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) { + remote_port = 0; + } else { + remote_port = sock->conn->pcb.udp->remote_port; + } } LOCK_TCPIP_CORE(); - if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); } else { #if LWIP_UDP @@ -1015,48 +954,18 @@ lwip_sendto(int s, const void *data, size_t size, int flags, buf.flags = 0; #endif /* LWIP_CHECKSUM_ON_COPY */ if (to) { -#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; + SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port); } else { 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; + ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); } + netbuf_fromport(&buf) = remote_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", s, data, short_size, flags)); -#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); - } + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + SOCKETS_DEBUG, &buf.addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); /* make the buffer point to the data that should be sent */ @@ -1066,7 +975,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, err = ERR_MEM; } else { #if LWIP_CHECKSUM_ON_COPY - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_RAW) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); netbuf_set_chksum(&buf, chksum); err = ERR_OK; @@ -1098,40 +1007,26 @@ lwip_socket(int domain, int type, int protocol) int i; #if !LWIP_IPV6 - LWIP_UNUSED_ARG(domain); + LWIP_UNUSED_ARG(domain); /* @todo: check this */ #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, + conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), (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) , + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, + ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , 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 */ + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); if (conn != NULL) { @@ -1399,8 +1294,6 @@ return_copy_fdsets: if (exceptset) { *exceptset = lexceptset; } - - return nready; } @@ -1573,63 +1466,31 @@ static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; + struct sockaddr saddr; + ipX_addr_t naddr; + u16_t port; sock = get_socket(s); if (!sock) { return -1; } -#if LWIP_IPV6 - if (NETCONNTYPE_ISIPV6(sock->conn->type)) { - struct sockaddr_in6 sin6; - ip6_addr_t naddr6; + /* get the IP address and port */ + /* @todo: this does not work for IPv6, yet */ + netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local); + IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + &saddr, &naddr, port); - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), + SOCKETS_DEBUG, &naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - /* 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)); - ip6_addr_debug_print(SOCKETS_DEBUG, &naddr6); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin6.sin6_port)); - - sin6.sin6_port = htons(sin6.sin6_port); - inet6_addr_from_ip6addr(&sin6.sin6_addr, &naddr6); - - if (*namelen > sizeof(sin6)) { - *namelen = sizeof(sin6); - } - - MEMCPY(name, &sin6, *namelen); + if (*namelen > saddr.sa_len) { + *namelen = saddr.sa_len; } - else -#endif /* LWIP_IPV6 */ - { - struct sockaddr_in sin; - ip_addr_t naddr; + MEMCPY(name, &saddr, *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; } @@ -1703,12 +1564,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) err = EINVAL; } #if LWIP_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 */ + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; @@ -1750,7 +1606,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) if (*optlen < sizeof(u8_t)) { err = EINVAL; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; @@ -1772,7 +1628,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* If this is no TCP socket, ignore any options. */ - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) return 0; switch (optname) { @@ -1801,11 +1657,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* If this is no UDP lite socket, ignore any options. */ -#if LWIP_IPV6 - if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6)) { -#else /* LWIP_IPV6 */ - if (sock->conn->type != NETCONN_UDPLITE) { -#endif /* LWIP_IPV6 */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { return 0; } @@ -1899,7 +1751,7 @@ lwip_getsockopt_internal(void *arg) break; case SO_TYPE: - switch (NETCONNTYPE_GROUP(sock->conn->type)) { + switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { case NETCONN_RAW: *(int*)optval = SOCK_RAW; break; @@ -1910,11 +1762,11 @@ lwip_getsockopt_internal(void *arg) *(int*)optval = SOCK_DGRAM; break; default: /* unrecognized socket type */ - *(int*)optval = sock->conn->type; + *(int*)optval = netconn_type(sock->conn); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval)); - } /* switch (sock->conn->type) */ + } /* switch (netconn_type(sock->conn)) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval)); break; @@ -2109,12 +1961,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EINVAL; } #if LWIP_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 */ + if (NETCONNTYPE_GROUP((netconn_type(sock->conn) != NETCONN_UDP)) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; @@ -2145,7 +1992,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt if (optlen < sizeof(u8_t)) { err = EINVAL; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; @@ -2153,7 +2000,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt if (optlen < sizeof(struct in_addr)) { err = EINVAL; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; @@ -2161,7 +2008,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt if (optlen < sizeof(u8_t)) { err = EINVAL; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; @@ -2170,7 +2017,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt if (optlen < sizeof(struct ip_mreq)) { err = EINVAL; } - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; @@ -2191,7 +2038,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* If this is no TCP socket, ignore any options. */ - if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) return 0; switch (optname) { @@ -2220,11 +2067,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt } /* If this is no UDP lite socket, ignore any options. */ -#if LWIP_IPV6 - if ((sock->conn->type != NETCONN_UDPLITE) && (sock->conn->type != NETCONN_UDPLITE_IPV6)) -#else /* LWIP_IPV6 */ - if (sock->conn->type != NETCONN_UDPLITE) -#endif /* LWIP_IPV6 */ + if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) return 0; switch (optname) { diff --git a/src/core/ipv4/inet_chksum.c b/src/core/inet_chksum.c similarity index 79% rename from src/core/ipv4/inet_chksum.c rename to src/core/inet_chksum.c index b95f7f28..9d295159 100644 --- a/src/core/ipv4/inet_chksum.c +++ b/src/core/inet_chksum.c @@ -257,30 +257,13 @@ lwip_standard_chksum(void *dataptr, int len) } #endif -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len) +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) { - u32_t acc; - u32_t addr; struct pbuf *q; - u8_t swapped; + u8_t swapped = 0; - acc = 0; - swapped = 0; /* iterate through all pbuf in chain */ for(q = p; q != NULL; q = q->next) { LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", @@ -300,12 +283,7 @@ inet_chksum_pseudo(struct pbuf *p, if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } - addr = ip4_addr_get_u32(src); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); + acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); @@ -330,18 +308,63 @@ inet_chksum_pseudo(struct pbuf *p, * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t -inet_chksum_pseudo_partial(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len) +inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip_addr_t *src, ip_addr_t *dest) { u32_t acc; u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip6_addr_t *src, ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + + return inet_cksum_pseudo_base(p, proto, proto_len, acc); +} +#endif /* LWIP_IPV6 */ + +/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ +static u16_t +inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, u32_t acc) +{ struct pbuf *q; - u8_t swapped; + u8_t swapped = 0; u16_t chklen; - acc = 0; - swapped = 0; /* iterate through all pbuf in chain */ for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", @@ -366,12 +389,7 @@ inet_chksum_pseudo_partial(struct pbuf *p, if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } - addr = ip4_addr_get_u32(src); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); + acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); @@ -383,6 +401,70 @@ inet_chksum_pseudo_partial(struct pbuf *p, return (u16_t)~(acc & 0xffffUL); } +/* inet_chksum_pseudo_partial: + * + * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. + * IP addresses are expected to be in network byte order. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ip address (used for checksum of pseudo header) + * @param dst destination ip address (used for checksum of pseudo header) + * @param proto ip protocol (used for checksum of pseudo header) + * @param proto_len length of the ip data part (used for checksum of pseudo header) + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest) +{ + u32_t acc; + u32_t addr; + + addr = ip4_addr_get_u32(src); + acc = (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} + +#if LWIP_IPV6 +/** + * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. + * IPv6 addresses are expected to be in network byte order. Will only compute for a + * portion of the payload. + * + * @param p chain of pbufs over that a checksum should be calculated (ip data part) + * @param src source ipv6 address (used for checksum of pseudo header) + * @param dst destination ipv6 address (used for checksum of pseudo header) + * @param proto ipv6 protocol/next header (used for checksum of pseudo header) + * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) + * @param chksum_len number of payload bytes used to compute chksum + * @return checksum (as u16_t) to be saved directly in the protocol header + */ +u16_t +ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest) +{ + u32_t acc = 0; + u32_t addr; + u8_t addr_part; + + for (addr_part = 0; addr_part < 4; addr_part++) { + addr = src->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = dest->addr[addr_part]; + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + } + + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); +} +#endif /* LWIP_IPV6 */ + /* inet_chksum: * * Calculates the Internet checksum over a portion of memory. Used primarily for IP diff --git a/src/core/ipv4/inet.c b/src/core/ipv4/inet.c deleted file mode 100644 index e283a576..00000000 --- a/src/core/ipv4/inet.c +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file - * Functions common to all TCP/IPv4 modules, such as the byte order functions. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet.h" - diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip4.c similarity index 93% rename from src/core/ipv4/ip.c rename to src/core/ipv4/ip4.c index 5e9a387d..cd121867 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip4.c @@ -93,20 +93,8 @@ #define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 #endif /* LWIP_DHCP */ -/** - * The interface that provided the packet for the current callback - * invocation. - */ -struct netif *current_netif; - -/** - * Header of the input packet currently being processed. - */ -const struct ip_hdr *current_header; -/** Source IP address of current_header */ -ip_addr_t current_iphdr_src; -/** Destination IP address of current_header */ -ip_addr_t current_iphdr_dest; +/** Global data for both IPv4 and IPv6 */ +struct ip_globals ip_data; /** The IP header ID of the next outgoing IP packet */ static u16_t ip_id; @@ -164,19 +152,19 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) PERF_START; /* RFC3927 2.7: do not forward link-local addresses */ - if (ip_addr_islinklocal(¤t_iphdr_dest)) { + if (ip_addr_islinklocal(ip_current_dest_addr())) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); goto return_noroute; } /* Find network interface where to forward this IP packet to. */ - netif = ip_route(¤t_iphdr_dest); + netif = ip_route(ip_current_dest_addr()); if (netif == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); goto return_noroute; } /* Do not forward packets onto the same network interface on which @@ -208,8 +196,8 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) } LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), + ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); IP_STATS_INC(ip.fw); IP_STATS_INC(ip.xmit); @@ -217,7 +205,7 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) PERF_STOP("ip_forward"); /* transmit pbuf on chosen interface */ - netif->output(netif, p, ¤t_iphdr_dest); + netif->output(netif, p, ip_current_dest_addr()); return; return_noroute: snmp_inc_ipoutnoroutes(); @@ -311,13 +299,13 @@ ip_input(struct pbuf *p, struct netif *inp) pbuf_realloc(p, iphdr_len); /* copy IP addresses to aligned ip_addr_t */ - ip_addr_copy(current_iphdr_dest, iphdr->dest); - ip_addr_copy(current_iphdr_src, iphdr->src); + ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest); + ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src); /* match packet against an interface, i.e. is this packet for us? */ #if LWIP_IGMP - if (ip_addr_ismulticast(¤t_iphdr_dest)) { - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { + if (ip_addr_ismulticast(ip_current_dest_addr())) { + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) { netif = inp; } else { netif = NULL; @@ -340,9 +328,9 @@ ip_input(struct pbuf *p, struct netif *inp) /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ - if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || + if (ip_addr_cmp(ip_current_dest_addr(), &(netif->ip_addr)) || /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { + ip_addr_isbroadcast(ip_current_dest_addr(), netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ @@ -352,7 +340,7 @@ ip_input(struct pbuf *p, struct netif *inp) /* connections to link-local addresses must persist after changing the netif's address (RFC3927 ch. 1.9) */ if ((netif->autoip != NULL) && - ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { + ip_addr_cmp(ip_current_dest_addr(), &(netif->autoip->llipaddr))) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ @@ -400,10 +388,10 @@ ip_input(struct pbuf *p, struct netif *inp) /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ #if IP_ACCEPT_LINK_LAYER_ADDRESSING /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) + if (check_ip_src && !ip_addr_isany(ip_current_src_addr())) #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || - (ip_addr_ismulticast(¤t_iphdr_src))) { + { if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) || + (ip_addr_ismulticast(ip_current_src_addr()))) { /* packet source is not valid */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); /* free (drop) packet pbufs */ @@ -421,7 +409,7 @@ ip_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { + if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else @@ -480,8 +468,9 @@ ip_input(struct pbuf *p, struct netif *inp) ip_debug_print(p); LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - current_netif = inp; - current_header = iphdr; + ip_data.current_netif = inp; + ip_data.current_ip4_header = iphdr; + ip_data.current_ip_header_tot_len = IPH_LEN(iphdr); #if LWIP_RAW /* raw input did not eat the packet? */ @@ -517,14 +506,14 @@ ip_input(struct pbuf *p, struct netif *inp) #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); + igmp_input(p, inp, ip_current_dest_addr()); break; #endif /* LWIP_IGMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && - !ip_addr_ismulticast(¤t_iphdr_dest)) { + if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) && + !ip_addr_ismulticast(ip_current_dest_addr())) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } @@ -539,10 +528,12 @@ ip_input(struct pbuf *p, struct netif *inp) } } - current_netif = NULL; - current_header = NULL; - ip_addr_set_any(¤t_iphdr_src); - ip_addr_set_any(¤t_iphdr_dest); + /* @todo: this is not really necessary... */ + ip_data.current_netif = NULL; + ip_data.current_ip4_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip_addr_set_any(ip_current_src_addr()); + ip_addr_set_any(ip_current_dest_addr()); return ERR_OK; } @@ -805,9 +796,9 @@ ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, return ERR_RTE; } - netif->addr_hint = addr_hint; + NETIF_SET_HWADDRHINT(netif, addr_hint); err = ip_output_if(p, src, dest, ttl, tos, proto, netif); - netif->addr_hint = NULL; + NETIF_SET_HWADDRHINT(netif, NULL); return err; } diff --git a/src/core/ipv4/ip_addr.c b/src/core/ipv4/ip4_addr.c similarity index 100% rename from src/core/ipv4/ip_addr.c rename to src/core/ipv4/ip4_addr.c diff --git a/src/core/ipv6/ethip6.c b/src/core/ipv6/ethip6.c index 1a6001e3..99410103 100644 --- a/src/core/ipv6/ethip6.c +++ b/src/core/ipv6/ethip6.c @@ -48,13 +48,13 @@ #include "lwip/pbuf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp6.h" #include -#define ETHTYPE_IPV6 0x86dd +#define ETHTYPE_IPV6 0x86DD /** The ethernet address */ #ifdef PACK_STRUCT_USE_INCLUDES @@ -89,7 +89,30 @@ PACK_STRUCT_END #define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) -static err_t ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst); +/** + * Send an IPv6 packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; + + LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", + (netif->hwaddr_len == 6)); + SMEMCPY(ðhdr->dest, dst, 6); + SMEMCPY(ðhdr->src, src, 6); + ethhdr->type = PP_HTONS(ETHTYPE_IPV6); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); + /* send the packet */ + return netif->linkoutput(netif, p); +} /** * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. @@ -169,29 +192,4 @@ ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr) return ERR_OK; } -/** - * Send an IPv6 packet on the network using netif->linkoutput - * The ethernet header is filled in before sending. - * - * @params netif the lwIP network interface on which to send the packet - * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header - * @params src the source MAC address to be copied into the ethernet header - * @params dst the destination MAC address to be copied into the ethernet header - * @return ERR_OK if the packet was sent, any other err_t on failure - */ -static err_t -ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) -{ - struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; - - LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", - (netif->hwaddr_len == 6)); - SMEMCPY(ðhdr->dest, dst, 6); - SMEMCPY(ðhdr->src, src, 6); - ethhdr->type = PP_HTONS(ETHTYPE_IPV6); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); - /* send the packet */ - return netif->linkoutput(netif, p); -} - #endif /* LWIP_IPV6 && LWIP_ETHERNET */ diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index c92235e1..be725c2d 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -46,7 +46,7 @@ #include "lwip/icmp6.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/nd6.h" @@ -63,7 +63,7 @@ #endif /* Forward declarations */ -static void icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data); +static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); /** @@ -96,8 +96,8 @@ icmp6_input(struct pbuf *p, struct netif *inp) icmp6hdr = (struct icmp6_hdr *)p->payload; #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) { + if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), + ip6_current_dest_addr()) != 0) { /* Checksum failed */ pbuf_free(p); ICMP6_STATS_INC(icmp6.chkerr); @@ -171,8 +171,7 @@ icmp6_input(struct pbuf *p, struct netif *inp) ((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); + IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); /* Send reply. */ ICMP6_STATS_INC(icmp6.xmit); @@ -201,7 +200,7 @@ icmp6_input(struct pbuf *p, struct netif *inp) void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) { - icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0); + icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); } /** @@ -214,7 +213,7 @@ icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) void icmp6_packet_too_big(struct pbuf *p, u32_t mtu) { - icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu); + icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); } /** @@ -227,7 +226,7 @@ icmp6_packet_too_big(struct pbuf *p, u32_t mtu) void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) { - icmp6_send_response(p, ICMP6_TYPE_TE, c, 0); + icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); } /** @@ -241,7 +240,7 @@ icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) { - icmp6_send_response(p, ICMP6_TYPE_PP, c, pointer); + icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); } /** @@ -249,12 +248,12 @@ icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) * * @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 + * @param type Type of the ICMPv6 header */ static void -icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data) +icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) { struct pbuf *q; struct icmp6_hdr *icmp6hdr; @@ -281,7 +280,7 @@ icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data) IP6_HLEN + LWIP_ICMP6_DATASIZE); /* Select an address to use as source. */ - reply_src = ip6_select_source_address(current_netif, ip6_current_src_addr()); + reply_src = ip6_select_source_address(ip_current_netif(), ip6_current_src_addr()); if (reply_src == NULL) { /* drop */ pbuf_free(q); @@ -291,13 +290,12 @@ icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data) /* calculate checksum */ icmp6hdr->chksum = 0; - icmp6hdr->chksum = ip6_chksum_pseudo(q, reply_src, ip6_current_src_addr(), - IP6_NEXTH_ICMP6, q->tot_len); + icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, + reply_src, ip6_current_src_addr()); 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_ICMP6 && LWIP_IPV6 */ diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 5c58f05c..79cbc870 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -61,17 +61,6 @@ #include "lwip/stats.h" -/** 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: @@ -380,11 +369,11 @@ ip6_input(struct pbuf *p, struct netif *inp) 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); + ip6_addr_copy(ip_data.current_iphdr_dest.ip6, ip6hdr->dest); + ip6_addr_copy(ip_data.current_iphdr_src.ip6, ip6hdr->src); /* current header pointer. */ - current_ip6_header = ip6hdr; + ip_data.current_ip6_header = ip6hdr; /* match packet against an interface, i.e. is this packet for us? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { @@ -468,13 +457,13 @@ netif_found: } /* current netif pointer. */ - current_netif = inp; + ip_data.current_netif = inp; /* Save next header type. */ nexth = IP6H_NEXTH(ip6hdr); /* Init header length. */ - hlen = current_ip6_header_tot_len = IP6_HLEN; + hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; /* Move to payload. */ pbuf_header(p, -IP6_HLEN); @@ -490,7 +479,7 @@ netif_found: /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload) + 1); - current_ip6_header_tot_len += hlen; + ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { @@ -513,7 +502,7 @@ netif_found: /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload) + 1); - current_ip6_header_tot_len += hlen; + ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { @@ -536,7 +525,7 @@ netif_found: /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload) + 1); - current_ip6_header_tot_len += hlen; + ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { @@ -565,7 +554,7 @@ netif_found: /* Fragment Header length. */ hlen = 8; - current_ip6_header_tot_len += hlen; + ip_data.current_ip_header_tot_len += hlen; /* Make sure this header fits in current pbuf. */ if (hlen > p->len) { @@ -601,7 +590,7 @@ netif_found: * 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; + hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; pbuf_header(p, -IP6_HLEN); #else /* LWIP_IPV6_REASS */ @@ -623,7 +612,7 @@ netif_found: options_done: /* p points to IPv6 header again. */ - pbuf_header(p, current_ip6_header_tot_len); + pbuf_header(p, ip_data.current_ip_header_tot_len); /* send to upper layers */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); @@ -645,21 +634,21 @@ options_done: case IP6_NEXTH_UDPLITE: #endif /* LWIP_UDPLITE */ /* Point to payload. */ - pbuf_header(p, -current_ip6_header_tot_len); + pbuf_header(p, -ip_data.current_ip_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); + pbuf_header(p, -ip_data.current_ip_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); + pbuf_header(p, -ip_data.current_ip_header_tot_len); icmp6_input(p, inp); break; #endif /* LWIP_ICMP */ @@ -668,7 +657,7 @@ options_done: /* 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); + icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen); } #endif /* LWIP_ICMP */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr))); @@ -680,11 +669,11 @@ options_done: } 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); + ip_data.current_netif = NULL; + ip_data.current_ip6_header = NULL; + ip_data.current_ip_header_tot_len = 0; + ip6_addr_set_any(&ip_data.current_iphdr_src.ip6); + ip6_addr_set_any(&ip_data.current_iphdr_dest.ip6); return ERR_OK; } @@ -727,7 +716,7 @@ ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, 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) { + if (dest != IP_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")); @@ -883,9 +872,9 @@ ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, return ERR_RTE; } - netif->addr_hint = addr_hint; + NETIF_SET_HWADDRHINT(netif, addr_hint); err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); - netif->addr_hint = NULL; + NETIF_SET_HWADDRHINT(netif, NULL); return err; } diff --git a/src/core/ipv6/ip6_chksum.c b/src/core/ipv6/ip6_chksum.c deleted file mode 100644 index 311a166d..00000000 --- a/src/core/ipv6/ip6_chksum.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file - * - * IPv6 Checksum helper functions. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" -#include "lwip/inet_chksum.h" -#include "lwip/def.h" - -#ifndef LWIP_CHKSUM -# define LWIP_CHKSUM lwip_standard_chksum -extern u16_t lwip_standard_chksum(void *dataptr, u16_t len); -#endif - - -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dst destination ipv6 address (used for checksum of pseudo header) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo(struct pbuf *p, - ip6_addr_t *src, ip6_addr_t *dest, - u8_t proto, u16_t proto_len) -{ - u32_t acc; - u32_t addr; - struct pbuf *q; - u8_t swapped; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; q != NULL; q = q->next) { - acc += LWIP_CHKSUM(q->payload, q->len); - /* fold the upper bit down */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - } - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - - for (swapped = 0; swapped < 4; swapped++) { - addr = src->addr[swapped]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = dest->addr[swapped]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - } - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("ip6_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -/** - * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. - * IPv6 addresses are expected to be in network byte order. Will only compute for a - * portion of the payload. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ipv6 address (used for checksum of pseudo header) - * @param dst destination ipv6 address (used for checksum of pseudo header) - * @param proto ipv6 protocol/next header (used for checksum of pseudo header) - * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) - * @param chksum_len number of payload bytes used to compute chksum - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -ip6_chksum_pseudo_partial(struct pbuf *p, - ip6_addr_t *src, ip6_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len) -{ - u32_t acc; - u32_t addr; - struct pbuf *q; - u8_t swapped; - u16_t chklen; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { - chklen = q->len; - if (chklen > chksum_len) { - chklen = chksum_len; - } - acc += LWIP_CHKSUM(q->payload, chklen); - chksum_len -= chklen; - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - } - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - - for (swapped = 0; swapped < 4; swapped++) { - addr = src->addr[swapped]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = dest->addr[swapped]; - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - } - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("ip6_chksum_pseudo_partial(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -#endif /* LWIP_IPV6 */ diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index 2e9213b9..97132273 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -50,7 +50,7 @@ #include "lwip/icmp6.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/memp.h" @@ -560,8 +560,8 @@ mld6_send(struct mld_group *group, u8_t type) mld_hdr->reserved = 0; ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); - mld_hdr->chksum = ip6_chksum_pseudo(p, src_addr, &(group->group_address), - IP6_NEXTH_ICMP6, p->len); + mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, + src_addr, &(group->group_address)); /* Add hop-by-hop headers options: router alert with MLD value. */ ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 7a80e653..8797a025 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -51,7 +51,7 @@ #include "lwip/memp.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp6.h" #include "lwip/mld6.h" @@ -827,8 +827,8 @@ nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) target_addr = &multicast_address; } - ns_hdr->chksum = ip6_chksum_pseudo(p, src_addr, target_addr, - IP6_NEXTH_ICMP6, p->len); + ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + target_addr); /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); @@ -897,8 +897,8 @@ nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) dest_addr = ip6_current_src_addr(); } - na_hdr->chksum = ip6_chksum_pseudo(p, src_addr, dest_addr, - IP6_NEXTH_ICMP6, p->len); + na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + dest_addr); /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); @@ -964,8 +964,8 @@ nd6_send_rs(struct netif * netif) SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); } - rs_hdr->chksum = ip6_chksum_pseudo(p, src_addr, &multicast_address, - IP6_NEXTH_ICMP6, p->len); + rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + &multicast_address); /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); @@ -1407,12 +1407,11 @@ nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) s8_t i; #if LWIP_NETIF_HWADDRHINT - /* TODO should addr_hint point to nd6_cached_neighbor_index instead? */ if (netif->addr_hint != NULL) { /* per-pcb cached entry was given */ - i = *(netif->addr_hint); - if ((i >= 0) && (i < LWIP_ND6_NUM_DESTINATIONS)) { - nd6_cached_destination_index = i; + u8_t addr_hint = *(netif->addr_hint); + if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { + nd6_cached_destination_index = addr_hint; } } #endif /* LWIP_NETIF_HWADDRHINT */ @@ -1425,7 +1424,7 @@ nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) } else { /* Search destination cache. */ i = nd6_find_destination_cache_entry(ip6addr); - if (i>= 0) { + if (i >= 0) { /* found destination entry. make it our new cached index. */ nd6_cached_destination_index = i; } @@ -1465,7 +1464,6 @@ nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) } #if LWIP_NETIF_HWADDRHINT - /* TODO should addr_hint point to nd6_cached_neighbor_index instead? */ if (netif->addr_hint != NULL) { /* per-pcb cached entry was given */ *(netif->addr_hint) = nd6_cached_destination_index; diff --git a/src/core/netif.c b/src/core/netif.c index e93762af..f58ba1ab 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -202,9 +202,7 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, netif->state = state; netif->num = netifnum++; netif->input = input; -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ + NETIF_SET_HWADDRHINT(netif, NULL); #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ @@ -365,10 +363,10 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) pcb = tcp_active_pcbs; while (pcb != NULL) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr)) + if (ip_addr_cmp(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr)) #if LWIP_AUTOIP /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && !ip_addr_islinklocal(&(pcb->local_ip.ip4)) + && !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip)) #endif /* LWIP_AUTOIP */ ) { /* this connection must be aborted */ @@ -382,11 +380,11 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) } for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { /* PCB bound to current local interface address? */ - if ((!(ip_addr_isany(&(lpcb->local_ip.ip4)))) && - (ip_addr_cmp(&(lpcb->local_ip.ip4), &(netif->ip_addr)))) { + if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) && + (ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) { /* The PCB is listening to the old ipaddr and * is set to listen to the new one instead */ - ip_addr_set(&(lpcb->local_ip.ip4), ipaddr); + ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr); } } } diff --git a/src/core/pbuf.c b/src/core/pbuf.c index dd9ff64e..4649fb87 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -190,21 +190,21 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ - offset = 0; switch (layer) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ - offset += PBUF_TRANSPORT_HLEN; - /* FALLTHROUGH */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; + break; case PBUF_IP: /* add room for IP layer header */ - offset += PBUF_IP_HLEN; - /* FALLTHROUGH */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; + break; case PBUF_LINK: /* add room for link layer header */ - offset += PBUF_LINK_HLEN; + offset = PBUF_LINK_HLEN; break; case PBUF_RAW: + offset = 0; break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); @@ -348,21 +348,21 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); /* determine header offset */ - offset = 0; switch (l) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ - offset += PBUF_TRANSPORT_HLEN; - /* FALLTHROUGH */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; + break; case PBUF_IP: /* add room for IP layer header */ - offset += PBUF_IP_HLEN; - /* FALLTHROUGH */ + offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; + break; case PBUF_LINK: /* add room for link layer header */ - offset += PBUF_LINK_HLEN; + offset = PBUF_LINK_HLEN; break; case PBUF_RAW: + offset = 0; break; default: LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); diff --git a/src/core/raw.c b/src/core/raw.c index 8a0ce762..3ac3b687 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -105,17 +105,9 @@ raw_input(struct pbuf *p, struct netif *inp) /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { - if ((pcb->protocol == proto) && -#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 ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) && + (ipX_addr_isany(pcb->isipv6, &pcb->local_ip) || + ipX_addr_cmp(pcb->isipv6, &(pcb->local_ip), ipX_current_dest_addr()))) { #if IP_SOF_BROADCAST_RECV /* broadcast filter? */ if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp)) @@ -128,15 +120,7 @@ raw_input(struct pbuf *p, struct netif *inp) /* receive callback function available? */ if (pcb->recv.ip4 != NULL) { /* the receive callback function did not eat the packet? */ -#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()); - } + eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr()); if (eaten != 0) { /* receive function ate the packet */ p = NULL; @@ -177,15 +161,7 @@ raw_input(struct pbuf *p, struct netif *inp) err_t raw_bind(struct raw_pcb *pcb, ip_addr_t *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); - } + ipX_addr_set_ipaddr(pcb->isipv6, &pcb->local_ip, ipaddr); return ERR_OK; } @@ -205,15 +181,7 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) err_t raw_connect(struct raw_pcb *pcb, ip_addr_t *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); - } + ipX_addr_set_ipaddr(pcb->isipv6, &pcb->remote_ip, ipaddr); return ERR_OK; } @@ -258,38 +226,22 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) struct netif *netif; ip_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); - + s16_t header_size; #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 + ip6_addr_t *ip6addr = ip_2_ip6(ipaddr); #endif /* LWIP_IPV6 */ + + + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); + + header_size = ( +#if LWIP_IPV6 + pcb->isipv6 ? IP6_HLEN : +#endif /* LWIP_IPV6 */ + IP_HLEN); + /* not enough space to add an IP header to first pbuf in given p chain? */ - if (pbuf_header(p, IP_HLEN)) { + if (pbuf_header(p, header_size)) { /* allocate header in new pbuf */ q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); /* new header pbuf could not be allocated? */ @@ -306,7 +258,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } else { /* first pbuf q equals given pbuf */ q = p; - if(pbuf_header(q, -IP_HLEN)) { + if(pbuf_header(q, -header_size)) { LWIP_ASSERT("Can't restore header we just removed!", 0); return ERR_MEM; } @@ -314,20 +266,14 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) #if LWIP_IPV6 if (pcb->isipv6) { - if ((netif = ip6_route(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr)) == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to IPv6 destionation\n")); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_RTE; - } + netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ip6addr); } 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))); + netif = ip_route(ipaddr); + if (netif == NULL) { + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); + ipX_addr_debug_print(pcb->isipv6, RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ip_2_ipX(ipaddr)); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); @@ -337,8 +283,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) #if IP_SOF_BROADCAST #if LWIP_IPV6 - if (!netif->isipv6) { + /* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */ + 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)); @@ -348,54 +296,48 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } return ERR_VAL; } -#if LWIP_IPV6 } -#endif /* LWIP_IPV6 */ #endif /* IP_SOF_BROADCAST */ + NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); + #if LWIP_IPV6 if (pcb->isipv6) { - if (ip6_addr_isany(&pcb->local_ip.ip6)) { + ip6_addr_t *src6_ip; + if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { /* 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) { + src6_ip = ip6_select_source_address(netif, ip6addr); + if (src6_ip == NULL) { /* No suitable source address was found. */ + err = ERR_RTE; + NETIF_SET_HWADDRHINT(netif, NULL); + /* did we chain a header earlier? */ if (q != p) { + /* free the header */ 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); + src6_ip = ipX_2_ip6(&pcb->local_ip); } - } - 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.ip4); - } - -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = &(pcb->addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT*/ -#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); + err = ip6_output_if(q, src6_ip, ip6addr, 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 (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { + /* 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 = ipX_2_ip(&pcb->local_ip); + } + err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); } -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = NULL; -#endif /* LWIP_NETIF_HWADDRHINT*/ + NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ if (q != p) { /* free the header */ @@ -414,13 +356,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) err_t raw_send(struct raw_pcb *pcb, struct pbuf *p) { -#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 raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip)); } /** @@ -499,9 +435,7 @@ raw_new_ip6(u8_t proto) { struct raw_pcb *pcb; pcb = raw_new(proto); - if (pcb != NULL) { - pcb->isipv6 = 1; - } + ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ diff --git a/src/core/snmp/mib2.c b/src/core/snmp/mib2.c index 29decd30..7d587f8c 100644 --- a/src/core/snmp/mib2.c +++ b/src/core/snmp/mib2.c @@ -1797,7 +1797,7 @@ void snmp_insert_udpidx_tree(struct udp_pcb *pcb) u8_t level; LWIP_ASSERT("pcb != NULL", pcb != NULL); - snmp_iptooid(&pcb->local_ip, &udpidx[0]); + snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); udpidx[4] = pcb->local_port; udp_rn = &udp_root; @@ -1850,7 +1850,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb) u8_t bindings, fc, level, del_cnt; LWIP_ASSERT("pcb != NULL", pcb != NULL); - snmp_iptooid(&pcb->local_ip, &udpidx[0]); + snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); udpidx[4] = pcb->local_port; /* count PCBs for a given binding @@ -1859,7 +1859,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb) npcb = udp_pcbs; while ((npcb != NULL)) { - if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) && + if (ipX_addr_cmp(0, &npcb->local_ip, &pcb->local_ip) && (npcb->local_port == udpidx[4])) { bindings++; @@ -3881,17 +3881,17 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; struct udp_pcb *pcb; - ip_addr_t ip; + ipX_addr_t ip; u16_t port; LWIP_UNUSED_ARG(len); - snmp_oidtoip(&od->id_inst_ptr[1], &ip); + snmp_oidtoip(&od->id_inst_ptr[1], (ip_addr_t*)&ip); LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff)); port = (u16_t)od->id_inst_ptr[5]; pcb = udp_pcbs; while ((pcb != NULL) && - !(ip_addr_cmp(&pcb->local_ip, &ip) && + !(ipX_addr_cmp(0, &pcb->local_ip, &ip) && (pcb->local_port == port))) { pcb = pcb->next; @@ -3905,8 +3905,8 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value) { case 1: /* udpLocalAddress */ { - ip_addr_t *dst = (ip_addr_t*)value; - *dst = pcb->local_ip; + ipX_addr_t *dst = (ipX_addr_t*)value; + ipX_addr_copy(0, *dst, pcb->local_ip); } break; case 2: /* udpLocalPort */ diff --git a/src/core/tcp.c b/src/core/tcp.c index 1d62def6..8aa53a02 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -150,17 +150,8 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) /* don't call tcp_abort here: we must not deallocate the pcb since that might not be expected when calling tcp_close */ -#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_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port, pcb->isipv6); tcp_pcb_purge(pcb); @@ -330,8 +321,6 @@ void tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno; - /*u16_t remote_port, local_port; - ip_addr_t remote_ip, local_ip; */ #if LWIP_CALLBACK_API tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ @@ -349,10 +338,6 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) } else { seqno = pcb->snd_nxt; ackno = pcb->rcv_nxt; - /*ip_addr_copy(local_ip, pcb->local_ip.ip4); - ip_addr_copy(remote_ip, pcb->remote_ip.ip4); - local_port = pcb->local_port; - remote_port = pcb->remote_port;*/ #if LWIP_CALLBACK_API errf = pcb->errf; #endif /* LWIP_CALLBACK_API */ @@ -371,15 +356,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) #endif /* TCP_QUEUE_OOSEQ */ if (reset) { LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); -#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); - } + tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, pcb->isipv6); } memp_free(MEMP_TCP_PCB, pcb); TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); @@ -452,40 +429,20 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) ((cpcb->so_options & SOF_REUSEADDR) == 0)) #endif /* SO_REUSE */ { - 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.ip4), ipaddr))) { + /* @todo: check accept_any_ip_version */ + if (IP_PCB_IPVER_EQ(pcb, cpcb) && + (ipX_addr_isany(PCB_ISIPV6(pcb), &cpcb->local_ip) || + ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr)) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, ip_2_ipX(ipaddr)))) { return ERR_USE; } -#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.ip4 = *ipaddr; + if (!ipX_addr_isany(pcb->isipv6, ip_2_ipX(ipaddr))) { + ipX_addr_set(pcb->isipv6, &pcb->local_ip, ip_2_ipX(ipaddr)); } pcb->local_port = port; TCP_REG(&tcp_bound_pcbs, pcb); @@ -539,16 +496,9 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) is declared (listen-/connection-pcb), we have to make sure now that this port is only used once for every local IP. */ for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if (lpcb->local_port == pcb->local_port) { - if (( -#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))) { + if ((lpcb->local_port == pcb->local_port) && + IP_PCB_IPVER_EQ(pcb, lpcb)) { + if (ipX_addr_cmp(pcb->isipv6, &lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ return NULL; } @@ -570,14 +520,9 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) lpcb->tos = pcb->tos; #if LWIP_IPV6 lpcb->isipv6 = pcb->isipv6; - if (lpcb->isipv6) { - ip6_addr_copy(lpcb->local_ip.ip6, pcb->local_ip.ip6); - } - else + lpcb->accept_any_ip_version = 0; #endif /* LWIP_IPV6 */ - { - ip_addr_copy(lpcb->local_ip.ip4, pcb->local_ip.ip4); - } + ipX_addr_copy(pcb->isipv6, lpcb->local_ip, pcb->local_ip); if (pcb->local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } @@ -593,7 +538,28 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) return (struct tcp_pcb *)lpcb; } -/** +#if LWIP_IPV6 +/** + * Same as tcp_listen_with_backlog, but allows to accept IPv4 and IPv6 + * connections, if the pcb's local address is set to ANY. + */ +struct tcp_pcb * +tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog) +{ + struct tcp_pcb *lpcb; + + if (!ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + return NULL; + } + lpcb = tcp_listen_with_backlog(pcb, backlog); + if (lpcb != NULL) { + ((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1; + } + return lpcb; +} +#endif /* LWIP_IPV6 */ + +/** * Update the state that tracks the available window space to advertise. * * Returns how much extra window would be advertised if we sent an @@ -716,15 +682,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { -#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; - } + ipX_addr_set(PCB_ISIPV6(pcb), &pcb->remote_ip, ip_2_ipX(ipaddr)); } else { return ERR_VAL; } @@ -733,38 +691,38 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, /* check if we have a route to the remote host */ #if LWIP_IPV6 if (pcb->isipv6) { - if (ip6_addr_isany(&(pcb->local_ip.ip6))) { + if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { /* no local IPv6 address set, yet. */ ip6_addr_t * local_addr6; - struct netif *netif = ip6_route(&(pcb->remote_ip.ip6), &(pcb->remote_ip.ip6)); + struct netif *netif = ip6_route(ipX_2_ip6(&pcb->remote_ip), ipX_2_ip6(&pcb->remote_ip)); 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)); + local_addr6 = ip6_select_source_address(netif, ipX_2_ip6(&pcb->remote_ip)); 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); + ip6_addr_set(ipX_2_ip6(&pcb->local_ip), local_addr6); } } else #endif /* LWIP_IPV6 */ - if (ip_addr_isany(&(pcb->local_ip.ip4))) { + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { /* no local IP address set, yet. */ - struct netif *netif = ip_route(&(pcb->remote_ip.ip4)); + struct netif *netif = ip_route(ipX_2_ip(&pcb->remote_ip)); 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.ip4, netif->ip_addr); + ip_addr_copy(*ipX_2_ip(&pcb->local_ip), netif->ip_addr); } old_local_port = pcb->local_port; @@ -782,18 +740,9 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if ((cpcb->local_port == pcb->local_port) && (cpcb->remote_port == port) && -#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)))) { + IP_PCB_IPVER_EQ(cpcb, pcb) && + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, &pcb->local_ip) && + ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->remote_ip, ip_2_ipX(ipaddr))) { /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } @@ -814,15 +763,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS -#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); - } + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, pcb->isipv6); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; @@ -962,11 +903,7 @@ tcp_slowtmr(void) #endif /* LWIP_TCP_KEEPALIVE */ { 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); - } + ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); ++pcb_remove; @@ -1032,17 +969,8 @@ tcp_slowtmr(void) TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); if (pcb_reset) { -#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_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port, pcb->isipv6); } pcb2 = pcb; @@ -1401,10 +1329,7 @@ tcp_new_ip6(void) { struct tcp_pcb * pcb; pcb = tcp_alloc(TCP_PRIO_NORMAL); - /* could allocate TCP PCB? */ - if (pcb != NULL) { - pcb->isipv6 = 1; - } + ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ @@ -1519,18 +1444,9 @@ tcp_pcb_purge(struct tcp_pcb *pcb) tcp_listen_pcbs.listen_pcbs != NULL); for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && -#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))))) { + IP_PCB_IPVER_EQ(pcb, lpcb) && + (ipX_addr_isany(lpcb->isipv6, &lpcb->local_ip) || + ipX_addr_cmp(lpcb->isipv6, &pcb->local_ip, &lpcb->local_ip))) { /* port and address of the listen pcb match the timed-out pcb */ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", lpcb->accepts_pending > 0); @@ -1629,14 +1545,35 @@ tcp_next_iss(void) * calculating the minimum of TCP_MSS and that netif's mtu (if set). */ u16_t -tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) +tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest +#if LWIP_IPV6 + , ipX_addr_t *src, u8_t isipv6 +#endif /* LWIP_IPV6 */ + ) { u16_t mss_s; struct netif *outif; + s16_t mtu; + s16_t iphlen = IP_HLEN; - outif = ip_route(addr); - if ((outif != NULL) && (outif->mtu != 0)) { - mss_s = outif->mtu - IP_HLEN - TCP_HLEN; +#if LWIP_IPV6 + if (isipv6) { + /* First look in destination cache, to see if there is a Path MTU. */ + outif = ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)); + mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif); + iphlen = IP6_HLEN; + } else +#endif /* LWIP_IPV6 */ + { + outif = ip_route(ipX_2_ip(dest)); + if (outif == NULL) { + return sendmss; + } + mtu = outif->mtu; + } + + if (mtu != 0) { + mss_s = mtu - iphlen - 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(), and don't support IP options. @@ -1645,35 +1582,6 @@ tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) } return sendmss; } - -#if LWIP_IPV6 -/** - * Calculates the effective send mss that can be used for a specific IPv6 - * address by using ip6_route to determine the netif used to send to the - * address and calculating the minimum of TCP_MSS and that netif's mtu (if set). - */ -u16_t -tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest) -{ - u16_t mss_s; - struct netif *outif; - s16_t mtu; - - /* First look in destination cache, to see if there is a PAth MTU. */ - outif = ip6_route(src, dest); - mtu = nd6_get_destination_mtu(dest, outif); - - if (mtu != 0) { - mss_s = mtu - IP6_HLEN - TCP_HLEN; - /* RFC 1122, chap 4.2.2.6: - * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * We correct for TCP options in tcp_write(). - */ - sendmss = LWIP_MIN(sendmss, mss_s); - } - return sendmss; -} -#endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ const char* diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 86bb93e7..ea4c3c33 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -57,7 +57,7 @@ #include "arch/perf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #if LWIP_ND6_TCP_REACHABILITY_HINTS #include "lwip/nd6.h" #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ @@ -104,6 +104,7 @@ tcp_input(struct pbuf *p, struct netif *inp) #endif /* SO_REUSE */ u8_t hdrlen; err_t err; + u16_t chksum; PERF_START; @@ -121,62 +122,26 @@ tcp_input(struct pbuf *p, struct netif *inp) /* drop short packets */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); TCP_STATS_INC(tcp.lenerr); - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; + goto dropped; } /* Don't even process incoming broadcasts/multicasts. */ - if (( -#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())))) { + if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) || + ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) { TCP_STATS_INC(tcp.proterr); - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; + goto dropped; } #if CHECKSUM_CHECK_TCP -#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) { + chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len, + ipX_current_src_addr(), ipX_current_dest_addr()); + if (chksum != 0) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_TCP, p->tot_len))); -#if TCP_DEBUG + chksum)); tcp_debug_print(tcphdr); -#endif /* TCP_DEBUG */ TCP_STATS_INC(tcp.chkerr); - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; + goto dropped; } #endif /* CHECKSUM_CHECK_TCP */ @@ -187,10 +152,7 @@ tcp_input(struct pbuf *p, struct netif *inp) /* drop short packets */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); TCP_STATS_INC(tcp.lenerr); - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; + goto dropped; } /* Convert fields in TCP header to host byte order. */ @@ -214,18 +176,9 @@ tcp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); if (pcb->remote_port == tcphdr->src && 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())))) { - + IP_PCB_IPVER_INPUT_MATCH(pcb) && + ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && + ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ @@ -248,17 +201,9 @@ tcp_input(struct pbuf *p, struct netif *inp) 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 && - (( -#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())))) { + IP_PCB_IPVER_INPUT_MATCH(pcb) && + ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && + ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ @@ -274,53 +219,31 @@ tcp_input(struct pbuf *p, struct netif *inp) prev = NULL; for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if (lpcb->local_port == tcphdr->dest) { +#if LWIP_IPV6 + if (lpcb->accept_any_ip_version) { + /* found an ANY-match */ #if SO_REUSE -#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; - } - } + lpcb_any = lpcb; + lpcb_prev = prev; #else /* SO_REUSE */ -#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))) { + break; +#endif /* SO_REUSE */ + } else +#endif /* LWIP_IPV6 */ + if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) { + if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) { /* found an exact match */ break; - } - } - else if (!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 */ + } else if (ipX_addr_isany(ip_current_is_v6(), &lpcb->local_ip)) { + /* found an ANY-match */ +#if SO_REUSE + lpcb_any = lpcb; + lpcb_prev = prev; +#else /* SO_REUSE */ break; + #endif /* SO_REUSE */ } } -#endif /* SO_REUSE */ } prev = (struct tcp_pcb *)lpcb; } @@ -387,10 +310,7 @@ tcp_input(struct pbuf *p, struct netif *inp) /* Drop incoming packets because pcb is "full" (only if the incoming segment contains data). */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); - return; + goto dropped; } } tcp_input_pcb = pcb; @@ -493,25 +413,19 @@ aborted: if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); -#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); - } + tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } pbuf_free(p); } LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); PERF_STOP("tcp_input"); + return; +dropped: + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); } /** @@ -538,19 +452,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); -#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); - } + tcp_rst(ackno + 1, seqno + tcplen, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG @@ -573,17 +476,10 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ #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 + npcb->isipv6 = ip_current_is_v6(); #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()); - } + ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr()); + ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr()); npcb->local_port = pcb->local_port; npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; @@ -605,15 +501,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) /* Parse any options in the SYN. */ tcp_parseopt(npcb); #if TCP_CALCULATE_EFF_SEND_MSS -#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)); - } + npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, + &npcb->remote_ip, npcb->isipv6); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); @@ -655,17 +544,8 @@ tcp_timewait_input(struct tcp_pcb *pcb) should be sent in reply */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { /* If the SYN is in the window it is an error, send a reset */ -#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); - } + tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); return ERR_OK; } } else if (flags & TCP_FIN) { @@ -762,15 +642,8 @@ tcp_process(struct tcp_pcb *pcb) pcb->state = ESTABLISHED; #if TCP_CALCULATE_EFF_SEND_MSS -#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)); - } + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, + pcb->isipv6); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect @@ -806,17 +679,8 @@ tcp_process(struct tcp_pcb *pcb) /* received ACK? possibly a half-open connection */ else if (flags & TCP_ACK) { /* send a RST to bring the other side in a non-synchronized state. */ -#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); - } + tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } break; case SYN_RCVD: @@ -858,17 +722,8 @@ tcp_process(struct tcp_pcb *pcb) } } else { /* incorrect ACK number, send RST */ -#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); - } + tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), + ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { /* Looks like another copy of the SYN - retransmit our SYN-ACK */ diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 308b8273..d9ab0a92 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -54,7 +54,7 @@ #include "lwip/snmp.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include @@ -868,34 +868,17 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) } #endif -#if LWIP_IPV6 - if (pcb->isipv6) { - /* Chksum is mandatory over IPv6 */ - tcphdr->chksum = ip6_chksum_pseudo(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), - IP6_NEXTH_TCP, p->tot_len); -#if LWIP_NETIF_HWADDRHINT - ip6_output_hinted(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, - IP6_NEXTH_TCP, &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip6_output(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, - IP6_NEXTH_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - } - else -#endif /* LWIP_IPV6 */ - { #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = ipX_chksum_pseudo(pcb->isipv6, p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); #endif #if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); + ipX_output_hinted(pcb->isipv6, p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, + IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos, - IP_PROTO_TCP); + ipX_output(pcb->isipv6, p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, + IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ - } pbuf_free(p); return ERR_OK; @@ -1108,28 +1091,28 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) calling ip_route(). */ #if LWIP_IPV6 if (pcb->isipv6) { - if (ip6_addr_isany(&(pcb->local_ip.ip6))) { + if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { ip6_addr_t * local_addr6; - netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->remote_ip.ip6)); + netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ipX_2_ip6(&pcb->remote_ip)); if (netif == NULL) { return; } /* Select and IPv6 address from the netif. */ - local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6)); + local_addr6 = ip6_select_source_address(netif, ipX_2_ip6(&pcb->remote_ip)); if (local_addr6 == NULL) { return; } - ip6_addr_set(&pcb->local_ip.ip6, local_addr6); + ip6_addr_set(ipX_2_ip6(&pcb->local_ip), local_addr6); } } else #endif /* LWIP_IPV6 */ - if (ip_addr_isany(&(pcb->local_ip.ip4))) { - netif = ip_route(&(pcb->remote_ip.ip4)); + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { + netif = ip_route(ipX_2_ip(&pcb->remote_ip)); if (netif == NULL) { return; } - ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr); + ip_addr_copy(*ipX_2_ip(&pcb->local_ip), netif->ip_addr); } if (pcb->rttest == 0) { @@ -1154,20 +1137,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) { u32_t acc; #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - 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); - } + u16_t chksum_slow = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { LWIP_ASSERT("data included but not checksummed", @@ -1175,19 +1146,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) } /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ -#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); - } + acc = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, + seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip); /* add payload checksum */ if (seg->chksum_swapped) { seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); @@ -1205,46 +1165,21 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ } #else /* 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); + seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* CHECKSUM_GEN_TCP */ } #endif /* TCP_CHECKSUM_ON_COPY */ TCP_STATS_INC(tcp.xmit); -#if LWIP_IPV6 - if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip6_output_hinted(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, - IP6_NEXTH_TCP, &(pcb->addr_hint)); + ipX_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ - ip6_output(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos, - IP6_NEXTH_TCP); + ipX_output(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + pcb->tos, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ - } - 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*/ - } } /** @@ -1268,9 +1203,13 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) * @param remote_port the remote TCP port to send the segment to */ void -tcp_rst(u32_t seqno, u32_t ackno, - ip_addr_t *local_ip, ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) +tcp_rst_impl(u32_t seqno, u32_t ackno, + ipX_addr_t *local_ip, ipX_addr_t *remote_ip, + u16_t local_port, u16_t remote_port +#if LWIP_IPV6 + , u8_t isipv6 +#endif /* LWIP_IPV6 */ + ) { struct pbuf *p; struct tcp_hdr *tcphdr; @@ -1292,77 +1231,19 @@ tcp_rst(u32_t seqno, u32_t ackno, tcphdr->chksum = 0; tcphdr->urgp = 0; + TCP_STATS_INC(tcp.xmit); + snmp_inc_tcpoutrsts(); + #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = ipX_chksum_pseudo(isipv6, p, IP_PROTO_TCP, p->tot_len, + local_ip, remote_ip); #endif - TCP_STATS_INC(tcp.xmit); - snmp_inc_tcpoutrsts(); - /* Send output with hardcoded TTL since we have no access to the pcb */ - ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); + /* Send output with hardcoded TTL/HL since we have no access to the pcb */ + ipX_output(isipv6, p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); pbuf_free(p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); } -#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 * @@ -1495,11 +1376,7 @@ tcp_keepalive(struct tcp_pcb *pcb) struct tcp_hdr *tcphdr; 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); - } + ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", @@ -1513,41 +1390,18 @@ tcp_keepalive(struct tcp_pcb *pcb) } tcphdr = (struct tcp_hdr *)p->payload; -#if LWIP_IPV6 - if (pcb->isipv6) { - tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, - IP6_NEXTH_TCP, p->tot_len); - } - else -#endif /* LWIP_IPV6 */ - { -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, - IP_PROTO_TCP, p->tot_len); -#endif - } + tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); TCP_STATS_INC(tcp.xmit); /* Send output to IP */ -#if LWIP_IPV6 - if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP, - &(pcb->addr_hint)); + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ - ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP); + ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_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); @@ -1574,11 +1428,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) u8_t is_fin; 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); - } + ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, @@ -1616,41 +1466,19 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); } -#if LWIP_IPV6 - if (pcb->isipv6) { - tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, - IP6_NEXTH_TCP, p->tot_len); - } - else -#endif /* LWIP_IPV6 */ - { #if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); #endif - } TCP_STATS_INC(tcp.xmit); /* Send output to IP */ -#if LWIP_IPV6 - if (pcb->isipv6) { #if LWIP_NETIF_HWADDRHINT - ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP, - &(pcb->addr_hint)); + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ - ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP); + ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_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); diff --git a/src/core/udp.c b/src/core/udp.c index 2594657c..b983609b 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -57,7 +57,7 @@ #include "lwip/ip_addr.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" -#include "lwip/ip6_chksum.h" +#include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" #include "lwip/icmp6.h" @@ -93,6 +93,7 @@ udp_input(struct pbuf *p, struct netif *inp) u16_t src, dest; u8_t local_match; u8_t broadcast; + u8_t for_us; PERF_START; @@ -114,7 +115,7 @@ udp_input(struct pbuf *p, struct netif *inp) /* is broadcast packet ? */ #if LWIP_IPV6 - broadcast = (ip_current_header() != NULL) && ip_addr_isbroadcast(ip_current_dest_addr(), inp); + broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp); #else /* LWIP_IPV6 */ broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp); #endif /* LWIP_IPV6 */ @@ -129,17 +130,9 @@ udp_input(struct pbuf *p, struct netif *inp) /* print the UDP source and destination */ 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()); - } + ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_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()); - } + ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src))); #if LWIP_DHCP @@ -152,13 +145,10 @@ udp_input(struct pbuf *p, struct netif *inp) if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - - inp->dhcp->pcb->remote == ANY or iphdr->src */ - if ( -#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())))) { + - inp->dhcp->pcb->remote == ANY or iphdr->src + (no need to check for IPv6 since the dhcp struct always uses IPv4) */ + if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) || + ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) { pcb = inp->dhcp->pcb; } } @@ -177,36 +167,27 @@ udp_input(struct pbuf *p, struct netif *inp) local_match = 0; /* print the PCB local and remote address */ 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG, &pcb->local_ip); 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && #if LWIP_IPV6 - ((pcb->isipv6 && - (ip6_current_header() != NULL) && - (ip6_addr_isany(&pcb->local_ip.ip6) || + ((pcb->isipv6 && (ip_current_is_v6()) && + (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) || #if LWIP_IPV6_MLD ip6_addr_ismulticast(ip6_current_dest_addr()) || #endif /* LWIP_IPV6_MLD */ - ip6_addr_cmp(&pcb->local_ip.ip6, ip6_current_dest_addr()))) || + ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), 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()) || + ((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) || + ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) || #if LWIP_IGMP ip_addr_ismulticast(ip_current_dest_addr()) || #endif /* LWIP_IGMP */ @@ -224,19 +205,9 @@ udp_input(struct pbuf *p, struct netif *inp) } /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && - (pcb->remote_port == src) && -#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())))))) { + (pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) && + (ipX_addr_isany(pcb->isipv6, &pcb->remote_ip) || + ipX_addr_cmp(pcb->isipv6, &pcb->remote_ip, ipX_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -258,28 +229,24 @@ udp_input(struct pbuf *p, struct netif *inp) } /* Check checksum if this is a match or if it was directed at us. */ - if ((pcb != NULL) || + if (pcb != NULL) { + for_us = 1; + } else { #if LWIP_IPV6 - ((ip6_current_header() != NULL) && - netif_matches_ip6_addr(inp, ip6_current_dest_addr())) || - ((ip_current_header() != NULL) && -#else /* LWIP_IPV6 */ - ( + if (ip_current_is_v6()) { + for_us = netif_matches_ip6_addr(inp, ip6_current_dest_addr()); + } else #endif /* LWIP_IPV6 */ - ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()))) { + { + for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()); + } + } + if (for_us) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); -#if LWIP_UDPLITE - if ( -#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 +#if LWIP_UDPLITE + if (ip_current_header_proto() == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ u16_t chklen = ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { @@ -289,72 +256,26 @@ udp_input(struct pbuf *p, struct netif *inp) } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; + goto chkerr; } } -#if 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; - } + if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE, + p->tot_len, chklen, + ipX_current_src_addr(), ipX_current_dest_addr()) != 0) { + goto chkerr; } - 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")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } -#endif /* CHECKSUM_CHECK_UDP */ } else #endif /* LWIP_UDPLITE */ { -#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, - ("udp_input: UDP datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; + if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len, + ipX_current_src_addr(), + ipX_current_dest_addr()) != 0) { + goto chkerr; } } -#endif /* CHECKSUM_CHECK_UDP */ } +#endif /* CHECKSUM_CHECK_UDP */ if(pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); @@ -376,15 +297,7 @@ udp_input(struct pbuf *p, struct netif *inp) 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); - } + s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ @@ -392,13 +305,13 @@ udp_input(struct pbuf *p, struct netif *inp) #if LWIP_IPV6 ((mpcb->isipv6 && (ip6_addr_ismulticast(ip6_current_dest_addr()) || - ip6_addr_cmp(&mpcb->local_ip.ip6, ip6_current_dest_addr()))) || + ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), 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()) || + ((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) || + ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) || #if LWIP_IGMP ip_addr_ismulticast(ip_current_dest_addr()) || #endif /* LWIP_IGMP */ @@ -470,23 +383,9 @@ udp_input(struct pbuf *p, struct netif *inp) !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 */ - } + /* move payload pointer back to ip header */ + pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN); + icmp_port_unreach(ip_current_is_v6(), p); } #endif /* LWIP_ICMP || LWIP_ICMP6 */ UDP_STATS_INC(udp.proterr); @@ -499,6 +398,15 @@ udp_input(struct pbuf *p, struct netif *inp) } end: PERF_STOP("udp_input"); + return; +chkerr: + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); + UDP_STATS_INC(udp.chkerr); + UDP_STATS_INC(udp.drop); + snmp_inc_udpinerrors(); + pbuf_free(p); + PERF_STOP("udp_input"); } /** @@ -523,7 +431,7 @@ err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port); + return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port); } #if LWIP_CHECKSUM_ON_COPY @@ -534,7 +442,7 @@ udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum) { /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto_chksum(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port, + return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port, have_chksum, chksum); } #endif /* LWIP_CHECKSUM_ON_COPY */ @@ -577,12 +485,12 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* find the outgoing network interface for this packet */ #if LWIP_IPV6 if (pcb->isipv6) { - if (ip6_addr_ismulticast((ip6_addr_t *)dst_ip)) { + if (ip6_addr_ismulticast(ip_2_ip6(dst_ip))) { /* For multicast, find a netif based on source address. */ - netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->local_ip.ip6)); + netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ipX_2_ip6(&pcb->local_ip)); } else { - netif = ip6_route(&(pcb->local_ip.ip6), (ip6_addr_t *)dst_ip); + netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ip_2_ip6(dst_ip)); } } else @@ -598,11 +506,7 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* no outgoing network interface could be found? */ if (netif == NULL) { 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip)); LWIP_DEBUGF(UDP_DEBUG, ("\n")); UDP_STATS_INC(udp.rterr); return ERR_RTE; @@ -652,6 +556,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, ip_addr_t *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */ + u8_t ip_proto; #if IP_SOF_BROADCAST /* broadcast filter? */ @@ -669,7 +574,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); - err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port); + err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port); if (err != ERR_OK) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); return err; @@ -714,7 +619,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, ( #if LWIP_IPV6_MLD (pcb->isipv6 && - ip6_addr_ismulticast((ip6_addr_t*)dst_ip)) || + ip6_addr_ismulticast(ip_2_ip6(dst_ip))) || #endif /* LWIP_IPV6_MLD */ (!pcb->isipv6 && #else /* LWIP_IPV6 */ @@ -729,8 +634,8 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* PCB local address is IP_ANY_ADDR? */ #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 (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { + src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); if (src_ip == NULL) { /* No suitable source address was found. */ if (q != p) { @@ -742,7 +647,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } } else { /* use UDP PCB local IPv6 address as source address, if still valid. */ - if (netif_matches_ip6_addr(netif, &(pcb->local_ip.ip6)) < 0) { + if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) { /* Address isn't valid anymore. */ if (q != p) { /* free the header pbuf */ @@ -751,18 +656,18 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } return ERR_RTE; } - src_ip = (ip_addr_t *)&(pcb->local_ip.ip6); + src_ip = ipX_2_ip(&pcb->local_ip); } } else #endif /* LWIP_IPV6 */ - if (ip_addr_isany(&pcb->local_ip.ip4)) { + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ - if (!ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr))) { + if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) { /* local_ip doesn't match, drop the packet */ if (q != p) { /* free the header pbuf */ @@ -773,7 +678,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, return ERR_VAL; } /* use UDP PCB local IP address as source address */ - src_ip = &(pcb->local_ip.ip4); + src_ip = ipX_2_ip(&(pcb->local_ip)); } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); @@ -800,88 +705,51 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } udphdr->len = htons(chklen_hdr); /* calculate checksum */ -#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; - } - } - 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 */ +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + chklen = UDP_HLEN; + } +#endif /* LWIP_CHECKSUM_ON_COPY */ + udphdr->chksum = ipX_chksum_pseudo_partial(pcb->isipv6, q, IP_PROTO_UDPLITE, + q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ - /* 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; + } #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*/ -#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*/ + + ip_proto = IP_PROTO_UDPLITE; } else #endif /* LWIP_UDPLITE */ { /* UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); udphdr->len = htons(q->tot_len); /* calculate checksum */ -#if LWIP_IPV6 +#if CHECKSUM_GEN_UDP /* Checksum is mandatory over IPv6. */ - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { u16_t udpchksum; #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { u32_t acc; - udpchksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, - q->tot_len, UDP_HLEN); + udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, + q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); acc = udpchksum + (u16_t)~(chksum); udpchksum = FOLD_U32T(acc); } else #endif /* LWIP_CHECKSUM_ON_COPY */ { - udpchksum = ip6_chksum_pseudo(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, q->tot_len); + udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len, + ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); } /* chksum zero must become 0xffff, as zero means 'no checksum' */ @@ -890,52 +758,17 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } udphdr->chksum = udpchksum; } - else -#endif /* LWIP_IPV6 */ - { -#if CHECKSUM_GEN_UDP - if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - u16_t udpchksum; -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, - q->tot_len, UDP_HLEN); - acc = udpchksum + (u16_t)~(chksum); - udpchksum = FOLD_U32T(acc); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); - } - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udpchksum == 0x0000) { - udpchksum = 0xffff; - } - udphdr->chksum = udpchksum; - } #endif /* CHECKSUM_GEN_UDP */ - } - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); - /* output to IP */ -#if LWIP_NETIF_HWADDRHINT - netif->addr_hint = &(pcb->addr_hint); -#endif /* LWIP_NETIF_HWADDRHINT*/ -#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*/ + ip_proto = IP_PROTO_UDP; } + + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); + LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); + /* output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ipX_output_if(pcb->isipv6, q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + /* TODO: must this be increased even if error occured? */ snmp_inc_udpoutdatagrams(); @@ -977,11 +810,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) u8_t rebind; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr)); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); rebind = 0; @@ -1005,22 +834,11 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) /* port matches that of PCB in list and REUSEADDR not set -> reject */ else { #endif /* SO_REUSE */ - if ((ipcb->local_port == port) && + if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) && /* IP address matches, or one is IP_ADDR_ANY? */ -#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))))) { + (ipX_addr_isany(ipcb->isipv6, &(ipcb->local_ip)) || + ipX_addr_isany(ipcb->isipv6, ip_2_ipX(ipaddr)) || + ipX_addr_cmp(ipcb->isipv6, &(ipcb->local_ip), ip_2_ipX(ipaddr)))) { /* other PCB already binds to this local IP and port */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); @@ -1029,15 +847,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } } -#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); - } + ipX_addr_set_ipaddr(pcb->isipv6, &pcb->local_ip, ipaddr); /* no port specified? */ if (port == 0) { @@ -1075,14 +885,11 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) udp_pcbs = pcb; } 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); return ERR_OK; } + /** * Connect an UDP PCB. * @@ -1106,21 +913,13 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) struct udp_pcb *ipcb; if (pcb->local_port == 0) { - err_t err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port); + err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port); if (err != ERR_OK) { return err; } } -#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); - } + ipX_addr_set_ipaddr(pcb->isipv6, &pcb->remote_ip, ipaddr); pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; /** TODO: this functionality belongs in upper layers */ @@ -1130,29 +929,27 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) #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)) { + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { struct netif *netif; - if ((netif = ip_route(&(pcb->remote_ip.ip4))) == NULL) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.ip4.addr)); + if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", + ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip)))); UDP_STATS_INC(udp.rterr); return ERR_RTE; } /** TODO: this will bind the udp pcb locally, to the interface which is used to route output packets to the remote address. However, we might want to accept incoming packets on any interface! */ - pcb->local_ip.ip4 = netif->ip_addr; - } else if (ip_addr_isany(&pcb->remote_ip.ip4)) { - pcb->local_ip.ip4.addr = 0; + ipX_addr_copy(0, pcb->local_ip, netif->ip_addr); + } else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { + ipX_addr_set_any(0, &pcb->local_ip); } } #endif 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); - } + ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ @@ -1177,15 +974,7 @@ void udp_disconnect(struct udp_pcb *pcb) { /* reset remote address association */ -#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); - } + ipX_addr_set_any(pcb->isipv6, &pcb->remote_ip); pcb->remote_port = 0; /* mark PCB as unconnected */ pcb->flags &= ~UDP_FLAGS_CONNECTED; @@ -1278,10 +1067,7 @@ udp_new_ip6(void) { struct udp_pcb *pcb; pcb = udp_new(); - /* could allocate UDP PCB? */ - if (pcb != NULL) { - pcb->isipv6 = 1; - } + ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ diff --git a/src/include/ipv4/lwip/icmp.h b/src/include/ipv4/lwip/icmp.h index d47a7d8a..fa893b6b 100644 --- a/src/include/ipv4/lwip/icmp.h +++ b/src/include/ipv4/lwip/icmp.h @@ -37,6 +37,10 @@ #include "lwip/ip_addr.h" #include "lwip/netif.h" +#if LWIP_IPV6 && LWIP_ICMP6 +#include "lwip/icmp6.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -104,6 +108,16 @@ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); #endif /* LWIP_ICMP */ +#if (LWIP_IPV6 && LWIP_ICMP6) +#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ + icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ + icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) +#elif LWIP_ICMP +#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) +#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ +#define icmp_port_unreach(isipv6, pbuf) +#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ + #ifdef __cplusplus } #endif diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip4.h similarity index 57% rename from src/include/ipv4/lwip/ip.h rename to src/include/ipv4/lwip/ip4.h index 18a2abb8..bfe1153d 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip4.h @@ -29,8 +29,8 @@ * Author: Adam Dunkels * */ -#ifndef __LWIP_IP_H__ -#define __LWIP_IP_H__ +#ifndef __LWIP_IP4_H__ +#define __LWIP_IP4_H__ #include "lwip/opt.h" @@ -56,74 +56,6 @@ extern "C" { #define IP_PROTO_UDPLITE 136 #define IP_PROTO_TCP 6 -/* This is passed as the destination address to ip_output_if (not - to ip_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#ifdef IP_HDRINCL -#undef IP_HDRINCL -#endif /* IP_HDRINCL */ -#define IP_HDRINCL NULL - -#if LWIP_NETIF_HWADDRHINT -#define IP_PCB_ADDRHINT ;u8_t addr_hint -#else -#define IP_PCB_ADDRHINT -#endif /* LWIP_NETIF_HWADDRHINT */ - -#if LWIP_IPV6 -#define IP_PCB_ISIPV6 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 */ \ - 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 */ \ - u8_t tos; \ - /* Time To Live */ \ - u8_t ttl \ - /* link layer address resolution hint */ \ - IP_PCB_ADDRHINT - -struct ip_pcb { -/* Common members of all PCB types */ - IP_PCB; -}; - -/* - * Option flags per-socket. These are the same like SO_XXX. - */ -/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ -#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ -#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ -#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ -/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ -#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ -#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ -/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ -/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ - -/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ -#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) - #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" @@ -175,16 +107,8 @@ PACK_STRUCT_END #define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) -/** The interface that provided the packet for the current callback invocation. */ -extern struct netif *current_netif; -/** Header of the input packet currently being processed. */ -extern const struct ip_hdr *current_header; -/** Source IP address of current_header */ -extern ip_addr_t current_iphdr_src; -/** Destination IP address of current_header */ -extern ip_addr_t current_iphdr_dest; -#define ip_init() /* Compatibility define, not init needed. */ +#define ip_init() /* Compatibility define, no init needed. */ struct netif *ip_route(ip_addr_t *dest); err_t ip_input(struct pbuf *p, struct netif *inp); err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, @@ -201,18 +125,6 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen); #endif /* IP_OPTIONS_SEND */ -/** Get the interface that received the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip_current_netif() (current_netif) -/** Get the IP header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip_current_header() (current_header) -/** Source IP address of current_header */ -#define ip_current_src_addr() (¤t_iphdr_src) -/** Destination IP address of current_header */ -#define ip_current_dest_addr() (¤t_iphdr_dest) #if IP_DEBUG void ip_debug_print(struct pbuf *p); diff --git a/src/include/ipv4/lwip/ip_addr.h b/src/include/ipv4/lwip/ip4_addr.h similarity index 99% rename from src/include/ipv4/lwip/ip_addr.h rename to src/include/ipv4/lwip/ip4_addr.h index 77f84e02..b05ae537 100644 --- a/src/include/ipv4/lwip/ip_addr.h +++ b/src/include/ipv4/lwip/ip4_addr.h @@ -29,8 +29,8 @@ * Author: Adam Dunkels * */ -#ifndef __LWIP_IP_ADDR_H__ -#define __LWIP_IP_ADDR_H__ +#ifndef __LWIP_IP4_ADDR_H__ +#define __LWIP_IP4_ADDR_H__ #include "lwip/opt.h" #include "lwip/def.h" diff --git a/src/include/ipv6/lwip/ip6.h b/src/include/ipv6/lwip/ip6.h index b7d53344..f8f7e8eb 100644 --- a/src/include/ipv6/lwip/ip6.h +++ b/src/include/ipv6/lwip/ip6.h @@ -71,15 +71,6 @@ extern "C" { #define IP6_NEXTH_UDPLITE 136 -/* This is passed as the destination address to ip6_output_if (not - to ip6_output), meaning that an IP header already is constructed - in the pbuf. This is used when TCP retransmits. */ -#ifdef IP6_HDRINCL -#undef IP6_HDRINCL -#endif /* IP6_HDRINCL */ -#define IP6_HDRINCL NULL - - /* The IPv6 header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" @@ -171,16 +162,6 @@ PACK_STRUCT_END #define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) - -/** Header of the input IPv6 packet currently being processed. */ -extern const struct ip6_hdr *current_ip6_header; -/** Total header length of current_ip6_header (i.e. after this, the UDP/TCP header starts) */ -extern u16_t current_ip6_header_tot_len; -/** Source IPv6 address of current_header */ -extern ip6_addr_t current_ip6hdr_src; -/** Destination IPv6 address of current_header */ -extern ip6_addr_t current_ip6hdr_dest; - #define ip6_init() /* TODO should we init current addresses and header pointer? */ struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest); ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest); @@ -198,17 +179,6 @@ err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); #endif /* LWIP_IPV6_MLD */ -/** Get the IPv6 header of the current packet. - * This function must only be called from a receive callback (udp_recv, - * raw_recv, tcp_accept). It will return NULL otherwise. */ -#define ip6_current_header() (current_ip6_header) -/** Total header length of current_ip6_header (i.e. after this, the UDP/TCP header starts) */ -#define ip6_current_header_tot_len() (current_ip6_header_tot_len) -/** Source IPv6 address of current_header */ -#define ip6_current_src_addr() (¤t_ip6hdr_src) -/** Destination IPv6 address of current_header */ -#define ip6_current_dest_addr() (¤t_ip6hdr_dest) - #if IP6_DEBUG void ip6_debug_print(struct pbuf *p); #else diff --git a/src/include/ipv6/lwip/ip6_addr.h b/src/include/ipv6/lwip/ip6_addr.h index f7e9da10..c962c769 100644 --- a/src/include/ipv6/lwip/ip6_addr.h +++ b/src/include/ipv6/lwip/ip6_addr.h @@ -115,35 +115,35 @@ Little-endian version, stored in network order (no htonl). */ #define IP6_ADDR_BLOCK8(ip6addr) ((htonl((ip6addr)->addr[3])) & 0xffff) /** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ -#define ip6_addr_copy(dest, src) {(dest).addr[0] = (src).addr[0]; \ - (dest).addr[1] = (src).addr[1]; \ - (dest).addr[2] = (src).addr[2]; \ - (dest).addr[3] = (src).addr[3];} +#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ + (dest).addr[1] = (src).addr[1]; \ + (dest).addr[2] = (src).addr[2]; \ + (dest).addr[3] = (src).addr[3];}while(0) /** Safely copy one IPv6 address to another (src may be NULL) */ -#define ip6_addr_set(dest, src) {(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ - (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ - (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ - (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];} +#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ + (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ + (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ + (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) /** Set complete address to zero */ -#define ip6_addr_set_zero(ip6addr) {(ip6addr)->addr[0] = 0; \ +#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = 0;} + (ip6addr)->addr[3] = 0;}while(0) /** Set address to ipv6 'any' (no need for htonl()) */ #define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) /** Set address to ipv6 loopback address */ -#define ip6_addr_set_loopback(ip6addr) {(ip6addr)->addr[0] = 0; \ - (ip6addr)->addr[1] = 0; \ - (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);} +#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ + (ip6addr)->addr[1] = 0; \ + (ip6addr)->addr[2] = 0; \ + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) /** Safely copy one IPv6 address to another and change byte order * from host- to network-order. */ -#define ip6_addr_set_hton(dest, src) {(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ - (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ - (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ - (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);} +#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ + (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ + (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ + (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0) @@ -211,28 +211,28 @@ Little-endian version, stored in network order (no htonl). */ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) -#define ip6_addr_set_allnodes_linklocal(ip6addr) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ +#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);} + (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) #define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) -#define ip6_addr_set_allrouters_linklocal(ip6addr) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ +#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ - (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);} + (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0) #define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) -#define ip6_addr_set_solicitednode(ip6addr, if_id) {(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ +#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ - (ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));} + (ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}while(0) /* IPv6 address states. */ diff --git a/src/include/ipv6/lwip/ip6_chksum.h b/src/include/ipv6/lwip/ip6_chksum.h deleted file mode 100644 index 600257c7..00000000 --- a/src/include/ipv6/lwip/ip6_chksum.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file - * - * IPv6 Checksum helper functions. - */ - -/* - * Copyright (c) 2010 Inico Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Ivan Delamer - * - * - * Please coordinate changes and requests with Ivan Delamer - * - */ -#ifndef __LWIP_IP6_CHKSUM_H__ -#define __LWIP_IP6_CHKSUM_H__ - -#include "lwip/opt.h" - -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/ip6_addr.h" -#include "lwip/inet_chksum.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -u16_t ip6_chksum_pseudo(struct pbuf *p, - ip6_addr_t *src, ip6_addr_t *dest, - u8_t proto, u16_t proto_len); -u16_t ip6_chksum_pseudo_partial(struct pbuf *p, - ip6_addr_t *src, ip6_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len); - - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_IPV6 */ - -#endif /* __LWIP_IP6_CHKSUM_H__ */ diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index f85a2dc9..71988108 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -76,34 +76,39 @@ extern "C" { /* Helpers to process several netconn_types by the same code */ -#define NETCONNTYPE_GROUP(t) ((t)&0xF0) -#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) -#define NETCONNTYPE_ISIPV6(t) ((t)&0x08) -#define NETCONNTYPE_ISUDPLITE(t)(((t)&0xF7) == NETCONN_UDPLITE) -#define NETCONNTYPE_ISUDPNOCHKSUM(t)(((t)&0xF7) == NETCONN_UDPNOCHKSUM) +#define NETCONNTYPE_GROUP(t) ((t)&0xF0) +#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) +#if LWIP_IPV6 +#define NETCONN_TYPE_IPV6 0x08 +#define NETCONNTYPE_ISIPV6(t) ((t)&0x08) +#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM) +#else /* LWIP_IPV6 */ +#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) +#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) +#endif /* LWIP_IPV6 */ /** Protocol family and type of the netconn */ enum netconn_type { - NETCONN_INVALID = 0, + NETCONN_INVALID = 0, /* NETCONN_TCP Group */ - NETCONN_TCP = 0x10, + NETCONN_TCP = 0x10, #if LWIP_IPV6 - NETCONN_TCP_IPV6 = 0x18, + NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, #endif /* LWIP_IPV6 */ /* NETCONN_UDP Group */ - NETCONN_UDP = 0x20, - NETCONN_UDPLITE = 0x21, - NETCONN_UDPNOCHKSUM= 0x22, + NETCONN_UDP = 0x20, + NETCONN_UDPLITE = 0x21, + NETCONN_UDPNOCHKSUM = 0x22, #if LWIP_IPV6 - NETCONN_UDP_IPV6 = 0x28, - NETCONN_UDPLITE_IPV6 = 0x29, - NETCONN_UDPNOCHKSUM_IPV6= 0x2a, + NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, + NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, + NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, #endif /* LWIP_IPV6 */ /* NETCONN_RAW Group */ - NETCONN_RAW = 0x40 + NETCONN_RAW = 0x40, #if LWIP_IPV6 - , - NETCONN_RAW_IPV6 = 0x48 + NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */, #endif /* LWIP_IPV6 */ }; @@ -258,15 +263,17 @@ err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, 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) + +#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) +#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) +#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL) #if LWIP_IPV6_MLD -#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) \ - netconn_join_leave_group(conn, (ip_addr_t*)multiaddr, (ip_addr_t*)srcaddr, join_or_leave) +#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \ + netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\ + ERR_VAL) #endif /* LWIP_IPV6_MLD*/ #endif /* LWIP_IPV6 */ diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index 2541e641..fca361d9 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -80,7 +80,7 @@ struct api_msg_msg { } bc; /** used for do_getaddr */ struct { - ip_addr_t *ipaddr; + ipX_addr_t *ipaddr; u16_t *port; u8_t local; } ad; @@ -101,8 +101,8 @@ struct api_msg_msg { #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** used for do_join_leave_group */ struct { - ip_addr_t *multiaddr; - ip_addr_t *netif_addr; + ipX_addr_t *multiaddr; + ipX_addr_t *netif_addr; enum netconn_igmp join_or_leave; } jl; #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ diff --git a/src/include/ipv4/lwip/inet_chksum.h b/src/include/lwip/inet_chksum.h similarity index 70% rename from src/include/ipv4/lwip/inet_chksum.h rename to src/include/lwip/inet_chksum.h index 79a2d90f..e1687888 100644 --- a/src/include/ipv4/lwip/inet_chksum.h +++ b/src/include/lwip/inet_chksum.h @@ -72,16 +72,38 @@ extern "C" { u16_t inet_chksum(void *dataptr, u16_t len); u16_t inet_chksum_pbuf(struct pbuf *p); -u16_t inet_chksum_pseudo(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len); -u16_t inet_chksum_pseudo_partial(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len); +u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip_addr_t *src, ip_addr_t *dest); +u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, + u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest); #if LWIP_CHKSUM_COPY_ALGORITHM u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); #endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +#if LWIP_IPV6 +u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, + ip6_addr_t *src, ip6_addr_t *dest); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, + u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest); + +#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ + ((isipv6) ? \ + ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ + inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest))) +#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ + ((isipv6) ? \ + ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ + inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest))) + +#else /* LWIP_IPV6 */ + +#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ + inet_chksum_pseudo(p, proto, proto_len, src, dest) +#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ + inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest) + +#endif /* LWIP_IPV6 */ + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h new file mode 100644 index 00000000..4f856271 --- /dev/null +++ b/src/include/lwip/ip.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" +#include "lwip/ip4.h" +#include "lwip/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is passed as the destination address to ip_output_if (not + to ip_output), meaning that an IP header already is constructed + in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +#if LWIP_IPV6 +#define IP_PCB_ISIPV6_MEMBER u8_t isipv6; +#define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6) +#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \ + ((pcb)->isipv6 != 0) : \ + ((pcb)->isipv6 == 0)) +#define PCB_ISIPV6(pcb) ((pcb)->isipv6) +#else +#define IP_PCB_ISIPV6_MEMBER +#define IP_PCB_IPVER_EQ(pcb1, pcb2) 1 +#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1 +#define PCB_ISIPV6(pcb) 0 +#endif /* LWIP_IPV6 */ + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB \ + IP_PCB_ISIPV6_MEMBER \ + /* ip addresses in network byte order */ \ + ipX_addr_t local_ip; \ + ipX_addr_t remote_ip; \ + /* Socket options */ \ + u8_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl \ + /* link layer address resolution hint */ \ + IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ + IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ +#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) + +/* Global variables of this module, kept in a struct for efficient access using base+index. */ +struct ip_globals +{ + /** The interface that provided the packet for the current callback invocation. */ + struct netif *current_netif; + /** Header of the input packet currently being processed. */ + const struct ip_hdr *current_ip4_header; +#if LWIP_IPV6 + /** Header of the input IPv6 packet currently being processed. */ + const struct ip6_hdr *current_ip6_header; +#endif /* LWIP_IPV6 */ + /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ + u16_t current_ip_header_tot_len; + /** Source IP address of current_header */ + ipX_addr_t current_iphdr_src; + /** Destination IP address of current_header */ + ipX_addr_t current_iphdr_dest; +}; +extern struct ip_globals ip_data; + + +/** Get the interface that received the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_netif() (ip_data.current_netif) +/** Get the IP header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip_current_header() (ip_data.current_ip4_header) +/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ +#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) +/** Source IP address of current_header */ +#define ipX_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP address of current_header */ +#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if LWIP_IPV6 +/** Get the IPv6 header of the current packet. + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. */ +#define ip6_current_header() (ip_data.current_ip6_header) +/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ +#define ip_current_is_v6() (ip6_current_header() != NULL) +/** Source IPv6 address of current_header */ +#define ip6_current_src_addr() (ipX_2_ip6(&ip_data.current_iphdr_src)) +/** Destination IPv6 address of current_header */ +#define ip6_current_dest_addr() (ipX_2_ip6(&ip_data.current_iphdr_dest)) +/** Get the transport layer protocol */ +#define ip_current_header_proto() (ip_current_is_v6() ? \ + IP6H_NEXTH(ip6_current_header()) :\ + IPH_PROTO(ip_current_header())) +/** Get the transport layer header */ +#define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \ + (u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len())) + +/** Set an IP_PCB to IPv6 (IPv4 is the default) */ +#define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0) + +/** Source IP4 address of current_header */ +#define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src)) +/** Destination IP4 address of current_header */ +#define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest)) + +#else /* LWIP_IPV6 */ + +/** Always returns FALSE when only supporting IPv4 */ +#define ip_current_is_v6() 0 +/** Get the transport layer protocol */ +#define ip_current_header_proto() IPH_PROTO(ip_current_header()) +/** Get the transport layer header */ +#define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len())) +/** Source IP4 address of current_header */ +#define ip_current_src_addr() (&ip_data.current_iphdr_src) +/** Destination IP4 address of current_header */ +#define ip_current_dest_addr() (&ip_data.current_iphdr_dest) + +#endif /* LWIP_IPV6 */ + +/** Union source address of current_header */ +#define ipX_current_src_addr() (&ip_data.current_iphdr_src) +/** Union destination address of current_header */ +#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest) + +#if LWIP_IPV6 +#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ + ((isipv6) ? \ + ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \ + ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto)) +#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ((isipv6) ? \ + ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip_output_if(p, (src), (dest), ttl, tos, proto, netif)) +#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ + ((isipv6) ? \ + ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \ + ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint)) +#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p)) +#else /* LWIP_IPV6 */ +#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ + ip_output(p, src, dest, ttl, tos, proto) +#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ip_output_if(p, src, dest, ttl, tos, proto, netif) +#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ + ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ipX_debug_print(is_ipv6, p) ip_debug_print(p) +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h new file mode 100644 index 00000000..04ffa534 --- /dev/null +++ b/src/include/lwip/ip_addr.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" + +#include "lwip/ip4_addr.h" +#include "lwip/ip6_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_IPV6 +/* A union struct for both IP version's addresses. */ +typedef union { + ip_addr_t ip4; + ip6_addr_t ip6; +} ipX_addr_t; + +/** These functions only exist for type-safe conversion from ip_addr_t to + ip6_addr_t and back */ +#if LWIP_ALLOW_STATIC_FN_IN_HEADER +static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr) +{ return (ip6_addr_t*)ipaddr;} +static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr) +{ return (ip_addr_t*)ip6addr; } +static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr) +{ return (ipX_addr_t*)ipaddr; } +#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */ +#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) +#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) +#define ip_2_ipX(ip_addr_t *ipaddr) ((ipX_addr_t*)ipaddr) +#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/ +#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6)) +#define ipX_2_ip(ipaddr) (&((ipaddr)->ip4)) + +#define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_copy((dest).ip6, (src).ip6); }else{ \ + ip_addr_copy((dest).ip4, (src).ip4); }}while(0) +#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \ + ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0) +#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \ + ip_addr_set(ipX_2_ip(dest), src); }}while(0) +#define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ + ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \ + ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0) +#define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \ + ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \ + ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0) +#define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \ + ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \ + ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2))) +#define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \ + ip6_addr_isany(ipX_2_ip6(ipaddr)) : \ + ip_addr_isany(ipX_2_ip(ipaddr))) +#define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \ + ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \ + ip_addr_ismulticast(ipX_2_ip(ipaddr))) +#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \ + ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \ + ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0) + +#else /* LWIP_IPV6 */ + +typedef ip_addr_t ipX_addr_t; +#define ipX_2_ip(ipaddr) (ipaddr) +#define ip_2_ipX(ipaddr) (ipaddr) + +#define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src) +#define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src) +#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src) +#define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr) +#define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr) +#define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr) +#define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src) +#define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2) +#define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr) +#define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr) +#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr) + +#endif /* LWIP_IPV6 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/src/include/lwip/netbuf.h b/src/include/lwip/netbuf.h index 82d3d701..d12fe270 100644 --- a/src/include/lwip/netbuf.h +++ b/src/include/lwip/netbuf.h @@ -46,18 +46,9 @@ 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; - union { - ip_addr_t ip4; - NETBUF_IP6 - } addr; + ipX_addr_t addr; u16_t port; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY @@ -65,10 +56,7 @@ struct netbuf { #endif /* LWIP_CHECKSUM_ON_COPY */ u16_t toport_chksum; #if LWIP_NETBUF_RECVINFO - union { - ip_addr_t ip4; - NETBUF_IP6 - } toaddr; + ipX_addr_t toaddr; #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ }; @@ -94,12 +82,12 @@ void netbuf_first (struct netbuf *buf); #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) #define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) #define netbuf_len(buf) ((buf)->p->tot_len) -#define netbuf_fromaddr(buf) (&((buf)->addr.ip4)) -#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr.ip4), fromaddr) +#define netbuf_fromaddr(buf) (ipX_2_ip(&((buf)->addr))) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr) #define netbuf_fromport(buf) ((buf)->port) #if LWIP_NETBUF_RECVINFO -#define netbuf_destaddr(buf) (&((buf)->toaddr.ip4)) -#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->toaddr.ip4), destaddr) +#define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr))) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr) #define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) #endif /* LWIP_NETBUF_RECVINFO */ #if LWIP_CHECKSUM_ON_COPY @@ -108,12 +96,15 @@ void netbuf_first (struct netbuf *buf); #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) +#define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr))) +#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr) +#define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr))) +#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr) #endif /* LWIP_IPV6 */ +#define netbuf_fromaddr_ipX(buf) (&((buf)->addr)) +#define netbuf_destaddr_ipX(buf) (&((buf)->toaddr)) + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index a8527f88..c14289b8 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -367,6 +367,11 @@ s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr); void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit); #endif /* LWIP_IPV6 */ +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint)) +#else /* LWIP_NETIF_HWADDRHINT */ +#define NETIF_SET_HWADDRHINT(netif, hint) +#endif /* LWIP_NETIF_HWADDRHINT */ #ifdef __cplusplus } diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index e5b5eed8..a8243b6a 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2309,7 +2309,7 @@ * IP6_DEBUG: Enable debugging for IPv6. */ #ifndef IP6_DEBUG -#define IP6_DEBUG LWIP_DBG_ON +#define IP6_DEBUG LWIP_DBG_OFF #endif #endif /* __LWIP_OPT_H__ */ diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 59eec8c5..53fdc69b 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -44,6 +44,9 @@ extern "C" { * of IP_FRAG */ #define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) +/* @todo: We need a mechanism to prevent wasting memory in every pbuf + (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ + #define PBUF_TRANSPORT_HLEN 20 #if LWIP_IPV6 #define PBUF_IP_HLEN 40 diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 09842b67..5ce4a4f9 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -54,7 +54,8 @@ struct sockaddr_in { u8_t sin_family; u16_t sin_port; struct in_addr sin_addr; - char sin_zero[8]; +#define SIN_ZERO_LEN 8 + char sin_zero[SIN_ZERO_LEN]; }; #if LWIP_IPV6 diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 53bc5320..fdd12567 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -281,7 +281,7 @@ struct tcp_pcb { u8_t keep_cnt_sent; }; -struct tcp_pcb_listen { +struct tcp_pcb_listen { /* Common members of all PCB types */ IP_PCB; /* Protocol specific PCB members */ @@ -291,6 +291,9 @@ struct tcp_pcb_listen { u8_t backlog; u8_t accepts_pending; #endif /* TCP_LISTEN_BACKLOG */ +#if LWIP_IPV6 + u8_t accept_any_ip_version; +#endif /* LWIP_IPV6 */ }; #if LWIP_EVENT_API @@ -372,9 +375,14 @@ 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) + tcp_bind(pcb, ip6_2_ip(ip6addr), port) #define tcp_connect_ip6(pcb, ip6addr, port, connected) \ - udp_connect(pcb, (ip_addr_t *)ip6addr, port, connected) + udp_connect(pcb, ip6_2_ip(ip6addr), port, connected) +struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#define tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) +#else /* LWIP_IPV6 */ +#define tcp_listen_dual_with_backlog(pcb, backlog) tcp_listen_with_backlog(pcb, backlog) +#define tcp_listen_dual(pcb) tcp_listen(pcb) #endif /* LWIP_IPV6 */ diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 126e8eb0..f3ae40d2 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -428,13 +428,19 @@ err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); -void tcp_rst(u32_t seqno, u32_t ackno, - ip_addr_t *local_ip, ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port); +void tcp_rst_impl(u32_t seqno, u32_t ackno, + ipX_addr_t *local_ip, ipX_addr_t *remote_ip, + u16_t local_port, u16_t remote_port #if LWIP_IPV6 -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); + , u8_t isipv6 +#endif /* LWIP_IPV6 */ + ); +#if LWIP_IPV6 +#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ + tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) +#else /* LWIP_IPV6 */ +#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ + tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port) #endif /* LWIP_IPV6 */ u32_t tcp_next_iss(void); @@ -443,9 +449,15 @@ void tcp_keepalive(struct tcp_pcb *pcb); void tcp_zero_window_probe(struct tcp_pcb *pcb); #if TCP_CALCULATE_EFF_SEND_MSS -u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr); +u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest #if LWIP_IPV6 -u16_t tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest); + , ipX_addr_t *src, u8_t isipv6 +#endif /* LWIP_IPV6 */ + ); +#if LWIP_IPV6 +#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest, src, isipv6) +#else /* LWIP_IPV6 */ +#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest) #endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ From 2ef29d6839ebdc5bb583279c95e598d2f9b2b583 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 25 May 2011 17:22:13 +0000 Subject: [PATCH 006/151] Use conversion defines instead of casting IP addresses --- src/include/lwip/raw.h | 6 +++--- src/include/lwip/udp.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index a3751f81..f0c8ed47 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -112,10 +112,10 @@ 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_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr)) +#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr)) #define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg) -#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, (ip_addr_t *)ip6addr) +#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr)) #endif /* LWIP_IPV6 */ /* The following functions are the lower layer interface to RAW. */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 68b7b4e1..648c9a46 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -183,20 +183,20 @@ void udp_input (struct pbuf *p, struct netif *inp); #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) + udp_bind(pcb, ip6_2_ip(ip6addr), port) #define udp_connect_ip6(pcb, ip6addr, port) \ - udp_connect(pcb, (ip_addr_t *)ip6addr, port) + udp_connect(pcb, ip6_2_ip(ip6addr), port) #define udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \ udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg) #define udp_sendto_ip6(pcb, pbuf, ip6addr, port) \ - udp_sendto(pcb, pbuf, (ip_addr_t *)ip6addr, port) + udp_sendto(pcb, pbuf, ip6_2_ip(ip6addr), port) #define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \ - udp_sendto_if(pcb, pbuf, (ip_addr_t *)ip6addr, port, netif) + udp_sendto_if(pcb, pbuf, ip6_2_ip(ip6addr), port, netif) #if LWIP_CHECKSUM_ON_COPY #define udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \ - udp_sendto_chksum(pcb, pbuf, (ip_addr_t *)ip6addr, port, have_chk, chksum) + udp_sendto_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, have_chk, chksum) #define udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \ - udp_sendto_if_chksum(pcb, pbuf, (ip_addr_t *)ip6addr, port, netif, have_chk, chksum) + udp_sendto_if_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, netif, have_chk, chksum) #endif /*LWIP_CHECKSUM_ON_COPY */ #endif /* LWIP_IPV6 */ From 853d1eac96d4d39b5f16596a642979c76ea0adcd Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 25 May 2011 17:22:56 +0000 Subject: [PATCH 007/151] Fixed pointless conversion when checking TCP port range (bug #33398) --- src/core/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 8aa53a02..55d8cce0 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -644,7 +644,7 @@ tcp_new_port(void) static u16_t port = TCP_LOCAL_PORT_RANGE_START; again: - if (port++ >= TCP_LOCAL_PORT_RANGE_END) { + if (port++ == TCP_LOCAL_PORT_RANGE_END) { port = TCP_LOCAL_PORT_RANGE_START; } /* Check all PCB lists. */ From 1b2b05413941d95f309188c68d7fa2a1e517e8ba Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 25 May 2011 17:40:42 +0000 Subject: [PATCH 008/151] Fixed bug #33337 (which is #32906 reappearing after adding IPv6 support) --- src/api/sockets.c | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index d897397b..d0b15b89 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -865,13 +865,12 @@ lwip_sendto(int s, const void *data, size_t size, int flags, sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); #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...) */ + /* Special speedup for fast UDP/RAW sending: call the raw API directly + instead of using the netconn functions. */ { struct pbuf* p; - ip_addr_t *remote_addr; -#if LWIP_IPV6 - ip6_addr_t *remote_addr6; -#endif /* LWIP_IPV6 */ + ipX_addr_t *remote_addr; + ipX_addr_t remote_addr_tmp; #if LWIP_NETIF_TX_SINGLE_PBUF p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); @@ -890,33 +889,11 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 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 = ip6_2_ip(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); - } + SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6, + to, &remote_addr_tmp, remote_port); + remote_addr = &remote_addr_tmp; } else { - remote_addr = IP_ADDR_ANY; -#if LWIP_IPV6 - if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn))) { - remote_addr = ip6_2_ip(IP6_ADDR_ANY); - } - else -#endif /* LWIP_IPV6 */ - { - remote_addr = IP_ADDR_ANY; - } + remote_addr = &sock->conn->pcb.raw->remote_ip; if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) { remote_port = 0; } else { @@ -926,7 +903,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, LOCK_TCPIP_CORE(); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { - err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); + err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr)); } else { #if LWIP_UDP #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF From 92fcfd7a6f021021155da80cdeae3fbbc486ef53 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 26 May 2011 14:47:28 +0000 Subject: [PATCH 009/151] Fixed two compilation errors with different opt.h settings --- src/api/sockets.c | 4 ++-- src/core/tcp_out.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index d0b15b89..7e25f7a4 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -908,10 +908,10 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #if LWIP_UDP #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, - remote_addr, remote_port, 1, chksum); + ipX_2_ip(remote_addr), remote_port, 1, chksum); #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, - remote_addr, remote_port); + ipX_2_ip(remote_addr), remote_port); #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ #else /* LWIP_UDP */ err = ERR_ARG; diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index d9ab0a92..aeb0bc65 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1169,7 +1169,6 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* CHECKSUM_GEN_TCP */ - } #endif /* TCP_CHECKSUM_ON_COPY */ TCP_STATS_INC(tcp.xmit); From ccd7dbe0e4aa698cb96f85a88dab149066420bb3 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 26 May 2011 15:46:44 +0000 Subject: [PATCH 010/151] Added ipX versions for routing --- src/core/raw.c | 62 ++++++++++--------------------------- src/core/tcp.c | 47 ++++++++-------------------- src/core/tcp_out.c | 29 ++++------------- src/core/udp.c | 29 +++++++++-------- src/include/ipv4/lwip/ip4.h | 2 ++ src/include/ipv6/lwip/ip6.h | 2 ++ src/include/lwip/ip.h | 17 ++++++++++ src/include/lwip/ip_addr.h | 9 ++++-- 8 files changed, 77 insertions(+), 120 deletions(-) diff --git a/src/core/raw.c b/src/core/raw.c index 3ac3b687..08840bea 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -224,13 +224,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) { err_t err; struct netif *netif; - ip_addr_t *src_ip; + ipX_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ s16_t header_size; -#if LWIP_IPV6 - ip6_addr_t *ip6addr = ip_2_ip6(ipaddr); -#endif /* LWIP_IPV6 */ - + ipX_addr_t *dst_ip = ip_2_ipX(ipaddr); LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); @@ -264,16 +261,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } } -#if LWIP_IPV6 - if (pcb->isipv6) { - netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ip6addr); - } - else -#endif /* LWIP_IPV6 */ - netif = ip_route(ipaddr); + netif = ipX_route(pcb->isipv6, &pcb->local_ip, dst_ip); if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); - ipX_addr_debug_print(pcb->isipv6, RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ip_2_ipX(ipaddr)); + ipX_addr_debug_print(pcb->isipv6, RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); @@ -299,45 +290,26 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } #endif /* IP_SOF_BROADCAST */ - NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - + if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + /* use outgoing network interface IP address as source address */ + src_ip = ipX_netif_get_local_ipX(pcb->isipv6, netif, dst_ip); #if LWIP_IPV6 - if (pcb->isipv6) { - ip6_addr_t *src6_ip; - if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { - /* select an IPv6 address from the netif as source address */ - src6_ip = ip6_select_source_address(netif, ip6addr); - if (src6_ip == NULL) { - /* No suitable source address was found. */ - err = ERR_RTE; - NETIF_SET_HWADDRHINT(netif, NULL); - /* did we chain a header earlier? */ - if (q != p) { - /* free the header */ - pbuf_free(q); - } - return ERR_RTE; + if (src_ip == NULL) { + if (q != p) { + pbuf_free(q); } - } else { - /* use RAW PCB local IPv6 address as source address */ - src6_ip = ipX_2_ip6(&pcb->local_ip); + return ERR_RTE; } - err = ip6_output_if(q, src6_ip, ip6addr, pcb->ttl, pcb->tos, pcb->protocol, netif); - } - else #endif /* LWIP_IPV6 */ - { - if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* use RAW PCB local IP address as source address */ - src_ip = ipX_2_ip(&pcb->local_ip); - } - err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); + } else { + /* use RAW PCB local IP address as source address */ + src_ip = &pcb->local_ip; } + NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); + err = ipX_output_if(pcb->isipv6, q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); + /* did we chain a header earlier? */ if (q != p) { /* free the header */ diff --git a/src/core/tcp.c b/src/core/tcp.c index 55d8cce0..aa886171 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -689,40 +689,18 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, pcb->remote_port = port; /* check if we have a route to the remote host */ -#if LWIP_IPV6 - if (pcb->isipv6) { - if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { - /* no local IPv6 address set, yet. */ - ip6_addr_t * local_addr6; - struct netif *netif = ip6_route(ipX_2_ip6(&pcb->remote_ip), ipX_2_ip6(&pcb->remote_ip)); - 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, ipX_2_ip6(&pcb->remote_ip)); - 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(ipX_2_ip6(&pcb->local_ip), local_addr6); - } - } - else -#endif /* LWIP_IPV6 */ - if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { + if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { /* no local IP address set, yet. */ - struct netif *netif = ip_route(ipX_2_ip(&pcb->remote_ip)); - if (netif == NULL) { + struct netif *netif; + ipX_addr_t *local_ip; + ipX_route_get_local_ipX(pcb->isipv6, &pcb->remote_ip, &pcb->remote_ip, netif, local_ip); + if ((netif == NULL) || (local_ip == NULL)) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ return ERR_RTE; } /* Use the netif's IP address as local address. */ - ip_addr_copy(*ipX_2_ip(&pcb->local_ip), netif->ip_addr); + ipX_addr_copy(pcb->isipv6, pcb->local_ip, *local_ip); } old_local_port = pcb->local_port; @@ -769,7 +747,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, pcb->ssthresh = pcb->mss * 10; #if LWIP_CALLBACK_API pcb->connected = connected; -#else /* LWIP_CALLBACK_API */ +#else /* LWIP_CALLBACK_API */ LWIP_UNUSED_ARG(connected); #endif /* LWIP_CALLBACK_API */ @@ -1554,18 +1532,15 @@ tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest u16_t mss_s; struct netif *outif; s16_t mtu; - s16_t iphlen = IP_HLEN; + outif = ipX_route(isipv6, src, dest); #if LWIP_IPV6 if (isipv6) { /* First look in destination cache, to see if there is a Path MTU. */ - outif = ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)); mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif); - iphlen = IP6_HLEN; } else #endif /* LWIP_IPV6 */ { - outif = ip_route(ipX_2_ip(dest)); if (outif == NULL) { return sendmss; } @@ -1573,7 +1548,11 @@ tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest } if (mtu != 0) { - mss_s = mtu - iphlen - TCP_HLEN; + mss_s = mtu - IP_HLEN - TCP_HLEN; +#if LWIP_IPV6 + /* for IPv6, substract the difference in header size */ + mss_s -= (IP6_HLEN - IP_HLEN); +#endif /* LWIP_IPV6 */ /* RFC 1122, chap 4.2.2.6: * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize * We correct for TCP options in tcp_write(), and don't support IP options. diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index aeb0bc65..ad1e0e97 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1049,7 +1049,6 @@ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) { u16_t len; - struct netif *netif; u32_t *opts; /** @bug Exclude retransmitted segments from this count. */ @@ -1089,30 +1088,14 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* If we don't have a local IP address, we get one by calling ip_route(). */ -#if LWIP_IPV6 - if (pcb->isipv6) { - if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { - ip6_addr_t * local_addr6; - netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ipX_2_ip6(&pcb->remote_ip)); - if (netif == NULL) { - return; - } - /* Select and IPv6 address from the netif. */ - local_addr6 = ip6_select_source_address(netif, ipX_2_ip6(&pcb->remote_ip)); - if (local_addr6 == NULL) { - return; - } - ip6_addr_set(ipX_2_ip6(&pcb->local_ip), local_addr6); - } - } - else -#endif /* LWIP_IPV6 */ - if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { - netif = ip_route(ipX_2_ip(&pcb->remote_ip)); - if (netif == NULL) { + if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + struct netif *netif; + ipX_addr_t *local_ip; + ipX_route_get_local_ipX(pcb->isipv6, &pcb->local_ip, &pcb->remote_ip, netif, local_ip); + if ((netif == NULL) || (local_ip == NULL)) { return; } - ip_addr_copy(*ipX_2_ip(&pcb->local_ip), netif->ip_addr); + ipX_addr_copy(pcb->isipv6, pcb->local_ip, *local_ip); } if (pcb->rttest == 0) { diff --git a/src/core/udp.c b/src/core/udp.c index b983609b..25d53111 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -479,29 +479,28 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, { #endif /* LWIP_CHECKSUM_ON_COPY */ struct netif *netif; + ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - /* find the outgoing network interface for this packet */ +#if LWIP_IPV6 || LWIP_IGMP + if (ipX_addr_ismulticast(pcb->isipv6, dst_ip_route)) { + /* For multicast, find a netif based on source address. */ #if LWIP_IPV6 - if (pcb->isipv6) { - if (ip6_addr_ismulticast(ip_2_ip6(dst_ip))) { - /* For multicast, find a netif based on source address. */ - netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ipX_2_ip6(&pcb->local_ip)); - } - else { - netif = ip6_route(ipX_2_ip6(&pcb->local_ip), ip_2_ip6(dst_ip)); - } - } - else + if (pcb->isipv6) { + dst_ip_route = &pcb->local_ip; + } else #endif /* LWIP_IPV6 */ - { #if LWIP_IGMP - netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); -#else - netif = ip_route(dst_ip); + { + dst_ip_route = ip_2_ipX(&pcb->multicast_ip); + } #endif /* LWIP_IGMP */ } +#endif /* LWIP_IPV6 || LWIP_IGMP */ + + /* find the outgoing network interface for this packet */ + netif = ipX_route(pcb->isipv6, &pcb->local_ip, dst_ip_route); /* no outgoing network interface could be found? */ if (netif == NULL) { diff --git a/src/include/ipv4/lwip/ip4.h b/src/include/ipv4/lwip/ip4.h index bfe1153d..0d3c70b6 100644 --- a/src/include/ipv4/lwip/ip4.h +++ b/src/include/ipv4/lwip/ip4.h @@ -126,6 +126,8 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u16_t optlen); #endif /* IP_OPTIONS_SEND */ +#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL) + #if IP_DEBUG void ip_debug_print(struct pbuf *p); #else diff --git a/src/include/ipv6/lwip/ip6.h b/src/include/ipv6/lwip/ip6.h index f8f7e8eb..b199c95a 100644 --- a/src/include/ipv6/lwip/ip6.h +++ b/src/include/ipv6/lwip/ip6.h @@ -178,6 +178,8 @@ err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *des err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); #endif /* LWIP_IPV6_MLD */ +#define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \ + ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL) #if IP6_DEBUG void ip6_debug_print(struct pbuf *p); diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 4f856271..6564ea83 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -210,6 +210,14 @@ extern struct ip_globals ip_data; ((isipv6) ? \ ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \ ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint)) +#define ipX_route(isipv6, src, dest) \ + ((isipv6) ? \ + ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \ + ip_route(ipX_2_ip(dest))) +#define ipX_netif_get_local_ipX(isipv6, netif, dest) \ + ((isipv6) ? \ + ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \ + ip_netif_get_local_ipX(netif)) #define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p)) #else /* LWIP_IPV6 */ #define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ @@ -218,9 +226,18 @@ extern struct ip_globals ip_data; ip_output_if(p, src, dest, ttl, tos, proto, netif) #define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ipX_route(isipv6, src, dest) \ + ip_route(ipX_2_ip(dest)) +#define ipX_netif_get_local_ip(isipv6, netif, dest) \ + ip_get_local_ip(netif) #define ipX_debug_print(is_ipv6, p) ip_debug_print(p) #endif /* LWIP_IPV6 */ +#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \ + (netif) = ipX_route(isipv6, src, dest); \ + (ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \ +}while(0) + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index 04ffa534..ae8e6ff3 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -58,10 +58,13 @@ static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr) { return (ip_addr_t*)ip6addr; } static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr) { return (ipX_addr_t*)ipaddr; } +static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr) +{ return (ipX_addr_t*)ip6addr; } #else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */ -#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) -#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) -#define ip_2_ipX(ip_addr_t *ipaddr) ((ipX_addr_t*)ipaddr) +#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) +#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) +#define ip_2_ipX(ip_addr_t *ipaddr) ((ipX_addr_t*)ipaddr) +#define ip6_2_ipX(ip6_addr_t *ip6addr) ((ipX_addr_t*)ip6addr) #endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/ #define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6)) #define ipX_2_ip(ipaddr) (&((ipaddr)->ip4)) From 2aec3a9789619acfcbd73c0a15ea7d922fee6d73 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 28 May 2011 09:28:18 +0000 Subject: [PATCH 011/151] use PCB_IS_IPV6(pcb) instead of pcb->isipv6 everywhere --- src/api/api_lib.c | 2 +- src/api/api_msg.c | 14 +++++++------- src/core/raw.c | 24 ++++++++++++------------ src/core/tcp.c | 34 +++++++++++++++++----------------- src/core/tcp_in.c | 10 +++++----- src/core/tcp_out.c | 16 ++++++++-------- 6 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 47767512..6434dbe4 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -540,7 +540,7 @@ err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) { if (buf != NULL) { - ipX_addr_set_ipaddr(conn->pcb.ip->isipv6, &buf->addr, addr); + ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr); buf->port = port; return netconn_send(conn, buf); } diff --git a/src/api/api_msg.c b/src/api/api_msg.c index de226a5a..3d3eed10 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -113,7 +113,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->p = q; buf->ptr = q; - ipX_addr_copy(pcb->isipv6, buf->addr, *ipX_current_src_addr()); + ipX_addr_copy(PCB_ISIPV6(pcb), buf->addr, *ipX_current_src_addr()); buf->port = pcb->protocol; len = q->tot_len; @@ -1118,7 +1118,7 @@ do_send(struct api_msg_msg *msg) switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { + if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr)); @@ -1128,7 +1128,7 @@ do_send(struct api_msg_msg *msg) #if LWIP_UDP case NETCONN_UDP: #if LWIP_CHECKSUM_ON_COPY - if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { + if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } else { @@ -1137,7 +1137,7 @@ do_send(struct api_msg_msg *msg) msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } #else /* LWIP_CHECKSUM_ON_COPY */ - if (ipX_addr_isany(msg->conn->pcb.ip->isipv6, &msg->msg.b->addr)) { + if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); } else { msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port); @@ -1374,10 +1374,10 @@ do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { if (msg->msg.ad.local) { - ipX_addr_copy(msg->conn->pcb.ip->isipv6, *(msg->msg.ad.ipaddr), + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr), msg->conn->pcb.ip->local_ip); } else { - ipX_addr_copy(msg->conn->pcb.ip->isipv6, *(msg->msg.ad.ipaddr), + ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr), msg->conn->pcb.ip->remote_ip); } msg->err = ERR_OK; @@ -1478,7 +1478,7 @@ do_join_leave_group(struct api_msg_msg *msg) if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP #if LWIP_IPV6 && LWIP_IPV6_MLD - if (msg->conn->pcb.udp->isipv6) { + if (PCB_ISIPV6(msg->conn->pcb.udp)) { if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr), ipX_2_ip6(msg->msg.jl.multiaddr)); diff --git a/src/core/raw.c b/src/core/raw.c index 08840bea..2adc8a96 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -106,13 +106,13 @@ raw_input(struct pbuf *p, struct netif *inp) /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) && - (ipX_addr_isany(pcb->isipv6, &pcb->local_ip) || - ipX_addr_cmp(pcb->isipv6, &(pcb->local_ip), ipX_current_dest_addr()))) { + (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) { #if IP_SOF_BROADCAST_RECV /* broadcast filter? */ if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp)) #if LWIP_IPV6 - && !pcb->isipv6 + && !PCB_ISIPV6(pcb) #endif /* LWIP_IPV6 */ ) #endif /* IP_SOF_BROADCAST_RECV */ @@ -161,7 +161,7 @@ raw_input(struct pbuf *p, struct netif *inp) err_t raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) { - ipX_addr_set_ipaddr(pcb->isipv6, &pcb->local_ip, ipaddr); + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr); return ERR_OK; } @@ -181,7 +181,7 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) err_t raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) { - ipX_addr_set_ipaddr(pcb->isipv6, &pcb->remote_ip, ipaddr); + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr); return ERR_OK; } @@ -233,7 +233,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) header_size = ( #if LWIP_IPV6 - pcb->isipv6 ? IP6_HLEN : + PCB_ISIPV6(pcb) ? IP6_HLEN : #endif /* LWIP_IPV6 */ IP_HLEN); @@ -261,10 +261,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } } - netif = ipX_route(pcb->isipv6, &pcb->local_ip, dst_ip); + netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip); if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); - ipX_addr_debug_print(pcb->isipv6, RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); @@ -275,7 +275,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) #if IP_SOF_BROADCAST #if LWIP_IPV6 /* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */ - if (!netif->isipv6) + if (!PCB_ISIPV6(pcb)) #endif /* LWIP_IPV6 */ { /* broadcast filter? */ @@ -290,9 +290,9 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } #endif /* IP_SOF_BROADCAST */ - if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* use outgoing network interface IP address as source address */ - src_ip = ipX_netif_get_local_ipX(pcb->isipv6, netif, dst_ip); + src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip); #if LWIP_IPV6 if (src_ip == NULL) { if (q != p) { @@ -307,7 +307,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) } NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - err = ipX_output_if(pcb->isipv6, q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); + err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ diff --git a/src/core/tcp.c b/src/core/tcp.c index aa886171..e6b7bb31 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -151,7 +151,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) /* don't call tcp_abort here: we must not deallocate the pcb since that might not be expected when calling tcp_close */ tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port, pcb->isipv6); + pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); tcp_pcb_purge(pcb); @@ -356,7 +356,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) #endif /* TCP_QUEUE_OOSEQ */ if (reset) { LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, pcb->isipv6); + tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); } memp_free(MEMP_TCP_PCB, pcb); TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); @@ -441,8 +441,8 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } } - if (!ipX_addr_isany(pcb->isipv6, ip_2_ipX(ipaddr))) { - ipX_addr_set(pcb->isipv6, &pcb->local_ip, ip_2_ipX(ipaddr)); + if (!ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr))) { + ipX_addr_set(PCB_ISIPV6(pcb), &pcb->local_ip, ip_2_ipX(ipaddr)); } pcb->local_port = port; TCP_REG(&tcp_bound_pcbs, pcb); @@ -498,7 +498,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && IP_PCB_IPVER_EQ(pcb, lpcb)) { - if (ipX_addr_cmp(pcb->isipv6, &lpcb->local_ip, &pcb->local_ip)) { + if (ipX_addr_cmp(PCB_ISIPV6(pcb), &lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ return NULL; } @@ -519,10 +519,10 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; #if LWIP_IPV6 - lpcb->isipv6 = pcb->isipv6; + PCB_ISIPV6(lpcb) = PCB_ISIPV6(pcb); lpcb->accept_any_ip_version = 0; #endif /* LWIP_IPV6 */ - ipX_addr_copy(pcb->isipv6, lpcb->local_ip, pcb->local_ip); + ipX_addr_copy(PCB_ISIPV6(pcb), lpcb->local_ip, pcb->local_ip); if (pcb->local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } @@ -548,7 +548,7 @@ tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { struct tcp_pcb *lpcb; - if (!ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + if (!ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { return NULL; } lpcb = tcp_listen_with_backlog(pcb, backlog); @@ -689,18 +689,18 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, pcb->remote_port = port; /* check if we have a route to the remote host */ - if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* no local IP address set, yet. */ struct netif *netif; ipX_addr_t *local_ip; - ipX_route_get_local_ipX(pcb->isipv6, &pcb->remote_ip, &pcb->remote_ip, netif, local_ip); + ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip); if ((netif == NULL) || (local_ip == NULL)) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ return ERR_RTE; } - /* Use the netif's IP address as local address. */ - ipX_addr_copy(pcb->isipv6, pcb->local_ip, *local_ip); + /* Use the address as local address of the pcb. */ + ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip); } old_local_port = pcb->local_port; @@ -741,7 +741,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, pcb->isipv6); + pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; @@ -881,7 +881,7 @@ tcp_slowtmr(void) #endif /* LWIP_TCP_KEEPALIVE */ { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); - ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); ++pcb_remove; @@ -948,7 +948,7 @@ tcp_slowtmr(void) TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); if (pcb_reset) { tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port, pcb->isipv6); + pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); } pcb2 = pcb; @@ -1423,8 +1423,8 @@ tcp_pcb_purge(struct tcp_pcb *pcb) for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && IP_PCB_IPVER_EQ(pcb, lpcb) && - (ipX_addr_isany(lpcb->isipv6, &lpcb->local_ip) || - ipX_addr_cmp(lpcb->isipv6, &pcb->local_ip, &lpcb->local_ip))) { + (ipX_addr_isany(PCB_ISIPV6(lpcb), &lpcb->local_ip) || + ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) { /* port and address of the listen pcb match the timed-out pcb */ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", lpcb->accepts_pending > 0); diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index ea4c3c33..aeac353e 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -476,7 +476,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ #if LWIP_IPV6 - npcb->isipv6 = ip_current_is_v6(); + PCB_ISIPV6(npcb) = ip_current_is_v6(); #endif /* LWIP_IPV6 */ ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr()); ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr()); @@ -502,7 +502,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) tcp_parseopt(npcb); #if TCP_CALCULATE_EFF_SEND_MSS npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, - &npcb->remote_ip, npcb->isipv6); + &npcb->remote_ip, PCB_ISIPV6(npcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); @@ -643,7 +643,7 @@ tcp_process(struct tcp_pcb *pcb) #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, - pcb->isipv6); + PCB_ISIPV6(pcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect @@ -1027,7 +1027,7 @@ tcp_receive(struct tcp_pcb *pcb) pcb->polltmr = 0; #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb)) { /* Inform neighbor reachability of forward progress. */ nd6_reachability_hint(ip6_current_src_addr()); } @@ -1350,7 +1350,7 @@ tcp_receive(struct tcp_pcb *pcb) tcp_ack(pcb); #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb)) { /* Inform neighbor reachability of forward progress. */ nd6_reachability_hint(ip6_current_src_addr()); } diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index ad1e0e97..fb0e8741 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -869,14 +869,14 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) #endif #if CHECKSUM_GEN_TCP - tcphdr->chksum = ipX_chksum_pseudo(pcb->isipv6, p, IP_PROTO_TCP, p->tot_len, + tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif #if LWIP_NETIF_HWADDRHINT - ipX_output_hinted(pcb->isipv6, p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, + ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ - ipX_output(pcb->isipv6, p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, + ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); @@ -1088,14 +1088,14 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* If we don't have a local IP address, we get one by calling ip_route(). */ - if (ipX_addr_isany(pcb->isipv6, &pcb->local_ip)) { + if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { struct netif *netif; ipX_addr_t *local_ip; - ipX_route_get_local_ipX(pcb->isipv6, &pcb->local_ip, &pcb->remote_ip, netif, local_ip); + ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip); if ((netif == NULL) || (local_ip == NULL)) { return; } - ipX_addr_copy(pcb->isipv6, pcb->local_ip, *local_ip); + ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip); } if (pcb->rttest == 0) { @@ -1358,7 +1358,7 @@ tcp_keepalive(struct tcp_pcb *pcb) struct tcp_hdr *tcphdr; LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); - ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", @@ -1410,7 +1410,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) u8_t is_fin; LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); - ipX_addr_debug_print(pcb->isipv6, TCP_DEBUG, &pcb->remote_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, From d80be7961cdd824391d34f5c48b1b448a893dde7 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 28 May 2011 09:30:43 +0000 Subject: [PATCH 012/151] use PCB_IS_IPV6(pcb) instead of pcb->isipv6 everywhere; fixed compilation with LWIP_IPV6==1 but LWIP_IGMP==0 --- src/core/udp.c | 64 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index 25d53111..f948d1e1 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -167,21 +167,21 @@ udp_input(struct pbuf *p, struct netif *inp) local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG, &pcb->local_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG, &pcb->remote_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && #if LWIP_IPV6 - ((pcb->isipv6 && (ip_current_is_v6()) && + ((PCB_ISIPV6(pcb) && (ip_current_is_v6()) && (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) || #if LWIP_IPV6_MLD ip6_addr_ismulticast(ip6_current_dest_addr()) || #endif /* LWIP_IPV6_MLD */ ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) || - (!pcb->isipv6 && + (!PCB_ISIPV6(pcb) && (ip_current_header() != NULL) && #else /* LWIP_IPV6 */ (( @@ -206,8 +206,8 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) && - (ipX_addr_isany(pcb->isipv6, &pcb->remote_ip) || - ipX_addr_cmp(pcb->isipv6, &pcb->remote_ip, ipX_current_src_addr()))) { + (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) || + ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -303,10 +303,10 @@ udp_input(struct pbuf *p, struct netif *inp) /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && #if LWIP_IPV6 - ((mpcb->isipv6 && + ((PCB_ISIPV6(mpcb) && (ip6_addr_ismulticast(ip6_current_dest_addr()) || ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) || - (!mpcb->isipv6 && + (!PCB_ISIPV6(mpcb) && #else /* LWIP_IPV6 */ (( #endif /* LWIP_IPV6 */ @@ -335,7 +335,7 @@ udp_input(struct pbuf *p, struct netif *inp) /* move payload to UDP data */ pbuf_header(q, -hdrs_len); #if LWIP_IPV6 - if (mpcb->isipv6) { + if (PCB_ISIPV6(mpcb)) { mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src); } else @@ -359,7 +359,7 @@ udp_input(struct pbuf *p, struct netif *inp) if (pcb->recv.ip4 != NULL) { /* now the recv function is responsible for freeing p */ #if LWIP_IPV6 - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb)) { pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src); } else @@ -484,28 +484,28 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); #if LWIP_IPV6 || LWIP_IGMP - if (ipX_addr_ismulticast(pcb->isipv6, dst_ip_route)) { + if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) { /* For multicast, find a netif based on source address. */ #if LWIP_IPV6 - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb)) { dst_ip_route = &pcb->local_ip; } else #endif /* LWIP_IPV6 */ -#if LWIP_IGMP { +#if LWIP_IGMP dst_ip_route = ip_2_ipX(&pcb->multicast_ip); - } #endif /* LWIP_IGMP */ + } } #endif /* LWIP_IPV6 || LWIP_IGMP */ /* find the outgoing network interface for this packet */ - netif = ipX_route(pcb->isipv6, &pcb->local_ip, dst_ip_route); + netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route); /* no outgoing network interface could be found? */ if (netif == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip)); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip)); LWIP_DEBUGF(UDP_DEBUG, ("\n")); UDP_STATS_INC(udp.rterr); return ERR_RTE; @@ -561,7 +561,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* broadcast filter? */ if ( ((pcb->so_options & SOF_BROADCAST) == 0) && #if LWIP_IPV6 - !pcb->isipv6 && + !PCB_ISIPV6(pcb) && #endif /* LWIP_IPV6 */ ip_addr_isbroadcast(dst_ip, netif) ) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, @@ -617,10 +617,10 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, #if LWIP_IPV6 ( #if LWIP_IPV6_MLD - (pcb->isipv6 && + (PCB_ISIPV6(pcb) && ip6_addr_ismulticast(ip_2_ip6(dst_ip))) || #endif /* LWIP_IPV6_MLD */ - (!pcb->isipv6 && + (!PCB_ISIPV6(pcb) && #else /* LWIP_IPV6 */ (( #endif /* LWIP_IPV6 */ @@ -632,7 +632,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, /* PCB local address is IP_ANY_ADDR? */ #if LWIP_IPV6 - if (pcb->isipv6) { + if (PCB_ISIPV6(pcb)) { if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); if (src_ip == NULL) { @@ -710,7 +710,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, chklen = UDP_HLEN; } #endif /* LWIP_CHECKSUM_ON_COPY */ - udphdr->chksum = ipX_chksum_pseudo_partial(pcb->isipv6, q, IP_PROTO_UDPLITE, + udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE, q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { @@ -765,7 +765,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); /* output to IP */ NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ipX_output_if(pcb->isipv6, q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); + err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* TODO: must this be increased even if error occured? */ @@ -809,7 +809,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) u8_t rebind; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr)); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr)); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); rebind = 0; @@ -835,9 +835,9 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) #endif /* SO_REUSE */ if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) && /* IP address matches, or one is IP_ADDR_ANY? */ - (ipX_addr_isany(ipcb->isipv6, &(ipcb->local_ip)) || - ipX_addr_isany(ipcb->isipv6, ip_2_ipX(ipaddr)) || - ipX_addr_cmp(ipcb->isipv6, &(ipcb->local_ip), ip_2_ipX(ipaddr)))) { + (ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) || + ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) || + ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) { /* other PCB already binds to this local IP and port */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); @@ -846,7 +846,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } } - ipX_addr_set_ipaddr(pcb->isipv6, &pcb->local_ip, ipaddr); + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr); /* no port specified? */ if (port == 0) { @@ -884,7 +884,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) udp_pcbs = pcb; } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip); + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); return ERR_OK; } @@ -918,13 +918,13 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } } - ipX_addr_set_ipaddr(pcb->isipv6, &pcb->remote_ip, ipaddr); + ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr); pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; /** TODO: this functionality belongs in upper layers */ #ifdef LWIP_UDP_TODO #if LWIP_IPV6 - if (!pcb->isipv6) + if (!PCB_ISIPV6(pcb)) #endif /* LWIP_IPV6 */ { /* Nail down local IP for netconn_addr()/getsockname() */ @@ -947,7 +947,7 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) } #endif LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); - ipX_addr_debug_print(pcb->isipv6, UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); @@ -973,7 +973,7 @@ void udp_disconnect(struct udp_pcb *pcb) { /* reset remote address association */ - ipX_addr_set_any(pcb->isipv6, &pcb->remote_ip); + ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip); pcb->remote_port = 0; /* mark PCB as unconnected */ pcb->flags &= ~UDP_FLAGS_CONNECTED; From 98b6e2bcce653f03643bd3b43832875affd59c95 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 28 May 2011 09:32:07 +0000 Subject: [PATCH 013/151] Fixed ip_2_ipX() and ip6_2_ipX() macros #if !LWIP_ALLOW_STATIC_FN_IN_HEADER --- src/include/lwip/ip_addr.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/lwip/ip_addr.h b/src/include/lwip/ip_addr.h index ae8e6ff3..9690bf8f 100644 --- a/src/include/lwip/ip_addr.h +++ b/src/include/lwip/ip_addr.h @@ -61,10 +61,10 @@ static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr) static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr) { return (ipX_addr_t*)ip6addr; } #else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */ -#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) -#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) -#define ip_2_ipX(ip_addr_t *ipaddr) ((ipX_addr_t*)ipaddr) -#define ip6_2_ipX(ip6_addr_t *ip6addr) ((ipX_addr_t*)ip6addr) +#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) +#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) +#define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr) +#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr) #endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/ #define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6)) #define ipX_2_ip(ipaddr) (&((ipaddr)->ip4)) From d765c9de3776e89f63e0ba6f9ffd302c110d9d99 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 28 May 2011 09:32:42 +0000 Subject: [PATCH 014/151] Fixed ipX_netif_get_local_ipX for LWIP_IPV6==0 --- src/include/lwip/ip.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 6564ea83..f29ebf67 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -228,8 +228,8 @@ extern struct ip_globals ip_data; ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) #define ipX_route(isipv6, src, dest) \ ip_route(ipX_2_ip(dest)) -#define ipX_netif_get_local_ip(isipv6, netif, dest) \ - ip_get_local_ip(netif) +#define ipX_netif_get_local_ipX(isipv6, netif, dest) \ + ip_netif_get_local_ipX(netif) #define ipX_debug_print(is_ipv6, p) ip_debug_print(p) #endif /* LWIP_IPV6 */ From 604e69c7ae069058165b42a5b9b915e92d501d16 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 6 Jun 2011 16:00:06 +0000 Subject: [PATCH 015/151] - fixed bug #33485 (forgot '!' before SOCK_ADDR_MATCH*); - fixed 'cast increases alignment' by casting via 'void*'; - introduced 'struct sockaddr_aligned' where the 'base' type is instantiated to make sure the alignment is correct; --- src/api/sockets.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 7e25f7a4..966f4f62 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -84,18 +84,18 @@ inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0) #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \ if (isipv6) { \ - IP6ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in6*)(sockaddr)), ipXaddr, port); \ + IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ } else { \ - IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)(sockaddr)), ipXaddr, port); \ + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ } } while(0) #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \ inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \ (port) = (sin6)->sin6_port; }while(0) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \ if (isipv6) { \ - SOCKADDR6_TO_IP6ADDR_PORT(((struct sockaddr_in6*)(sockaddr)), ipXaddr, port); \ + SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ } else { \ - SOCKADDR4_TO_IP4ADDR_PORT(((struct sockaddr_in*)(sockaddr)), ipXaddr, port); \ + SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ } } while(0) #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (((domain) == AF_INET) ? \ (netconn_type) : ((netconn_type) | NETCONN_TYPE_IPV6)) @@ -104,9 +104,9 @@ #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) #define SOCK_ADDR_TYPE_MATCH(name, sock) 1 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \ - IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)sockaddr), ipXaddr, port) + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \ - IP4ADDR_PORT_TO_SOCKADDR(((struct sockaddr_in*)(sockaddr)), ipXaddr, port) + IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) #endif /* LWIP_IPV6 */ @@ -182,6 +182,22 @@ struct lwip_setgetsockopt_data { err_t err; }; +/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ + * sockaddr_in6 if instantiated. + */ +struct sockaddr_aligned { + u8_t sa_len; + u8_t sa_family; + u16_t alignment1; + u32_t alignment2; +#if LWIP_IPV6 + u8_t sa_data[SIN_ZERO_LEN + 8]; +#else /* LWIP_IPV6 */ + u8_t sa_data[SIN_ZERO_LEN]; +#endif /* LWIP_IPV6 */ +}; + + /** The global array of available sockets */ static struct lwip_sock sockets[NUM_SOCKETS]; /** The global list of tasks waiting for select */ @@ -406,7 +422,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) * not be NULL if addr is valid. */ if (addr != NULL) { - struct sockaddr tempaddr; + struct sockaddr_aligned tempaddr; /* get the IP address and port of the remote host */ err = netconn_peer(newconn, ipX_2_ip(&naddr), &port); if (err != ERR_OK) { @@ -468,7 +484,7 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) return -1; } - if (SOCK_ADDR_TYPE_MATCH(name, sock)) { + if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; @@ -534,7 +550,7 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) return -1; } - if (SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { + if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; @@ -721,7 +737,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, u16_t port; ipX_addr_t tmpaddr; ipX_addr_t *fromaddr; - struct sockaddr saddr; + struct sockaddr_aligned saddr; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { fromaddr = &tmpaddr; @@ -850,7 +866,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } - if (SOCK_ADDR_TYPE_MATCH(to, sock)) { + if (!SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; @@ -1443,7 +1459,7 @@ static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; - struct sockaddr saddr; + struct sockaddr_aligned saddr; ipX_addr_t naddr; u16_t port; From af5a913019364c10a7f0a8169fda03c3d2b0fd0e Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 6 Jun 2011 16:04:06 +0000 Subject: [PATCH 016/151] Fixed compilation with LWIP_IPV6==0 --- src/api/sockets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 966f4f62..ab5c3211 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -106,7 +106,7 @@ #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \ IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \ - IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) + SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) #endif /* LWIP_IPV6 */ From d30246dc052a9d022ee5a1505a43c71d2ff0343c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:05:22 +0000 Subject: [PATCH 017/151] Fixed bug #33492 (fixed stats for IPv6 protocols) --- src/core/stats.c | 9 +++++++-- src/include/lwip/stats.h | 12 ++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/core/stats.c b/src/core/stats.c index 69f97d41..8dde990e 100644 --- a/src/core/stats.c +++ b/src/core/stats.c @@ -88,9 +88,9 @@ stats_display_proto(struct stats_proto *proto, char *name) #if IGMP_STATS void -stats_display_igmp(struct stats_igmp *igmp) +stats_display_igmp(struct stats_igmp *igmp, const char *name) { - LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); + LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); @@ -159,9 +159,14 @@ stats_display(void) LINK_STATS_DISPLAY(); ETHARP_STATS_DISPLAY(); IPFRAG_STATS_DISPLAY(); + IP6_FRAG_STATS_DISPLAY(); IP_STATS_DISPLAY(); + ND6_STATS_DISPLAY(); + IP6_STATS_DISPLAY(); IGMP_STATS_DISPLAY(); + MLD6_STATS_DISPLAY(); ICMP_STATS_DISPLAY(); + ICMP6_STATS_DISPLAY(); UDP_STATS_DISPLAY(); TCP_STATS_DISPLAY(); MEM_STATS_DISPLAY(); diff --git a/src/include/lwip/stats.h b/src/include/lwip/stats.h index 3ca6ed22..d9112160 100644 --- a/src/include/lwip/stats.h +++ b/src/include/lwip/stats.h @@ -205,7 +205,7 @@ void stats_init(void); #if IGMP_STATS #define IGMP_STATS_INC(x) STATS_INC(x) -#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP") #else #define IGMP_STATS_INC(x) #define IGMP_STATS_DISPLAY() @@ -309,7 +309,7 @@ void stats_init(void); #if MLD6_STATS #define MLD6_STATS_INC(x) STATS_INC(x) -#define MLD6_STATS_DISPLAY() stats_display_proto(&lwip_stats.mld6, "MLDv1") +#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") #else #define MLD6_STATS_INC(x) #define MLD6_STATS_DISPLAY() @@ -326,15 +326,15 @@ void stats_init(void); /* Display of statistics */ #if LWIP_STATS_DISPLAY void stats_display(void); -void stats_display_proto(struct stats_proto *proto, char *name); -void stats_display_igmp(struct stats_igmp *igmp); -void stats_display_mem(struct stats_mem *mem, char *name); +void stats_display_proto(struct stats_proto *proto, const char *name); +void stats_display_igmp(struct stats_igmp *igmp, const char *name); +void stats_display_mem(struct stats_mem *mem, const char *name); void stats_display_memp(struct stats_mem *mem, int index); void stats_display_sys(struct stats_sys *sys); #else /* LWIP_STATS_DISPLAY */ #define stats_display() #define stats_display_proto(proto, name) -#define stats_display_igmp(igmp) +#define stats_display_igmp(igmp, name) #define stats_display_mem(mem, name) #define stats_display_memp(mem, index) #define stats_display_sys(sys) From 5a674f419dee62abb2133ed8ff842bd6b5a09de3 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:07:00 +0000 Subject: [PATCH 018/151] Restructured the code a bit to help my dump compiler not creating a jump table in ROM --- src/api/tcpip.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 42561c40..9cda0a9d 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -177,22 +177,22 @@ tcpip_input(struct pbuf *p, struct netif *inp) #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ struct tcpip_msg *msg; - if (sys_mbox_valid(&mbox)) { - msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); - if (msg == NULL) { - return ERR_MEM; - } - - msg->type = TCPIP_MSG_INPKT; - msg->msg.inp.p = p; - msg->msg.inp.netif = inp; - if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { - memp_free(MEMP_TCPIP_MSG_INPKT, msg); - return ERR_MEM; - } - return ERR_OK; + if (!sys_mbox_valid(&mbox)) { + return ERR_VAL; } - return ERR_VAL; + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); + if (msg == NULL) { + return ERR_MEM; + } + + msg->type = TCPIP_MSG_INPKT; + msg->msg.inp.p = p; + msg->msg.inp.netif = inp; + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { + memp_free(MEMP_TCPIP_MSG_INPKT, msg); + return ERR_MEM; + } + return ERR_OK; #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ } From 5b04860b8bd36b2130a9b6c9dceb798c3408176f Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:10:10 +0000 Subject: [PATCH 019/151] Moved common call to pbuf_header outside the switch() --- src/core/ipv4/ip4.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index cd121867..0aef63c2 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -477,6 +477,7 @@ ip_input(struct pbuf *p, struct netif *inp) if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { + pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ switch (IPH_PROTO(iphdr)) { #if LWIP_UDP @@ -485,27 +486,23 @@ ip_input(struct pbuf *p, struct netif *inp) case IP_PROTO_UDPLITE: #endif /* LWIP_UDPLITE */ snmp_inc_ipindelivers(); - pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP_PROTO_TCP: snmp_inc_ipindelivers(); - pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP case IP_PROTO_ICMP: snmp_inc_ipindelivers(); - pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ icmp_input(p, inp); break; #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: - pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ igmp_input(p, inp, ip_current_dest_addr()); break; #endif /* LWIP_IGMP */ @@ -514,6 +511,7 @@ ip_input(struct pbuf *p, struct netif *inp) /* send ICMP destination protocol unreachable unless is was a broadcast */ if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) && !ip_addr_ismulticast(ip_current_dest_addr())) { + pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */ p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } From 732cac1c0eceabcade0004b41089e7542c14b8e0 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:10:55 +0000 Subject: [PATCH 020/151] Moved static variable from inside the function to global scope --- src/core/dhcp.c | 7 +++++-- src/core/netif.c | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core/dhcp.c b/src/core/dhcp.c index ad2ad8fd..ecfe283b 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -126,6 +126,11 @@ u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; @todo: move this into struct dhcp? */ u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; +#ifdef DHCP_GLOBAL_XID +static u32_t xid; +static u8_t xid_initialised; +#endif /* DHCP_GLOBAL_XID */ + #define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) #define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) #define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) @@ -1628,8 +1633,6 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ static u32_t xid = 0xABCD0000; #else - static u32_t xid; - static u8_t xid_initialised = 0; if (!xid_initialised) { xid = DHCP_GLOBAL_XID; xid_initialised = !xid_initialised; diff --git a/src/core/netif.c b/src/core/netif.c index f58ba1ab..754f1112 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -82,6 +82,8 @@ struct netif *netif_list; struct netif *netif_default; +static u8_t netif_num; + #if LWIP_HAVE_LOOPIF static struct netif loop_netif; @@ -144,7 +146,6 @@ struct netif * netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { - static u8_t netifnum = 0; #if LWIP_IPV6 u32_t i; #endif @@ -200,7 +201,7 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, /* remember netif specific state information data */ netif->state = state; - netif->num = netifnum++; + netif->num = netif_num++; netif->input = input; NETIF_SET_HWADDRHINT(netif, NULL); #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS From 91532b2d5ca3d59f05a6c63037cebe71442d9f44 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:19:24 +0000 Subject: [PATCH 021/151] Removed unused static function --- src/core/ipv4/igmp.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index cf2e8ce1..22a1e161 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -139,7 +139,6 @@ static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr); static err_t igmp_remove_group(struct igmp_group *group); static void igmp_timeout( struct igmp_group *group); static void igmp_start_timer(struct igmp_group *group, u8_t max_time); -static void igmp_stop_timer(struct igmp_group *group); static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); static void igmp_send(struct igmp_group *group, u8_t type); @@ -704,17 +703,6 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time) group->timer = (LWIP_RAND() % (max_time - 1)) + 1; } -/** - * Stop a timer for an igmp_group - * - * @param group the igmp_group for which to stop the timer - */ -static void -igmp_stop_timer(struct igmp_group *group) -{ - group->timer = 0; -} - /** * Delaying membership report for a group if necessary * From 2ed5413e247ffb9ccf31a91835aa1c24a7ee6911 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:32:20 +0000 Subject: [PATCH 022/151] use const char for name pointers in display functions --- src/core/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/stats.c b/src/core/stats.c index 8dde990e..5bdd5a23 100644 --- a/src/core/stats.c +++ b/src/core/stats.c @@ -69,7 +69,7 @@ void stats_init(void) #if LWIP_STATS_DISPLAY void -stats_display_proto(struct stats_proto *proto, char *name) +stats_display_proto(struct stats_proto *proto, const char *name) { LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); @@ -110,7 +110,7 @@ stats_display_igmp(struct stats_igmp *igmp, const char *name) #if MEM_STATS || MEMP_STATS void -stats_display_mem(struct stats_mem *mem, char *name) +stats_display_mem(struct stats_mem *mem, const char *name) { LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); From e584557afe6708f2bf2181ef95886ef49c05f79f Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 7 Jun 2011 19:36:05 +0000 Subject: [PATCH 023/151] - sockaddr_aligned: use a union instead of a manually aligned struct; - fixed compilation for different configurations --- src/api/sockets.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index ab5c3211..98488221 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -97,8 +97,8 @@ } else { \ SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ } } while(0) -#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (((domain) == AF_INET) ? \ - (netconn_type) : ((netconn_type) | NETCONN_TYPE_IPV6)) +#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ + (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) #else /* LWIP_IPV6 */ #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) @@ -185,16 +185,12 @@ struct lwip_setgetsockopt_data { /** A struct sockaddr replacement that has the same alignment as sockaddr_in/ * sockaddr_in6 if instantiated. */ -struct sockaddr_aligned { - u8_t sa_len; - u8_t sa_family; - u16_t alignment1; - u32_t alignment2; +union sockaddr_aligned { + struct sockaddr sa; #if LWIP_IPV6 - u8_t sa_data[SIN_ZERO_LEN + 8]; -#else /* LWIP_IPV6 */ - u8_t sa_data[SIN_ZERO_LEN]; + struct sockaddr_in6 sin6; #endif /* LWIP_IPV6 */ + struct sockaddr_in sin; }; @@ -422,7 +418,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) * not be NULL if addr is valid. */ if (addr != NULL) { - struct sockaddr_aligned tempaddr; + sockaddr_aligned tempaddr; /* get the IP address and port of the remote host */ err = netconn_peer(newconn, ipX_2_ip(&naddr), &port); if (err != ERR_OK) { @@ -434,8 +430,8 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port); - if (*addrlen > tempaddr.sa_len) { - *addrlen = tempaddr.sa_len; + if (*addrlen > tempaddr.sa.sa_len) { + *addrlen = tempaddr.sa.sa_len; } MEMCPY(addr, &tempaddr, *addrlen); } @@ -494,6 +490,7 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(namelen); SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); @@ -560,6 +557,7 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(namelen); if (name->sa_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); @@ -737,7 +735,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, u16_t port; ipX_addr_t tmpaddr; ipX_addr_t *fromaddr; - struct sockaddr_aligned saddr; + sockaddr_aligned saddr; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { fromaddr = &tmpaddr; @@ -879,6 +877,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, (IS_SOCK_ADDR_LEN_VALID(tolen) && IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + LWIP_UNUSED_ARG(tolen); #if LWIP_TCPIP_CORE_LOCKING /* Special speedup for fast UDP/RAW sending: call the raw API directly @@ -1459,7 +1458,7 @@ static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; - struct sockaddr_aligned saddr; + sockaddr_aligned saddr; ipX_addr_t naddr; u16_t port; @@ -1479,8 +1478,8 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) SOCKETS_DEBUG, &naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); - if (*namelen > saddr.sa_len) { - *namelen = saddr.sa_len; + if (*namelen > saddr.sa.sa_len) { + *namelen = saddr.sa.sa_len; } MEMCPY(name, &saddr, *namelen); @@ -1954,7 +1953,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EINVAL; } #if LWIP_UDP - if (NETCONNTYPE_GROUP((netconn_type(sock->conn) != NETCONN_UDP)) || + if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; From 89a14206092b32a90285e3e802dfdb333c8f863a Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 8 Jun 2011 16:31:55 +0000 Subject: [PATCH 024/151] Fix compilation error when checking for hidden variable names ('s8_t i' was hidden in some case statements in nd6_input()). --- src/core/ipv6/nd6.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 8797a025..db624972 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -336,7 +336,6 @@ nd6_input(struct pbuf *p, struct netif *inp) { struct ra_header * ra_hdr; u8_t * buffer; /* Used to copy options. */ - s8_t i; u16_t offset; /* Check that RA header fits in packet. */ @@ -486,7 +485,6 @@ nd6_input(struct pbuf *p, struct netif *inp) case ICMP6_TYPE_RD: /* Redirect */ { struct redirect_header * redir_hdr; - s8_t i; struct lladdr_option * lladdr_opt; /* Check that Redir header fits in packet. */ @@ -556,7 +554,6 @@ nd6_input(struct pbuf *p, struct netif *inp) { struct icmp6_hdr *icmp6hdr; /* Packet too big message */ struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */ - s8_t i; /* Check that ICMPv6 header + IPv6 header fit in payload */ if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { From 2911c84a69d3743e4b57a64745d260127d7d8841 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 12 Jun 2011 11:57:34 +0000 Subject: [PATCH 025/151] Fixed compilation error after converting sockaddr_aligned from struct to union --- src/api/sockets.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 98488221..df7c737c 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -418,7 +418,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) * not be NULL if addr is valid. */ if (addr != NULL) { - sockaddr_aligned tempaddr; + union sockaddr_aligned tempaddr; /* get the IP address and port of the remote host */ err = netconn_peer(newconn, ipX_2_ip(&naddr), &port); if (err != ERR_OK) { @@ -735,7 +735,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, u16_t port; ipX_addr_t tmpaddr; ipX_addr_t *fromaddr; - sockaddr_aligned saddr; + union sockaddr_aligned saddr; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { fromaddr = &tmpaddr; @@ -1458,7 +1458,7 @@ static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; - sockaddr_aligned saddr; + union sockaddr_aligned saddr; ipX_addr_t naddr; u16_t port; From 629fad6f5f67f38b2eb25d0015618f630ea2fee8 Mon Sep 17 00:00:00 2001 From: idelamer Date: Fri, 17 Jun 2011 11:03:15 +0000 Subject: [PATCH 026/151] Minor edits for for IPv6 compilation --- src/core/ipv6/ip6_frag.c | 8 ++++---- src/include/ipv6/lwip/dhcp6.h | 2 +- src/include/ipv6/lwip/ip6_frag.h | 8 ++++---- src/include/lwip/tcp.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index d6f7ee1d..f33f4fb9 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -51,7 +51,7 @@ #include -#if LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ /** Setting this to 0, you can turn off checking the fragments for overlapping @@ -518,9 +518,9 @@ nullreturn: return NULL; } -#endif /* LWIP_IPV6_REASS */ +#endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */ -#if LWIP_IPV6_FRAG +#if LWIP_IPV6 && LWIP_IPV6_FRAG /** Allocate a new struct pbuf_custom_ref */ static struct pbuf_custom_ref* @@ -686,4 +686,4 @@ ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest) return ERR_OK; } -#endif /* LWIP_IPV6_FRAG */ +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ diff --git a/src/include/ipv6/lwip/dhcp6.h b/src/include/ipv6/lwip/dhcp6.h index e116f5c7..83ce306b 100644 --- a/src/include/ipv6/lwip/dhcp6.h +++ b/src/include/ipv6/lwip/dhcp6.h @@ -50,7 +50,7 @@ struct dhcp6 { - TODO: implement DHCP6 + //TODO: implement DHCP6 }; #endif /* LWIP_IPV6_DHCP6 */ diff --git a/src/include/ipv6/lwip/ip6_frag.h b/src/include/ipv6/lwip/ip6_frag.h index 12294a97..75898b8f 100644 --- a/src/include/ipv6/lwip/ip6_frag.h +++ b/src/include/ipv6/lwip/ip6_frag.h @@ -51,7 +51,7 @@ extern "C" { #endif -#if LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ /* The IPv6 reassembly timer interval in milliseconds. */ #define IP6_REASS_TMR_INTERVAL 1000 @@ -73,9 +73,9 @@ struct ip6_reassdata { void ip6_reass_tmr(void); struct pbuf * ip6_reass(struct pbuf *p); -#endif /* LWIP_IPV6_REASS */ +#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ -#if LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ /** A custom pbuf that holds a reference to another pbuf, which is freed * when this custom pbuf is freed. This is used to create a custom PBUF_REF @@ -92,7 +92,7 @@ struct pbuf_custom_ref { err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest); -#endif /* LWIP_IPV6_FRAG */ +#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ #ifdef __cplusplus diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index fdd12567..b37d5cf4 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -377,7 +377,7 @@ struct tcp_pcb * tcp_new_ip6 (void); #define tcp_bind_ip6(pcb, ip6addr, port) \ tcp_bind(pcb, ip6_2_ip(ip6addr), port) #define tcp_connect_ip6(pcb, ip6addr, port, connected) \ - udp_connect(pcb, ip6_2_ip(ip6addr), port, connected) + tcp_connect(pcb, ip6_2_ip(ip6addr), port, connected) struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog); #define tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) #else /* LWIP_IPV6 */ From 137953605e309e4611940818373c21b3913d4592 Mon Sep 17 00:00:00 2001 From: idelamer Date: Fri, 17 Jun 2011 11:04:47 +0000 Subject: [PATCH 027/151] Allow IPv6 addresses with arbitrary prefix. --- src/core/ipv6/ip6.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 79cbc870..ab17bbb9 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -216,6 +216,14 @@ ip6_select_source_address(struct netif *netif, ip6_addr_t * dest) } } + /* Last resort: see if arbitrary prefix matches. */ + 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_ip6_addr(netif, i); + } + } + return NULL; } From 12a948dacb001b4dad39c347950880198b01c7e5 Mon Sep 17 00:00:00 2001 From: idelamer Date: Fri, 17 Jun 2011 11:05:38 +0000 Subject: [PATCH 028/151] Allow routing IPv6 packets to neighbours with manually-configured non-link-local addresses. --- src/core/ipv6/nd6.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index db624972..3cabedec 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1197,6 +1197,13 @@ nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif) return 1; } } + /* Check to see if address prefix matches a (manually?) configured address. */ + for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { + return 1; + } + } return 0; } From 0f56d838ec7219714ec07e473956ed0caf3573e4 Mon Sep 17 00:00:00 2001 From: idelamer Date: Fri, 17 Jun 2011 11:06:06 +0000 Subject: [PATCH 029/151] Process IPv6 packets arriving from non-Ethernet links. --- src/api/tcpip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 9cda0a9d..6688870e 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -103,6 +103,11 @@ tcpip_thread(void *arg) ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); } else #endif /* LWIP_ETHERNET */ +#if LWIP_IPV6 + if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) { + ip6_input(msg->msg.inp.p, msg->msg.inp.netif); + } else +#endif /* LWIP_IPV6 */ { ip_input(msg->msg.inp.p, msg->msg.inp.netif); } From 4eb5acd9e2890524dbf44b7b70307df47dfa48d3 Mon Sep 17 00:00:00 2001 From: idelamer Date: Wed, 22 Jun 2011 12:14:58 +0000 Subject: [PATCH 030/151] Don't forward IPv6 packets that are larger than outgoing MTU, send ICMPv6 message back for Path MTU discovery. --- src/core/ipv6/ip6.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index ab17bbb9..bae27ece 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -295,6 +295,17 @@ ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) return; } + if (netif->mtu && (p->tot_len > netif->mtu)) { +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_packet_too_big(p, netif->mtu); + } +#endif /* LWIP_ICMP6 */ + IP6_STATS_INC(ip6.drop); + return; + } + 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()), From 12c2d7e4cf42526ca4519f9057149df72e1ea67b Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 25 Jun 2011 18:39:37 +0000 Subject: [PATCH 031/151] - changed "struct ip_addr" to "ip_addr_t"; - tcp_accepted(): added a note to call this on the listening pcb, not the connection pcb; - tcp_write(): change last parameter from "copy" to "apiflags", documented the apiflags --- doc/rawapi.txt | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/doc/rawapi.txt b/doc/rawapi.txt index bd452cf9..8c190305 100644 --- a/doc/rawapi.txt +++ b/doc/rawapi.txt @@ -107,7 +107,7 @@ incoming connections or be explicitly connected to another host. Creates a new connection identifier (PCB). If memory is not available for creating the new pcb, NULL is returned. -- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, +- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Binds the pcb to a local IP address and port number. The IP address @@ -147,6 +147,8 @@ incoming connections or be explicitly connected to another host. usually be called from the accept callback. This allows lwIP to perform housekeeping tasks, such as allowing further incoming connections to be queued in the listen backlog. + ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed + into the accept callback! - void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, @@ -154,8 +156,8 @@ incoming connections or be explicitly connected to another host. Specified the callback function that should be called when a new connection arrives on a listening connection. - -- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, + +- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)); @@ -176,7 +178,7 @@ incoming connections or be explicitly connected to another host. available for enqueueing the SYN segment. If the SYN indeed was enqueued successfully, the tcp_connect() function returns ERR_OK. - + --- Sending TCP data TCP data is sent by enqueueing the data with a call to @@ -184,15 +186,19 @@ tcp_write(). When the data is successfully transmitted to the remote host, the application will be notified with a call to a specified callback function. -- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, - u8_t copy) +- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags) Enqueues the data pointed to by the argument dataptr. The length of - the data is passed as the len parameter. The copy argument is either - 0 or 1 and indicates whether the new memory should be allocated for - the data to be copied into. If the argument is 0, no new memory - should be allocated and the data should only be referenced by - pointer. + the data is passed as the len parameter. The apiflags can be one or more of: + - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated + for the data to be copied into. If this flag is not given, no new memory + should be allocated and the data should only be referenced by pointer. This + also means that the memory behind dataptr must not change until the data is + ACKed by the remote host + - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is given, + the PSH flag is set in the last segment created by this call to tcp_write. + If this flag is given, the PSH flag is not set. The tcp_write() function will fail and return ERR_MEM if the length of the data exceeds the current send buffer size or if the length of @@ -238,7 +244,7 @@ window. Must be called when the application has received the data. The len argument indicates the length of the received data. - + --- Application polling @@ -253,7 +259,7 @@ again when the connection has been idle for a while. - void tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), - u8_t interval) + u8_t interval) Specifies the polling interval and the callback function that should be called to poll the application. The interval is specified in @@ -322,14 +328,14 @@ level of complexity of UDP, the interface is significantly simpler. Removes and deallocates the pcb. -- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, +- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Binds the pcb to a local address. The IP-address argument "ipaddr" can be IP_ADDR_ANY to indicate that it should listen to any local IP address. The function currently always return ERR_OK. -- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, +- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Sets the remote end of the pcb. This function does not generate any @@ -347,7 +353,7 @@ level of complexity of UDP, the interface is significantly simpler. - void udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, - struct ip_addr *addr, + ip_addr_t *addr, u16_t port), void *recv_arg) @@ -408,8 +414,8 @@ Call these functions in the order of appearance: Note: you must call tcp_fasttmr() and tcp_slowtmr() at the predefined regular intervals after this initialization. -- netif_add(struct netif *netif, struct ip_addr *ipaddr, - struct ip_addr *netmask, struct ip_addr *gw, +- netif_add(struct netif *netif, ip_addr_t *ipaddr, + ip_addr_t *netmask, ip_addr_t *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif)) From 93b5cd5ddde91d125445b42f701be9e4a4819786 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 16:50:28 +0000 Subject: [PATCH 032/151] Provide a default for SNMP_GET_SYSUPTIME() based on sys_now() --- src/core/snmp/mib2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/snmp/mib2.c b/src/core/snmp/mib2.c index 7d587f8c..dcd3b62c 100644 --- a/src/core/snmp/mib2.c +++ b/src/core/snmp/mib2.c @@ -73,7 +73,7 @@ #endif #ifndef SNMP_GET_SYSUPTIME -#define SNMP_GET_SYSUPTIME(sysuptime) +#define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10)) #endif static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); From d0026793bf54cc41b1fc0640a4633655543bd076 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 16:51:04 +0000 Subject: [PATCH 033/151] Cleaned up usage of sys.h a bit --- src/core/dhcp.c | 1 - src/core/tcp_out.c | 5 +++-- src/core/timers.c | 1 + src/include/lwip/tcp.h | 1 - src/include/lwip/tcp_impl.h | 1 - src/include/lwip/timers.h | 2 ++ src/netif/ethernetif.c | 1 - src/netif/slipif.c | 6 +++++- 8 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/dhcp.c b/src/core/dhcp.c index ecfe283b..fe85a7e8 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -76,7 +76,6 @@ #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/def.h" -#include "lwip/sys.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "lwip/dns.h" diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index fb0e8741..78093c16 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -46,7 +46,6 @@ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/memp.h" -#include "lwip/sys.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/inet_chksum.h" @@ -55,6 +54,9 @@ #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" +#if LWIP_TCP_TIMESTAMPS +#include "lwip/sys.h" +#endif #include @@ -813,7 +815,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) return ERR_OK; } - #if LWIP_TCP_TIMESTAMPS /* Build a timestamp option (12 bytes long) at the specified options pointer) diff --git a/src/core/timers.c b/src/core/timers.c index da6278f0..c804c3d1 100644 --- a/src/core/timers.c +++ b/src/core/timers.c @@ -59,6 +59,7 @@ #include "lwip/nd6.h" #include "lwip/ip6_frag.h" #include "lwip/mld6.h" +#include "lwip/sys.h" /** The one and only timeout list */ static struct sys_timeo *next_timeout; diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index b37d5cf4..ffa5f68e 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -36,7 +36,6 @@ #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ -#include "lwip/sys.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/ip.h" diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index f3ae40d2..14c92fbb 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -37,7 +37,6 @@ #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/tcp.h" -#include "lwip/sys.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/ip.h" diff --git a/src/include/lwip/timers.h b/src/include/lwip/timers.h index fb92b4b4..04e78e0f 100644 --- a/src/include/lwip/timers.h +++ b/src/include/lwip/timers.h @@ -41,7 +41,9 @@ #if LWIP_TIMERS #include "lwip/err.h" +#if !NO_SYS #include "lwip/sys.h" +#endif #ifdef __cplusplus extern "C" { diff --git a/src/netif/ethernetif.c b/src/netif/ethernetif.c index c22731ec..46900bdb 100644 --- a/src/netif/ethernetif.c +++ b/src/netif/ethernetif.c @@ -50,7 +50,6 @@ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" -#include "lwip/sys.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/ethip6.h" diff --git a/src/netif/slipif.c b/src/netif/slipif.c index c19333dd..c908a1e4 100644 --- a/src/netif/slipif.c +++ b/src/netif/slipif.c @@ -49,10 +49,12 @@ #include "lwip/def.h" #include "lwip/pbuf.h" -#include "lwip/sys.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/sio.h" +#if !NO_SYS +#include "lwip/sys.h" +#endif #define SLIP_BLOCK 1 #define SLIP_DONTBLOCK 0 @@ -335,9 +337,11 @@ slipif_init(struct netif *netif) */ NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0); +#if !NO_SYS /* Create a thread to poll the serial line. */ sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); +#endif return ERR_OK; } From 4444db299096bf845b920f5196d476cfcfff6935 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:07:13 +0000 Subject: [PATCH 034/151] Added some more asserts to check that pcb->state != LISTEN --- src/core/tcp.c | 13 ++++++++++++- src/core/tcp_out.c | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index e6b7bb31..43fe3758 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -601,6 +601,9 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) { int wnd_inflation; + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_recved for listen-pcbs", + pcb->state != LISTEN); LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", len <= 0xffff - pcb->rcv_wnd ); @@ -1321,7 +1324,9 @@ tcp_new_ip6(void) */ void tcp_arg(struct tcp_pcb *pcb, void *arg) -{ +{ + /* This function is allowed to be called for both listen pcbs and + connection pcbs. */ pcb->callback_arg = arg; } #if LWIP_CALLBACK_API @@ -1336,6 +1341,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg) void tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) { + LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); pcb->recv = recv; } @@ -1349,6 +1355,7 @@ tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) void tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) { + LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); pcb->sent = sent; } @@ -1363,6 +1370,7 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) void tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) { + LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); pcb->errf = err; } @@ -1377,6 +1385,8 @@ tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) void tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) { + /* This function is allowed to be called for both listen pcbs and + connection pcbs. */ pcb->accept = accept; } #endif /* LWIP_CALLBACK_API */ @@ -1391,6 +1401,7 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) void tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) { + LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); #if LWIP_CALLBACK_API pcb->poll = poll; #else /* LWIP_CALLBACK_API */ diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 78093c16..069df893 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -901,6 +901,10 @@ tcp_output(struct tcp_pcb *pcb) s16_t i = 0; #endif /* TCP_CWND_DEBUG */ + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_output for listen-pcbs", + pcb->state != LISTEN); + /* First, check if we are invoked by the TCP input processing code. If so, we do not output anything. Instead, we rely on the input processing code to call us when input processing is done From ba28d36e673946298e6c5511b8720966127c113c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:13:57 +0000 Subject: [PATCH 035/151] Fixed bug #33544 (warning in mem.c in lwip 1.4.0 with NO_SYS=1) --- CHANGELOG | 8 +++++++- src/core/mem.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index c47b87a6..e6386505 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,7 +6,11 @@ HISTORY ++ New features: - 2011-05-25: Simon Goldschmidt + 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) + * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that + pcb->state != LISTEN + + 2011-05-25: Simon Goldschmidt * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP @@ -23,6 +27,8 @@ HISTORY ++ Bugfixes: + 2011-06-26: Simon Goldschmidt + * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" diff --git a/src/core/mem.c b/src/core/mem.c index 98375553..9dbbaf65 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -190,7 +190,9 @@ static struct mem *ram_end; static struct mem *lfree; /** concurrent access protection */ +#if !NO_SYS static sys_mutex_t mem_mutex; +#endif #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT From 4002aef594bec2c6229356eac9df1fcd052c173d Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:31:10 +0000 Subject: [PATCH 036/151] fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an unaligned pointer. --- CHANGELOG | 4 ++++ src/core/mem.c | 11 ++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e6386505..5bb2c4f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,10 @@ HISTORY ++ Bugfixes: + 2011-06-26: Simon Goldschmidt + * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an + unaligned pointer. + 2011-06-26: Simon Goldschmidt * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" diff --git a/src/core/mem.c b/src/core/mem.c index 9dbbaf65..2128a28e 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -78,9 +78,10 @@ void * mem_malloc(mem_size_t size) { + void *ret; struct memp_malloc_helper *element; memp_t poolnr; - mem_size_t required_size = size + sizeof(struct memp_malloc_helper); + mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { #if MEM_USE_POOLS_TRY_BIGGER_POOL @@ -113,9 +114,9 @@ again: /* save the pool number this element came from */ element->poolnr = poolnr; /* and return a pointer to the memory directly after the struct memp_malloc_helper */ - element++; + ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - return element; + return ret; } /** @@ -128,13 +129,13 @@ again: void mem_free(void *rmem) { - struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem; + struct memp_malloc_helper *hmem; LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); /* get the original struct memp_malloc_helper */ - hmem--; + hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); LWIP_ASSERT("hmem != NULL", (hmem != NULL)); LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); From 6a4c30fe5d652f594d54e27e27169b05ce9e2bef Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:37:09 +0000 Subject: [PATCH 037/151] fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by updating its documentation only. --- CHANGELOG | 4 ++++ src/core/tcp.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5bb2c4f9..f46974a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,10 @@ HISTORY ++ Bugfixes: 2011-06-26: Simon Goldschmidt + * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by + updating its documentation only. + + 2011-06-26: Simon Goldschmidt * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an unaligned pointer. diff --git a/src/core/tcp.c b/src/core/tcp.c index 43fe3758..5ae323e3 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1142,7 +1142,8 @@ tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) #endif /* LWIP_CALLBACK_API */ /** - * Kills the oldest active connection that has lower priority than prio. + * Kills the oldest active connection that has the same or lower priority than + * 'prio'. * * @param prio minimum priority */ From b666ab067336cac833a7f5d3a9759b76b749c72c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:51:55 +0000 Subject: [PATCH 038/151] Init checks: LWIP_RAND is needed for IPv6, too --- src/core/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/init.c b/src/core/init.c index 30f09845..da118ed8 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -178,8 +178,8 @@ #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" #endif -#if LWIP_IGMP && !defined(LWIP_RAND) - #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" +#if (LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND) + #error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" #endif #if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" From 4b934945f3a12bdf18756b70a0592aa16eb8a032 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Jun 2011 17:53:45 +0000 Subject: [PATCH 039/151] Slightly reorderd fields of struct tcp_pcb to plug holes introduced by member alignment (to reduce RAM usage) --- src/include/lwip/tcp.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index ffa5f68e..8a7f418b 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -157,11 +157,11 @@ enum tcp_state { */ #define TCP_PCB_COMMON(type) \ type *next; /* for the linked list */ \ - enum tcp_state state; /* TCP state */ \ - u8_t prio; \ void *callback_arg; \ /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ DEF_ACCEPT_CALLBACK \ + enum tcp_state state; /* TCP state */ \ + u8_t prio; \ /* ports are in host byte order */ \ u16_t local_port @@ -188,21 +188,22 @@ struct tcp_pcb { /* the rest of the fields are in host byte order as we have to do some math with them */ + + /* Timers */ + u8_t polltmr, pollinterval; + u32_t tmr; + /* receiver variables */ u32_t rcv_nxt; /* next seqno expected */ u16_t rcv_wnd; /* receiver window available */ u16_t rcv_ann_wnd; /* receiver window to announce */ u32_t rcv_ann_right_edge; /* announced right edge of window */ - /* Timers */ - u32_t tmr; - u8_t polltmr, pollinterval; - /* Retransmission timer. */ s16_t rtime; - + u16_t mss; /* maximum segment size */ - + /* RTT (round trip time) estimation variables */ u32_t rttest; /* RTT estimate in 500ms ticks */ u32_t rtseq; /* sequence number being timed */ @@ -212,22 +213,22 @@ struct tcp_pcb { u8_t nrtx; /* number of retransmissions */ /* fast retransmit/recovery */ - u32_t lastack; /* Highest acknowledged seqno. */ u8_t dupacks; - + u32_t lastack; /* Highest acknowledged seqno. */ + /* congestion avoidance/control variables */ - u16_t cwnd; + u16_t cwnd; u16_t ssthresh; /* sender variables */ u32_t snd_nxt; /* next new seqno to be sent */ - u16_t snd_wnd; /* sender window */ u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last window update. */ u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ + u16_t snd_wnd; /* sender window */ u16_t acked; - + u16_t snd_buf; /* Available buffer space for sending (in bytes). */ #define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ From 2bd498524d6f92da34ffe7ac14cfd1af78906522 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 29 Jun 2011 19:46:21 +0000 Subject: [PATCH 040/151] Fixed bug #33653 (ip_data.current_ip_header_tot_len calculation errors!) introduced while mergin IPv4 and IPv6 --- src/core/ipv4/ip4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 0aef63c2..3ec50b66 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -470,7 +470,7 @@ ip_input(struct pbuf *p, struct netif *inp) ip_data.current_netif = inp; ip_data.current_ip4_header = iphdr; - ip_data.current_ip_header_tot_len = IPH_LEN(iphdr); + ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4; #if LWIP_RAW /* raw input did not eat the packet? */ From cc84f28d1b67e39de9ed9471d613f047da93a7f1 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 29 Jun 2011 19:54:33 +0000 Subject: [PATCH 041/151] Fixed bug #33672 (checksum calculate error!!!) by folding 'acc' to u16_t before calling checksum_pseudo_*_base functions --- src/core/inet_chksum.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/core/inet_chksum.c b/src/core/inet_chksum.c index 9d295159..f47d3c5b 100644 --- a/src/core/inet_chksum.c +++ b/src/core/inet_chksum.c @@ -259,10 +259,11 @@ lwip_standard_chksum(void *dataptr, int len) /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t -inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_base) { struct pbuf *q; u8_t swapped = 0; + u32_t acc = chksum_base; /* iterate through all pbuf in chain */ for(q = p; q != NULL; q = q->next) { @@ -320,8 +321,11 @@ inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, addr = ip4_addr_get_u32(dest); acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); - return inet_cksum_pseudo_base(p, proto, proto_len, acc); + return inet_cksum_pseudo_base(p, proto, proto_len, (u16_t)acc); } #if LWIP_IPV6 /** @@ -351,19 +355,23 @@ ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); - return inet_cksum_pseudo_base(p, proto, proto_len, acc); + return inet_cksum_pseudo_base(p, proto, proto_len, (u16_t)acc); } #endif /* LWIP_IPV6 */ /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, u32_t acc) + u16_t chksum_len, u16_t chksum_base) { struct pbuf *q; u8_t swapped = 0; u16_t chklen; + u32_t acc = chksum_base; /* iterate through all pbuf in chain */ for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { @@ -426,8 +434,11 @@ inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, addr = ip4_addr_get_u32(dest); acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, (u16_t)acc); } #if LWIP_IPV6 @@ -460,8 +471,11 @@ ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); } + /* fold down to 16 bits */ + acc = FOLD_U32T(acc); + acc = FOLD_U32T(acc); - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, (u16_t)acc); } #endif /* LWIP_IPV6 */ From c2fd905e322914030f73a6944d066eb9afc23628 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 4 Jul 2011 19:10:49 +0000 Subject: [PATCH 042/151] No need to pass 'acc' as u16_t since the _base functions are internal (we save one AND op when passing as u32_t) --- src/core/inet_chksum.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/inet_chksum.c b/src/core/inet_chksum.c index f47d3c5b..8bc42c14 100644 --- a/src/core/inet_chksum.c +++ b/src/core/inet_chksum.c @@ -259,11 +259,10 @@ lwip_standard_chksum(void *dataptr, int len) /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t -inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_base) +inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) { struct pbuf *q; u8_t swapped = 0; - u32_t acc = chksum_base; /* iterate through all pbuf in chain */ for(q = p; q != NULL; q = q->next) { @@ -325,7 +324,7 @@ inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); - return inet_cksum_pseudo_base(p, proto, proto_len, (u16_t)acc); + return inet_cksum_pseudo_base(p, proto, proto_len, acc); } #if LWIP_IPV6 /** @@ -359,19 +358,18 @@ ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); - return inet_cksum_pseudo_base(p, proto, proto_len, (u16_t)acc); + return inet_cksum_pseudo_base(p, proto, proto_len, acc); } #endif /* LWIP_IPV6 */ /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, - u16_t chksum_len, u16_t chksum_base) + u16_t chksum_len, u32_t acc) { struct pbuf *q; u8_t swapped = 0; u16_t chklen; - u32_t acc = chksum_base; /* iterate through all pbuf in chain */ for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { @@ -438,7 +436,7 @@ inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, (u16_t)acc); + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); } #if LWIP_IPV6 @@ -475,7 +473,7 @@ ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); - return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, (u16_t)acc); + return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); } #endif /* LWIP_IPV6 */ From 09ac68c19646070a6298030dcd1dc0d9d1791b44 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 4 Jul 2011 19:33:33 +0000 Subject: [PATCH 043/151] Fixed documentation after changing sys arch prototypes for 1.4.0 --- CHANGELOG | 3 ++ doc/sys_arch.txt | 77 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f46974a3..4876c42a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,9 @@ HISTORY ++ Bugfixes: + 2011-07-04: Simon Goldschmidt + * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. + 2011-06-26: Simon Goldschmidt * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by updating its documentation only. diff --git a/doc/sys_arch.txt b/doc/sys_arch.txt index 38377b66..847cd777 100644 --- a/doc/sys_arch.txt +++ b/doc/sys_arch.txt @@ -34,26 +34,36 @@ in the sys_arch.h file. Mailboxes are equivalently represented by the type "sys_mbox_t". lwIP does not place any restrictions on how sys_sem_t or sys_mbox_t are represented internally. +Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that +allows both using pointers or actual OS structures to be used. This way, memory +required for such types can be either allocated in place (globally or on the +stack) or on the heap (allocated internally in the "*_new()" functions). + The following functions must be implemented by the sys_arch: - void sys_init(void) Is called to initialize the sys_arch layer. -- sys_sem_t sys_sem_new(u8_t count) +- err_t sys_sem_new(sys_sem_t *sem, u8_t count) - Creates and returns a new semaphore. The "count" argument specifies - the initial state of the semaphore. + Creates a new semaphore. The semaphore is allocated to the memory that 'sem' + points to (which can be both a pointer or the actual OS structure). + The "count" argument specifies the initial state of the semaphore (which is + either 0 or 1). + If the semaphore has been created, ERR_OK should be returned. Returning any + other error will provide a hint what went wrong, but except for assertions, + no real error handling is implemented. -- void sys_sem_free(sys_sem_t sem) +- void sys_sem_free(sys_sem_t *sem) Deallocates a semaphore. -- void sys_sem_signal(sys_sem_t sem) +- void sys_sem_signal(sys_sem_t *sem) Signals a semaphore. -- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) +- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) Blocks the thread while waiting for the semaphore to be signaled. If the "timeout" argument is non-zero, the thread should @@ -70,30 +80,47 @@ The following functions must be implemented by the sys_arch: Notice that lwIP implements a function with a similar name, sys_sem_wait(), that uses the sys_arch_sem_wait() function. -- sys_mbox_t sys_mbox_new(int size) +- int sys_sem_valid(sys_sem_t *sem) + + Returns 1 if the semaphore is valid, 0 if it is not valid. + When using pointers, a simple way is to check the pointer for != NULL. + When directly using OS structures, implementing this may be more complex. + This may also be a define, in which case the function is not prototyped. + +- void sys_sem_set_invalid(sys_sem_t *sem) + + Invalidate a semaphore so that sys_sem_valid() returns 0. + ATTENTION: This does NOT mean that the semaphore shall be deallocated: + sys_sem_free() is always called before calling this function! + This may also be a define, in which case the function is not prototyped. + +- err_t sys_mbox_new(sys_mbox_t *mbox, int size) Creates an empty mailbox for maximum "size" elements. Elements stored in mailboxes are pointers. You have to define macros "_MBOX_SIZE" in your lwipopts.h, or ignore this parameter in your implementation and use a default size. + If the mailbox has been created, ERR_OK should be returned. Returning any + other error will provide a hint what went wrong, but except for assertions, + no real error handling is implemented. -- void sys_mbox_free(sys_mbox_t mbox) +- void sys_mbox_free(sys_mbox_t *mbox) Deallocates a mailbox. If there are messages still present in the mailbox when the mailbox is deallocated, it is an indication of a programming error in lwIP and the developer should be notified. -- void sys_mbox_post(sys_mbox_t mbox, void *msg) +- void sys_mbox_post(sys_mbox_t *mbox, void *msg) Posts the "msg" to the mailbox. This function have to block until the "msg" is really posted. -- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg) +- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full, else, ERR_OK if the "msg" is posted. -- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) +- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) Blocks the thread until a message arrives in the mailbox, but does not block the thread longer than "timeout" milliseconds (similar to @@ -110,7 +137,7 @@ The following functions must be implemented by the sys_arch: Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP. -- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) +- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) This is similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox, it immediately returns with the code @@ -122,7 +149,21 @@ The following functions must be implemented by the sys_arch: #define sys_arch_mbox_tryfetch(mbox,msg) \ sys_arch_mbox_fetch(mbox,msg,1) although this would introduce unnecessary delays. - + +- int sys_mbox_valid(sys_mbox_t *mbox) + + Returns 1 if the mailbox is valid, 0 if it is not valid. + When using pointers, a simple way is to check the pointer for != NULL. + When directly using OS structures, implementing this may be more complex. + This may also be a define, in which case the function is not prototyped. + +- void sys_mbox_set_invalid(sys_mbox_t *mbox) + + Invalidate a mailbox so that sys_mbox_valid() returns 0. + ATTENTION: This does NOT mean that the mailbox shall be deallocated: + sys_mbox_free() is always called before calling this function! + This may also be a define, in which case the function is not prototyped. + If threads are supported by the underlying operating system and if such functionality is needed in lwIP, the following function will have to be implemented as well: @@ -156,6 +197,16 @@ to be implemented as well: more information. This function is only required if your port is supporting an operating system. +For some configurations, you also need: + +- u32_t sys_now(void) + + This optional function returns the current time in milliseconds (don't care + for wraparound, this is only used for time diffs). + Not implementing this function means you cannot use some modules (e.g. TCP + timestamps, internal timeouts for NO_SYS==1). + + Note: Be carefull with using mem_malloc() in sys_arch. When malloc() refers to From 1813d11b9dff98be39a713989faccb54ff397ec7 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 4 Jul 2011 19:39:16 +0000 Subject: [PATCH 044/151] Fixed invalid SOCK_ADDR_TYPE_MATCH check in lwip_sendto() --- src/api/sockets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index df7c737c..deb4e849 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -864,7 +864,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } - if (!SOCK_ADDR_TYPE_MATCH(to, sock)) { + if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; From a93d9c4310c01b1a5fb420f40d7c4f89e716e1a4 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 5 Jul 2011 19:42:23 +0000 Subject: [PATCH 045/151] Fixed bug #33561 bugs in recvfrom() and sendto() --- src/api/sockets.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index deb4e849..4e10ea5f 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -66,7 +66,7 @@ memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \ inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \ - (port) = (sin)->sin_port; }while(0) + (port) = ntohs((sin)->sin_port); }while(0) #if LWIP_IPV6 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ @@ -90,7 +90,7 @@ } } while(0) #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \ inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \ - (port) = (sin6)->sin6_port; }while(0) + (port) = ntohs((sin6)->sin6_port); }while(0) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \ if (isipv6) { \ SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ @@ -750,6 +750,10 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), SOCKETS_DEBUG, fromaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); + if (*fromlen > saddr.sa.sa_len) { + *fromlen = saddr.sa.sa_len; + } + MEMCPY(from, &saddr, *fromlen); } } @@ -775,7 +779,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, } } while (!done); - if (off > 0) { + if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { /* update receive window */ netconn_recved(sock->conn, (u32_t)off); } From 1f4b814d0b955c03e453bf31b8f521adaff833e1 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 6 Jul 2011 07:13:45 +0000 Subject: [PATCH 046/151] Include opt.h so that LWIP_ERROR works correctly --- src/include/lwip/debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/lwip/debug.h b/src/include/lwip/debug.h index d8359ea3..0fe04139 100644 --- a/src/include/lwip/debug.h +++ b/src/include/lwip/debug.h @@ -33,6 +33,7 @@ #define __LWIP_DEBUG_H__ #include "lwip/arch.h" +#include "lwip/opt.h" /** lower two bits indicate debug level * - 0 all From 7385449f333fd080af3d5e8a339fe119e5203b07 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 6 Jul 2011 07:18:06 +0000 Subject: [PATCH 047/151] Fixed wrong endianess of port in bind() and connect() broken with the last commit --- src/api/sockets.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 4e10ea5f..9af71c4e 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -495,9 +495,9 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); - err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), ntohs(local_port)); + err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), local_port); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); @@ -567,9 +567,9 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); - err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), ntohs(remote_port)); + err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), remote_port); } if (err != ERR_OK) { From fb0ad2f9ea968835e477798d4ac224f3cfe66291 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 19 Jul 2011 21:52:40 +0200 Subject: [PATCH 048/151] Fixed bug #33802 tcpip: tcpip_callbackmsg_new sets msg->type to wrong type --- src/api/tcpip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/tcpip.c b/src/api/tcpip.c index 6688870e..ef6fed5f 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -416,7 +416,7 @@ struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, voi if (msg == NULL) { return NULL; } - msg->type = TCPIP_MSG_CALLBACK; + msg->type = TCPIP_MSG_CALLBACK_STATIC; msg->msg.cb.function = function; msg->msg.cb.ctx = ctx; return (struct tcpip_callback_msg*)msg; From 435ac2a65048e15ed345a636aadf9159bee7d68c Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 19 Jul 2011 21:56:19 +0200 Subject: [PATCH 049/151] Fixed bug #33801 Corruption of nd6 tables --- src/core/ipv6/nd6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 3cabedec..772e239c 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1491,7 +1491,7 @@ nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) i = nd6_new_neighbor_cache_entry(); if (i >= 0) { /* got new neighbor entry. make it our new cached index. */ - nd6_cached_destination_index = i; + nd6_cached_neighbor_index = i; } else { /* Could not create a neighbor cache entry. */ return ERR_MEM; From fc280c7cd69073273b4ec4bb58d09833c2af062c Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 20 Jul 2011 06:56:20 +0200 Subject: [PATCH 050/151] Fixed bug #33804 LWIP_IPV6_MLD #define missing from mld6.c --- src/core/ipv6/mld6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index 97132273..9db25bab 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -44,7 +44,7 @@ #include "lwip/opt.h" -#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ #include "lwip/mld6.h" #include "lwip/icmp6.h" From bd69890ccd148c5c539f536ea052dd977f0cf692 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 20:15:39 +0200 Subject: [PATCH 051/151] (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram. --- CHANGELOG | 4 ++++ src/api/sockets.c | 37 +++++++++++++++++++++++++++++++++---- src/include/lwip/opt.h | 12 ++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4876c42a..02ec9030 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-07-21: Simon Goldschmidt + * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes + ioctl/FIONREAD return the size of the next pending datagram. + 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that pcb->state != LISTEN diff --git a/src/api/sockets.c b/src/api/sockets.c index 9af71c4e..ba68e726 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -2330,13 +2330,38 @@ lwip_ioctl(int s, long cmd, void *argp) } switch (cmd) { -#if LWIP_SO_RCVBUF +#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE case FIONREAD: if (!argp) { sock_set_errno(sock, EINVAL); return -1; } +#if LWIP_FIONREAD_LINUXMODE + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + struct pbuf *p; + if (sock->lastdata) { + p = ((struct netbuf *)sock->lastdata)->p; + } else { + struct netbuf *rxbuf; + err_t err; + if (sock->rcvevent <= 0) { + *((u16_t*)argp) = 0; + } else { + err = netconn_recv(sock->conn, &rxbuf); + if (err != ERR_OK) { + *((u16_t*)argp) = 0; + } else { + sock->lastdata = rxbuf; + *((u16_t*)argp) = rxbuf->p->tot_len; + } + } + } + return 0; + } +#endif /* LWIP_FIONREAD_LINUXMODE */ +#if LWIP_SO_RCVBUF + /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); if (recv_avail < 0) { recv_avail = 0; @@ -2358,7 +2383,10 @@ lwip_ioctl(int s, long cmd, void *argp) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); sock_set_errno(sock, 0); return 0; +#else /* LWIP_SO_RCVBUF */ + break; #endif /* LWIP_SO_RCVBUF */ +#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ case FIONBIO: val = 0; @@ -2371,10 +2399,11 @@ lwip_ioctl(int s, long cmd, void *argp) return 0; default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); - sock_set_errno(sock, ENOSYS); /* not yet implemented */ - return -1; + break; } /* switch (cmd) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); + sock_set_errno(sock, ENOSYS); /* not yet implemented */ + return -1; } /** A minimal implementation of fcntl. diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index a8243b6a..911b6251 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1443,6 +1443,18 @@ #define SO_REUSE_RXTOALL 0 #endif +/** + * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of + * pending data in the network buffer. This is the way windows does it. It's + * the default for lwIP since it is smaller. + * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next + * pending datagram in bytes. This is the way linux does it. This code is only + * here for compatibility. + */ +#ifndef LWIP_FIONREAD_LINUXMODE +#define LWIP_FIONREAD_LINUXMODE 0 +#endif + /* ---------------------------------------- ---------- Statistics options ---------- From ef9891e8ff33613915f6002dad2320b8834a3bd4 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 20:28:18 +0200 Subject: [PATCH 052/151] fixed bug #33551 (ARP entries may time out although in use) by sending an ARP request when an ARP entry is used in the last minute before it would time out. --- CHANGELOG | 5 ++ src/netif/etharp.c | 168 +++++++++++++++++++++++++++++---------------- 2 files changed, 112 insertions(+), 61 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 02ec9030..b05055e0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,6 +31,11 @@ HISTORY ++ Bugfixes: + 2011-07-21: Simon Goldschmidt + * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by + sending an ARP request when an ARP entry is used in the last minute before + it would time out. + 2011-07-04: Simon Goldschmidt * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 99ae853a..58476315 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -72,7 +72,11 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}}; * for ARP_TMR_INTERVAL = 5000, this is * (240 * 5) seconds = 20 minutes. */ -#define ARP_MAXAGE 240 +#define ARP_MAXAGE 240 +/** Re-request a used ARP entry 1 minute before it would expire to prevent + * breaking a steadily used connection because the ARP entry timed out. */ +#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12) + /** the time an ARP entry stays pending after first request, * for ARP_TMR_INTERVAL = 5000, this is * (2 * 5) seconds = 10 seconds. @@ -87,7 +91,8 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}}; enum etharp_state { ETHARP_STATE_EMPTY = 0, ETHARP_STATE_PENDING, - ETHARP_STATE_STABLE + ETHARP_STATE_STABLE, + ETHARP_STATE_STABLE_REREQUESTING }; struct etharp_entry { @@ -99,10 +104,8 @@ struct etharp_entry { struct pbuf *q; #endif /* ARP_QUEUEING */ ip_addr_t ipaddr; - struct eth_addr ethaddr; -#if LWIP_SNMP struct netif *netif; -#endif /* LWIP_SNMP */ + struct eth_addr ethaddr; u8_t state; u8_t ctime; #if ETHARP_SUPPORT_STATIC_ENTRIES @@ -186,9 +189,7 @@ free_entry(int i) #ifdef LWIP_DEBUG /* for debugging, clean out the complete entry */ arp_table[i].ctime = 0; -#if LWIP_SNMP arp_table[i].netif = NULL; -#endif /* LWIP_SNMP */ ip_addr_set_zero(&arp_table[i].ipaddr); arp_table[i].ethaddr = ethzero; #endif /* LWIP_DEBUG */ @@ -220,10 +221,16 @@ etharp_tmr(void) (arp_table[i].ctime >= ARP_MAXPENDING))) { /* pending or stable entry has become old! */ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", - arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); + arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); /* clean up entries that have just been expired */ free_entry(i); } + else if ((arp_table[i].ctime >= ARP_AGE_REREQUEST_USED) && + (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING)) { + /* stable entry that is in use is about to expire: re-request it to + prevent it from breaking communication when it expires */ + etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); + } #if ARP_QUEUEING /* still pending entry? (not expired) */ if (arp_table[i].state == ETHARP_STATE_PENDING) { @@ -289,8 +296,8 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) /* remember first empty entry */ empty = i; } else if (state != ETHARP_STATE_EMPTY) { - LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE", - state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE); + LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", + state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i)); @@ -314,7 +321,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) } } /* stable entry? */ - } else if (state == ETHARP_STATE_STABLE) { + } else if (state >= ETHARP_STATE_STABLE) { #if ETHARP_SUPPORT_STATIC_ENTRIES /* don't record old_stable for static entries since they never expire */ if (arp_table[i].static_entry == 0) @@ -473,10 +480,8 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd /* mark it stable */ arp_table[i].state = ETHARP_STATE_STABLE; -#if LWIP_SNMP /* record network interface */ arp_table[i].netif = netif; -#endif /* LWIP_SNMP */ /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); @@ -558,7 +563,7 @@ etharp_remove_static_entry(ip_addr_t *ipaddr) return (err_t)i; } - if ((arp_table[i].state != ETHARP_STATE_STABLE) || + if ((arp_table[i].state < ETHARP_STATE_STABLE) || (arp_table[i].static_entry == 0)) { /* entry wasn't a static entry, cannot remove it */ return ERR_ARG; @@ -592,7 +597,7 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, LWIP_UNUSED_ARG(netif); i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); - if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { + if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; return i; @@ -816,6 +821,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) pbuf_free(p); } +/** Just a small helper function that sends a pbuf to an ethernet address + * in the arp_table specified by the index 'arp_idx'. + */ +static err_t +etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) +{ + LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", + arp_table[arp_idx].state >= ETHARP_STATE_STABLE); + /* if arp table entry is about to expire: re-request it, + but only if its state is ETHARP_STATE_STABLE to prevent flooding the + network with ARP requests if this address is used frequently. */ + if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && + (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { + if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; + } + } + + return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), + &arp_table[arp_idx].ethaddr); +} + /** * Resolve and fill-in Ethernet address header for outgoing IP packet. * @@ -837,7 +864,13 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) { - struct eth_addr *dest, mcastaddr; + struct eth_addr *dest; + struct eth_addr mcastaddr; + ip_addr_t *dst_addr = ipaddr; + + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("q != NULL", q != NULL); + LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); /* make room for Ethernet header - should not fail */ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { @@ -848,8 +881,48 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) return ERR_BUF; } - /* assume unresolved Ethernet address */ - dest = NULL; + /* outside local network? if so, this can neither be a global broadcast nor + a subnet broadcast. */ + if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && + !ip_addr_islinklocal(ipaddr)) { +#if LWIP_AUTOIP + struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + + sizeof(struct eth_hdr)); + /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with + a link-local source address must always be "directly to its destination + on the same physical link. The host MUST NOT send the packet to any + router for forwarding". */ + if (!ip_addr_islinklocal(&iphdr->src)) +#endif /* LWIP_AUTOIP */ + { + /* interface has default gateway? */ + if (!ip_addr_isany(&netif->gw)) { + /* send to hardware address of default gateway IP address */ + dst_addr = &(netif->gw); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + } +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t etharp_cached_entry = *(netif->addr_hint); + if (etharp_cached_entry < ARP_TABLE_SIZE) { +#endif /* LWIP_NETIF_HWADDRHINT */ + if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && + (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { + /* the per-pcb-cached entry is stable and the right one! */ + ETHARP_STATS_INC(etharp.cachehit); + return etharp_output_to_arp_index(netif, q, etharp_cached_entry); + } +#if LWIP_NETIF_HWADDRHINT + } + } +#endif /* LWIP_NETIF_HWADDRHINT */ + /* Determine on destination hardware address. Broadcasts and multicasts * are special, other IP addresses are looked up in the ARP table. */ @@ -870,49 +943,20 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) dest = &mcastaddr; /* unicast destination IP address? */ } else { - /* outside local network? */ - if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && - !ip_addr_islinklocal(ipaddr)) { -#if LWIP_AUTOIP - struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + - sizeof(struct eth_hdr)); - /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with - a link-local source address must always be "directly to its destination - on the same physical link. The host MUST NOT send the packet to any - router for forwarding". */ - if (!ip_addr_islinklocal(&iphdr->src)) -#endif /* LWIP_AUTOIP */ - { - /* interface has default gateway? */ - if (!ip_addr_isany(&netif->gw)) { - /* send to hardware address of default gateway IP address */ - ipaddr = &(netif->gw); - /* no default gateway available */ - } else { - /* no route to destination error (default gateway missing) */ - return ERR_RTE; - } + s8_t i; + /* find stable entry: do this here since this is a critical path for + throughput and find_entry() is kind of slow */ + for (i = 0; i < ARP_TABLE_SIZE; i++) { + if ((arp_table[i].state >= ETHARP_STATE_STABLE) && + (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { + /* found an existing, stable entry */ + ETHARP_SET_HINT(netif, i); + return etharp_output_to_arp_index(netif, q, i); } } -#if LWIP_NETIF_HWADDRHINT - if (netif->addr_hint != NULL) { - /* per-pcb cached entry was given */ - u8_t etharp_cached_entry = *(netif->addr_hint); - if (etharp_cached_entry < ARP_TABLE_SIZE) { -#endif /* LWIP_NETIF_HWADDRHINT */ - if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) && - (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) { - /* the per-pcb-cached entry is stable and the right one! */ - ETHARP_STATS_INC(etharp.cachehit); - return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), - &arp_table[etharp_cached_entry].ethaddr); - } -#if LWIP_NETIF_HWADDRHINT - } - } -#endif /* LWIP_NETIF_HWADDRHINT */ - /* queue on destination Ethernet address belonging to ipaddr */ - return etharp_query(netif, ipaddr, q); + /* no stable entry found, use the (slower) query function: + queue on destination Ethernet address belonging to ipaddr */ + return etharp_query(netif, dst_addr, q); } /* continuation for multicast/broadcast destinations */ @@ -990,7 +1034,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) /* { i is either a STABLE or (new or existing) PENDING entry } */ LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", ((arp_table[i].state == ETHARP_STATE_PENDING) || - (arp_table[i].state == ETHARP_STATE_STABLE))); + (arp_table[i].state >= ETHARP_STATE_STABLE))); /* do we have a pending entry? or an implicit query request? */ if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { @@ -1010,7 +1054,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) /* packet given? */ LWIP_ASSERT("q != NULL", q != NULL); /* stable entry? */ - if (arp_table[i].state == ETHARP_STATE_STABLE) { + if (arp_table[i].state >= ETHARP_STATE_STABLE) { /* we have a valid IP->Ethernet address mapping */ ETHARP_SET_HINT(netif, i); /* send the packet */ @@ -1128,6 +1172,8 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const u8_t * ethdst_hwaddr; #endif /* LWIP_AUTOIP */ + LWIP_ASSERT("netif != NULL", netif != NULL); + /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM); /* could allocate a pbuf for an ARP request? */ From 206b1f4631cc9b01295d9194b4a31b559440dbad Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 20:40:30 +0200 Subject: [PATCH 053/151] ETHARP_SUPPORT_STATIC_ENTRIES: don't need the member 'static_entry' on struct etharp_entry, we can use 'state' to mark them as static --- src/netif/etharp.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 58476315..8f2b9625 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -93,6 +93,9 @@ enum etharp_state { ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, ETHARP_STATE_STABLE_REREQUESTING +#if ETHARP_SUPPORT_STATIC_ENTRIES + ,ETHARP_STATE_STATIC +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ }; struct etharp_entry { @@ -108,9 +111,6 @@ struct etharp_entry { struct eth_addr ethaddr; u8_t state; u8_t ctime; -#if ETHARP_SUPPORT_STATIC_ENTRIES - u8_t static_entry; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ }; static struct etharp_entry arp_table[ARP_TABLE_SIZE]; @@ -123,7 +123,9 @@ static u8_t etharp_cached_entry; the cache (even if this means removing an active entry or so). */ #define ETHARP_FLAG_TRY_HARD 1 #define ETHARP_FLAG_FIND_ONLY 2 +#if ETHARP_SUPPORT_STATIC_ENTRIES #define ETHARP_FLAG_STATIC_ENTRY 4 +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ #if LWIP_NETIF_HWADDRHINT #define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ @@ -183,9 +185,6 @@ free_entry(int i) } /* recycle entry for re-use */ arp_table[i].state = ETHARP_STATE_EMPTY; -#if ETHARP_SUPPORT_STATIC_ENTRIES - arp_table[i].static_entry = 0; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ #ifdef LWIP_DEBUG /* for debugging, clean out the complete entry */ arp_table[i].ctime = 0; @@ -212,7 +211,7 @@ etharp_tmr(void) u8_t state = arp_table[i].state; if (state != ETHARP_STATE_EMPTY #if ETHARP_SUPPORT_STATIC_ENTRIES - && (arp_table[i].static_entry == 0) + && (state != ETHARP_STATE_STATIC) #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ ) { arp_table[i].ctime++; @@ -324,7 +323,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) } else if (state >= ETHARP_STATE_STABLE) { #if ETHARP_SUPPORT_STATIC_ENTRIES /* don't record old_stable for static entries since they never expire */ - if (arp_table[i].static_entry == 0) + if (state < ETHARP_STATE_STATIC) #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ { /* remember entry with oldest stable entry in oldest, its age in maxtime */ @@ -398,9 +397,6 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) ip_addr_copy(arp_table[i].ipaddr, *ipaddr); } arp_table[i].ctime = 0; -#if ETHARP_SUPPORT_STATIC_ENTRIES - arp_table[i].static_entry = 0; -#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ return (err_t)i; } @@ -473,12 +469,13 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd #if ETHARP_SUPPORT_STATIC_ENTRIES if (flags & ETHARP_FLAG_STATIC_ENTRY) { /* record static type */ - arp_table[i].static_entry = 1; - } + arp_table[i].state = ETHARP_STATE_STATIC; + } else #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ - - /* mark it stable */ - arp_table[i].state = ETHARP_STATE_STABLE; + { + /* mark it stable */ + arp_table[i].state = ETHARP_STATE_STABLE; + } /* record network interface */ arp_table[i].netif = netif; @@ -563,8 +560,7 @@ etharp_remove_static_entry(ip_addr_t *ipaddr) return (err_t)i; } - if ((arp_table[i].state < ETHARP_STATE_STABLE) || - (arp_table[i].static_entry == 0)) { + if (arp_table[i].state != ETHARP_STATE_STATIC) { /* entry wasn't a static entry, cannot remove it */ return ERR_ARG; } From 2694a409c65762b53e10f14e58f34cfaf016ec97 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 20:47:29 +0200 Subject: [PATCH 054/151] ETHARP_STATE_STABLE_REREQUESTING: no need for member 'netif' in 'struct etharp_entry' if we re-request only from etharp_output() and use etharp_tmr() to reset the state of such entries to ETHARP_STATE_STABLE: that way, we also only send one ARP request per ARP_TMR_INTERVAL, but only if the entry is really still used. --- src/netif/etharp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 8f2b9625..96d7bb91 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -107,7 +107,9 @@ struct etharp_entry { struct pbuf *q; #endif /* ARP_QUEUEING */ ip_addr_t ipaddr; +#if LWIP_SNMP struct netif *netif; +#endif /* LWIP_SNMP */ struct eth_addr ethaddr; u8_t state; u8_t ctime; @@ -183,12 +185,14 @@ free_entry(int i) free_etharp_q(arp_table[i].q); arp_table[i].q = NULL; } - /* recycle entry for re-use */ + /* recycle entry for re-use */ arp_table[i].state = ETHARP_STATE_EMPTY; #ifdef LWIP_DEBUG /* for debugging, clean out the complete entry */ arp_table[i].ctime = 0; +#if LWIP_SNMP arp_table[i].netif = NULL; +#endif /* LWIP_SNMP */ ip_addr_set_zero(&arp_table[i].ipaddr); arp_table[i].ethaddr = ethzero; #endif /* LWIP_DEBUG */ @@ -224,11 +228,10 @@ etharp_tmr(void) /* clean up entries that have just been expired */ free_entry(i); } - else if ((arp_table[i].ctime >= ARP_AGE_REREQUEST_USED) && - (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING)) { - /* stable entry that is in use is about to expire: re-request it to - prevent it from breaking communication when it expires */ - etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); + else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { + /* Reset state to stable, so that the next transmitted packet will + re-send an ARP request. */ + arp_table[i].state = ETHARP_STATE_STABLE; } #if ARP_QUEUEING /* still pending entry? (not expired) */ @@ -478,7 +481,9 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd } /* record network interface */ +#if LWIP_SNMP arp_table[i].netif = netif; +#endif /* LWIP_SNMP */ /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); From 860072aaaf17252a3489431d08170b2b25074358 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 21:16:04 +0200 Subject: [PATCH 055/151] correctly prefix all functions with 'etharp_' (also static functions) --- src/netif/etharp.c | 56 ++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 96d7bb91..004d2274 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -136,8 +136,6 @@ static u8_t etharp_cached_entry; #define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) #endif /* LWIP_NETIF_HWADDRHINT */ -static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags); - /* Some checks, instead of etharp_init(): */ #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) @@ -174,14 +172,14 @@ free_etharp_q(struct etharp_q_entry *q) /** Clean up ARP table entries */ static void -free_entry(int i) +etharp_free_entry(int i) { /* remove from SNMP ARP index tree */ snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); /* and empty packet queue */ if (arp_table[i].q != NULL) { /* remove all queued packets */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); free_etharp_q(arp_table[i].q); arp_table[i].q = NULL; } @@ -226,7 +224,7 @@ etharp_tmr(void) LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); /* clean up entries that have just been expired */ - free_entry(i); + etharp_free_entry(i); } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { /* Reset state to stable, so that the next transmitted packet will @@ -265,7 +263,7 @@ etharp_tmr(void) * entry is found or could be recycled. */ static s8_t -find_entry(ip_addr_t *ipaddr, u8_t flags) +etharp_find_entry(ip_addr_t *ipaddr, u8_t flags) { s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; s8_t empty = ARP_TABLE_SIZE; @@ -294,7 +292,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) u8_t state = arp_table[i].state; /* no empty entry found yet and now we do find one? */ if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { - LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); /* remember first empty entry */ empty = i; } else if (state != ETHARP_STATE_EMPTY) { @@ -302,7 +300,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ return i; } @@ -344,7 +342,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || /* or no empty entry found and not allowed to recycle? */ ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); return (s8_t)ERR_MEM; } @@ -360,34 +358,34 @@ find_entry(ip_addr_t *ipaddr, u8_t flags) /* 1) empty entry available? */ if (empty < ARP_TABLE_SIZE) { i = empty; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); } else { /* 2) found recyclable stable entry? */ if (old_stable < ARP_TABLE_SIZE) { /* recycle oldest stable*/ i = old_stable; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); /* no queued packets should exist on stable entries */ LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); /* 3) found recyclable pending entry without queued packets? */ } else if (old_pending < ARP_TABLE_SIZE) { /* recycle oldest pending */ i = old_pending; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); /* 4) found recyclable pending entry with queued packets? */ } else if (old_queue < ARP_TABLE_SIZE) { - /* recycle oldest pending (queued packets are free in free_entry) */ + /* recycle oldest pending (queued packets are free in etharp_free_entry) */ i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); /* no empty or recyclable entries found */ } else { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n")); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); return (s8_t)ERR_MEM; } /* { empty or recyclable entry found } */ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - free_entry(i); + etharp_free_entry(i); } LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); @@ -447,11 +445,11 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct * @see pbuf_free() */ static err_t -update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) +etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) { s8_t i; LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); @@ -459,11 +457,11 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } /* find or create ARP entry */ - i = find_entry(ipaddr, flags); + i = etharp_find_entry(ipaddr, flags); /* bail out if no entry could be found */ if (i < 0) { return (err_t)i; @@ -487,7 +485,7 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); /* update address */ ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); /* reset time stamp */ @@ -540,7 +538,7 @@ etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) return ERR_RTE; } - return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); + return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); } /** Remove a static entry from the ARP table previously added with a call to @@ -559,7 +557,7 @@ etharp_remove_static_entry(ip_addr_t *ipaddr) ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); /* find or create ARP entry */ - i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); /* bail out if no entry could be found */ if (i < 0) { return (err_t)i; @@ -570,7 +568,7 @@ etharp_remove_static_entry(ip_addr_t *ipaddr) return ERR_ARG; } /* entry found, free it */ - free_entry(i); + etharp_free_entry(i); return ERR_OK; } #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ @@ -597,7 +595,7 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, LWIP_UNUSED_ARG(netif); - i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); + i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; @@ -652,7 +650,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p) /* update the source IP address in the cache, if present */ /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk * back soon (for example, if the destination IP address is ours. */ - update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); + etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); } #endif /* ETHARP_TRUST_IP_MAC */ @@ -745,7 +743,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) can result in directly sending the queued packets for this host. ARP message not directed to us? -> update the source IP address in the cache, if present */ - update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), + etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); /* now act on the message itself */ @@ -946,7 +944,7 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) } else { s8_t i; /* find stable entry: do this here since this is a critical path for - throughput and find_entry() is kind of slow */ + throughput and etharp_find_entry() is kind of slow */ for (i = 0; i < ARP_TABLE_SIZE; i++) { if ((arp_table[i].state >= ETHARP_STATE_STABLE) && (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { @@ -1015,7 +1013,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) } /* find entry in ARP cache, ask to create entry if queueing packet */ - i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); + i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); /* could not find or create entry? */ if (i < 0) { From 78ac382fdf54c865d60318ce6737322d2b05d293 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 21 Jul 2011 21:47:25 +0200 Subject: [PATCH 056/151] bug #33634 ip_forward() have a faulty behaviour: Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. Also added code to allow ip_forward() to forward non-broadcast packets to the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). --- CHANGELOG | 6 +++++ src/core/ipv4/ip4.c | 57 ++++++++++++++++++++++++++++++++++++++++- src/include/lwip/opt.h | 39 ++++++++++++++++++++++++++++ src/include/lwip/pbuf.h | 4 +++ src/netif/etharp.c | 25 +++++++++++++++--- 5 files changed, 127 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b05055e0..4c946eae 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,12 @@ HISTORY ++ New features: + 2011-07-21: Simon Goldschmidt (patch by hanhui) + * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: + Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. + Also added code to allow ip_forward() to forward non-broadcast packets to + the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). + 2011-07-21: Simon Goldschmidt * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram. diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 3ec50b66..0f7960e3 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -113,8 +113,15 @@ ip_route(ip_addr_t *dest) { struct netif *netif; +#ifdef LWIP_HOOK_IP4_ROUTE + netif = LWIP_HOOK_IP4_ROUTE(dest); + if (netif != NULL) { + return netif; + } +#endif + /* iterate through netifs */ - for(netif = netif_list; netif != NULL; netif = netif->next) { + for (netif = netif_list; netif != NULL; netif = netif->next) { /* network mask matches? */ if (netif_is_up(netif)) { if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { @@ -135,6 +142,41 @@ ip_route(ip_addr_t *dest) } #if IP_FORWARD +/** + * Determine whether an IP address is in a reserved set of addresses + * that may not be forwarded, or whether datagrams to that destination + * may be forwarded. + * @param p the packet to forward + * @param dest the destination IP address + * @return 1: can forward 0: discard + */ +static int +ip_canforward(struct pbuf *p) +{ + u32_t addr = ip4_addr_get_u32(ip_current_dest_addr()); + + if (p->flags & PBUF_FLAG_LLBCAST) { + /* don't route link-layer broadcasts */ + return 0; + } + if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) { + /* don't route link-layer multicasts unless the destination address is an IP + multicast address */ + return 0; + } + if (IP_EXPERIMENTAL(addr)) { + return 0; + } + if (IP_CLASSA(addr)) { + u32_t net = addr & IP_CLASSA_NET; + if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { + /* don't route loopback packets */ + return 0; + } + } + return 1; +} + /** * Forwards an IP packet. It finds an appropriate route for the * packet, decrements the TTL value of the packet, adjusts the @@ -151,6 +193,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) PERF_START; + if (!ip_canforward(p)) { + goto return_noroute; + } + /* RFC3927 2.7: do not forward link-local addresses */ if (ip_addr_islinklocal(ip_current_dest_addr())) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", @@ -167,12 +213,14 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); goto return_noroute; } +#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); goto return_noroute; } +#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ /* decrement TTL */ IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); @@ -252,6 +300,13 @@ ip_input(struct pbuf *p, struct netif *inp) return ERR_OK; } +#ifdef LWIP_HOOK_IP4_INPUT + if (LWIP_HOOK_IP4_INPUT(p, inp)) { + /* the packet has been eaten */ + return ERR_OK; + } +#endif + /* obtain IP header length in number of 32-bit words */ iphdr_hlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 911b6251..f4647b64 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -593,6 +593,17 @@ #define IP_SOF_BROADCAST_RECV 0 #endif +/** + * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back + * out on the netif where it was received. This should only be used for + * wireless networks. + * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming + * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! + */ +#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF +#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 +#endif + /* ---------------------------------- ---------- ICMP options ---------- @@ -2056,6 +2067,34 @@ #define LWIP_IPV6_DHCP6 0 #endif +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ + +/* Hooks are undefined by default, define them to a function if you need them. */ + +/** + * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): + * - called from ip_input() (IPv4) + * - pbuf: received struct pbuf passed to ip_input() + * - input_netif: struct netif on which the packet has been received + * Return values: + * - 0: Hook has not consumed the packet, packet is processed as normal + * - != 0: Hook has consumed the packet. + * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook + * (i.e. free it when done). + */ + +/** + * LWIP_HOOK_IP4_ROUTE(dest): + * - called from ip_route() (IPv4) + * - dest: destination IPv4 address + * Returns the destination netif or NULL if no destination netif is found. In + * that case, ip_route() continues as normal. + */ + /* --------------------------------------- ---------- Debugging options ---------- diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 53fdc69b..50407e90 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -76,6 +76,10 @@ typedef enum { #define PBUF_FLAG_IS_CUSTOM 0x02U /** indicates this pbuf is UDP multicast to be looped back */ #define PBUF_FLAG_MCASTLOOP 0x04U +/** indicates this pbuf was received as link-level broadcast */ +#define PBUF_FLAG_LLBCAST 0x08U +/** indicates this pbuf was received as link-level multicast */ +#define PBUF_FLAG_LLMCAST 0x10U struct pbuf { /** next pbuf in singly linked pbuf chain */ diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 004d2274..f2b87e27 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -66,6 +66,11 @@ const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; const struct eth_addr ethzero = {{0,0,0,0,0,0}}; +/** The 24-bit IANA multicast OUI is 01-00-5e: */ +#define LL_MULTICAST_ADDR_0 0x01 +#define LL_MULTICAST_ADDR_1 0x00 +#define LL_MULTICAST_ADDR_2 0x5e + #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** the time an ARP entry stays valid after its last update, @@ -932,9 +937,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) /* multicast destination IP address? */ } else if (ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address.*/ - mcastaddr.addr[0] = 0x01; - mcastaddr.addr[1] = 0x00; - mcastaddr.addr[2] = 0x5e; + mcastaddr.addr[0] = LL_MULTICAST_ADDR_0; + mcastaddr.addr[1] = LL_MULTICAST_ADDR_1; + mcastaddr.addr[2] = LL_MULTICAST_ADDR_2; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); @@ -1308,6 +1313,20 @@ ethernet_input(struct pbuf *p, struct netif *netif) netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ + if (ethhdr->dest.addr[0] & 1) { + /* this might be a multicast or broadcast packet */ + if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) { + if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) && + (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) { + /* mark the pbuf as link-layer multicast */ + p->flags |= PBUF_FLAG_LLMCAST; + } + } else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { + /* mark the pbuf as link-layer broadcast */ + p->flags |= PBUF_FLAG_LLBCAST; + } + } + switch (type) { #if LWIP_ARP /* IP packet? */ From cc3b4dff20205288c76b11c27ad1e3f287e3f721 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 22 Jul 2011 21:05:10 +0200 Subject: [PATCH 057/151] freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level. --- src/core/pbuf.c | 62 ++++++++++++++++++++++++++--------------- src/core/timers.c | 4 +++ src/include/lwip/pbuf.h | 18 ++++++++++++ 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 4649fb87..285b1508 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -84,18 +84,25 @@ aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) -#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ #define PBUF_POOL_IS_EMPTY() -#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ -/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ -#ifndef PBUF_POOL_FREE_OOSEQ -#define PBUF_POOL_FREE_OOSEQ 1 -#endif /* PBUF_POOL_FREE_OOSEQ */ +#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ -#if PBUF_POOL_FREE_OOSEQ +#if !NO_SYS +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL #include "lwip/tcpip.h" +#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ + if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \ + SYS_ARCH_PROTECT(old_level); \ + pbuf_free_ooseq_pending = 0; \ + SYS_ARCH_UNPROTECT(old_level); \ + } } while(0) +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ +#endif /* !NO_SYS */ + +volatile u8_t pbuf_free_ooseq_pending; #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() -static u8_t pbuf_free_ooseq_queued; + /** * Attempt to reclaim some memory from queued out-of-sequence TCP segments * if we run out of pool pbufs. It's better to give priority to new packets @@ -104,15 +111,14 @@ static u8_t pbuf_free_ooseq_queued; * This must be done in the correct thread context therefore this function * can only be used with NO_SYS=0 and through tcpip_callback. */ -static void -pbuf_free_ooseq(void* arg) +void +pbuf_free_ooseq() { struct tcp_pcb* pcb; SYS_ARCH_DECL_PROTECT(old_level); - LWIP_UNUSED_ARG(arg); SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_queued = 0; + pbuf_free_ooseq_pending = 0; SYS_ARCH_UNPROTECT(old_level); for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { @@ -126,29 +132,39 @@ pbuf_free_ooseq(void* arg) } } +/** + * Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq(). + */ +static void +pbuf_free_ooseq_callback(void *arg) +{ + LWIP_UNUSED_ARG(arg); + pbuf_free_ooseq(); +} + /** Queue a call to pbuf_free_ooseq if not already queued. */ static void pbuf_pool_is_empty(void) { - u8_t queued; SYS_ARCH_DECL_PROTECT(old_level); - +#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL SYS_ARCH_PROTECT(old_level); - queued = pbuf_free_ooseq_queued; - pbuf_free_ooseq_queued = 1; + pbuf_free_ooseq_pending = 1; + SYS_ARCH_UNPROTECT(old_level); +#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ + u8_t queued; + SYS_ARCH_PROTECT(old_level); + queued = pbuf_free_ooseq_pending; + pbuf_free_ooseq_pending = 1; SYS_ARCH_UNPROTECT(old_level); if(!queued) { /* queue a call to pbuf_free_ooseq if not already queued */ - if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) { - SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_queued = 0; - SYS_ARCH_UNPROTECT(old_level); - } + PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); } +#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ } -#endif /* PBUF_POOL_FREE_OOSEQ */ -#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ +#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ /** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). diff --git a/src/core/timers.c b/src/core/timers.c index c804c3d1..3c4f8d1d 100644 --- a/src/core/timers.c +++ b/src/core/timers.c @@ -60,6 +60,7 @@ #include "lwip/ip6_frag.h" #include "lwip/mld6.h" #include "lwip/sys.h" +#include "lwip/pbuf.h" /** The one and only timeout list */ static struct sys_timeo *next_timeout; @@ -428,6 +429,9 @@ sys_check_timeouts(void) diff = LWIP_U32_DIFF(now, timeouts_last_time); do { +#if PBUF_POOL_FREE_OOSEQ + PBUF_CHECK_FREE_OOSEQ(); +#endif /* PBUF_POOL_FREE_OOSEQ */ had_one = 0; tmptimeout = next_timeout; if (tmptimeout->time <= diff) { diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 50407e90..41c49099 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -127,6 +127,24 @@ struct pbuf_custom { }; #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ +#if LWIP_TCP && TCP_QUEUE_OOSEQ +/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ +#ifndef PBUF_POOL_FREE_OOSEQ +#define PBUF_POOL_FREE_OOSEQ 1 +#endif /* PBUF_POOL_FREE_OOSEQ */ +#if NO_SYS && PBUF_POOL_FREE_OOSEQ +extern volatile u8_t pbuf_free_ooseq_pending; +void pbuf_free_ooseq(); +/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level to check if ooseq pbufs need to be + freed! */ +#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ + /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ + ooseq queued pbufs now */ \ + pbuf_free_ooseq(); }}while(0) +#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/ +#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */ + /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ #define pbuf_init() From d94bdb75c897a3d80a8f10406164fc9147c2068c Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 22 Jul 2011 21:07:09 +0200 Subject: [PATCH 058/151] forgot CHANGELOG: freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level. --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4c946eae..0ec0df34 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,6 +37,11 @@ HISTORY ++ Bugfixes: + 2011-07-22: Simon Goldschmidt + * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented + for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() + at regular intervals from main level. + 2011-07-21: Simon Goldschmidt * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by sending an ARP request when an ARP entry is used in the last minute before From 6323e09a0a52a4e550c39bc8d61a2c825bf7ebf7 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 22 Jul 2011 21:59:16 +0200 Subject: [PATCH 059/151] init.c: changed some checks from runtime to compiletime (had to adapt some defines in ip.h for that) --- src/core/init.c | 40 +++++++++++++++++++++++++++------------- src/include/lwip/ip.h | 20 ++++++++++---------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/core/init.c b/src/core/init.c index da118ed8..3d8e2bb6 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -59,6 +59,7 @@ #include "lwip/ip6.h" #include "lwip/nd6.h" #include "lwip/mld6.h" +#include "lwip/api.h" /* Compile-time sanity checks for configuration errors. * These can be done independently of LWIP_DEBUG, without penalty. @@ -190,6 +191,32 @@ #if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" #endif +#if LWIP_NETCONN && LWIP_TCP +#if NETCONN_COPY != TCP_WRITE_FLAG_COPY + #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" +#endif +#if NETCONN_MORE != TCP_WRITE_FLAG_MORE + #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" +#endif +#endif /* LWIP_NETCONN && LWIP_TCP */ +#if LWIP_SOCKET +/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ +#if SO_ACCEPTCONN != SOF_ACCEPTCONN + #error "SO_ACCEPTCONN != SOF_ACCEPTCONN" +#endif +#if SO_REUSEADDR != SOF_REUSEADDR + #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" +#endif +#if SO_KEEPALIVE != SOF_KEEPALIVE + #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" +#endif +#if SO_BROADCAST != SOF_BROADCAST + #error "WARNING: SO_BROADCAST != SOF_BROADCAST" +#endif +#if SO_LINGER != SOF_LINGER + #error "WARNING: SO_LINGER != SOF_LINGER" +#endif +#endif /* LWIP_SOCKET */ /* Compile-time checks for deprecated options. @@ -238,19 +265,6 @@ lwip_sanity_check(void) if (TCP_WND < TCP_MSS) LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); #endif /* LWIP_TCP */ -#if LWIP_SOCKET - /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ - if (SO_ACCEPTCONN != SOF_ACCEPTCONN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n")); - if (SO_REUSEADDR != SOF_REUSEADDR) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n")); - if (SO_KEEPALIVE != SOF_KEEPALIVE) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n")); - if (SO_BROADCAST != SOF_BROADCAST) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n")); - if (SO_LINGER != SOF_LINGER) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n")); -#endif /* LWIP_SOCKET */ } #else /* LWIP_DEBUG */ #define lwip_sanity_check() diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index f29ebf67..6de95b18 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -100,16 +100,16 @@ struct ip_pcb { /* * Option flags per-socket. These are the same like SO_XXX. */ -/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ -#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ -#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ -#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ -/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ -#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ -#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ -/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ -/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ +/*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */ +#define SOF_REUSEADDR 0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE 0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER 0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */ /* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ #define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) From 46af0d38fa7b0f9c85322077b30133d5c3d00372 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 22 Jul 2011 22:05:24 +0200 Subject: [PATCH 060/151] fixed bug #31084 (socket API returns always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now lwip_send() sends as much as possible for non-blocking sockets and only returns EWOULDBLOCK if the buffers are full --- CHANGELOG | 5 +++ src/api/api_lib.c | 23 +++++++++-- src/api/api_msg.c | 94 +++++++++++++++++++++--------------------- src/api/sockets.c | 16 +++---- src/include/lwip/api.h | 6 ++- 5 files changed, 81 insertions(+), 63 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0ec0df34..42cf341a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,6 +37,11 @@ HISTORY ++ Bugfixes: + 2011-07-22: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns + always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now + lwip_send() sends as much as possible for non-blocking sockets + 2011-07-22: Simon Goldschmidt * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 6434dbe4..f7375b0f 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -582,22 +582,30 @@ netconn_send(struct netconn *conn, struct netbuf *buf) * - NETCONN_COPY: data will be copied into memory belonging to the stack * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once + * @param bytes_written pointer to a location that receives the number of written bytes * @return ERR_OK if data was sent, any other err_t on error */ err_t -netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) +netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written) { struct api_msg msg; err_t err; + u8_t dontblock; LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); if (size == 0) { return ERR_OK; } + dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); + if (dontblock && !bytes_written) { + /* This implies netconn_write() cannot be used for non-blocking send, since + it has no way to return the number of bytes written. */ + return ERR_VAL; + } - /* @todo: for non-blocking write, check if 'size' would ever fit into - snd_queue or snd_buf */ + /* non-blocking write sends as much */ msg.function = do_write; msg.msg.conn = conn; msg.msg.msg.w.dataptr = dataptr; @@ -607,6 +615,15 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl but if it is, this is done inside api_msg.c:do_write(), so we can use the non-blocking version here. */ err = TCPIP_APIMSG(&msg); + if ((err == ERR_OK) && (bytes_written != NULL)) { + if (dontblock) { + /* nonblocking write: maybe the data has been sent partly */ + *bytes_written = msg.msg.msg.w.len; + } else { + /* blocking call succeeded: all data has been sent if it */ + *bytes_written = size; + } + } NETCONN_SET_SAFE_ERR(conn, err); return err; diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 3d3eed10..9d0895ac 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1198,7 +1198,7 @@ do_recv(struct api_msg_msg *msg) static err_t do_writemore(struct netconn *conn) { - err_t err = ERR_OK; + err_t err; void *dataptr; u16_t len, available; u8_t write_finished = 0; @@ -1229,62 +1229,62 @@ do_writemore(struct netconn *conn) if (available < len) { /* don't try to write more than sendbuf */ len = available; + if (dontblock){ + if (!len) { + err = ERR_WOULDBLOCK; + goto err_mem; + } + } else { #if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif - apiflags |= TCP_WRITE_FLAG_MORE; + apiflags |= TCP_WRITE_FLAG_MORE; + } } - if (dontblock && (len < conn->current_msg->msg.w.len)) { - /* failed to send all data at once -> nonblocking write not possible */ - err = ERR_MEM; - } - if (err == ERR_OK) { - LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); - } - if (dontblock && (err == ERR_MEM)) { - /* nonblocking write failed */ - write_finished = 1; - err = ERR_WOULDBLOCK; - /* let poll_tcp check writable space to mark the pcb - writable again */ - conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - /* let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - } else { - /* if OK or memory error, check available space */ - if (((err == ERR_OK) || (err == ERR_MEM)) && - ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { + LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + /* if OK or memory error, check available space */ + if ((err == ERR_OK) || (err == ERR_MEM)) { +err_mem: + if (dontblock && (len < conn->current_msg->msg.w.len)) { + /* non-blocking write did not write everything: mark the pcb non-writable + and let poll_tcp check writable space to mark the pcb writable again */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { /* The queued byte- or pbuf-count exceeds the configured low-water limit, let select mark this pcb as non-writable. */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); } + } - if (err == ERR_OK) { - conn->write_offset += len; - if (conn->write_offset == conn->current_msg->msg.w.len) { - /* everything was written */ - write_finished = 1; - conn->write_offset = 0; - } - tcp_output(conn->pcb.tcp); - } else if (err == ERR_MEM) { - /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called - we do NOT return to the application thread, since ERR_MEM is - only a temporary error! */ - - /* tcp_write returned ERR_MEM, try tcp_output anyway */ - tcp_output(conn->pcb.tcp); - - #if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; - #endif - } else { - /* On errors != ERR_MEM, we don't try writing any more but return - the error to the application thread. */ + if (err == ERR_OK) { + conn->write_offset += len; + if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { + /* return sent length */ + conn->current_msg->msg.w.len = conn->write_offset; + /* everything was written */ write_finished = 1; + conn->write_offset = 0; } + tcp_output(conn->pcb.tcp); + } else if ((err == ERR_MEM) && !dontblock) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called + we do NOT return to the application thread, since ERR_MEM is + only a temporary error! */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + tcp_output(conn->pcb.tcp); + +#if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; +#endif + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + conn->current_msg->msg.w.len = 0; } if (write_finished) { diff --git a/src/api/sockets.c b/src/api/sockets.c index ba68e726..e3e01ca4 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -805,6 +805,7 @@ lwip_send(int s, const void *data, size_t size, int flags) struct lwip_sock *sock; err_t err; u8_t write_flags; + size_t written; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", s, data, size, flags)); @@ -823,22 +824,15 @@ lwip_send(int s, const void *data, size_t size, int flags) #endif /* (LWIP_UDP || LWIP_RAW) */ } - if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) { - if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) { - /* too much data to ever send nonblocking! */ - sock_set_errno(sock, EMSGSIZE); - return -1; - } - } - write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); - err = netconn_write(sock->conn, data, size, write_flags); + written = 0; + err = netconn_write_partly(sock->conn, data, size, write_flags, &written); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); sock_set_errno(sock, err_to_errno(err)); - return (err == ERR_OK ? (int)size : -1); + return (err == ERR_OK ? (int)written : -1); } int diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 71988108..5b0486c4 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -250,8 +250,10 @@ void netconn_recved(struct netconn *conn, u32_t length); err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port); err_t netconn_send(struct netconn *conn, struct netbuf *buf); -err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, - u8_t apiflags); +err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags, size_t *bytes_written); +#define netconn_write(conn, dataptr, size, apiflags) \ + netconn_write_partly(conn, dataptr, size, apiflags, NULL) err_t netconn_close(struct netconn *conn); err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); From d79c5baa1bb80adcb1e106cbbd9c1308caf8c4bf Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 24 Jul 2011 17:18:55 +0200 Subject: [PATCH 061/151] Removed commas from the end of enum lists --- src/include/ipv6/lwip/icmp6.h | 2 +- src/include/lwip/api.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/include/ipv6/lwip/icmp6.h b/src/include/ipv6/lwip/icmp6.h index c552e339..74bfdbe0 100644 --- a/src/include/ipv6/lwip/icmp6.h +++ b/src/include/ipv6/lwip/icmp6.h @@ -96,7 +96,7 @@ enum icmp6_te_code { enum icmp6_pp_code { ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */ ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */ - ICMP6_PP_OPTION = 2, /* Unrecognized IPv6 option encountered */ + ICMP6_PP_OPTION = 2 /* Unrecognized IPv6 option encountered */ }; /** This is the standard ICMP6 header. */ diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 5b0486c4..326528a2 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -106,9 +106,10 @@ enum netconn_type { NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, #endif /* LWIP_IPV6 */ /* NETCONN_RAW Group */ - NETCONN_RAW = 0x40, + NETCONN_RAW = 0x40 #if LWIP_IPV6 - NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */, + , + NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ #endif /* LWIP_IPV6 */ }; From 7465be91d0b1c3104a08291d74bbfce1178bb1d6 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 24 Jul 2011 17:19:17 +0200 Subject: [PATCH 062/151] Fixed some C compiler warnings --- src/core/pbuf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 285b1508..b95cf021 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -112,7 +112,7 @@ volatile u8_t pbuf_free_ooseq_pending; * can only be used with NO_SYS=0 and through tcpip_callback. */ void -pbuf_free_ooseq() +pbuf_free_ooseq(void) { struct tcp_pcb* pcb; SYS_ARCH_DECL_PROTECT(old_level); @@ -132,6 +132,7 @@ pbuf_free_ooseq() } } +#if !NO_SYS /** * Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq(). */ @@ -141,18 +142,20 @@ pbuf_free_ooseq_callback(void *arg) LWIP_UNUSED_ARG(arg); pbuf_free_ooseq(); } +#endif /* !NO_SYS */ /** Queue a call to pbuf_free_ooseq if not already queued. */ static void pbuf_pool_is_empty(void) { - SYS_ARCH_DECL_PROTECT(old_level); #ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL + SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); pbuf_free_ooseq_pending = 1; SYS_ARCH_UNPROTECT(old_level); #else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ u8_t queued; + SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); queued = pbuf_free_ooseq_pending; pbuf_free_ooseq_pending = 1; From a745528b4047946eee892c63a9d11dcf344eee7f Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 26 Jul 2011 20:21:33 +0200 Subject: [PATCH 063/151] Prevent non-static function that is not declared in header file --- src/core/pbuf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/pbuf.c b/src/core/pbuf.c index b95cf021..6c45dbf2 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -111,6 +111,9 @@ volatile u8_t pbuf_free_ooseq_pending; * This must be done in the correct thread context therefore this function * can only be used with NO_SYS=0 and through tcpip_callback. */ +#if !NO_SYS +static +#endif /* !NO_SYS */ void pbuf_free_ooseq(void) { From 41c785d77affca79c7d89cd7ecd7d00ab219cc41 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 26 Jul 2011 20:55:32 +0200 Subject: [PATCH 064/151] IPv4: splitted IPv4 header fields version/len and tos, made macros depend on BYTE_ORDER to prevent unnecessary calls to htons() --- src/core/ipv4/ip4.c | 5 +++-- src/include/ipv4/lwip/ip4.h | 24 ++++++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 0f7960e3..8cbaa23f 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -705,9 +705,10 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; #endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); + IPH_VHL_SET(iphdr, 4, ip_hlen / 4); + IPH_TOS_SET(iphdr, tos); #if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_v_hl_tos; + chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl); #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_LEN_SET(iphdr, htons(p->tot_len)); #if CHECKSUM_GEN_IP_INLINE diff --git a/src/include/ipv4/lwip/ip4.h b/src/include/ipv4/lwip/ip4.h index 0d3c70b6..64c9b4d7 100644 --- a/src/include/ipv4/lwip/ip4.h +++ b/src/include/ipv4/lwip/ip4.h @@ -62,8 +62,10 @@ extern "C" { #endif PACK_STRUCT_BEGIN struct ip_hdr { - /* version / header length / type of service */ - PACK_STRUCT_FIELD(u16_t _v_hl_tos); + /* version / header length */ + PACK_STRUCT_FIELD(u8_t _v_hl); + /* type of service */ + PACK_STRUCT_FIELD(u8_t _tos); /* total length */ PACK_STRUCT_FIELD(u16_t _len); /* identification */ @@ -89,9 +91,14 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif -#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12) -#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) -#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#if BYTE_ORDER == LITTLE_ENDIAN +#define IPH_V(hdr) ((hdr)->_v_hl >> 4) +#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) +#else /* BYTE_ORDER == LITTLE_ENDIAN */ +#define IPH_V(hdr) ((hdr)->_v_hl & 0x0f) +#define IPH_HL(hdr) ((hdr)->_v_hl >> 4) +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +#define IPH_TOS(hdr) ((hdr)->_tos) #define IPH_LEN(hdr) ((hdr)->_len) #define IPH_ID(hdr) ((hdr)->_id) #define IPH_OFFSET(hdr) ((hdr)->_offset) @@ -99,7 +106,12 @@ PACK_STRUCT_END #define IPH_PROTO(hdr) ((hdr)->_proto) #define IPH_CHKSUM(hdr) ((hdr)->_chksum) -#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#if BYTE_ORDER == LITTLE_ENDIAN +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl)) +#else /* BYTE_ORDER == LITTLE_ENDIAN */ +#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = ((v) | ((hl) << 4)) +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) #define IPH_ID_SET(hdr, id) (hdr)->_id = (id) #define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) From 242dc34115143b502e9165ecf337c90bd62e2a87 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 26 Jul 2011 21:03:27 +0200 Subject: [PATCH 065/151] ETHARP_SUPPORT_VLAN: add support for an external VLAN filter function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) --- CHANGELOG | 4 ++++ src/include/lwip/opt.h | 2 ++ src/netif/etharp.c | 8 ++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 42cf341a..e31b2985 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-08-26: Simon Goldschmidt + * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter + function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) + 2011-07-21: Simon Goldschmidt (patch by hanhui) * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index f4647b64..8ae6ba4d 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -461,6 +461,8 @@ * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. + * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) + * that returns 1 to accept a packet or 0 to drop a packet. */ #ifndef ETHARP_SUPPORT_VLAN #define ETHARP_SUPPORT_VLAN 0 diff --git a/src/netif/etharp.c b/src/netif/etharp.c index f2b87e27..8b333dd9 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -1297,13 +1297,17 @@ ethernet_input(struct pbuf *p, struct netif *netif) ETHARP_STATS_INC(etharp.drop); goto free_and_return; } -#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ +#if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ +#ifdef ETHARP_VLAN_CHECK_FN + if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { +#elif defined(ETHARP_VLAN_CHECK) if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { +#endif /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } -#endif /* ETHARP_VLAN_CHECK */ +#endif /* defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ type = vlan->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } From c9e1d6cca847d63e6fab286f3d9ca7512c6221fc Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 26 Jul 2011 21:55:32 +0200 Subject: [PATCH 066/151] adapted unit tests to changes after adding IPv6 support --- test/unit/tcp/tcp_helper.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/test/unit/tcp/tcp_helper.c b/test/unit/tcp/tcp_helper.c index 01bdf958..5aee8319 100644 --- a/test/unit/tcp/tcp_helper.c +++ b/test/unit/tcp/tcp_helper.c @@ -69,7 +69,8 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, /* fill IP header */ iphdr->dest.addr = dst_ip->addr; iphdr->src.addr = src_ip->addr; - IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0); + IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); + IPH_TOS_SET(iphdr, 0); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); @@ -89,8 +90,8 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, /* calculate checksum */ - tcphdr->chksum = inet_chksum_pseudo(p, src_ip, dst_ip, - IP_PROTO_TCP, p->tot_len); + tcphdr->chksum = inet_chksum_pseudo(p, + IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); pbuf_header(p, sizeof(struct ip_hdr)); @@ -200,17 +201,18 @@ test_tcp_new_counters_pcb(struct test_tcp_counters* counters) void test_tcp_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; - ip_addr_copy(current_iphdr_dest, iphdr->dest); - ip_addr_copy(current_iphdr_src, iphdr->src); - current_netif = inp; - current_header = iphdr; + /* these lines are a hack, don't use them as an example :-) */ + ip_addr_copy(*ipX_current_dest_addr(), iphdr->dest); + ip_addr_copy(*ipX_current_src_addr(), iphdr->src); + ip_current_netif() = inp; + ip_current_header() = iphdr; tcp_input(p, inp); - current_iphdr_dest.addr = 0; - current_iphdr_src.addr = 0; - current_netif = NULL; - current_header = NULL; + ipX_current_dest_addr()->addr = 0; + ipX_current_src_addr()->addr = 0; + ip_current_netif() = NULL; + ip_current_header() = NULL; } static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, From f4c0018d7a515ac1d3241d7fad5e4e10b96ccf46 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 28 Jul 2011 21:59:28 +0200 Subject: [PATCH 067/151] Fixed complier error for CHECKSUM_CHECK_TCP==0 --- src/core/tcp_in.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index aeac353e..316dc3d9 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -104,7 +104,9 @@ tcp_input(struct pbuf *p, struct netif *inp) #endif /* SO_REUSE */ u8_t hdrlen; err_t err; +#if CHECKSUM_CHECK_TCP u16_t chksum; +#endif /* CHECKSUM_CHECK_TCP */ PERF_START; From 45070831485eb533ae577af452a389c5aa440bbc Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Thu, 4 Aug 2011 14:18:33 -0600 Subject: [PATCH 068/151] Fixed bug in serialization of IPv6 addresses. Change-Id: Ib63540123803317ec25f7cbf580c5159e4100222 --- src/core/ipv6/ip6_addr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 3b682051..6c047491 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -208,6 +208,7 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) } else { buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); + zero_flag = 0; if (i >= buflen) return NULL; } @@ -216,6 +217,7 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) } else { buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); + zero_flag = 0; if (i >= buflen) return NULL; } @@ -224,6 +226,7 @@ ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) } else { buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); + zero_flag = 0; if (i >= buflen) return NULL; } From b3f5c8f6b2e4964a3db1e186d7d804f7bbbf4eb8 Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Thu, 4 Aug 2011 16:36:44 -0600 Subject: [PATCH 069/151] Use target address as source address in IPv6 neighbour advertisement messages. Change-Id: I06d28eb2903c539de0b51bd7420a81ebf4f28963 --- src/core/ipv6/nd6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 772e239c..c7402c62 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -851,7 +851,9 @@ nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) ip6_addr_t * dest_addr; /* Use link-local address as source address. */ - src_addr = &(netif->ip6_addr[0]); + /* src_addr = &(netif->ip6_addr[0]); */ + /* Use target address as source address. */ + src_addr = target_addr; /* Allocate a packet. */ p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + sizeof(struct lladdr_option), PBUF_RAM); From 17efa04ea686f81ebdbf51363bdec5886e03a51c Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Tue, 9 Aug 2011 13:55:40 -0600 Subject: [PATCH 070/151] Add cast to IP6_ADDR_BLOCKx --- src/include/ipv6/lwip/ip6_addr.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/include/ipv6/lwip/ip6_addr.h b/src/include/ipv6/lwip/ip6_addr.h index c962c769..68e93e06 100644 --- a/src/include/ipv6/lwip/ip6_addr.h +++ b/src/include/ipv6/lwip/ip6_addr.h @@ -105,14 +105,14 @@ Little-endian version, stored in network order (no htonl). */ #endif /** Access address in 16-bit block */ -#define IP6_ADDR_BLOCK1(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xffff) -#define IP6_ADDR_BLOCK2(ip6addr) ((htonl((ip6addr)->addr[0])) & 0xffff) -#define IP6_ADDR_BLOCK3(ip6addr) ((htonl((ip6addr)->addr[1]) >> 16) & 0xffff) -#define IP6_ADDR_BLOCK4(ip6addr) ((htonl((ip6addr)->addr[1])) & 0xffff) -#define IP6_ADDR_BLOCK5(ip6addr) ((htonl((ip6addr)->addr[2]) >> 16) & 0xffff) -#define IP6_ADDR_BLOCK6(ip6addr) ((htonl((ip6addr)->addr[2])) & 0xffff) -#define IP6_ADDR_BLOCK7(ip6addr) ((htonl((ip6addr)->addr[3]) >> 16) & 0xffff) -#define IP6_ADDR_BLOCK8(ip6addr) ((htonl((ip6addr)->addr[3])) & 0xffff) +#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0])) & 0xffff) +#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1])) & 0xffff) +#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2])) & 0xffff) +#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3]) >> 16) & 0xffff) +#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3])) & 0xffff) /** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ #define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ From b5305d5a8cb12fc2c7f69cba1259f8864635a6a5 Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Fri, 12 Aug 2011 09:04:29 -0600 Subject: [PATCH 071/151] Initialize recvmbox size for undefined netconn type, to supress compiler warning. Change-Id: I14c3f1786a8ca3513b5d4cf375c4951e4c09ebd6 --- src/api/api_msg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 9d0895ac..54fbabcf 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -601,6 +601,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) #endif /* LWIP_TCP */ default: LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); + size = 0; break; } #endif From ed0626afebf342843ef1505dff46089cfd465bf1 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 22 Aug 2011 18:52:27 +0200 Subject: [PATCH 072/151] fixed bug #33962 TF_FIN not always set after FIN is sent. (This merely prevents nagle from not transmitting fast after closing.) --- CHANGELOG | 4 ++++ src/core/tcp_out.c | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index e31b2985..3c7b2c6e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,10 @@ HISTORY ++ Bugfixes: + 2011-08-22: Simon Goldschmidt + * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This + merely prevents nagle from not transmitting fast after closing.) + 2011-07-22: Simon Goldschmidt * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 069df893..db9e1157 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -136,6 +136,7 @@ tcp_send_fin(struct tcp_pcb *pcb) if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); + pcb->flags |= TF_FIN; return ERR_OK; } } From bf4ec9be22d85a92cdbc4fa1274a55416f183da3 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 19:52:06 +0200 Subject: [PATCH 073/151] fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr --- CHANGELOG | 3 +++ src/core/netif.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3c7b2c6e..41992f31 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,9 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr + 2011-08-22: Simon Goldschmidt * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This merely prevents nagle from not transmitting fast after closing.) diff --git a/src/core/netif.c b/src/core/netif.c index 754f1112..6da84234 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -358,7 +358,7 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) struct tcp_pcb_listen *lpcb; /* address is actually being changed? */ - if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { + if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); pcb = tcp_active_pcbs; From c55f6b40eca50d9b57fed847c9376e37b9ab5768 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 20:12:23 +0200 Subject: [PATCH 074/151] fixed bug #34122 dhcp: hostname can overflow --- CHANGELOG | 3 +++ src/core/dhcp.c | 59 ++++++++++++++++++++++--------------------------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 41992f31..da015a13 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,9 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * dhcp.c: fixed bug #34122 dhcp: hostname can overflow + 2011-08-24: Simon Goldschmidt * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr diff --git a/src/core/dhcp.c b/src/core/dhcp.c index fe85a7e8..644290b9 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -168,6 +168,9 @@ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); static void dhcp_option_short(struct dhcp *dhcp, u16_t value); static void dhcp_option_long(struct dhcp *dhcp, u32_t value); +#if LWIP_NETIF_HOSTNAME +static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif); +#endif /* LWIP_NETIF_HOSTNAME */ /* always add the DHCP options trailer to end and pad */ static void dhcp_option_trailer(struct dhcp *dhcp); @@ -299,17 +302,7 @@ dhcp_select(struct netif *netif) dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); #if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } + dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ dhcp_option_trailer(dhcp); @@ -1029,17 +1022,7 @@ dhcp_renew(struct netif *netif) dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } + dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ #if 0 @@ -1092,17 +1075,7 @@ dhcp_rebind(struct netif *netif) dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if LWIP_NETIF_HOSTNAME - if (netif->hostname != NULL) { - const char *p = (const char*)netif->hostname; - u8_t namelen = (u8_t)strlen(p); - if (namelen > 0) { - LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); - while (*p) { - dhcp_option_byte(dhcp, *p++); - } - } - } + dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ #if 0 @@ -1314,6 +1287,26 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value) dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); } +#if LWIP_NETIF_HOSTNAME +static void +dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) +{ + if (netif->hostname != NULL) { + size_t namelen = strlen(netif->hostname); + if (namelen > 0) { + u8_t len; + const char *p = netif->hostname; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= 255); + len = LWIP_MAX(namelen, 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); + while (len--) { + dhcp_option_byte(dhcp, *p++); + } + } + } +} +#endif /* LWIP_NETIF_HOSTNAME */ + /** * Extract the DHCP message and the DHCP options. * From cd5d1ceadfb64e135cfa0eee7dcaad2fe56aff9f Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 20:18:47 +0200 Subject: [PATCH 075/151] fixed bug #34112 Odd check in pbuf_alloced_custom (typo) --- CHANGELOG | 3 +++ src/core/pbuf.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index da015a13..4c35cba8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,9 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) + 2011-08-24: Simon Goldschmidt * dhcp.c: fixed bug #34122 dhcp: hostname can overflow diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 6c45dbf2..cb79a987 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -391,7 +391,7 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust return NULL; } - if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) { + if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); return NULL; } From 2e69b54a4f2566b604878657f9d11ac8cbc4eecd Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 20:22:21 +0200 Subject: [PATCH 076/151] fixed bug #34057 socklen_t should be a typedef --- CHANGELOG | 3 +++ src/include/lwip/sockets.h | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4c35cba8..fcfde34b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,9 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * sockets.h: fixed bug #34057 socklen_t should be a typedef + 2011-08-24: Simon Goldschmidt * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 5ce4a4f9..e578a7b0 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -78,8 +78,10 @@ struct sockaddr { #endif /* LWIP_IPV6 */ }; -#ifndef socklen_t -# define socklen_t u32_t +/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED + to prevent this code from redefining it. */ +#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) +typedef u32_t socklen_t; #endif /* Socket protocol types (TCP/UDP/RAW) */ From f64808c38509057d504546a57b5011c3a7555657 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 21:12:12 +0200 Subject: [PATCH 077/151] fixed bug #33956 Wrong error returned when calling accept() on UDP connections --- CHANGELOG | 4 ++++ src/api/api_msg.c | 2 ++ src/api/sockets.c | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index fcfde34b..73f38413 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,10 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling + accept() on UDP connections + 2011-08-24: Simon Goldschmidt * sockets.h: fixed bug #34057 socklen_t should be a typedef diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 54fbabcf..7cffe3eb 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1095,6 +1095,8 @@ do_listen(struct api_msg_msg *msg) } } } + } else { + msg->err = ERR_ARG; } } } diff --git a/src/api/sockets.c b/src/api/sockets.c index e3e01ca4..2982f191 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -407,6 +407,10 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) err = netconn_accept(sock->conn, &newconn); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return EOPNOTSUPP; + } sock_set_errno(sock, err_to_errno(err)); return -1; } @@ -611,6 +615,10 @@ lwip_listen(int s, int backlog) if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return EOPNOTSUPP; + } sock_set_errno(sock, err_to_errno(err)); return -1; } From 249e19769bc43c53b057d51c6309e09b9f17371f Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 21:40:09 +0200 Subject: [PATCH 078/151] fixed bug #34124 struct in6_addr does not conform to the standard --- CHANGELOG | 3 +++ src/include/ipv6/lwip/inet6.h | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 73f38413..34fb7ac8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -41,6 +41,9 @@ HISTORY ++ Bugfixes: + 2011-08-24: Simon Goldschmidt + * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard + 2011-08-24: Simon Goldschmidt * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling accept() on UDP connections diff --git a/src/include/ipv6/lwip/inet6.h b/src/include/ipv6/lwip/inet6.h index fbbdcf19..d9800060 100644 --- a/src/include/ipv6/lwip/inet6.h +++ b/src/include/ipv6/lwip/inet6.h @@ -54,22 +54,25 @@ extern "C" { /** For compatibility with BSD code */ struct in6_addr { - u32_t s_addr[4]; + union { + u8_t u8_addr[16]; + u32_t u32_addr[4]; + } un; +#define s6_addr un.u32_addr }; #define IN6ADDR_ANY_INIT {0,0,0,0} #define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)} - -#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s_addr[0] = (source_ip6addr)->addr[0]; \ - (target_in6addr)->s_addr[1] = (source_ip6addr)->addr[1]; \ - (target_in6addr)->s_addr[2] = (source_ip6addr)->addr[2]; \ - (target_in6addr)->s_addr[3] = (source_ip6addr)->addr[3];} -#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ - (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ - (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \ - (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0];} +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ + (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} +#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ + (target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0];} /* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ #define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) From 0a5755145c1cae11f87626545818e81ed7d2efa7 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 24 Aug 2011 22:00:10 +0200 Subject: [PATCH 079/151] added netif remove callback (bug #32397) --- CHANGELOG | 5 ++++- src/core/netif.c | 18 ++++++++++++++++++ src/include/lwip/netif.h | 7 +++++++ src/include/lwip/opt.h | 8 ++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 34fb7ac8..7cad2831 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,7 +6,10 @@ HISTORY ++ New features: - 2011-08-26: Simon Goldschmidt + 2011-08-24: Simon Goldschmidt + * opt.h, netif.h/.c: added netif remove callback (bug #32397) + + 2011-07-26: Simon Goldschmidt * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) diff --git a/src/core/netif.c b/src/core/netif.c index 6da84234..c882eade 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -306,6 +306,11 @@ netif_remove(struct netif *netif) /* reset default netif */ netif_set_default(NULL); } +#if LWIP_NETIF_REMOVE_CALLBACK + if (netif->remove_callback) { + netif->remove_callback(netif); + } +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); } @@ -550,6 +555,19 @@ void netif_set_status_callback(struct netif *netif, netif_status_callback_fn sta } #endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +/** + * Set callback to be called when the interface has been removed + */ +void +netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) +{ + if (netif) { + netif->remove_callback = remove_callback; + } +} +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ + /** * Called by a driver when its link goes up */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index c14289b8..a658e51b 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -197,6 +197,10 @@ struct netif { */ netif_status_callback_fn link_callback; #endif /* LWIP_NETIF_LINK_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK + /** This function is called when the netif has been removed */ + netif_status_callback_fn remove_callback; +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ /** This field can be set by the device driver and could point * to state information for the device. */ void *state; @@ -331,6 +335,9 @@ void netif_set_down(struct netif *netif); #if LWIP_NETIF_STATUS_CALLBACK void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_REMOVE_CALLBACK +void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); +#endif /* LWIP_NETIF_REMOVE_CALLBACK */ void netif_set_link_up(struct netif *netif); void netif_set_link_down(struct netif *netif); diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 8ae6ba4d..a345a149 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1115,6 +1115,14 @@ #define LWIP_NETIF_LINK_CALLBACK 0 #endif +/** + * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called + * when a netif has been removed + */ +#ifndef LWIP_NETIF_REMOVE_CALLBACK +#define LWIP_NETIF_REMOVE_CALLBACK 0 +#endif + /** * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table * indices) in struct netif. TCP and UDP can make use of this to prevent From aea17bfae20b0d8da51092921ad44d6d5a027eb2 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 30 Aug 2011 13:15:10 +0200 Subject: [PATCH 080/151] Fixed bogus IPH_V/HL and IPH_VHL_SET endianess dependency --- src/include/ipv4/lwip/ip4.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/include/ipv4/lwip/ip4.h b/src/include/ipv4/lwip/ip4.h index 64c9b4d7..04b5b8a6 100644 --- a/src/include/ipv4/lwip/ip4.h +++ b/src/include/ipv4/lwip/ip4.h @@ -91,13 +91,8 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif -#if BYTE_ORDER == LITTLE_ENDIAN #define IPH_V(hdr) ((hdr)->_v_hl >> 4) #define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) -#else /* BYTE_ORDER == LITTLE_ENDIAN */ -#define IPH_V(hdr) ((hdr)->_v_hl & 0x0f) -#define IPH_HL(hdr) ((hdr)->_v_hl >> 4) -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define IPH_TOS(hdr) ((hdr)->_tos) #define IPH_LEN(hdr) ((hdr)->_len) #define IPH_ID(hdr) ((hdr)->_id) @@ -106,11 +101,7 @@ PACK_STRUCT_END #define IPH_PROTO(hdr) ((hdr)->_proto) #define IPH_CHKSUM(hdr) ((hdr)->_chksum) -#if BYTE_ORDER == LITTLE_ENDIAN #define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl)) -#else /* BYTE_ORDER == LITTLE_ENDIAN */ -#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = ((v) | ((hl) << 4)) -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) #define IPH_ID_SET(hdr, id) (hdr)->_id = (id) From b9c17dd1f0a7095c069ee414c539a134415f42b2 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 1 Sep 2011 21:00:11 +0200 Subject: [PATCH 081/151] fixed bug #34111 RST for ACK to listening pcb has wrong seqno --- CHANGELOG | 3 +++ src/core/tcp_in.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7cad2831..25f2ccef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,9 @@ HISTORY ++ Bugfixes: + 2011-09-01: Simon Goldschmidt + * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno + 2011-08-24: Simon Goldschmidt * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 316dc3d9..9d40ec53 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -448,13 +448,18 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) struct tcp_pcb *npcb; err_t rc; + if (flags & TCP_RST) { + /* An incoming RST should be ignored. Return. */ + return ERR_OK; + } + /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno + 1, seqno + tcplen, ipX_current_dest_addr(), + tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); From 55011e5308482dfdf7708502b9a605074dcd7b07 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 1 Sep 2011 22:25:03 +0200 Subject: [PATCH 082/151] fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared to other options --- CHANGELOG | 4 ++++ src/include/lwip/opt.h | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 25f2ccef..0082a786 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,10 @@ HISTORY ++ Bugfixes: + 2011-09-01: Simon Goldschmidt + * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared + to other options + 2011-09-01: Simon Goldschmidt * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index a345a149..1db77da4 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1045,14 +1045,11 @@ * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all * events (accept, sent, etc) that happen in the system. * LWIP_CALLBACK_API==1: The PCB callback function is called directly - * for the event. + * for the event. This is the default. */ -#ifndef LWIP_EVENT_API +#if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) #define LWIP_EVENT_API 0 #define LWIP_CALLBACK_API 1 -#else -#define LWIP_EVENT_API 1 -#define LWIP_CALLBACK_API 0 #endif From d0877153bf61355a2d978202dd514de906503c6c Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 3 Sep 2011 21:24:06 +0200 Subject: [PATCH 083/151] netconn_alloc(): return on invalid protocol instead of initializing mbox size to 0 --- src/api/api_msg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 7cffe3eb..fe97d3bc 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -601,19 +601,16 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) #endif /* LWIP_TCP */ default: LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); - size = 0; - break; + goto free_and_return; } #endif if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { - memp_free(MEMP_NETCONN, conn); - return NULL; + goto free_and_return; } if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { sys_sem_free(&conn->op_completed); - memp_free(MEMP_NETCONN, conn); - return NULL; + goto free_and_return; } #if LWIP_TCP @@ -638,6 +635,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) #endif /* LWIP_SO_RCVBUF */ conn->flags = 0; return conn; +free_and_return: + memp_free(MEMP_NETCONN, conn); + return NULL; } /** From 17a5ba08e4a72e51771b58d1518329a7ec07b30d Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 3 Sep 2011 21:25:51 +0200 Subject: [PATCH 084/151] unit tests: correctly handle small PBUF_POOL_BUFSIZE settings, prevent NULL-pointer-deref. (ooseq test is still not running correctly...) --- test/unit/tcp/tcp_helper.c | 27 ++++++++++++++++++++++----- test/unit/tcp/test_tcp_oos.c | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/test/unit/tcp/tcp_helper.c b/test/unit/tcp/tcp_helper.c index 5aee8319..02724986 100644 --- a/test/unit/tcp/tcp_helper.c +++ b/test/unit/tcp/tcp_helper.c @@ -54,16 +54,23 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags) { - struct pbuf* p; + struct pbuf *p, *q; struct ip_hdr* iphdr; struct tcp_hdr* tcphdr; u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); EXPECT_RETNULL(p != NULL); - EXPECT_RETNULL(p->next == NULL); + /* first pbuf must be big enough to hold the headers */ + EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); + if (data_len > 0) { + /* first pbuf must be big enough to hold at least 1 data byte, too */ + EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); + } - memset(p->payload, 0, p->len); + for(q = p; q != NULL; q = q->next) { + memset(q->payload, 0, q->len); + } iphdr = p->payload; /* fill IP header */ @@ -74,6 +81,7 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + /* let p point to TCP header */ pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); tcphdr = p->payload; @@ -85,8 +93,14 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, TCPH_FLAGS_SET(tcphdr, headerflags); tcphdr->wnd = htons(TCP_WND); - /* copy data */ - memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len); + if (data_len > 0) { + /* let p point to TCP data */ + pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); + /* copy data */ + pbuf_take(p, data, data_len); + /* let p point to TCP header again */ + pbuf_header(p, sizeof(struct tcp_hdr)); + } /* calculate checksum */ @@ -207,6 +221,9 @@ void test_tcp_input(struct pbuf *p, struct netif *inp) ip_current_netif() = inp; ip_current_header() = iphdr; + /* since adding IPv6, p->payload must point to tcp header, not ip header */ + pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); + tcp_input(p, inp); ipX_current_dest_addr()->addr = 0; diff --git a/test/unit/tcp/test_tcp_oos.c b/test/unit/tcp/test_tcp_oos.c index 56944e20..8e517b9f 100644 --- a/test/unit/tcp/test_tcp_oos.c +++ b/test/unit/tcp/test_tcp_oos.c @@ -478,7 +478,7 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) int count, expected_datalen; struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT(p != NULL); + EXPECT_RET(p != NULL); /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ @@ -502,7 +502,7 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) /* pass in one more segment, cleary overrunning the rxwin */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); - EXPECT(p_ovr != NULL); + EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ test_tcp_input(p_ovr, &netif); /* check if counters are as expected */ From a0bf8d5740f5ec8d9f9ff93ef7f0e5972c056a35 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 3 Sep 2011 21:57:26 +0200 Subject: [PATCH 085/151] fixed bug #33952 PUSH flag in incoming packet is lost when packet is aggregated and sent to application --- CHANGELOG | 4 ++++ src/core/tcp_in.c | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0082a786..8af059e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,10 @@ HISTORY ++ Bugfixes: + 2011-09-03: Simon Goldschmidt + * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet + is aggregated and sent to application + 2011-09-01: Simon Goldschmidt * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared to other options diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 9d40ec53..0cfb437b 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -300,6 +300,10 @@ tcp_input(struct pbuf *p, struct netif *inp) recv_data = NULL; recv_flags = 0; + if (flags & TCP_PSH) { + p->flags |= PBUF_FLAG_PUSH; + } + /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { /* Notify again application with data previously received. */ @@ -354,9 +358,6 @@ tcp_input(struct pbuf *p, struct netif *inp) tcp_abort(pcb); goto aborted; } - if (flags & TCP_PSH) { - recv_data->flags |= PBUF_FLAG_PUSH; - } /* Notify application that data has been received. */ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); From e27d34d1186c47ebabfa04c0cd45536e2a8bc873 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 3 Sep 2011 22:27:06 +0200 Subject: [PATCH 086/151] DHCP uses LWIP_RAND() for xid's (bug #30302) --- CHANGELOG | 3 +++ src/core/dhcp.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 8af059e9..5c6875dd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 2011-09-03: Simon Goldschmidt + * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) + 2011-08-24: Simon Goldschmidt * opt.h, netif.h/.c: added netif remove callback (bug #32397) diff --git a/src/core/dhcp.c b/src/core/dhcp.c index 644290b9..f224587b 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -83,6 +83,13 @@ #include +/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using + * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) + */ +#ifndef DHCP_CREATE_RAND_XID +#define DHCP_CREATE_RAND_XID 1 +#endif + /** Default for DHCP_GLOBAL_XID is 0xABCD0000 * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" @@ -1623,7 +1630,11 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) * with a packet analyser). We simply increment for each new request. * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + static u32_t xid; +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ static u32_t xid = 0xABCD0000; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ #else if (!xid_initialised) { xid = DHCP_GLOBAL_XID; @@ -1645,7 +1656,11 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) /* reuse transaction identifier in retransmissions */ if (dhcp->tries == 0) { - xid++; +#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) + xid = LWIP_RAND(); +#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ + xid++; +#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ } dhcp->xid = xid; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, From 5e8ee7e006284fe8f507d4bbf32029c0fef438ca Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 3 Sep 2011 22:27:30 +0200 Subject: [PATCH 087/151] Make LWIP_RAND optional (useful for small targets) --- src/core/ipv4/igmp.c | 2 ++ src/core/ipv6/mld6.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/ipv4/igmp.c b/src/core/ipv4/igmp.c index 22a1e161..bd52744f 100644 --- a/src/core/ipv4/igmp.c +++ b/src/core/ipv4/igmp.c @@ -699,8 +699,10 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time) if (max_time == 0) { max_time = 1; } +#ifdef LWIP_RAND /* ensure the random value is > 0 */ group->timer = (LWIP_RAND() % (max_time - 1)) + 1; +#endif /* LWIP_RAND */ } /** diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index 9db25bab..1cb2dd9c 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -493,8 +493,10 @@ mld6_delayed_report(struct mld_group *group, u16_t maxresp) maxresp = 1; } - /* Randomize maxresp. */ +#ifdef LWIP_RAND + /* Randomize maxresp. (if LWIP_RAND is supported) */ maxresp = (LWIP_RAND() % (maxresp - 1)) + 1; +#endif /* LWIP_RAND */ /* Apply timer value if no report has been scheduled already. */ if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || From 4849eb4c543ea4ddc9869ee51698d4760d107cb0 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 9 Sep 2011 22:25:59 +0200 Subject: [PATCH 088/151] fixed bug #34072: UDP broadcast is received from wrong UDP pcb if udp port matches --- CHANGELOG | 4 ++++ src/core/udp.c | 24 ++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5c6875dd..2321f9f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -47,6 +47,10 @@ HISTORY ++ Bugfixes: + 2011-09-09: Simon Goldschmidt + * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if + udp port matches + 2011-09-03: Simon Goldschmidt * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet is aggregated and sent to application diff --git a/src/core/udp.c b/src/core/udp.c index f948d1e1..87a64916 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -173,7 +173,8 @@ udp_input(struct pbuf *p, struct netif *inp) 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) && + if (pcb->local_port == dest) { + if ( #if LWIP_IPV6 ((PCB_ISIPV6(pcb) && (ip_current_is_v6()) && (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) || @@ -192,15 +193,18 @@ udp_input(struct pbuf *p, struct netif *inp) ip_addr_ismulticast(ip_current_dest_addr()) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV - (broadcast && (pcb->so_options & SOF_BROADCAST)))))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast))))) { -#endif /* IP_SOF_BROADCAST_RECV */ - local_match = 1; - if ((uncon_pcb == NULL) && - ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; + (broadcast && (pcb->so_options & SOF_BROADCAST) && + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask)))))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast && + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask)))))) { +#endif /* IP_SOF_BROADCAST_RECV */ + local_match = 1; + if ((uncon_pcb == NULL) && + ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { + /* the first unconnected matching PCB */ + uncon_pcb = pcb; + } } } /* compare PCB remote addr+port to UDP source addr+port */ From 1b98a64e90fda815067f327b470f173c18a31c06 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 9 Sep 2011 22:28:01 +0200 Subject: [PATCH 089/151] Fixed typo: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN (as checked in init.c), not greater --- src/include/lwip/opt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 1db77da4..fdad392e 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -983,7 +983,7 @@ #endif /** - * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below * this number, select returns writable (combined with TCP_SNDLOWAT). */ From 5be300736e805da6a1d6c32132bcd0193be79f56 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 9 Sep 2011 23:20:34 +0200 Subject: [PATCH 090/151] lwip_accept: fixed warning about accessing uninitialized 'port' when SOCKETS_DEBUG is enabled --- src/api/sockets.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index 2982f191..81cbf24e 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -386,7 +386,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) struct lwip_sock *sock, *nsock; struct netconn *newconn; ipX_addr_t naddr; - u16_t port; + u16_t port = 0; int newsock; err_t err; SYS_ARCH_DECL_PROTECT(lev); From 112158b056c7b55498537cdb60e106b8075f465d Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 11 Sep 2011 12:44:01 +0200 Subject: [PATCH 091/151] Added a config option to randomize initial local TCP/UDP ports (so that different port ranges are used after a reboot; bug #33818; this one added tcp_init/udp_init functions again); fixed a possible endless loop in tcp_new_port() if the number of active PCBs exceeds the number of available ports; --- CHANGELOG | 5 +++ src/core/tcp.c | 55 ++++++++++++++++------- src/core/udp.c | 89 ++++++++++++++++++++++++++++--------- src/include/lwip/opt.h | 9 ++++ src/include/lwip/tcp_impl.h | 2 +- src/include/lwip/udp.h | 2 +- 6 files changed, 124 insertions(+), 38 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2321f9f4..aa47e307 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,11 @@ HISTORY ++ New features: + 2011-09-11: Simon Goldschmidt + * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize + initial local TCP/UDP ports (so that different port ranges are used after + a reboot; bug #33818; this one added tcp_init/udp_init functions again) + 2011-09-03: Simon Goldschmidt * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) diff --git a/src/core/tcp.c b/src/core/tcp.c index 5ae323e3..43244939 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -58,6 +58,14 @@ #include +#ifndef TCP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define TCP_LOCAL_PORT_RANGE_START 0xc000 +#define TCP_LOCAL_PORT_RANGE_END 0xffff +#define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START) +#endif + const char * const tcp_state_str[] = { "CLOSED", "LISTEN", @@ -72,6 +80,9 @@ const char * const tcp_state_str[] = { "TIME_WAIT" }; +/* last local TCP port */ +static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; + /* Incremented every coarse grained timer shot (typically every 500 ms). */ u32_t tcp_ticks; const u8_t tcp_backoff[13] = @@ -104,9 +115,19 @@ struct tcp_pcb *tcp_tmp_pcb; static u8_t tcp_timer; static u16_t tcp_new_port(void); +/** + * Initialize this module. + */ +void +tcp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + /** * Called periodically to dispatch TCP timers. - * */ void tcp_tmr(void) @@ -415,6 +436,9 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) if (port == 0) { port = tcp_new_port(); + if (port == 0) { + return ERR_BUF; + } } /* Check if the address already is in use (on all lists) */ @@ -628,37 +652,33 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) } /** - * A nastly hack featuring 'goto' statements that allocates a - * new TCP local port. + * Allocate a new local TCP port. * * @return a new (free) local TCP port number */ static u16_t tcp_new_port(void) { - int i; + u8_t i; + u16_t n = 0; struct tcp_pcb *pcb; -#ifndef TCP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define TCP_LOCAL_PORT_RANGE_START 0xc000 -#define TCP_LOCAL_PORT_RANGE_END 0xffff -#endif - static u16_t port = TCP_LOCAL_PORT_RANGE_START; - again: - if (port++ == TCP_LOCAL_PORT_RANGE_END) { - port = TCP_LOCAL_PORT_RANGE_START; +again: + if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) { + tcp_port = TCP_LOCAL_PORT_RANGE_START; } /* Check all PCB lists. */ for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == port) { + if (pcb->local_port == tcp_port) { + if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { + return 0; + } goto again; } } } - return port; + return tcp_port; } /** @@ -709,6 +729,9 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, old_local_port = pcb->local_port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); + if (pcb->local_port == 0) { + return ERR_BUF; + } } #if SO_REUSE if ((pcb->so_options & SOF_REUSEADDR) != 0) { diff --git a/src/core/udp.c b/src/core/udp.c index 87a64916..ff4d6896 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -68,10 +68,77 @@ #include +#ifndef UDP_LOCAL_PORT_RANGE_START +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define UDP_LOCAL_PORT_RANGE_START 0xc000 +#define UDP_LOCAL_PORT_RANGE_END 0xffff +#define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START) +#endif + +/* last local UDP port */ +static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; + /* The list of UDP PCBs */ /* exported in udp.h (was static) */ struct udp_pcb *udp_pcbs; +/** + * Initialize this module. + */ +void +udp_init(void) +{ +#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) + udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); +#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ +} + +/** + * Allocate a new local UDP port. + * + * @return a new (free) local UDP port number + */ +static u16_t +udp_new_port(void) +{ + u16_t n = 0; + struct udp_pcb *pcb; + +again: + if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { + udp_port = UDP_LOCAL_PORT_RANGE_START; + } + /* Check all PCBs. */ + for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == udp_port) { + if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { + return 0; + } + goto again; + } + } + return udp_port; +#if 0 + struct udp_pcb *ipcb = udp_pcbs; + while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) { + if (ipcb->local_port == udp_port) { + /* port is already used by another udp_pcb */ + udp_port++; + /* restart scanning all udp pcbs */ + ipcb = udp_pcbs; + } else { + /* go on with next udp pcb */ + ipcb = ipcb->next; + } + } + if (ipcb != NULL) { + return 0; + } + return udp_port; +#endif +} + /** * Process an incoming UDP datagram. * @@ -854,26 +921,8 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) /* no port specified? */ if (port == 0) { -#ifndef UDP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define UDP_LOCAL_PORT_RANGE_START 0xc000 -#define UDP_LOCAL_PORT_RANGE_END 0xffff -#endif - port = UDP_LOCAL_PORT_RANGE_START; - ipcb = udp_pcbs; - while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { - if (ipcb->local_port == port) { - /* port is already used by another udp_pcb */ - port++; - /* restart scanning all udp pcbs */ - ipcb = udp_pcbs; - } else { - /* go on with next udp pcb */ - ipcb = ipcb->next; - } - } - if (ipcb != NULL) { + port = udp_new_port(); + if (port == 0) { /* no more ports available in local range */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); return ERR_USE; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index fdad392e..70d64bfe 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -606,6 +606,15 @@ #define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 #endif +/** + * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first + * local TCP/UDP pcb (default==0). This can prevent creating predictable port + * numbers after booting a device. + */ +#ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS +#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 +#endif + /* ---------------------------------- ---------- ICMP options ---------- diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 14c92fbb..3f83b132 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -52,7 +52,7 @@ extern "C" { /* Functions for interfacing with TCP: */ /* Lower layer interface to TCP: */ -#define tcp_init() /* Compatibility define, no init needed. */ +void tcp_init (void); /* Initialize this module. */ void tcp_tmr (void); /* Must be called every TCP_TMR_INTERVAL ms. (Typically 250 ms). */ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 648c9a46..aa1ad3fb 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -178,7 +178,7 @@ err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, /* The following functions are the lower layer interface to UDP. */ void udp_input (struct pbuf *p, struct netif *inp); -#define udp_init() /* Compatibility define, not init needed. */ +void udp_init (void); #if LWIP_IPV6 struct udp_pcb * udp_new_ip6(void); From dccad08508c045af7c4f2600db7a3138b7c8fdb5 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 11 Sep 2011 13:13:26 +0200 Subject: [PATCH 092/151] use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs (bug #34019) --- CHANGELOG | 4 ++++ src/core/tcp_out.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index aa47e307..dc14b71a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,6 +52,10 @@ HISTORY ++ Bugfixes: + 2011-09-11: Simon Goldschmidt + * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs + (bug #34019) + 2011-09-09: Simon Goldschmidt * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if udp port matches diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index db9e1157..2b1319c5 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -232,7 +232,7 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, LWIP_UNUSED_ARG(apiflags); LWIP_UNUSED_ARG(first_seg); /* always create MSS-sized pbufs */ - alloc = TCP_MSS; + alloc = pcb->mss; #else /* LWIP_NETIF_TX_SINGLE_PBUF */ if (length < max_length) { /* Should we allocate an oversized pbuf, or just the minimum From 6058389974f0266c2f9b3e25a32ec003c3e161b0 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 11 Sep 2011 13:44:08 +0200 Subject: [PATCH 093/151] nd6: use a static buffer to process RA options instead of using mem_malloc() --- src/core/ipv6/nd6.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index c7402c62..54290ef5 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -77,6 +77,9 @@ static u8_t nd6_cached_destination_index; /* Multicast address holder. */ static ip6_addr_t multicast_address; +/* Static buffer to parse RA packet options (size of a prefix option, biggest option) */ +static u8_t nd6_ra_buffer[sizeof(struct prefix_option)]; + /* Forward declarations. */ static s8_t nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr); static s8_t nd6_new_neighbor_cache_entry(void); @@ -392,17 +395,15 @@ nd6_input(struct pbuf *p, struct netif *inp) /* Offset to options. */ offset = sizeof(struct ra_header); - /* Allocate buffer to copy options (so we can traverse pbufs). */ - buffer = (u8_t *)mem_malloc(sizeof(struct prefix_option)); /* Size of a prefix option, biggest option. */ - if (buffer == NULL) { - pbuf_free(p); - ND6_STATS_INC(nd6.memerr); - return; - } - /* Process each option. */ while ((p->tot_len - offset) > 0) { - pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); + if (p->len == p->tot_len) { + /* no need to copy from contiguous pbuf */ + buffer = &((u8_t*)p->payload)[offset]; + } else { + buffer = nd6_ra_buffer; + pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); + } switch (buffer[0]) { case ND6_OPTION_TYPE_SOURCE_LLADDR: { @@ -476,10 +477,6 @@ nd6_input(struct pbuf *p, struct netif *inp) offset += 8 * ((u16_t)buffer[1]); } - - /* free options buffer. */ - mem_free(buffer); - break; /* ICMP6_TYPE_RA */ } case ICMP6_TYPE_RD: /* Redirect */ From d6227aece65668577f70a272a696650654375a86 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 11 Sep 2011 19:30:28 +0200 Subject: [PATCH 094/151] splitted ppp.h to an internal and external header file to get a clear separation of which functions an application or port may use (task #11281) --- CHANGELOG | 5 + src/netif/ppp/auth.c | 2 +- src/netif/ppp/chap.c | 2 +- src/netif/ppp/chpms.c | 2 +- src/netif/ppp/fsm.c | 2 +- src/netif/ppp/ipcp.c | 2 +- src/netif/ppp/lcp.c | 2 +- src/netif/ppp/magic.c | 2 +- src/netif/ppp/md5.c | 2 +- src/netif/ppp/pap.c | 2 +- src/netif/ppp/ppp.c | 7 +- src/netif/ppp/ppp.h | 316 ++-------------------------------- src/netif/ppp/ppp_impl.h | 363 +++++++++++++++++++++++++++++++++++++++ src/netif/ppp/ppp_oe.c | 2 +- src/netif/ppp/randm.c | 2 +- src/netif/ppp/vj.c | 2 +- 16 files changed, 401 insertions(+), 314 deletions(-) create mode 100644 src/netif/ppp/ppp_impl.h diff --git a/CHANGELOG b/CHANGELOG index dc14b71a..b7baeb42 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,11 @@ HISTORY ++ New features: 2011-09-11: Simon Goldschmidt + * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file + to get a clear separation of which functions an application or port may use + (task #11281) + + 2011-09-11: Simon Goldschmidt * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize initial local TCP/UDP ports (so that different port ranges are used after a reboot; bug #33818; this one added tcp_init/udp_init functions again) diff --git a/src/netif/ppp/auth.c b/src/netif/ppp/auth.c index c3c49d22..0fd87a37 100644 --- a/src/netif/ppp/auth.c +++ b/src/netif/ppp/auth.c @@ -68,7 +68,7 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "fsm.h" diff --git a/src/netif/ppp/chap.c b/src/netif/ppp/chap.c index 3a49ff8a..f10e27d2 100644 --- a/src/netif/ppp/chap.c +++ b/src/netif/ppp/chap.c @@ -72,7 +72,7 @@ #if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "magic.h" diff --git a/src/netif/ppp/chpms.c b/src/netif/ppp/chpms.c index 83acefce..81a887b8 100644 --- a/src/netif/ppp/chpms.c +++ b/src/netif/ppp/chpms.c @@ -75,7 +75,7 @@ #if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "md4.h" diff --git a/src/netif/ppp/fsm.c b/src/netif/ppp/fsm.c index 2e73c5af..e8a254ed 100644 --- a/src/netif/ppp/fsm.c +++ b/src/netif/ppp/fsm.c @@ -59,7 +59,7 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "fsm.h" diff --git a/src/netif/ppp/ipcp.c b/src/netif/ppp/ipcp.c index 461a600f..f0ab2e0e 100644 --- a/src/netif/ppp/ipcp.c +++ b/src/netif/ppp/ipcp.c @@ -55,7 +55,7 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "auth.h" diff --git a/src/netif/ppp/lcp.c b/src/netif/ppp/lcp.c index 21c83ac4..54f758aa 100644 --- a/src/netif/ppp/lcp.c +++ b/src/netif/ppp/lcp.c @@ -55,7 +55,7 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "fsm.h" diff --git a/src/netif/ppp/magic.c b/src/netif/ppp/magic.c index 39013308..3732a424 100644 --- a/src/netif/ppp/magic.c +++ b/src/netif/ppp/magic.c @@ -53,7 +53,7 @@ #if PPP_SUPPORT -#include "ppp.h" +#include "ppp_impl.h" #include "randm.h" #include "magic.h" diff --git a/src/netif/ppp/md5.c b/src/netif/ppp/md5.c index 3cb69e2b..dc3cc751 100644 --- a/src/netif/ppp/md5.c +++ b/src/netif/ppp/md5.c @@ -37,7 +37,7 @@ #if CHAP_SUPPORT || MD5_SUPPORT -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "md5.h" diff --git a/src/netif/ppp/pap.c b/src/netif/ppp/pap.c index 78ef490a..5fb9f886 100644 --- a/src/netif/ppp/pap.c +++ b/src/netif/ppp/pap.c @@ -55,7 +55,7 @@ #if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "auth.h" diff --git a/src/netif/ppp/ppp.c b/src/netif/ppp/ppp.c index e9b433b0..3838fcf2 100644 --- a/src/netif/ppp/ppp.c +++ b/src/netif/ppp/ppp.c @@ -83,9 +83,9 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ +#include "ppp_impl.h" #include "lwip/ip.h" /* for ip_input() */ -#include "ppp.h" #include "pppdebug.h" #include "randm.h" @@ -527,7 +527,7 @@ pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) * pppOpen() is directly defined to this function. */ int -pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx) { PPPControl *pc; int pd; @@ -595,7 +595,8 @@ pppOverEthernetClose(int pd) pppoe_destroy(&pc->netif); } -int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, + pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx) { PPPControl *pc; int pd; diff --git a/src/netif/ppp/ppp.h b/src/netif/ppp/ppp.h index a72ac957..08d6e62d 100644 --- a/src/netif/ppp/ppp.h +++ b/src/netif/ppp/ppp.h @@ -46,67 +46,6 @@ #include "lwip/sys.h" #include "lwip/timers.h" -/** Some defines for code we skip compared to the original pppd. - * These are just here to minimise the use of the ugly "#if 0". */ -#define PPP_ADDITIONAL_CALLBACKS 0 - -/** Some error checks to test for unsupported code */ -#if CBCP_SUPPORT -#error "CBCP is not supported in lwIP PPP" -#endif -#if CCP_SUPPORT -#error "CCP is not supported in lwIP PPP" -#endif - -/* - * pppd.h - PPP daemon global declarations. - * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - */ -/* - * ppp_defs.h - PPP definitions. - * - * Copyright (c) 1994 The Australian National University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. - * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. - */ - -#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) -#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) - #ifndef __u_char_defined @@ -118,123 +57,6 @@ typedef unsigned char u_char; #endif -/* - * Constants and structures defined by the internet system, - * Per RFC 790, September 1981, and numerous additions. - */ - -/* - * The basic PPP frame. - */ -#define PPP_HDRLEN 4 /* octets for standard ppp header */ -#define PPP_FCSLEN 2 /* octets for FCS */ - - -/* - * Significant octet values. - */ -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_FLAG 0x7e /* Flag Sequence */ -#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ -#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ - -/* - * Protocol field values. - */ -#define PPP_IP 0x21 /* Internet Protocol */ -#define PPP_AT 0x29 /* AppleTalk Protocol */ -#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ -#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ -#define PPP_COMP 0xfd /* compressed packet */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ -#define PPP_CCP 0x80fd /* Compression Control Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_LQR 0xc025 /* Link Quality Report protocol */ -#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ -#define PPP_CBCP 0xc029 /* Callback Control Protocol */ - -/* - * Values for FCS calculations. - */ -#define PPP_INITFCS 0xffff /* Initial FCS value */ -#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ -#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) - -/* - * Extended asyncmap - allows any character to be escaped. - */ -typedef u_char ext_accm[32]; - -/* - * What to do with network protocol (NP) packets. - */ -enum NPmode { - NPMODE_PASS, /* pass the packet through */ - NPMODE_DROP, /* silently drop the packet */ - NPMODE_ERROR, /* return an error */ - NPMODE_QUEUE /* save it up for later. */ -}; - -/* - * Inline versions of get/put char/short/long. - * Pointer is advanced; we assume that both arguments - * are lvalues and will already be in registers. - * cp MUST be u_char *. - */ -#define GETCHAR(c, cp) { \ - (c) = *(cp)++; \ -} -#define PUTCHAR(c, cp) { \ - *(cp)++ = (u_char) (c); \ -} - - -#define GETSHORT(s, cp) { \ - (s) = *(cp); (cp)++; (s) <<= 8; \ - (s) |= *(cp); (cp)++; \ -} -#define PUTSHORT(s, cp) { \ - *(cp)++ = (u_char) ((s) >> 8); \ - *(cp)++ = (u_char) (s & 0xff); \ -} - -#define GETLONG(l, cp) { \ - (l) = *(cp); (cp)++; (l) <<= 8; \ - (l) |= *(cp); (cp)++; (l) <<= 8; \ - (l) |= *(cp); (cp)++; (l) <<= 8; \ - (l) |= *(cp); (cp)++; \ -} -#define PUTLONG(l, cp) { \ - *(cp)++ = (u_char) ((l) >> 24); \ - *(cp)++ = (u_char) ((l) >> 16); \ - *(cp)++ = (u_char) ((l) >> 8); \ - *(cp)++ = (u_char) (l); \ -} - - -#define INCPTR(n, cp) ((cp) += (n)) -#define DECPTR(n, cp) ((cp) -= (n)) - -#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l)) -#define BCOPY(s, d, l) MEMCPY((d), (s), (l)) -#define BZERO(s, n) memset(s, 0, n) - -#if PPP_DEBUG -#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); } -#else /* PPP_DEBUG */ -#define PRINTMSG(m, l) -#endif /* PPP_DEBUG */ - -/* - * MAKEHEADER - Add PPP Header fields to a packet. - */ -#define MAKEHEADER(p, t) { \ - PUTCHAR(PPP_ALLSTATIONS, p); \ - PUTCHAR(PPP_UI, p); \ - PUTSHORT(t, p); } /************************* *** PUBLIC DEFINITIONS *** @@ -267,89 +89,10 @@ enum NPmode { *** PUBLIC DATA TYPES *** ************************/ -/* - * The following struct gives the addresses of procedures to call - * for a particular protocol. - */ -struct protent { - u_short protocol; /* PPP protocol number */ - /* Initialization procedure */ - void (*init) (int unit); - /* Process a received packet */ - void (*input) (int unit, u_char *pkt, int len); - /* Process a received protocol-reject */ - void (*protrej) (int unit); - /* Lower layer has come up */ - void (*lowerup) (int unit); - /* Lower layer has gone down */ - void (*lowerdown) (int unit); - /* Open the protocol */ - void (*open) (int unit); - /* Close the protocol */ - void (*close) (int unit, char *reason); -#if PPP_ADDITIONAL_CALLBACKS - /* Print a packet in readable form */ - int (*printpkt) (u_char *pkt, int len, - void (*printer) (void *, char *, ...), - void *arg); - /* Process a received data packet */ - void (*datainput) (int unit, u_char *pkt, int len); -#endif /* PPP_ADDITIONAL_CALLBACKS */ - int enabled_flag; /* 0 if protocol is disabled */ - char *name; /* Text name of protocol */ -#if PPP_ADDITIONAL_CALLBACKS - /* Check requested options, assign defaults */ - void (*check_options) (u_long); - /* Configure interface for demand-dial */ - int (*demand_conf) (int unit); - /* Say whether to bring up link for this pkt */ - int (*active_pkt) (u_char *pkt, int len); -#endif /* PPP_ADDITIONAL_CALLBACKS */ -}; - -/* - * The following structure records the time in seconds since - * the last NP packet was sent or received. - */ -struct ppp_idle { - u_short xmit_idle; /* seconds since last NP packet sent */ - u_short recv_idle; /* seconds since last NP packet received */ -}; - -struct ppp_settings { - - u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */ - u_int auth_required : 1; /* Peer is required to authenticate */ - u_int explicit_remote : 1; /* remote_name specified with remotename opt */ - u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */ - u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */ - u_int usehostname : 1; /* Use hostname for our_name */ - u_int usepeerdns : 1; /* Ask peer for DNS adds */ - - u_short idle_time_limit; /* Shut down link if idle for this long */ - int maxconnect; /* Maximum connect time (seconds) */ - - char user [MAXNAMELEN + 1]; /* Username for PAP */ - char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */ - char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */ - char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ -}; - struct ppp_addrs { ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2; }; -/***************************** -*** PUBLIC DATA STRUCTURES *** -*****************************/ - -/* Buffers for outgoing packets. */ -extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN]; - -extern struct ppp_settings ppp_settings; - -extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */ - /*********************** *** PUBLIC FUNCTIONS *** @@ -386,6 +129,10 @@ enum pppAuthType { void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd); +/* Link status callback function prototype */ +typedef void (*pppLinkStatusCB_fn)(void *ctx, int errCode, void *arg); + +#if PPPOS_SUPPORT /* * Open a new PPP connection using the given serial I/O device. * This initializes the PPP control block but does not @@ -393,12 +140,16 @@ void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) * Return a new PPP connection descriptor on success or * an error code (negative) on failure. */ -int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); +int pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx); +#endif /* PPPOS_SUPPORT */ +#if PPPOE_SUPPORT /* * Open a new PPP Over Ethernet (PPPOE) connection. */ -int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, + pppLinkStatusCB_fn linkStatusCB, void *linkStatusCtx); +#endif /* PPPOE_SUPPORT */ /* for source code compatibility */ #define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls) @@ -426,55 +177,22 @@ int pppIOCtl(int pd, int cmd, void *arg); */ u_short pppMTU(int pd); +#if PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD /* - * Write n characters to a ppp link. - * RETURN: >= 0 Number of characters written, -1 Failed to write to device. + * PPP over Serial: this is the input function to be called for received data. + * If PPP_INPROC_OWNTHREAD==1, a seperate input thread using the blocking + * sio_read() is used, so this is deactivated. */ -int pppWrite(int pd, const u_char *s, int n); - -void pppInProcOverEthernet(int pd, struct pbuf *pb); - -struct pbuf *pppSingleBuf(struct pbuf *p); - -void pppLinkTerminated(int pd); - -void pppLinkDown(int pd); - void pppos_input(int pd, u_char* data, int len); +#endif /* PPPOS_SUPPORT && !PPP_INPROC_OWNTHREAD */ -/* Configure i/f transmit parameters */ -void ppp_send_config (int, u16_t, u32_t, int, int); -/* Set extended transmit ACCM */ -void ppp_set_xaccm (int, ext_accm *); -/* Configure i/f receive parameters */ -void ppp_recv_config (int, int, u32_t, int, int); -/* Find out how long link has been idle */ -int get_idle_time (int, struct ppp_idle *); - -/* Configure VJ TCP header compression */ -int sifvjcomp (int, int, u8_t, u8_t); -/* Configure i/f down (for IP) */ -int sifup (int); -/* Set mode for handling packets for proto */ -int sifnpmode (int u, int proto, enum NPmode mode); -/* Configure i/f down (for IP) */ -int sifdown (int); -/* Configure IP addresses for i/f */ -int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t); -/* Reset i/f IP addresses */ -int cifaddr (int, u32_t, u32_t); -/* Create default route through i/f */ -int sifdefaultroute (int, u32_t, u32_t); -/* Delete default route through i/f */ -int cifdefaultroute (int, u32_t, u32_t); - -/* Get appropriate netmask for address */ -u32_t GetMask (u32_t); #if LWIP_NETIF_STATUS_CALLBACK +/* Set an lwIP-style status-callback for the selected PPP device */ void ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK +/* Set an lwIP-style link-callback for the selected PPP device */ void ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ diff --git a/src/netif/ppp/ppp_impl.h b/src/netif/ppp/ppp_impl.h new file mode 100644 index 00000000..89aea60b --- /dev/null +++ b/src/netif/ppp/ppp_impl.h @@ -0,0 +1,363 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher +* Ported to lwIP. +* 97-11-05 Guy Lancaster , Global Election Systems Inc. +* Original derived from BSD codes. +*****************************************************************************/ + +#ifndef PPP_IMPL_H +#define PPP_IMPL_H + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "lwip/def.h" +#include "lwip/sio.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" + +/** Some defines for code we skip compared to the original pppd. + * These are just here to minimise the use of the ugly "#if 0". */ +#define PPP_ADDITIONAL_CALLBACKS 0 + +/** Some error checks to test for unsupported code */ +#if CBCP_SUPPORT +#error "CBCP is not supported in lwIP PPP" +#endif +#if CCP_SUPPORT +#error "CCP is not supported in lwIP PPP" +#endif + +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) +#define UNTIMEOUT(f, a) sys_untimeout((f), (a)) + + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN 4 /* octets for standard ppp header */ +#define PPP_FCSLEN 2 /* octets for FCS */ + + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ +#define PPP_UI 0x03 /* Unnumbered Information */ +#define PPP_FLAG 0x7e /* Flag Sequence */ +#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ +#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS 0xffff /* Initial FCS value */ +#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_char ext_accm[32]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { + NPMODE_PASS, /* pass the packet through */ + NPMODE_DROP, /* silently drop the packet */ + NPMODE_ERROR, /* return an error */ + NPMODE_QUEUE /* save it up for later. */ +}; + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ + (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ + *(cp)++ = (u_char) (c); \ +} + + +#define GETSHORT(s, cp) { \ + (s) = *(cp); (cp)++; (s) <<= 8; \ + (s) |= *(cp); (cp)++; \ +} +#define PUTSHORT(s, cp) { \ + *(cp)++ = (u_char) ((s) >> 8); \ + *(cp)++ = (u_char) (s & 0xff); \ +} + +#define GETLONG(l, cp) { \ + (l) = *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (cp)++; (l) <<= 8; \ + (l) |= *(cp); (cp)++; \ +} +#define PUTLONG(l, cp) { \ + *(cp)++ = (u_char) ((l) >> 24); \ + *(cp)++ = (u_char) ((l) >> 16); \ + *(cp)++ = (u_char) ((l) >> 8); \ + *(cp)++ = (u_char) (l); \ +} + + +#define INCPTR(n, cp) ((cp) += (n)) +#define DECPTR(n, cp) ((cp) -= (n)) + +#define BCMP(s0, s1, l) memcmp((u_char *)(s0), (u_char *)(s1), (l)) +#define BCOPY(s, d, l) MEMCPY((d), (s), (l)) +#define BZERO(s, n) memset(s, 0, n) + +#if PPP_DEBUG +#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); } +#else /* PPP_DEBUG */ +#define PRINTMSG(m, l) +#endif /* PPP_DEBUG */ + +/* + * MAKEHEADER - Add PPP Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ + PUTCHAR(PPP_ALLSTATIONS, p); \ + PUTCHAR(PPP_UI, p); \ + PUTSHORT(t, p); } + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { + u_short protocol; /* PPP protocol number */ + /* Initialization procedure */ + void (*init) (int unit); + /* Process a received packet */ + void (*input) (int unit, u_char *pkt, int len); + /* Process a received protocol-reject */ + void (*protrej) (int unit); + /* Lower layer has come up */ + void (*lowerup) (int unit); + /* Lower layer has gone down */ + void (*lowerdown) (int unit); + /* Open the protocol */ + void (*open) (int unit); + /* Close the protocol */ + void (*close) (int unit, char *reason); +#if PPP_ADDITIONAL_CALLBACKS + /* Print a packet in readable form */ + int (*printpkt) (u_char *pkt, int len, + void (*printer) (void *, char *, ...), + void *arg); + /* Process a received data packet */ + void (*datainput) (int unit, u_char *pkt, int len); +#endif /* PPP_ADDITIONAL_CALLBACKS */ + int enabled_flag; /* 0 if protocol is disabled */ + char *name; /* Text name of protocol */ +#if PPP_ADDITIONAL_CALLBACKS + /* Check requested options, assign defaults */ + void (*check_options) (u_long); + /* Configure interface for demand-dial */ + int (*demand_conf) (int unit); + /* Say whether to bring up link for this pkt */ + int (*active_pkt) (u_char *pkt, int len); +#endif /* PPP_ADDITIONAL_CALLBACKS */ +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { + u_short xmit_idle; /* seconds since last NP packet sent */ + u_short recv_idle; /* seconds since last NP packet received */ +}; + +struct ppp_settings { + + u_int disable_defaultip : 1; /* Don't use hostname for default IP addrs */ + u_int auth_required : 1; /* Peer is required to authenticate */ + u_int explicit_remote : 1; /* remote_name specified with remotename opt */ + u_int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */ + u_int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */ + u_int usehostname : 1; /* Use hostname for our_name */ + u_int usepeerdns : 1; /* Ask peer for DNS adds */ + + u_short idle_time_limit; /* Shut down link if idle for this long */ + int maxconnect; /* Maximum connect time (seconds) */ + + char user [MAXNAMELEN + 1]; /* Username for PAP */ + char passwd [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */ + char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */ + char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ +}; + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +/* Buffers for outgoing packets. */ +extern u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN]; + +extern struct ppp_settings ppp_settings; + +extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */ + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* + * Write n characters to a ppp link. + * RETURN: >= 0 Number of characters written, -1 Failed to write to device. + */ +int pppWrite(int pd, const u_char *s, int n); + +void pppInProcOverEthernet(int pd, struct pbuf *pb); + +struct pbuf *pppSingleBuf(struct pbuf *p); + +void pppLinkTerminated(int pd); + +void pppLinkDown(int pd); + +/* Configure i/f transmit parameters */ +void ppp_send_config (int, u16_t, u32_t, int, int); +/* Set extended transmit ACCM */ +void ppp_set_xaccm (int, ext_accm *); +/* Configure i/f receive parameters */ +void ppp_recv_config (int, int, u32_t, int, int); +/* Find out how long link has been idle */ +int get_idle_time (int, struct ppp_idle *); + +/* Configure VJ TCP header compression */ +int sifvjcomp (int, int, u8_t, u8_t); +/* Configure i/f down (for IP) */ +int sifup (int); +/* Set mode for handling packets for proto */ +int sifnpmode (int u, int proto, enum NPmode mode); +/* Configure i/f down (for IP) */ +int sifdown (int); +/* Configure IP addresses for i/f */ +int sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t); +/* Reset i/f IP addresses */ +int cifaddr (int, u32_t, u32_t); +/* Create default route through i/f */ +int sifdefaultroute (int, u32_t, u32_t); +/* Delete default route through i/f */ +int cifdefaultroute (int, u32_t, u32_t); + +/* Get appropriate netmask for address */ +u32_t GetMask (u32_t); + +#endif /* PPP_SUPPORT */ + +#endif /* PPP_IMPL_H */ diff --git a/src/netif/ppp/ppp_oe.c b/src/netif/ppp/ppp_oe.c index 040a0bc9..fdf52ae2 100644 --- a/src/netif/ppp/ppp_oe.c +++ b/src/netif/ppp/ppp_oe.c @@ -74,7 +74,7 @@ #include "netif/ppp_oe.h" -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "lwip/timers.h" diff --git a/src/netif/ppp/randm.c b/src/netif/ppp/randm.c index 2f35caf6..b736091f 100644 --- a/src/netif/ppp/randm.c +++ b/src/netif/ppp/randm.c @@ -38,7 +38,7 @@ #include "md5.h" #include "randm.h" -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include diff --git a/src/netif/ppp/vj.c b/src/netif/ppp/vj.c index b7f2d54c..bce33221 100644 --- a/src/netif/ppp/vj.c +++ b/src/netif/ppp/vj.c @@ -32,7 +32,7 @@ #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -#include "ppp.h" +#include "ppp_impl.h" #include "pppdebug.h" #include "vj.h" From f13615d97aa9dbc13a3dd7276e46e78682f63b09 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 20 Sep 2011 07:21:19 +0200 Subject: [PATCH 095/151] fixed bug #34337 (possible NULL pointer in sys_check_timeouts) --- CHANGELOG | 3 +++ src/core/timers.c | 18 +++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b7baeb42..f1a32cea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -57,6 +57,9 @@ HISTORY ++ Bugfixes: + 2011-09-20: Simon Goldschmidt + * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) + 2011-09-11: Simon Goldschmidt * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs (bug #34019) diff --git a/src/core/timers.c b/src/core/timers.c index 3c4f8d1d..5ae6d0c4 100644 --- a/src/core/timers.c +++ b/src/core/timers.c @@ -416,15 +416,15 @@ sys_untimeout(sys_timeout_handler handler, void *arg) void sys_check_timeouts(void) { - struct sys_timeo *tmptimeout; - u32_t diff; - sys_timeout_handler handler; - void *arg; - int had_one; - u32_t now; - - now = sys_now(); if (next_timeout) { + struct sys_timeo *tmptimeout; + u32_t diff; + sys_timeout_handler handler; + void *arg; + u8_t had_one; + u32_t now; + + now = sys_now(); /* this cares for wraparounds */ diff = LWIP_U32_DIFF(now, timeouts_last_time); do @@ -434,7 +434,7 @@ sys_check_timeouts(void) #endif /* PBUF_POOL_FREE_OOSEQ */ had_one = 0; tmptimeout = next_timeout; - if (tmptimeout->time <= diff) { + if (tmptimeout && (tmptimeout->time <= diff)) { /* timeout has expired */ had_one = 1; timeouts_last_time = now; From b9a2feff5e500d0c0ebbf5cff3e1c1a60274f4ef Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 21 Sep 2011 18:35:29 +0200 Subject: [PATCH 096/151] Converted runtime-sanity-checks into compile-time checks that can be disabled (since runtime checks can often not be seen on embedded targets) --- CHANGELOG | 4 +++ src/core/init.c | 66 ++++++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f1a32cea..36118e4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-09-21: Simon Goldschmidt + * init.c: Converted runtime-sanity-checks into compile-time checks that can + be disabled (since runtime checks can often not be seen on embedded targets) + 2011-09-11: Simon Goldschmidt * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file to get a clear separation of which functions an application or port may use diff --git a/src/core/init.c b/src/core/init.c index 3d8e2bb6..fa21edce 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -240,35 +240,48 @@ #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." #endif -#ifdef LWIP_DEBUG -static void -lwip_sanity_check(void) -{ - /* Warnings */ +#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS +#define LWIP_DISABLE_TCP_SANITY_CHECKS 0 +#endif +#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 +#endif + +/* MEMP sanity checks */ +#if !LWIP_DISABLE_MEMP_SANITY_CHECKS #if LWIP_NETCONN - if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n")); +#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) +#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." +#endif #endif /* LWIP_NETCONN */ +#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ + +/* TCP sanity checks */ +#if !LWIP_DISABLE_TCP_SANITY_CHECKS #if LWIP_TCP - if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n")); - if (TCP_SND_BUF < 2 * TCP_MSS) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n")); - if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); - if (TCP_SNDLOWAT >= TCP_SND_BUF) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n")); - if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n")); - if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); - if (TCP_WND < TCP_MSS) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); +#if MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN + #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_BUF < (2 * TCP_MSS) + #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) + #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDLOWAT >= TCP_SND_BUF + #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN + #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))) + #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif +#if TCP_WND < TCP_MSS + #error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." +#endif #endif /* LWIP_TCP */ -} -#else /* LWIP_DEBUG */ -#define lwip_sanity_check() -#endif /* LWIP_DEBUG */ +#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ /** * Perform Sanity check of user-configurable values, and initialize all modules. @@ -276,9 +289,6 @@ lwip_sanity_check(void) void lwip_init(void) { - /* Sanity check user-configurable values */ - lwip_sanity_check(); - /* Modules initialization */ stats_init(); #if !NO_SYS From 8d5514603e2bf5645fa775997602697d9f8474a0 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 21 Sep 2011 18:47:44 +0200 Subject: [PATCH 097/151] fixed default value of TCP_SND_BUF to not violate the sanity checks in init.c --- CHANGELOG | 4 ++++ src/include/lwip/opt.h | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 36118e4c..82644b70 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -61,6 +61,10 @@ HISTORY ++ Bugfixes: + 2011-09-21: Simon Goldschmidt + * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks + in init.c + 2011-09-20: Simon Goldschmidt * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 70d64bfe..cd1e47d6 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -968,10 +968,11 @@ /** - * TCP_SND_BUF: TCP sender buffer space (bytes). + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. */ #ifndef TCP_SND_BUF -#define TCP_SND_BUF 256 +#define TCP_SND_BUF (2 * TCP_MSS) #endif /** @@ -1434,7 +1435,8 @@ #endif /** - * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. */ #ifndef LWIP_SO_RCVTIMEO #define LWIP_SO_RCVTIMEO 0 From a2aa43a426bb01f926f7935299c19fe00030ab4e Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 21 Sep 2011 19:36:09 +0200 Subject: [PATCH 098/151] Implemented timeout on send (TCP only, bug #33820) --- CHANGELOG | 4 ++ src/api/api_lib.c | 16 ++++- src/api/api_msg.c | 137 +++++++++++++++++++++---------------- src/api/sockets.c | 18 ++++- src/include/lwip/api.h | 11 +++ src/include/lwip/api_msg.h | 3 + src/include/lwip/opt.h | 8 +++ 7 files changed, 135 insertions(+), 62 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 82644b70..a06c4817 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-09-21: Simon Goldschmidt + * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on + send (TCP only, bug #33820) + 2011-09-21: Simon Goldschmidt * init.c: Converted runtime-sanity-checks into compile-time checks that can be disabled (since runtime checks can often not be seen on embedded targets) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index f7375b0f..e1018046 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -611,12 +611,26 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, msg.msg.msg.w.dataptr = dataptr; msg.msg.msg.w.apiflags = apiflags; msg.msg.msg.w.len = size; +#if LWIP_SO_SNDTIMEO + if (conn->send_timeout != 0) { + /* get the time we started, which is later compared to + sys_now() + conn->send_timeout */ + msg.msg.msg.w.time_started = sys_now(); + } else { + msg.msg.msg.w.time_started = 0; + } +#endif /* LWIP_SO_SNDTIMEO */ + /* For locking the core: this _can_ be delayed on low memory/low send buffer, but if it is, this is done inside api_msg.c:do_write(), so we can use the non-blocking version here. */ err = TCPIP_APIMSG(&msg); if ((err == ERR_OK) && (bytes_written != NULL)) { - if (dontblock) { + if (dontblock +#if LWIP_SO_SNDTIMEO + || (conn->send_timeout != 0) +#endif /* LWIP_SO_SNDTIMEO */ + ) { /* nonblocking write: maybe the data has been sent partly */ *bytes_written = msg.msg.msg.w.len; } else { diff --git a/src/api/api_msg.c b/src/api/api_msg.c index fe97d3bc..4227a632 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -626,6 +626,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) conn->current_msg = NULL; conn->write_offset = 0; #endif /* LWIP_TCP */ +#if LWIP_SO_SNDTIMEO + conn->send_timeout = 0; +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO conn->recv_timeout = 0; #endif /* LWIP_SO_RCVTIMEO */ @@ -1217,79 +1220,95 @@ do_writemore(struct netconn *conn) LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", conn->write_offset < conn->current_msg->msg.w.len); - dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; - diff = conn->current_msg->msg.w.len - conn->write_offset; - if (diff > 0xffffUL) { /* max_u16_t */ - len = 0xffff; -#if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; -#endif - apiflags |= TCP_WRITE_FLAG_MORE; - } else { - len = (u16_t)diff; - } - available = tcp_sndbuf(conn->pcb.tcp); - if (available < len) { - /* don't try to write more than sendbuf */ - len = available; - if (dontblock){ - if (!len) { - err = ERR_WOULDBLOCK; - goto err_mem; - } +#if LWIP_SO_SNDTIMEO + if ((conn->send_timeout != 0) && + ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { + write_finished = 1; + if (conn->write_offset == 0) { + /* nothing has been written */ + err = ERR_WOULDBLOCK; + conn->current_msg->msg.w.len = 0; } else { + /* partial write */ + err = ERR_OK; + conn->current_msg->msg.w.len = conn->write_offset; + } + } else +#endif /* LWIP_SO_SNDTIMEO */ + { + dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; + diff = conn->current_msg->msg.w.len - conn->write_offset; + if (diff > 0xffffUL) { /* max_u16_t */ + len = 0xffff; #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif apiflags |= TCP_WRITE_FLAG_MORE; + } else { + len = (u16_t)diff; } - } - LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); - err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); - /* if OK or memory error, check available space */ - if ((err == ERR_OK) || (err == ERR_MEM)) { + available = tcp_sndbuf(conn->pcb.tcp); + if (available < len) { + /* don't try to write more than sendbuf */ + len = available; + if (dontblock){ + if (!len) { + err = ERR_WOULDBLOCK; + goto err_mem; + } + } else { +#if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; +#endif + apiflags |= TCP_WRITE_FLAG_MORE; + } + } + LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + /* if OK or memory error, check available space */ + if ((err == ERR_OK) || (err == ERR_MEM)) { err_mem: - if (dontblock && (len < conn->current_msg->msg.w.len)) { - /* non-blocking write did not write everything: mark the pcb non-writable - and let poll_tcp check writable space to mark the pcb writable again */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); - conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; - } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || - (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { - /* The queued byte- or pbuf-count exceeds the configured low-water limit, - let select mark this pcb as non-writable. */ - API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + if (dontblock && (len < conn->current_msg->msg.w.len)) { + /* non-blocking write did not write everything: mark the pcb non-writable + and let poll_tcp check writable space to mark the pcb writable again */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + } } - } - if (err == ERR_OK) { - conn->write_offset += len; - if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { - /* return sent length */ - conn->current_msg->msg.w.len = conn->write_offset; - /* everything was written */ - write_finished = 1; - conn->write_offset = 0; - } - tcp_output(conn->pcb.tcp); - } else if ((err == ERR_MEM) && !dontblock) { - /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called - we do NOT return to the application thread, since ERR_MEM is - only a temporary error! */ + if (err == ERR_OK) { + conn->write_offset += len; + if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { + /* return sent length */ + conn->current_msg->msg.w.len = conn->write_offset; + /* everything was written */ + write_finished = 1; + conn->write_offset = 0; + } + tcp_output(conn->pcb.tcp); + } else if ((err == ERR_MEM) && !dontblock) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called + we do NOT return to the application thread, since ERR_MEM is + only a temporary error! */ - /* tcp_write returned ERR_MEM, try tcp_output anyway */ - tcp_output(conn->pcb.tcp); + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + tcp_output(conn->pcb.tcp); #if LWIP_TCPIP_CORE_LOCKING - conn->flags |= NETCONN_FLAG_WRITE_DELAYED; + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif - } else { - /* On errors != ERR_MEM, we don't try writing any more but return - the error to the application thread. */ - write_finished = 1; - conn->current_msg->msg.w.len = 0; + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + conn->current_msg->msg.w.len = 0; + } } - if (write_finished) { /* everything was written: set back connection state and back to application task */ diff --git a/src/api/sockets.c b/src/api/sockets.c index 81cbf24e..1734d63d 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1535,7 +1535,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) case SO_ERROR: case SO_KEEPALIVE: /* UNIMPL case SO_CONTIMEO: */ - /* UNIMPL case SO_SNDTIMEO: */ +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: #endif /* LWIP_SO_RCVTIMEO */ @@ -1780,6 +1782,11 @@ lwip_getsockopt_internal(void *arg) s, *(int *)optval)); break; +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + *(int *)optval = netconn_get_sendtimeout(sock->conn); + break; +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: *(int *)optval = netconn_get_recvtimeout(sock->conn); @@ -1934,7 +1941,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case case SO_CONTIMEO: */ - /* UNIMPL case case SO_SNDTIMEO: */ +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: #endif /* LWIP_SO_RCVTIMEO */ @@ -2160,6 +2169,11 @@ lwip_setsockopt_internal(void *arg) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off"))); break; +#if LWIP_SO_SNDTIMEO + case SO_SNDTIMEO: + netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval); + break; +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: netconn_set_recvtimeout(sock->conn, *(int*)optval); diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 326528a2..4c985800 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -180,6 +180,11 @@ struct netconn { #if LWIP_SOCKET int socket; #endif /* LWIP_SOCKET */ +#if LWIP_SO_SNDTIMEO + /** timeout to wait for sending data (which means enqueueing data for sending + in internal buffers) */ + s32_t send_timeout; +#endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening netconns) */ @@ -299,6 +304,12 @@ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); /** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ #define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) +#if LWIP_SO_SNDTIMEO +/** Set the send timeout in milliseconds */ +#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) +/** Get the send timeout in milliseconds */ +#define netconn_get_sendtimeout(conn) ((conn)->send_timeout) +#endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO /** Set the receive timeout in milliseconds */ #define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index fca361d9..cadaa8cb 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -89,6 +89,9 @@ struct api_msg_msg { const void *dataptr; size_t len; u8_t apiflags; +#if LWIP_SO_SNDTIMEO + u32_t time_started; +#endif /* LWIP_SO_SNDTIMEO */ } w; /** used for do_recv */ struct { diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index cd1e47d6..aab3c8be 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1434,6 +1434,14 @@ #define LWIP_TCP_KEEPALIVE 0 #endif +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#ifndef LWIP_SO_SNDTIMEO +#define LWIP_SO_SNDTIMEO 0 +#endif + /** * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and * SO_RCVTIMEO processing. From 0aea1b608ac660b241a735269172b112830747f9 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 22 Sep 2011 06:24:58 +0200 Subject: [PATCH 099/151] Corrected fix for bug #34072 (UDP broadcast is received from wrong UDP pcb if udp port matches): pcbs bound to IPADDR_ANY did not receive broadcasts any more (bug #34294) --- src/core/udp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/udp.c b/src/core/udp.c index ff4d6896..04d52b19 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -261,10 +261,12 @@ udp_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && (pcb->so_options & SOF_BROADCAST) && - ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask)))))) { + (ipX_addr_isany(0, &pcb->local_ip) || + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast && - ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask)))))) { + (ipX_addr_isany(0, &pcb->local_ip) || + ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { #endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && From bb5d0c5c4aebcf316fecf4f5d9e2cf416bbd8462 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 22 Sep 2011 18:50:18 +0200 Subject: [PATCH 100/151] fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account --- CHANGELOG | 4 ++++ src/include/lwip/tcp_impl.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a06c4817..c3c14259 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,10 @@ HISTORY ++ Bugfixes: + 2011-09-22: Simon Goldschmidt + * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into + account + 2011-09-21: Simon Goldschmidt * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks in init.c diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 3f83b132..e9be9d95 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -85,7 +85,8 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); #define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ - ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ((tpcb)->unsent->len >= (tpcb)->mss))) || \ + ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ ) ? 1 : 0) #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) From e145c1d31cb086a0709ab416bc5a0f90b7ee9836 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 22 Sep 2011 19:19:07 +0200 Subject: [PATCH 101/151] Fixed tcp_accepted define (need brackets around the parameter) --- src/include/lwip/tcp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 8a7f418b..6af71583 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -338,7 +338,7 @@ void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) #else /* TCP_LISTEN_BACKLOG */ #define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ - pcb->state == LISTEN) + (pcb)->state == LISTEN) #endif /* TCP_LISTEN_BACKLOG */ void tcp_recved (struct tcp_pcb *pcb, u16_t len); From 797f26e45ba762345dc398263fec0fb4478748f6 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 22 Sep 2011 21:38:56 +0200 Subject: [PATCH 102/151] fixed bug #34360 tcp_shutdown: RST on unacked is not send when shutting down both rx AND tx --- CHANGELOG | 4 ++++ src/core/tcp.c | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c3c14259..c829a720 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,10 @@ HISTORY ++ Bugfixes: + 2011-09-22: Simon Goldschmidt + * tcp.c: fixed bug #34360 tcp_shutdown: RST on unacked is not send when + shutting down both rx AND tx + 2011-09-22: Simon Goldschmidt * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account diff --git a/src/core/tcp.c b/src/core/tcp.c index 43244939..85315171 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -305,12 +305,7 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) return ERR_CONN; } if (shut_rx) { - /* shut down the receive side: free buffered data... */ - if (pcb->refused_data != NULL) { - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - /* ... and set a flag not to receive any more data */ + /* shut down the receive side: set a flag not to receive any more data */ pcb->flags |= TF_RXCLOSED; } if (shut_tx) { @@ -320,12 +315,18 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) case SYN_RCVD: case ESTABLISHED: case CLOSE_WAIT: - return tcp_close_shutdown(pcb, 0); + /* if shut_tx AND shut_rx, send RST if we have unacked data */ + return tcp_close_shutdown(pcb, (u8_t)shut_rx); default: /* don't shut down other states */ break; } } + if (shut_rx && (pcb->refused_data != NULL)) { + /* shut down the receive side: free buffered data if we come here */ + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } /* @todo: return another err_t if not in correct state or already shut? */ return ERR_OK; } From 918470affc19c0023b0983b9e29cba24ea919d6a Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 23 Sep 2011 19:14:17 +0200 Subject: [PATCH 103/151] fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data --- CHANGELOG | 4 ++++ src/core/tcp.c | 23 +++++++++++++++++++-- src/core/tcp_in.c | 44 +++++++++++++++++++++++++++++++---------- src/include/lwip/pbuf.h | 2 ++ 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c3c14259..df44d8d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,10 @@ HISTORY ++ Bugfixes: + 2011-09-23: Simon Goldschmidt + * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for + the last packet including FIN can lose data + 2011-09-22: Simon Goldschmidt * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account diff --git a/src/core/tcp.c b/src/core/tcp.c index 43244939..3a03ac1e 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1054,13 +1054,32 @@ tcp_fasttmr(void) if (pcb->refused_data != NULL) { /* Notify again application with data previously received. */ err_t err; + u8_t refused_flags = pcb->refused_data->flags; + /* set pcb->refused_data to NULL in case the callback frees it and then + closes the pcb */ + struct pbuf *refused_data = pcb->refused_data; + pcb->refused_data = NULL; LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); - TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); + TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); if (err == ERR_OK) { - pcb->refused_data = NULL; + /* did refused_data include a FIN? If so, handle it now. */ + if (refused_flags & PBUF_FLAG_TCP_FIN) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + pcb = NULL; + } + } } else if (err == ERR_ABRT) { /* if err == ERR_ABRT, 'pcb' is already deallocated */ pcb = NULL; + } else { + /* data is still refused */ + pcb->refused_data = refused_data; } } diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 0cfb437b..c659b494 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -306,17 +306,36 @@ tcp_input(struct pbuf *p, struct netif *inp) /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { + u8_t refused_flags = pcb->refused_data->flags; + /* set pcb->refused_data to NULL in case the callback frees it and then + closes the pcb */ + struct pbuf *refused_data = pcb->refused_data; + pcb->refused_data = NULL; /* Notify again application with data previously received. */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); - TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); + TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); if (err == ERR_OK) { - pcb->refused_data = NULL; + /* did refused_data include a FIN? */ + if (refused_flags & PBUF_FLAG_TCP_FIN) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto dropped; + } + } } else if ((err == ERR_ABRT) || (tcplen > 0)) { /* if err == ERR_ABRT, 'pcb' is already deallocated */ /* Drop incoming packets because pcb is "full" (only if the incoming segment contains data). */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); goto dropped; + } else { + /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ + pcb->refused_data = refused_data; } } tcp_input_pcb = pcb; @@ -375,14 +394,19 @@ tcp_input(struct pbuf *p, struct netif *inp) /* If a FIN segment was received, we call the callback function with a NULL buffer to indicate EOF. */ if (recv_flags & TF_GOT_FIN) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - goto aborted; + if (pcb->refused_data != NULL) { + /* Delay this if we have refused data. */ + pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; + } else { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto aborted; + } } } diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 41c49099..786b288b 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -80,6 +80,8 @@ typedef enum { #define PBUF_FLAG_LLBCAST 0x08U /** indicates this pbuf was received as link-level multicast */ #define PBUF_FLAG_LLMCAST 0x10U +/** indicates this pbuf includes a TCP FIN flag */ +#define PBUF_FLAG_TCP_FIN 0x20U struct pbuf { /** next pbuf in singly linked pbuf chain */ From 98274d2145ea8c713b2fcb11c1f42ca1e013e8b5 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Fri, 23 Sep 2011 19:26:29 +0200 Subject: [PATCH 104/151] Reverted invalid fix for invalid bug #34360 done yesterday... --- CHANGELOG | 4 ---- src/core/tcp.c | 15 +++++++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b5811da4..df44d8d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,10 +69,6 @@ HISTORY * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data - 2011-09-22: Simon Goldschmidt - * tcp.c: fixed bug #34360 tcp_shutdown: RST on unacked is not send when - shutting down both rx AND tx - 2011-09-22: Simon Goldschmidt * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account diff --git a/src/core/tcp.c b/src/core/tcp.c index cd94e748..3a03ac1e 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -305,7 +305,12 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) return ERR_CONN; } if (shut_rx) { - /* shut down the receive side: set a flag not to receive any more data */ + /* shut down the receive side: free buffered data... */ + if (pcb->refused_data != NULL) { + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + /* ... and set a flag not to receive any more data */ pcb->flags |= TF_RXCLOSED; } if (shut_tx) { @@ -315,18 +320,12 @@ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) case SYN_RCVD: case ESTABLISHED: case CLOSE_WAIT: - /* if shut_tx AND shut_rx, send RST if we have unacked data */ - return tcp_close_shutdown(pcb, (u8_t)shut_rx); + return tcp_close_shutdown(pcb, 0); default: /* don't shut down other states */ break; } } - if (shut_rx && (pcb->refused_data != NULL)) { - /* shut down the receive side: free buffered data if we come here */ - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } /* @todo: return another err_t if not in correct state or already shut? */ return ERR_OK; } From 6c56151d27dc619e4139303a5ac5aee0f0c0e451 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sat, 24 Sep 2011 13:59:33 +0200 Subject: [PATCH 105/151] fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 --- CHANGELOG | 3 +++ src/include/lwip/mem.h | 1 + 2 files changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index df44d8d4..d2c15bf3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,9 @@ HISTORY ++ Bugfixes: + 2011-09-24: Simon Goldschmidt + * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 + 2011-09-23: Simon Goldschmidt * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data diff --git a/src/include/lwip/mem.h b/src/include/lwip/mem.h index 9507c0ae..5bb906b6 100644 --- a/src/include/lwip/mem.h +++ b/src/include/lwip/mem.h @@ -43,6 +43,7 @@ extern "C" { #include /* for size_t */ typedef size_t mem_size_t; +#define MEM_SIZE_F SZT_F /* aliases for C library malloc() */ #define mem_init() From bcfe3dacc6e0c4913235251f88c3c861b47b6432 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 26 Sep 2011 22:09:27 +0200 Subject: [PATCH 106/151] fixed unit tests (one TCP test failed, removed comma at the end of array initializers) --- test/unit/core/test_mem.c | 4 ++-- test/unit/etharp/test_etharp.c | 2 +- test/unit/lwip_unittests.c | 2 +- test/unit/tcp/test_tcp.c | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/unit/core/test_mem.c b/test/unit/core/test_mem.c index 85f914ed..d3a5d540 100644 --- a/test/unit/core/test_mem.c +++ b/test/unit/core/test_mem.c @@ -7,7 +7,7 @@ #error "This tests needs MEM-statistics enabled" #endif #if LWIP_DNS -/*#error "This test needs DNS turned off (as it mallocs on init)"*/ +#error "This test needs DNS turned off (as it mallocs on init)" #endif /* Setups/teardown functions */ @@ -67,7 +67,7 @@ Suite * mem_suite(void) { TFun tests[] = { - test_mem_one, + test_mem_one }; return create_suite("MEM", tests, sizeof(tests)/sizeof(TFun), mem_setup, mem_teardown); } diff --git a/test/unit/etharp/test_etharp.c b/test/unit/etharp/test_etharp.c index 207d73fd..cbbc9502 100644 --- a/test/unit/etharp/test_etharp.c +++ b/test/unit/etharp/test_etharp.c @@ -256,7 +256,7 @@ Suite * etharp_suite(void) { TFun tests[] = { - test_etharp_table, + test_etharp_table }; return create_suite("ETHARP", tests, sizeof(tests)/sizeof(TFun), etharp_setup, etharp_teardown); } diff --git a/test/unit/lwip_unittests.c b/test/unit/lwip_unittests.c index e0931464..72d7e6e3 100644 --- a/test/unit/lwip_unittests.c +++ b/test/unit/lwip_unittests.c @@ -19,7 +19,7 @@ int main() tcp_suite, tcp_oos_suite, mem_suite, - etharp_suite, + etharp_suite }; size_t num = sizeof(suites)/sizeof(void*); LWIP_ASSERT("No suites defined", num > 0); diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index aa86ff93..7b5535c1 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -200,10 +200,10 @@ START_TEST(test_tcp_fast_retx_recover) }while(err == ERR_OK); EXPECT_RET(err != ERR_OK); } - //err = tcp_output(pcb); - //EXPECT_RET(err == ERR_OK); - EXPECT_RET(txcounters.num_tx_calls == 0); - EXPECT_RET(txcounters.num_tx_bytes == 0); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + //EXPECT_RET(txcounters.num_tx_calls == 0); + //EXPECT_RET(txcounters.num_tx_bytes == 0); memset(&txcounters, 0, sizeof(txcounters)); /* send even more data */ @@ -231,7 +231,7 @@ START_TEST(test_tcp_fast_retx_recover) p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); - EXPECT_RET(txcounters.num_tx_calls == 0); + //EXPECT_RET(txcounters.num_tx_calls == 0); /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); @@ -273,7 +273,7 @@ tcp_suite(void) TFun tests[] = { test_tcp_new_abort, test_tcp_recv_inseq, - test_tcp_fast_retx_recover, + test_tcp_fast_retx_recover }; return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown); } From 7524f9006ef6b325bd67870d1cddbcb16a8e5f2a Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 26 Sep 2011 22:10:11 +0200 Subject: [PATCH 107/151] added unit tests for data-after-FIN --- test/unit/tcp/test_tcp_oos.c | 230 +++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/test/unit/tcp/test_tcp_oos.c b/test/unit/tcp/test_tcp_oos.c index 8e517b9f..c62dc178 100644 --- a/test/unit/tcp/test_tcp_oos.c +++ b/test/unit/tcp/test_tcp_oos.c @@ -526,6 +526,220 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) } END_TEST +static void +check_rx_counters(struct tcp_pcb *pcb, struct test_tcp_counters *counters, u32_t exp_close_calls, u32_t exp_rx_calls, + u32_t exp_rx_bytes, u32_t exp_err_calls, int exp_oos_count, int exp_oos_len) +{ + int oos_len; + EXPECT(counters->close_calls == exp_close_calls); + EXPECT(counters->recv_calls == exp_rx_calls); + EXPECT(counters->recved_bytes == exp_rx_bytes); + EXPECT(counters->err_calls == exp_err_calls); + /* check that pbuf is queued in ooseq */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == exp_oos_count); + oos_len = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(exp_oos_len == oos_len); +} + +/* this test uses 4 packets: + * - data (len=TCP_MSS) + * - FIN + * - data after FIN (len=1) (invalid) + * - 2nd FIN (invalid) + * + * the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq + */ +static void test_tcp_recv_ooseq_double_FINs(int delay_packet) +{ + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq; + ip_addr_t remote_ip, local_ip; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0; + int first_dropped = 0xff; + int last_dropped = 0; + + for(i = 0; i < sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* create segments */ + p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); + p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN); + k = 1; + p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK); + p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN); + + if(delay_packet & 1) { + /* drop normal data */ + first_dropped = 1; + last_dropped = 1; + } else { + /* send normal data */ + test_tcp_input(p, &netif); + exp_rx_calls++; + exp_rx_bytes += TCP_MSS; + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 2) { + /* drop FIN */ + if(first_dropped > 2) { + first_dropped = 2; + } + last_dropped = 2; + } else { + /* send FIN */ + test_tcp_input(p_normal_fin, &netif); + if (first_dropped < 2) { + /* already dropped packets, this one is ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen++; + } else { + /* inseq */ + exp_close_calls++; + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 4) { + /* drop data-after-FIN */ + if(first_dropped > 3) { + first_dropped = 3; + } + last_dropped = 3; + } else { + /* send data-after-FIN */ + test_tcp_input(p_data_after_fin, &netif); + if (first_dropped < 3) { + /* already dropped packets, this one is ooseq */ + if (delay_packet & 2) { + /* correct FIN was ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen += k; + } + } else { + /* inseq: no change */ + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 8) { + /* drop 2nd-FIN */ + if(first_dropped > 4) { + first_dropped = 4; + } + last_dropped = 4; + } else { + /* send 2nd-FIN */ + test_tcp_input(p_2nd_fin_ooseq, &netif); + if (first_dropped < 3) { + /* already dropped packets, this one is ooseq */ + if (delay_packet & 2) { + /* correct FIN was ooseq */ + exp_oos_pbufs++; + exp_oos_tcplen++; + } + } else { + /* inseq: no change */ + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 1) { + /* dropped normal data before */ + test_tcp_input(p, &netif); + exp_rx_calls++; + exp_rx_bytes += TCP_MSS; + if((delay_packet & 2) == 0) { + /* normal FIN was NOT delayed */ + exp_close_calls++; + exp_oos_pbufs = exp_oos_tcplen = 0; + } + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 2) { + /* dropped normal FIN before */ + test_tcp_input(p_normal_fin, &netif); + exp_close_calls++; + exp_oos_pbufs = exp_oos_tcplen = 0; + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 4) { + /* dropped data-after-FIN before */ + test_tcp_input(p_data_after_fin, &netif); + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + if(delay_packet & 8) { + /* dropped 2nd-FIN before */ + test_tcp_input(p_2nd_fin_ooseq, &netif); + } + /* check if counters are as expected */ + check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); + + /* check that ooseq data has been dumped */ + EXPECT(pcb->ooseq == NULL); + + /* make sure the pcb is freed */ + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +} + +/** create multiple segments and pass them to tcp_input with the first segment missing + * to simulate overruning the rxwin with ooseq queueing enabled */ +#define FIN_TEST(name, num) \ + START_TEST(name) \ + { \ + LWIP_UNUSED_ARG(_i); \ + test_tcp_recv_ooseq_double_FINs(num); \ + } \ + END_TEST +FIN_TEST(test_tcp_recv_ooseq_double_FIN_0, 0) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_1, 1) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_2, 2) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_3, 3) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_4, 4) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_5, 5) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_6, 6) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_7, 7) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_8, 8) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_9, 9) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_10, 10) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_11, 11) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_12, 12) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_13, 13) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_14, 14) +FIN_TEST(test_tcp_recv_ooseq_double_FIN_15, 15) + /** Create the suite including all tests for this module */ Suite * @@ -535,6 +749,22 @@ tcp_oos_suite(void) test_tcp_recv_ooseq_FIN_OOSEQ, test_tcp_recv_ooseq_FIN_INSEQ, test_tcp_recv_ooseq_overrun_rxwin, + test_tcp_recv_ooseq_double_FIN_0, + test_tcp_recv_ooseq_double_FIN_1, + test_tcp_recv_ooseq_double_FIN_2, + test_tcp_recv_ooseq_double_FIN_3, + test_tcp_recv_ooseq_double_FIN_4, + test_tcp_recv_ooseq_double_FIN_5, + test_tcp_recv_ooseq_double_FIN_6, + test_tcp_recv_ooseq_double_FIN_7, + test_tcp_recv_ooseq_double_FIN_8, + test_tcp_recv_ooseq_double_FIN_9, + test_tcp_recv_ooseq_double_FIN_10, + test_tcp_recv_ooseq_double_FIN_11, + test_tcp_recv_ooseq_double_FIN_12, + test_tcp_recv_ooseq_double_FIN_13, + test_tcp_recv_ooseq_double_FIN_14, + test_tcp_recv_ooseq_double_FIN_15 }; return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(TFun), tcp_oos_setup, tcp_oos_teardown); } From cfb70bccc1bb987c4dc5968077606503d4efd607 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 27 Sep 2011 07:49:04 +0200 Subject: [PATCH 108/151] bug #34406 dhcp_option_hostname() can overflow the pbuf --- CHANGELOG | 3 +++ src/core/dhcp.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d2c15bf3..95190ce8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,9 @@ HISTORY ++ Bugfixes: + 2011-09-27: Simon Goldschmidt + * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf + 2011-09-24: Simon Goldschmidt * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 diff --git a/src/core/dhcp.c b/src/core/dhcp.c index f224587b..489e6bc9 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -1028,10 +1028,6 @@ dhcp_renew(struct netif *netif) dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - #if 0 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); @@ -1041,6 +1037,11 @@ dhcp_renew(struct netif *netif) dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); #endif + +#if LWIP_NETIF_HOSTNAME + dhcp_option_hostname(dhcp, netif); +#endif /* LWIP_NETIF_HOSTNAME */ + /* append DHCP message trailer */ dhcp_option_trailer(dhcp); @@ -1303,8 +1304,11 @@ dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) if (namelen > 0) { u8_t len; const char *p = netif->hostname; - LWIP_ASSERT("DHCP: hostname is too long!", namelen <= 255); - len = LWIP_MAX(namelen, 255); + /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME + and 1 byte for trailer) */ + size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; + LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); + len = LWIP_MIN(namelen, available); dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); while (len--) { dhcp_option_byte(dhcp, *p++); @@ -1744,9 +1748,8 @@ dhcp_option_trailer(struct dhcp *dhcp) LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; /* packet is too small, or not 4 byte aligned? */ - while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) { - /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ - LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); + while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && + (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { /* add a fill/padding byte */ dhcp->msg_out->options[dhcp->options_out_len++] = 0; } From 998f109fc81b8a9b8503cbb4936dd321f98b1415 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 27 Sep 2011 21:08:49 +0200 Subject: [PATCH 109/151] fixed bug #28288: Data after FIN in oos queue --- CHANGELOG | 3 +++ src/core/tcp_in.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95190ce8..998fa7e0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -65,6 +65,9 @@ HISTORY ++ Bugfixes: + 2011-09-27: Simon Goldschmidt + * tcp_in.c: fixed bug #28288: Data after FIN in oos queue + 2011-09-27: Simon Goldschmidt * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index c659b494..704d310c 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -892,6 +892,8 @@ tcp_receive(struct tcp_pcb *pcb) u16_t new_tot_len; int found_dupack = 0; + LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); + if (flags & TCP_ACK) { right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; @@ -1132,8 +1134,10 @@ tcp_receive(struct tcp_pcb *pcb) } /* If the incoming segment contains data, we must process it - further. */ - if (tcplen > 0) { + further unless the pcb already received a FIN. + (RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, + LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ + if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { /* This code basically does three things: +) If the incoming segment contains data that is the next From 07c610e068cbff44a2305e803ff1631dab1527a5 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 27 Sep 2011 22:42:46 +0200 Subject: [PATCH 110/151] Implemented limiting data on ooseq queue (task #9989) (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h), added unit test for this new feature --- CHANGELOG | 4 + src/core/tcp_in.c | 33 ++++++- src/include/lwip/opt.h | 16 ++++ test/unit/tcp/test_tcp_oos.c | 178 ++++++++++++++++++++++++++++++++++- 4 files changed, 226 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 998fa7e0..8138bbf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2011-09-27: Simon Goldschmidt + * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989) + (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h) + 2011-09-21: Simon Goldschmidt * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on send (TCP only, bug #33820) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 704d310c..df7c33dd 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -891,6 +891,10 @@ tcp_receive(struct tcp_pcb *pcb) u32_t right_wnd_edge; u16_t new_tot_len; int found_dupack = 0; +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS + u32_t ooseq_blen; + u16_t ooseq_qlen; +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); @@ -1275,8 +1279,7 @@ tcp_receive(struct tcp_pcb *pcb) pcb->ooseq = pcb->ooseq->next; tcp_seg_free(old_ooseq); } - } - else { + } else { next = pcb->ooseq; /* Remove all segments on ooseq that are covered by inseg already. * FIN is copied from ooseq to inseg if present. */ @@ -1516,8 +1519,32 @@ tcp_receive(struct tcp_pcb *pcb) prev = next; } } +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS + /* Check that the data on ooseq doesn't exceed one of the limits + and throw away everything above that limit. */ + ooseq_blen = 0; + ooseq_qlen = 0; + prev = NULL; + for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) { + struct pbuf *p = next->p; + ooseq_blen += p->tot_len; + ooseq_qlen += pbuf_clen(p); + if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || + (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { + /* too much ooseq data, dump this and everything after it */ + tcp_segs_free(next); + if (prev == NULL) { + /* first ooseq segment is too much, dump the whole queue */ + pcb->ooseq = NULL; + } else { + /* just dump 'next' and everything after it */ + prev->next = NULL; + } + break; + } + } +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ #endif /* TCP_QUEUE_OOSEQ */ - } } else { /* The incoming segment is not withing the window. */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index aab3c8be..2565022c 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1001,6 +1001,22 @@ #define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) #endif +/** + * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. + */ +#ifndef TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_BYTES 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. + * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. + */ +#ifndef TCP_OOSEQ_MAX_PBUFS +#define TCP_OOSEQ_MAX_PBUFS 0 +#endif + /** * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ diff --git a/test/unit/tcp/test_tcp_oos.c b/test/unit/tcp/test_tcp_oos.c index c62dc178..764de1c4 100644 --- a/test/unit/tcp/test_tcp_oos.c +++ b/test/unit/tcp/test_tcp_oos.c @@ -36,6 +36,18 @@ static int tcp_oos_count(struct tcp_pcb* pcb) return num; } +/** Get the numbers of pbufs on the ooseq list */ +static int tcp_oos_pbuf_count(struct tcp_pcb* pcb) +{ + int num = 0; + struct tcp_seg* seg = pcb->ooseq; + while(seg != NULL) { + num += pbuf_clen(seg->p); + seg = seg->next; + } + return num; +} + /** Get the seqno of a segment (by index) on the ooseq list * * @param pcb the pcb to check for ooseq segments @@ -440,6 +452,7 @@ static char data_full_wnd[TCP_WND]; * to simulate overruning the rxwin with ooseq queueing enabled */ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) { +#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS int i, k; struct test_tcp_counters counters; struct tcp_pcb* pcb; @@ -449,7 +462,6 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) struct netif netif; int datalen = 0; int datalen2; - LWIP_UNUSED_ARG(_i); for(i = 0; i < sizeof(data_full_wnd); i++) { data_full_wnd[i] = (char)i; @@ -523,6 +535,166 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +START_TEST(test_tcp_recv_ooseq_max_bytes) +{ +#if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + int i, k; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_ovr; + ip_addr_t remote_ip, local_ip; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ + + /* create segments and 'recv' them */ + for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) { + int count; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k], + TCP_MSS, k, 0, TCP_ACK); + EXPECT_RET(p != NULL); + EXPECT_RET(p->next == NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_pbuf_count(pcb); + EXPECT_OOSEQ(count == i); + datalen = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == (i * TCP_MSS)); + } + + /* pass in one more segment, overrunning the limit */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue (ensure the new segment was not accepted) */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS)); + + /* make sure the pcb is freed */ + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +#endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ + LWIP_UNUSED_ARG(_i); +} +END_TEST + +START_TEST(test_tcp_recv_ooseq_max_pbufs) +{ +#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) + int i; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p_ovr; + ip_addr_t remote_ip, local_ip; + u16_t remote_port = 0x100, local_port = 0x101; + struct netif netif; + int datalen = 0; + int datalen2; + + for(i = 0; i < sizeof(data_full_wnd); i++) { + data_full_wnd[i] = (char)i; + } + + /* initialize local vars */ + memset(&netif, 0, sizeof(netif)); + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + /* initialize counter struct */ + memset(&counters, 0, sizeof(counters)); + counters.expected_data_len = TCP_WND; + counters.expected_data = data_full_wnd; + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->rcv_nxt = 0x8000; + + /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ + + /* create segments and 'recv' them */ + for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) { + int count; + struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i], + 1, i, 0, TCP_ACK); + EXPECT_RET(p != NULL); + EXPECT_RET(p->next == NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue */ + count = tcp_oos_pbuf_count(pcb); + EXPECT_OOSEQ(count == i); + datalen = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen == i); + } + + /* pass in one more segment, overrunning the limit */ + p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK); + EXPECT_RET(p_ovr != NULL); + /* pass the segment to tcp_input */ + test_tcp_input(p_ovr, &netif); + /* check if counters are as expected */ + EXPECT(counters.close_calls == 0); + EXPECT(counters.recv_calls == 0); + EXPECT(counters.recved_bytes == 0); + EXPECT(counters.err_calls == 0); + /* check ooseq queue (ensure the new segment was not accepted) */ + EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); + datalen2 = tcp_oos_tcplen(pcb); + EXPECT_OOSEQ(datalen2 == (i-1)); + + /* make sure the pcb is freed */ + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ + LWIP_UNUSED_ARG(_i); } END_TEST @@ -662,7 +834,7 @@ static void test_tcp_recv_ooseq_double_FINs(int delay_packet) exp_oos_tcplen++; } } else { - /* inseq: no change */ + /* inseq: no change */ } } /* check if counters are as expected */ @@ -749,6 +921,8 @@ tcp_oos_suite(void) test_tcp_recv_ooseq_FIN_OOSEQ, test_tcp_recv_ooseq_FIN_INSEQ, test_tcp_recv_ooseq_overrun_rxwin, + test_tcp_recv_ooseq_max_bytes, + test_tcp_recv_ooseq_max_pbufs, test_tcp_recv_ooseq_double_FIN_0, test_tcp_recv_ooseq_double_FIN_1, test_tcp_recv_ooseq_double_FIN_2, From 5c68bbe16ffb2e091116cecf9aa9e85962c20e67 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 29 Sep 2011 21:12:34 +0200 Subject: [PATCH 111/151] Tried to fix bug #32417 ("TCP_OVERSIZE seems to have problems with (fast-)retransmission"): Reset pcb->unsent_oversize in 2 more places... --- CHANGELOG | 3 +++ src/core/tcp_in.c | 5 +++++ src/core/tcp_out.c | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 8138bbf7..36aafe7c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-09-27: Simon Goldschmidt + * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... + 2011-09-27: Simon Goldschmidt * tcp_in.c: fixed bug #28288: Data after FIN in oos queue diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index df7c33dd..82ccedff 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -1090,6 +1090,11 @@ tcp_receive(struct tcp_pcb *pcb) next = pcb->unsent; pcb->unsent = pcb->unsent->next; +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); /* Prevent ACK for FIN to generate a sent event */ diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 2b1319c5..1a6ff53b 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1256,6 +1256,7 @@ tcp_rexmit_rto(struct tcp_pcb *pcb) pcb->unsent = pcb->unacked; /* unacked queue is now empty */ pcb->unacked = NULL; + /* last unsent hasn't changed, no need to reset unsent_oversize */ /* increment number of retransmissions */ ++pcb->nrtx; @@ -1296,6 +1297,12 @@ tcp_rexmit(struct tcp_pcb *pcb) } seg->next = *cur_seg; *cur_seg = seg; +#if TCP_OVERSIZE + if (seg->next == NULL) { + /* the retransmitted segment is last in unsent, so reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ ++pcb->nrtx; From 9d31401d47a0ea1b1b15173465efaacc2a9cee5d Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 9 Oct 2011 14:30:49 +0200 Subject: [PATCH 112/151] fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong --- CHANGELOG | 3 +++ src/core/ipv4/ip4.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 36aafe7c..c88026e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-09: Simon Goldschmidt + * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong + 2011-09-27: Simon Goldschmidt * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 8cbaa23f..73b17ea0 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -83,7 +83,7 @@ || (LWIP_IP_ACCEPT_UDP_PORT(port))) #elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ /* accept custom port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port)) +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) #else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ /* accept DHCP client port only */ #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) From f29bdd21a778eef253f037aae444f61db7f3cc36 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Sun, 9 Oct 2011 20:11:33 +0200 Subject: [PATCH 113/151] fixed bug #34426: tcp_zero_window_probe() transmits incorrect byte value when pcb->unacked != NULL --- CHANGELOG | 4 ++++ src/core/tcp_out.c | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c88026e9..2f844e44 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-09: Simon Goldschmidt + * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect + byte value when pcb->unacked != NULL + 2011-10-09: Simon Goldschmidt * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 1a6ff53b..6ad1c1ae 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1456,9 +1456,11 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); } else { /* Data segment, copy in one byte from the head of the unacked queue */ - struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload; char *d = ((char *)p->payload + TCP_HLEN); - pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); + /* Depending on whether the segment has already been sent (unacked) or not + (unsent), seg->p->payload points to the IP header or TCP header. + Ensure we copy the first TCP data byte: */ + pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); } #if CHECKSUM_GEN_TCP From ce98df59f1bb18ff157f06932ad69c5274c97fbf Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 10 Oct 2011 21:06:50 +0200 Subject: [PATCH 114/151] Added unit test case for persist timer / zero window probes --- test/unit/tcp/tcp_helper.c | 71 +++++++++++----- test/unit/tcp/tcp_helper.h | 4 + test/unit/tcp/test_tcp.c | 160 ++++++++++++++++++++++++++++++++++++- 3 files changed, 213 insertions(+), 22 deletions(-) diff --git a/test/unit/tcp/tcp_helper.c b/test/unit/tcp/tcp_helper.c index 02724986..52a9a1f7 100644 --- a/test/unit/tcp/tcp_helper.c +++ b/test/unit/tcp/tcp_helper.c @@ -36,23 +36,11 @@ tcp_remove_all(void) fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0); } -/** Create a TCP segment usable for passing to tcp_input - * - IP-addresses, ports, seqno and ackno are taken from pcb - * - seqno and ackno can be altered with an offset - */ -struct pbuf* -tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, - u32_t ackno_offset, u8_t headerflags) -{ - return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, - data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); -} - /** Create a TCP segment usable for passing to tcp_input */ -struct pbuf* -tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, +static struct pbuf* +tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, - u32_t seqno, u32_t ackno, u8_t headerflags) + u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) { struct pbuf *p, *q; struct ip_hdr* iphdr; @@ -91,7 +79,7 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); TCPH_FLAGS_SET(tcphdr, headerflags); - tcphdr->wnd = htons(TCP_WND); + tcphdr->wnd = htons(wnd); if (data_len > 0) { /* let p point to TCP data */ @@ -112,6 +100,40 @@ tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, return p; } +/** Create a TCP segment usable for passing to tcp_input */ +struct pbuf* +tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, + u16_t src_port, u16_t dst_port, void* data, size_t data_len, + u32_t seqno, u32_t ackno, u8_t headerflags) +{ + return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data, + data_len, seqno, ackno, headerflags, TCP_WND); +} + +/** Create a TCP segment usable for passing to tcp_input + * - IP-addresses, ports, seqno and ackno are taken from pcb + * - seqno and ackno can be altered with an offset + */ +struct pbuf* +tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, + u32_t ackno_offset, u8_t headerflags) +{ + return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, + data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); +} + +/** Create a TCP segment usable for passing to tcp_input + * - IP-addresses, ports, seqno and ackno are taken from pcb + * - seqno and ackno can be altered with an offset + * - TCP window can be adjusted + */ +struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, + u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd) +{ + return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, + data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd); +} + /** Safely bring a tcp_pcb into the requested state */ void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, @@ -239,11 +261,18 @@ static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, LWIP_UNUSED_ARG(ipaddr); txcounters->num_tx_calls++; txcounters->num_tx_bytes += p->tot_len; - /*if (txcounters->tx_packets == NULL) { - txcounters->tx_packets = p; - } else { - pbuf_cat(txcounters->tx_packets, p); - }*/ + if (txcounters->copy_tx_packets) { + struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); + err_t err; + EXPECT(p_copy != NULL); + err = pbuf_copy(p_copy, p); + EXPECT(err == ERR_OK); + if (txcounters->tx_packets == NULL) { + txcounters->tx_packets = p_copy; + } else { + pbuf_cat(txcounters->tx_packets, p_copy); + } + } return ERR_OK; } diff --git a/test/unit/tcp/tcp_helper.h b/test/unit/tcp/tcp_helper.h index d82cef54..4a72c935 100644 --- a/test/unit/tcp/tcp_helper.h +++ b/test/unit/tcp/tcp_helper.h @@ -22,6 +22,8 @@ struct test_tcp_counters { struct test_tcp_txcounters { u32_t num_tx_calls; u32_t num_tx_bytes; + u8_t copy_tx_packets; + struct pbuf *tx_packets; }; /* Helper functions */ @@ -32,6 +34,8 @@ struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, u32_t seqno, u32_t ackno, u8_t headerflags); struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags); +struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, + u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd); void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port); void test_tcp_counters_err(void* arg, err_t err); diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index 7b5535c1..23903a89 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -7,6 +7,9 @@ #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS #error "This tests needs TCP- and MEMP-statistics enabled" #endif +#if TCP_SND_BUF <= TCP_WND +#error "This tests needs TCP_SND_BUF to be > TCP_WND" +#endif /* Setups/teardown functions */ @@ -265,6 +268,159 @@ START_TEST(test_tcp_fast_retx_recover) } END_TEST +static u8_t tx_data[TCP_WND*2]; + +/** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. + * At the end, send more data. */ +static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf *p; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; + u16_t sent_total, i; + u8_t expected = 0xFE; + + for (i = 0; i < sizeof(tx_data); i++) { + u8_t d = (u8_t)i; + if (d == 0xFE) { + d = 0xF0; + } + tx_data[i] = d; + } + if (zero_window_probe_from_unsent) { + tx_data[TCP_WND] = expected; + } else { + tx_data[0] = expected; + } + + /* initialize local vars */ + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + IP4_ADDR(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + memset(&txcounters, 0, sizeof(txcounters)); + + /* create and initialize the pcb */ + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = pcb->snd_wnd; + + /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */ + sent_total = 0; + if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) { + u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS; + err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + sent_total += initial_data_len; + } + for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + } + EXPECT(sent_total == (TCP_WND - TCP_MSS)); + + /* now ACK the packet before the first */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + /* ensure this didn't trigger a retransmission */ + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + + /* send the last packet, now a complete window has been sent */ + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + sent_total += TCP_MSS; + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + + if (zero_window_probe_from_unsent) { + /* ACK all data but close the TX window */ + p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0); + test_tcp_input(p, &netif); + /* ensure this didn't trigger any transmission */ + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + } + + /* send one byte more (out of window) -> persist timer starts */ + err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + err = tcp_output(pcb); + EXPECT_RET(err == ERR_OK); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + memset(&txcounters, 0, sizeof(txcounters)); + + /* call tcp_timer some more times to let persist timer count up */ + if (zero_window_probe_from_unsent) { + tcp_tmr(); + } + for (i = 0; i < 4; i++) { + tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + } + + /* this should trigger the zero-window-probe */ + txcounters.copy_tx_packets = 1; + tcp_tmr(); + txcounters.copy_tx_packets = 0; + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == 1 + 40U); + EXPECT(txcounters.tx_packets != NULL); + if (txcounters.tx_packets != NULL) { + u8_t sent; + u16_t ret; + ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); + EXPECT(ret == 1); + EXPECT(sent == expected); + } + if (txcounters.tx_packets != NULL) { + pbuf_free(txcounters.tx_packets); + txcounters.tx_packets = NULL; + } + + /* make sure the pcb is freed */ + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +} + +START_TEST(test_tcp_tx_full_window_lost_from_unsent) +{ + LWIP_UNUSED_ARG(_i); + test_tcp_tx_full_window_lost(1); +} +END_TEST + +START_TEST(test_tcp_tx_full_window_lost_from_unacked) +{ + LWIP_UNUSED_ARG(_i); + test_tcp_tx_full_window_lost(0); +} +END_TEST /** Create the suite including all tests for this module */ Suite * @@ -273,7 +429,9 @@ tcp_suite(void) TFun tests[] = { test_tcp_new_abort, test_tcp_recv_inseq, - test_tcp_fast_retx_recover + test_tcp_fast_retx_recover, + test_tcp_tx_full_window_lost_from_unacked, + test_tcp_tx_full_window_lost_from_unsent }; return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown); } From b4c4fae3f5e257c1f1a96ecb84550d4b98dcba6a Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 11 Oct 2011 21:41:58 +0200 Subject: [PATCH 115/151] slightly rearranged freeing an acked segment to prevent keeping the reference too long --- src/core/tcp_in.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 82ccedff..17ed0b01 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -688,6 +688,7 @@ tcp_process(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); rseg = pcb->unacked; pcb->unacked = rseg->next; + tcp_seg_free(rseg); /* If there's nothing left to acknowledge, stop the retransmit timer, otherwise reset it to start again */ @@ -698,8 +699,6 @@ tcp_process(struct tcp_pcb *pcb) pcb->nrtx = 0; } - tcp_seg_free(rseg); - /* Call the user specified function to call when sucessfully * connected. */ TCP_EVENT_CONNECTED(pcb, ERR_OK, err); From ab51f3bec04a526e599b5d0bae2977649e7eb483 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 11 Oct 2011 21:43:27 +0200 Subject: [PATCH 116/151] added unit test cases for seqno wraparound on fast-rexmit and rto-rexmit (unsent/unacked lists must be correctly sorted) --- test/unit/tcp/test_tcp.c | 232 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 5 deletions(-) diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index 23903a89..d6832504 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -4,6 +4,10 @@ #include "lwip/stats.h" #include "tcp_helper.h" +#ifdef _MSC_VER +#pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */ +#endif + #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS #error "This tests needs TCP- and MEMP-statistics enabled" #endif @@ -11,11 +15,30 @@ #error "This tests needs TCP_SND_BUF to be > TCP_WND" #endif +static u8_t test_tcp_timer; + +/* our own version of tcp_tmr so we can reset fast/slow timer state */ +static void +test_tcp_tmr(void) +{ + tcp_fasttmr(); + if (++test_tcp_timer & 1) { + tcp_slowtmr(); + } +} + /* Setups/teardown functions */ static void tcp_setup(void) { + /* reset iss to default (6510) */ + tcp_ticks = 0; + tcp_ticks = 0 - (tcp_next_iss() - 6510); + tcp_next_iss(); + tcp_ticks = 0; + + test_tcp_timer = 0; tcp_remove_all(); } @@ -270,6 +293,206 @@ END_TEST static u8_t tx_data[TCP_WND*2]; +static void +check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected) +{ + struct tcp_seg *s = segs; + int i; + for (i = 0; i < num_expected; i++, s = s->next) { + EXPECT_RET(s != NULL); + EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i])); + } + EXPECT(s == NULL); +} + +/** Send data with sequence numbers that wrap around the u32_t range. + * Then, provoke fast retransmission by duplicate ACKs and check that all + * segment lists are still properly sorted. */ +START_TEST(test_tcp_fast_rexmit_wraparound) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + struct pbuf* p; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; +#define SEQNO1 (0xFFFFFF00 - TCP_MSS) +#define ISS 6510 + u16_t i, sent_total = 0; + u32_t seqnos[] = { + SEQNO1, + SEQNO1 + (1 * TCP_MSS), + SEQNO1 + (2 * TCP_MSS), + SEQNO1 + (3 * TCP_MSS), + SEQNO1 + (4 * TCP_MSS), + SEQNO1 + (5 * TCP_MSS)}; + LWIP_UNUSED_ARG(_i); + + for (i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (u8_t)i; + } + + /* initialize local vars */ + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + IP4_ADDR(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + + /* create and initialize the pcb */ + tcp_ticks = SEQNO1 - ISS; + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + EXPECT(pcb->lastack == SEQNO1); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = 2*TCP_MSS; + + /* send 6 mss-sized segments */ + for (i = 0; i < 6; i++) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + sent_total += TCP_MSS; + } + check_seqnos(pcb->unsent, 6, seqnos); + EXPECT(pcb->unacked == NULL); + err = tcp_output(pcb); + EXPECT(txcounters.num_tx_calls == 2); + EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); + memset(&txcounters, 0, sizeof(txcounters)); + + check_seqnos(pcb->unacked, 2, seqnos); + check_seqnos(pcb->unsent, 4, &seqnos[2]); + + /* ACK the first segment */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK); + test_tcp_input(p, &netif); + /* ensure this didn't trigger a retransmission */ + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); + memset(&txcounters, 0, sizeof(txcounters)); + check_seqnos(pcb->unacked, 2, &seqnos[1]); + check_seqnos(pcb->unsent, 3, &seqnos[3]); + + /* 3 dupacks */ + EXPECT(pcb->dupacks == 0); + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(pcb->dupacks == 1); + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(pcb->dupacks == 2); + /* 3rd dupack -> fast rexmit */ + p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); + test_tcp_input(p, &netif); + EXPECT(pcb->dupacks == 3); + EXPECT(txcounters.num_tx_calls == 4); + memset(&txcounters, 0, sizeof(txcounters)); + EXPECT(pcb->unsent == NULL); + check_seqnos(pcb->unacked, 5, &seqnos[1]); + + /* make sure the pcb is freed */ + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +} +END_TEST + +/** Send data with sequence numbers that wrap around the u32_t range. + * Then, provoke RTO retransmission and check that all + * segment lists are still properly sorted. */ +START_TEST(test_tcp_rto_rexmit_wraparound) +{ + struct netif netif; + struct test_tcp_txcounters txcounters; + struct test_tcp_counters counters; + struct tcp_pcb* pcb; + ip_addr_t remote_ip, local_ip, netmask; + u16_t remote_port = 0x100, local_port = 0x101; + err_t err; +#define SEQNO1 (0xFFFFFF00 - TCP_MSS) +#define ISS 6510 + u16_t i, sent_total = 0; + u32_t seqnos[] = { + SEQNO1, + SEQNO1 + (1 * TCP_MSS), + SEQNO1 + (2 * TCP_MSS), + SEQNO1 + (3 * TCP_MSS), + SEQNO1 + (4 * TCP_MSS), + SEQNO1 + (5 * TCP_MSS)}; + LWIP_UNUSED_ARG(_i); + + for (i = 0; i < sizeof(tx_data); i++) { + tx_data[i] = (u8_t)i; + } + + /* initialize local vars */ + IP4_ADDR(&local_ip, 192, 168, 1, 1); + IP4_ADDR(&remote_ip, 192, 168, 1, 2); + IP4_ADDR(&netmask, 255, 255, 255, 0); + test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); + memset(&counters, 0, sizeof(counters)); + + /* create and initialize the pcb */ + tcp_ticks = 0; + tcp_ticks = 0 - tcp_next_iss(); + tcp_ticks = SEQNO1 - tcp_next_iss(); + pcb = test_tcp_new_counters_pcb(&counters); + EXPECT_RET(pcb != NULL); + EXPECT(pcb->lastack == SEQNO1); + tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); + pcb->mss = TCP_MSS; + /* disable initial congestion window (we don't send a SYN here...) */ + pcb->cwnd = 2*TCP_MSS; + + /* send 6 mss-sized segments */ + for (i = 0; i < 6; i++) { + err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); + EXPECT_RET(err == ERR_OK); + sent_total += TCP_MSS; + } + check_seqnos(pcb->unsent, 6, seqnos); + EXPECT(pcb->unacked == NULL); + err = tcp_output(pcb); + EXPECT(txcounters.num_tx_calls == 2); + EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); + memset(&txcounters, 0, sizeof(txcounters)); + + check_seqnos(pcb->unacked, 2, seqnos); + check_seqnos(pcb->unsent, 4, &seqnos[2]); + + /* call the tcp timer some times */ + for (i = 0; i < 10; i++) { + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 0); + } + /* 11th call to tcp_tmr: RTO rexmit fires */ + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 1); + check_seqnos(pcb->unacked, 1, seqnos); + check_seqnos(pcb->unsent, 5, &seqnos[1]); + + /* fake greater cwnd */ + pcb->cwnd = pcb->snd_wnd; + /* send more data */ + err = tcp_output(pcb); + EXPECT(err == ERR_OK); + /* check queues are sorted */ + EXPECT(pcb->unsent == NULL); + check_seqnos(pcb->unacked, 6, seqnos); + + /* make sure the pcb is freed */ + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); + tcp_abort(pcb); + EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); +} +END_TEST + /** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. * At the end, send more data. */ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) @@ -374,18 +597,15 @@ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) memset(&txcounters, 0, sizeof(txcounters)); /* call tcp_timer some more times to let persist timer count up */ - if (zero_window_probe_from_unsent) { - tcp_tmr(); - } for (i = 0; i < 4; i++) { - tcp_tmr(); + test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); } /* this should trigger the zero-window-probe */ txcounters.copy_tx_packets = 1; - tcp_tmr(); + test_tcp_tmr(); txcounters.copy_tx_packets = 0; EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == 1 + 40U); @@ -430,6 +650,8 @@ tcp_suite(void) test_tcp_new_abort, test_tcp_recv_inseq, test_tcp_fast_retx_recover, + test_tcp_fast_rexmit_wraparound, + test_tcp_rto_rexmit_wraparound, test_tcp_tx_full_window_lost_from_unacked, test_tcp_tx_full_window_lost_from_unsent }; From c74d881d3d854900e6ef8a7126356d45672342b6 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Wed, 12 Oct 2011 18:17:07 +0200 Subject: [PATCH 117/151] fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 --- CHANGELOG | 3 +++ src/core/pbuf.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2f844e44..36ca4151 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-12: Simon Goldschmidt + * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 + 2011-10-09: Simon Goldschmidt * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect byte value when pcb->unacked != NULL diff --git a/src/core/pbuf.c b/src/core/pbuf.c index cb79a987..01fc2157 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -358,7 +358,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) * @param p pointer to the custom pbuf to initialize (already allocated) * @param payload_mem pointer to the buffer that is used for payload and headers, * must be at least big enough to hold 'length' plus the header size, - * may be NULL if set later + * may be NULL if set later. + * ATTENTION: The caller is responsible for correct alignment of this buffer!! * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least * big enough to hold 'length' plus the header size */ @@ -398,7 +399,7 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust p->pbuf.next = NULL; if (payload_mem != NULL) { - p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset)); + p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); } else { p->pbuf.payload = NULL; } From dc34636598ed89919403f1501e33554ddca74ca4 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 13 Oct 2011 19:25:11 +0200 Subject: [PATCH 118/151] fixed bug #34540: compiler error when CORE_LOCKING is used and not all protocols are enabled --- CHANGELOG | 4 ++++ src/api/api_lib.c | 15 ++++++++++++--- src/api/sockets.c | 21 ++++++++++++++++----- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 36ca4151..e2fe0a23 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-13: Simon Goldschmidt + * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is + used and not all protocols are enabled + 2011-10-12: Simon Goldschmidt * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 diff --git a/src/api/api_lib.c b/src/api/api_lib.c index e1018046..cbae2214 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -372,7 +372,10 @@ netconn_recv_data(struct netconn *conn, void **new_buf) #endif /* LWIP_SO_RCVTIMEO*/ #if LWIP_TCP - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { if (!netconn_get_noautorecved(conn) || (buf == NULL)) { /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here @@ -461,7 +464,10 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); #if LWIP_TCP - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { struct pbuf *p = NULL; /* This is not a listening netconn, since recvmbox is set */ @@ -485,8 +491,11 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) *new_buf = buf; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; - } else + } #endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ { #if (LWIP_UDP || LWIP_RAW) return netconn_recv_data(conn, (void **)new_buf); diff --git a/src/api/sockets.c b/src/api/sockets.c index 1734d63d..081709ab 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -914,18 +914,29 @@ lwip_sendto(int s, const void *data, size_t size, int flags, to, &remote_addr_tmp, remote_port); remote_addr = &remote_addr_tmp; } else { - remote_addr = &sock->conn->pcb.raw->remote_ip; - if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) { - remote_port = 0; - } else { + remote_addr = &sock->conn->pcb.ip->remote_ip; +#if LWIP_UDP + if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) { remote_port = sock->conn->pcb.udp->remote_port; + } else +#endif /* LWIP_UDP */ + { + remote_port = 0; } } LOCK_TCPIP_CORE(); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { +#if LWIP_RAW err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr)); - } else { +#else /* LWIP_RAW */ + err = ERR_ARG; +#endif /* LWIP_RAW */ + } +#if LWIP_UDP && LWIP_RAW + else +#endif /* LWIP_UDP && LWIP_RAW */ + { #if LWIP_UDP #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, From cf1be4ae2d2b80b87df9b1e199e60e301ce6d1c5 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 13 Oct 2011 19:29:48 +0200 Subject: [PATCH 119/151] fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex: removed that define --- CHANGELOG | 3 +++ src/core/timers.c | 2 +- src/include/lwip/def.h | 4 ---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e2fe0a23..0f2bc6e5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-13: Simon Goldschmidt + * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex + 2011-10-13: Simon Goldschmidt * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is used and not all protocols are enabled diff --git a/src/core/timers.c b/src/core/timers.c index 5ae6d0c4..c8ead4e7 100644 --- a/src/core/timers.c +++ b/src/core/timers.c @@ -426,7 +426,7 @@ sys_check_timeouts(void) now = sys_now(); /* this cares for wraparounds */ - diff = LWIP_U32_DIFF(now, timeouts_last_time); + diff = now - timeouts_last_time; do { #if PBUF_POOL_FREE_OOSEQ diff --git a/src/include/lwip/def.h b/src/include/lwip/def.h index 9b6de6a8..73a1b560 100644 --- a/src/include/lwip/def.h +++ b/src/include/lwip/def.h @@ -47,10 +47,6 @@ extern "C" { #define NULL ((void *)0) #endif -/** Get the absolute difference between 2 u32_t values (correcting overflows) - * 'a' is expected to be 'higher' (without overflow) than 'b'. */ -#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) - /* Endianess-optimized shifting of two u8_t to create one u16_t */ #if BYTE_ORDER == LITTLE_ENDIAN #define LWIP_MAKE_U16(a, b) ((a << 8) | b) From 0333e81616c05edf6309838f2abc9ebd3870185c Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Thu, 13 Oct 2011 21:18:16 +0200 Subject: [PATCH 120/151] fixed bug #34517 (persist timer is started although no zero window is received) by starting the persist timer when a zero window is received, not when we have more data queued for sending than fits into the window --- CHANGELOG | 6 +++++ src/core/tcp_in.c | 9 ++++++- src/core/tcp_out.c | 9 +------ test/unit/tcp/test_tcp.c | 55 +++++++++++++++++++++++----------------- 4 files changed, 47 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0f2bc6e5..789e1aa7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,12 @@ HISTORY ++ Bugfixes: + 2011-10-13: Simon Goldschmidt + * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no + zero window is received) by starting the persist timer when a zero window is + received, not when we have more data queued for sending than fits into the + window + 2011-10-13: Simon Goldschmidt * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 17ed0b01..1824e92c 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -907,7 +907,14 @@ tcp_receive(struct tcp_pcb *pcb) pcb->snd_wnd = tcphdr->wnd; pcb->snd_wl1 = seqno; pcb->snd_wl2 = ackno; - if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { + if (pcb->snd_wnd == 0) { + if (pcb->persist_backoff == 0) { + /* start persist timer */ + pcb->persist_cnt = 0; + pcb->persist_backoff = 1; + } + } else if (pcb->persist_backoff > 0) { + /* stop persist timer */ pcb->persist_backoff = 0; } LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 6ad1c1ae..93ed21fa 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1034,13 +1034,6 @@ tcp_output(struct tcp_pcb *pcb) } #endif /* TCP_OVERSIZE */ - if (seg != NULL && pcb->persist_backoff == 0 && - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { - /* prepare for persist timer */ - pcb->persist_cnt = 0; - pcb->persist_backoff = 1; - } - pcb->flags &= ~TF_NAGLEMEMERR; return ERR_OK; } @@ -1071,7 +1064,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* Add any requested options. NB MSS option is only set on SYN packets, so ignore it here */ - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); + //LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); opts = (u32_t *)(void *)(seg->tcphdr + 1); if (seg->flags & TF_SEG_OPTS_MSS) { TCP_BUILD_MSS_OPTION(*opts); diff --git a/test/unit/tcp/test_tcp.c b/test/unit/tcp/test_tcp.c index d6832504..52a7d00e 100644 --- a/test/unit/tcp/test_tcp.c +++ b/test/unit/tcp/test_tcp.c @@ -568,6 +568,7 @@ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); + EXPECT(pcb->persist_backoff == 0); /* send the last packet, now a complete window has been sent */ err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); sent_total += TCP_MSS; @@ -577,6 +578,7 @@ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); memset(&txcounters, 0, sizeof(txcounters)); + EXPECT(pcb->persist_backoff == 0); if (zero_window_probe_from_unsent) { /* ACK all data but close the TX window */ @@ -585,6 +587,7 @@ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) /* ensure this didn't trigger any transmission */ EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); + EXPECT(pcb->persist_backoff == 1); } /* send one byte more (out of window) -> persist timer starts */ @@ -595,31 +598,37 @@ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); memset(&txcounters, 0, sizeof(txcounters)); + if (!zero_window_probe_from_unsent) { + /* no persist timer unless a zero window announcement has been received */ + EXPECT(pcb->persist_backoff == 0); + } else { + EXPECT(pcb->persist_backoff == 1); - /* call tcp_timer some more times to let persist timer count up */ - for (i = 0; i < 4; i++) { + /* call tcp_timer some more times to let persist timer count up */ + for (i = 0; i < 4; i++) { + test_tcp_tmr(); + EXPECT(txcounters.num_tx_calls == 0); + EXPECT(txcounters.num_tx_bytes == 0); + } + + /* this should trigger the zero-window-probe */ + txcounters.copy_tx_packets = 1; test_tcp_tmr(); - EXPECT(txcounters.num_tx_calls == 0); - EXPECT(txcounters.num_tx_bytes == 0); - } - - /* this should trigger the zero-window-probe */ - txcounters.copy_tx_packets = 1; - test_tcp_tmr(); - txcounters.copy_tx_packets = 0; - EXPECT(txcounters.num_tx_calls == 1); - EXPECT(txcounters.num_tx_bytes == 1 + 40U); - EXPECT(txcounters.tx_packets != NULL); - if (txcounters.tx_packets != NULL) { - u8_t sent; - u16_t ret; - ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); - EXPECT(ret == 1); - EXPECT(sent == expected); - } - if (txcounters.tx_packets != NULL) { - pbuf_free(txcounters.tx_packets); - txcounters.tx_packets = NULL; + txcounters.copy_tx_packets = 0; + EXPECT(txcounters.num_tx_calls == 1); + EXPECT(txcounters.num_tx_bytes == 1 + 40U); + EXPECT(txcounters.tx_packets != NULL); + if (txcounters.tx_packets != NULL) { + u8_t sent; + u16_t ret; + ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); + EXPECT(ret == 1); + EXPECT(sent == expected); + } + if (txcounters.tx_packets != NULL) { + pbuf_free(txcounters.tx_packets); + txcounters.tx_packets = NULL; + } } /* make sure the pcb is freed */ From e039d4103fcdf3e2b87cd34942da8ae4a6c89ae4 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Mon, 17 Oct 2011 19:38:47 +0200 Subject: [PATCH 121/151] fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api --- CHANGELOG | 3 +++ src/api/api_msg.c | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 789e1aa7..eb699311 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-17: Simon Goldschmidt + * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api + 2011-10-13: Simon Goldschmidt * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no zero window is received) by starting the persist timer when a zero window is diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 4227a632..d1d26bcf 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -778,21 +778,21 @@ do_close_internal(struct netconn *conn) } } /* Try to close the connection */ - if (shut == NETCONN_SHUT_RDWR) { + if (close) { err = tcp_close(conn->pcb.tcp); } else { - err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); + err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); } if (err == ERR_OK) { /* Closing succeeded */ conn->current_msg->err = ERR_OK; conn->current_msg = NULL; conn->state = NETCONN_NONE; - /* Set back some callback pointers as conn is going away */ - conn->pcb.tcp = NULL; - /* Trigger select() in socket layer. Make sure everybody notices activity - on the connection, error first! */ if (close) { + /* Set back some callback pointers as conn is going away */ + conn->pcb.tcp = NULL; + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ API_EVENT(conn, NETCONN_EVT_ERROR, 0); } if (shut_rx) { From 8b9f70ac08ec8b76d0d6e7b568243845412b28a9 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 18 Oct 2011 11:00:10 +0200 Subject: [PATCH 122/151] fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS --- CHANGELOG | 3 +++ src/include/lwip/sockets.h | 1 + 2 files changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index eb699311..6f070438 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-18: Simon Goldschmidt + * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS + 2011-10-17: Simon Goldschmidt * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index e578a7b0..697f200d 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -387,6 +387,7 @@ int lwip_fcntl(int s, int cmd, int val); #define read(a,b,c) lwip_read(a,b,c) #define write(a,b,c) lwip_write(a,b,c) #define close(s) lwip_close(s) +#define fcntl(a,b,c) lwip_fcntl(a,b,c) #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ #endif /* LWIP_COMPAT_SOCKETS */ From 2f58ef781c0ceef00bbcb136baf56b428122a595 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 18 Oct 2011 11:04:08 +0200 Subject: [PATCH 123/151] fixed bug #34581 missing parentheses in udplite sockets code --- CHANGELOG | 3 +++ src/api/sockets.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6f070438..caa6090f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-18: Simon Goldschmidt + * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code + 2011-10-18: Simon Goldschmidt * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS diff --git a/src/api/sockets.c b/src/api/sockets.c index 081709ab..d83847fd 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -2310,7 +2310,7 @@ lwip_setsockopt_internal(void *arg) case IPPROTO_UDPLITE: switch (optname) { case UDPLITE_SEND_CSCOV: - if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { + if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_tx = 8; } else { @@ -2320,7 +2320,7 @@ lwip_setsockopt_internal(void *arg) s, (*(int*)optval)) ); break; case UDPLITE_RECV_CSCOV: - if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { + if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_rx = 8; } else { From 1f396946e5b9b641506a0b310c43913358493677 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 18 Oct 2011 20:11:39 +0200 Subject: [PATCH 124/151] fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't consider netif->mtu, causes slow network --- CHANGELOG | 4 ++++ src/core/tcp_out.c | 2 +- src/include/lwip/tcp_impl.h | 5 +---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index caa6090f..a93d34c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-18: Simon Goldschmidt + * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't + consider netif->mtu, causes slow network + 2011-10-18: Simon Goldschmidt * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 93ed21fa..49c9679a 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -1067,7 +1067,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) //LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); opts = (u32_t *)(void *)(seg->tcphdr + 1); if (seg->flags & TF_SEG_OPTS_MSS) { - TCP_BUILD_MSS_OPTION(*opts); + *opts = TCP_BUILD_MSS_OPTION(pcb->mss); opts += 1; } #if LWIP_TCP_TIMESTAMPS diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index e9be9d95..694583fa 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -303,10 +303,7 @@ struct tcp_seg { (flags & TF_SEG_OPTS_TS ? 12 : 0) /** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ - ((u32_t)4 << 16) | \ - (((u32_t)TCP_MSS / 256) << 8) | \ - (TCP_MSS & 255)) +#define TCP_BUILD_MSS_OPTION(mss) htonl(0x02040000 | ((mss) & 0xFFFF)) /* Global variables: */ extern struct tcp_pcb *tcp_input_pcb; From 01839b9c1498480a78305ae4d322633a68bd1440 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 18 Oct 2011 20:22:09 +0200 Subject: [PATCH 125/151] fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small windows (bug #34176 select after non-blocking send times out) --- CHANGELOG | 4 ++++ src/include/lwip/opt.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a93d34c3..7848ee68 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-18: Simon Goldschmidt + * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small + windows (bug #34176 select after non-blocking send times out) + 2011-10-18: Simon Goldschmidt * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't consider netif->mtu, causes slow network diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 2565022c..9b03e75a 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -989,7 +989,7 @@ * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). */ #ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) +#define TCP_SNDLOWAT LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1) #endif /** @@ -998,7 +998,7 @@ * this number, select returns writable (combined with TCP_SNDLOWAT). */ #ifndef TCP_SNDQUEUELOWAT -#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) +#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) #endif /** From d00fa906cfd9c0a5bb2daccb3e76b183b3735409 Mon Sep 17 00:00:00 2001 From: Simon Goldschmidt Date: Tue, 18 Oct 2011 20:56:08 +0200 Subject: [PATCH 126/151] fixed bug #34592: lwip_gethostbyname_r uses nonstandard error value, removed those unused (nonstandard?) error values from arch.h --- CHANGELOG | 4 ++++ src/api/netdb.c | 2 +- src/include/lwip/arch.h | 21 --------------------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7848ee68..1cba75a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-18: Simon Goldschmidt + * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard + error value + 2011-10-18: Simon Goldschmidt * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small windows (bug #34176 select after non-blocking send times out) diff --git a/src/api/netdb.c b/src/api/netdb.c index a7e4e06b..afce2b7b 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -200,7 +200,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, err = netconn_gethostbyname(name, &(h->addr)); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); - *h_errnop = ENSRNOTFOUND; + *h_errnop = HOST_NOT_FOUND; return -1; } diff --git a/src/include/lwip/arch.h b/src/include/lwip/arch.h index 524af6be..4d6df773 100644 --- a/src/include/lwip/arch.h +++ b/src/include/lwip/arch.h @@ -204,27 +204,6 @@ extern "C" { #define ENOMEDIUM 123 /* No medium found */ #define EMEDIUMTYPE 124 /* Wrong medium type */ - -#define ENSROK 0 /* DNS server returned answer with no data */ -#define ENSRNODATA 160 /* DNS server returned answer with no data */ -#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ -#define ENSRSERVFAIL 162 /* DNS server returned general failure */ -#define ENSRNOTFOUND 163 /* Domain name not found */ -#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ -#define ENSRREFUSED 165 /* DNS server refused query */ -#define ENSRBADQUERY 166 /* Misformatted DNS query */ -#define ENSRBADNAME 167 /* Misformatted domain name */ -#define ENSRBADFAMILY 168 /* Unsupported address family */ -#define ENSRBADRESP 169 /* Misformatted DNS reply */ -#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ -#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ -#define ENSROF 172 /* End of file */ -#define ENSRFILE 173 /* Error reading file */ -#define ENSRNOMEM 174 /* Out of memory */ -#define ENSRDESTRUCTION 175 /* Application terminated lookup */ -#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ -#define ENSRCNAMELOOP 177 /* Domain name is too long */ - #ifndef errno extern int errno; #endif From 309e936ad927bc59e2449a4734c2388d475a17bf Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 19 Oct 2011 12:55:32 +0200 Subject: [PATCH 127/151] Fix default value of TCP_SNDLOWAT for small values of TCP_SND_BUF (broken with my 2nd-last commit) --- src/include/lwip/opt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 9b03e75a..4f52811c 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -989,7 +989,7 @@ * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). */ #ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1) +#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) #endif /** From 43ac5ad70d14cfc3c2d2716afd688faf90464b50 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 21 Oct 2011 13:24:33 +0200 Subject: [PATCH 128/151] removed the need to disable ARP_QUEUEING when LWIP_ARP is disabled an TCP_QUEUE_OOSEQ when LWIP_TCP is disabled --- src/core/init.c | 6 ------ src/core/pbuf.c | 2 +- src/include/lwip/memp_std.h | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/core/init.c b/src/core/init.c index fa21edce..1d093fe8 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -70,9 +70,6 @@ #if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" #endif -#if (!LWIP_ARP && ARP_QUEUEING) - #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h" -#endif #if (!LWIP_UDP && LWIP_UDPLITE) #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" #endif @@ -167,9 +164,6 @@ #if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" #endif -#if (TCP_QUEUE_OOSEQ && !LWIP_TCP) - #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" -#endif #if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" #endif diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 01fc2157..40cfca38 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -70,7 +70,7 @@ #include "lwip/pbuf.h" #include "lwip/sys.h" #include "arch/perf.h" -#if TCP_QUEUE_OOSEQ +#if LWIP_TCP && TCP_QUEUE_OOSEQ #include "lwip/tcp_impl.h" #endif #if LWIP_CHECKSUM_ON_COPY diff --git a/src/include/lwip/memp_std.h b/src/include/lwip/memp_std.h index e7b90f29..90679f6d 100644 --- a/src/include/lwip/memp_std.h +++ b/src/include/lwip/memp_std.h @@ -63,9 +63,9 @@ LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ #endif /* NO_SYS==0 */ -#if ARP_QUEUEING +#if LWIP_ARP && ARP_QUEUEING LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") -#endif /* ARP_QUEUEING */ +#endif /* LWIP_ARP && ARP_QUEUEING */ #if LWIP_IGMP LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") From 2750d61e9299b9d809bea075f8f1dce8c6ffefd1 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 21 Oct 2011 19:47:37 +0200 Subject: [PATCH 129/151] added missing valid/set_invalid defines for NO_SYS --- src/include/lwip/sys.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h index 9f62c754..dc935133 100644 --- a/src/include/lwip/sys.h +++ b/src/include/lwip/sys.h @@ -51,16 +51,22 @@ typedef u8_t sys_mbox_t; #define sys_sem_wait(s) #define sys_arch_sem_wait(s,t) #define sys_sem_free(s) +#define sys_sem_valid(s) 0 +#define sys_sem_set_invalid(s) #define sys_mutex_new(mu) ERR_OK #define sys_mutex_lock(mu) #define sys_mutex_unlock(mu) #define sys_mutex_free(mu) +#define sys_mutex_valid(mu) 0 +#define sys_mutex_set_invalid(mu) #define sys_mbox_new(m, s) ERR_OK #define sys_mbox_fetch(m,d) #define sys_mbox_tryfetch(m,d) #define sys_mbox_post(m,d) #define sys_mbox_trypost(m,d) #define sys_mbox_free(m) +#define sys_mbox_valid(m) +#define sys_mbox_set_invalid(m) #define sys_thread_new(n,t,a,s,p) From 3d1a306518a5c000796fe06247ade543b4d5ea4d Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 21 Oct 2011 22:25:44 +0200 Subject: [PATCH 130/151] SLIP netif: add support for multiple input strategies (threaded, polling, RX from ISR) --- src/include/netif/slipif.h | 30 +++ src/netif/slipif.c | 404 +++++++++++++++++++++++++------------ 2 files changed, 303 insertions(+), 131 deletions(-) diff --git a/src/include/netif/slipif.h b/src/include/netif/slipif.h index ccd03c8a..7b6ce5e2 100644 --- a/src/include/netif/slipif.h +++ b/src/include/netif/slipif.h @@ -34,14 +34,44 @@ #ifndef __NETIF_SLIPIF_H__ #define __NETIF_SLIPIF_H__ +#include "lwip/opt.h" #include "lwip/netif.h" +/** Set this to 1 to start a thread that blocks reading on the serial line + * (using sio_read()). + */ +#ifndef SLIP_USE_RX_THREAD +#define SLIP_USE_RX_THREAD !NO_SYS +#endif + +/** Set this to 1 to enable functions to pass in RX bytes from ISR context. + * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled + * packets on a queue, which is fed into lwIP from slipif_poll(). + * If disabled, slipif_poll() polls the serila line (using sio_tryread()). + */ +#ifndef SLIP_RX_FROM_ISR +#define SLIP_RX_FROM_ISR 0 +#endif + +/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets + * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. + * If disabled, packets will be dropped if more than one packet is received. + */ +#ifndef SLIP_RX_QUEUE +#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR +#endif + #ifdef __cplusplus extern "C" { #endif err_t slipif_init(struct netif * netif); void slipif_poll(struct netif *netif); +#if SLIP_RX_FROM_ISR +void slipif_process_rxqueue(struct netif *netif); +void slipif_received_byte(struct netif *netif, u8_t data); +void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); +#endif /* SLIP_RX_FROM_ISR */ #ifdef __cplusplus } diff --git a/src/netif/slipif.c b/src/netif/slipif.c index c908a1e4..c7daa3b3 100644 --- a/src/netif/slipif.c +++ b/src/netif/slipif.c @@ -35,6 +35,19 @@ * This file is built upon the file: src/arch/rtxc/netif/sioslip.c * * Author: Magnus Ivarsson + * Simon Goldschmidt + * + * Usage: This netif can be used in three ways: + * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() + * until data is received. + * 2) In your main loop, call slipif_poll() to check for new RX bytes, + * completed packets are fed into netif->input(). + * 3) Call slipif_received_byte[s]() from your serial RX ISR and + * slipif_process_rxqueue() from your main loop. ISR level decodes + * packets and puts completed packets on a queue which is fed into + * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for + * pbuf_alloc to work on ISR level!). + * */ /* @@ -52,19 +65,25 @@ #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/sio.h" -#if !NO_SYS #include "lwip/sys.h" + +#define SLIP_END 0xC0 /* 0300: start and end of every packet */ +#define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ +#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ +#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ + +/** Maximum packet size that is received by this netif */ +#ifndef SLIP_MAX_SIZE +#define SLIP_MAX_SIZE 1500 #endif -#define SLIP_BLOCK 1 -#define SLIP_DONTBLOCK 0 - -#define SLIP_END 0300 /* 0xC0 */ -#define SLIP_ESC 0333 /* 0xDB */ -#define SLIP_ESC_END 0334 /* 0xDC */ -#define SLIP_ESC_ESC 0335 /* 0xDD */ - -#define SLIP_MAX_SIZE 1500 +/** Define this to the interface speed for SNMP + * (sio_fd is the sio_fd_t returned by sio_open). + * The default value of zero means 'unknown'. + */ +#ifndef SLIP_SIO_SPEED +#define SLIP_SIO_SPEED(sio_fd) 0 +#endif enum slipif_recv_state { SLIP_RECV_NORMAL, @@ -75,8 +94,11 @@ struct slipif_priv { sio_fd_t sd; /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ struct pbuf *p, *q; - enum slipif_recv_state state; + u8_t state; u16_t i, recved; +#if SLIP_RX_FROM_ISR + struct pbuf *rxpackets; +#endif }; /** @@ -103,9 +125,11 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) LWIP_UNUSED_ARG(ipaddr); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); priv = netif->state; /* Send pbuf out on the serial I/O device. */ + /* Start with packet delimiter. */ sio_send(SLIP_END, priv->sd); for (q = p; q != NULL; q = q->next) { @@ -113,59 +137,39 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) c = ((u8_t *)q->payload)[i]; switch (c) { case SLIP_END: + /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ sio_send(SLIP_ESC, priv->sd); sio_send(SLIP_ESC_END, priv->sd); break; case SLIP_ESC: + /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ sio_send(SLIP_ESC, priv->sd); sio_send(SLIP_ESC_ESC, priv->sd); break; default: + /* normal byte - no need for escaping */ sio_send(c, priv->sd); break; } } } + /* End with packet delimiter. */ sio_send(SLIP_END, priv->sd); return ERR_OK; } -/** - * Static function for easy use of blockig or non-blocking - * sio_read - * - * @param fd serial device handle - * @param data pointer to data buffer for receiving - * @param len maximum length (in bytes) of data to receive - * @param block if 1, call sio_read; if 0, call sio_tryread - * @return return value of sio_read of sio_tryread - */ -static u32_t -slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block) -{ - if (block) { - return sio_read(fd, data, len); - } else { - return sio_tryread(fd, data, len); - } -} - /** * Handle the incoming SLIP stream character by character * - * Poll the serial layer by calling sio_read() or sio_tryread(). - * * @param netif the lwip network interface structure for this slipif - * @param block if 1, block until data is received; if 0, return when all data - * from the buffer is received (multiple calls to this function will + * @param c received character (multiple calls to this function will * return a complete packet, NULL is returned before - used for polling) * @return The IP packet when SLIP_END is received */ -static struct pbuf * -slipif_input(struct netif *netif, u8_t block) +static struct pbuf* +slipif_rxbyte(struct netif *netif, u8_t c) { struct slipif_priv *priv; - u8_t c; struct pbuf *t; LWIP_ASSERT("netif != NULL", (netif != NULL)); @@ -173,89 +177,105 @@ slipif_input(struct netif *netif, u8_t block) priv = netif->state; - while (slip_sio_read(priv->sd, &c, 1, block) > 0) { - switch (priv->state) { - case SLIP_RECV_NORMAL: - switch (c) { - case SLIP_END: - if (priv->recved > 0) { - /* Received whole packet. */ - /* Trim the pbuf to the size of the received packet. */ - pbuf_realloc(priv->q, priv->recved); + switch (priv->state) { + case SLIP_RECV_NORMAL: + switch (c) { + case SLIP_END: + if (priv->recved > 0) { + /* Received whole packet. */ + /* Trim the pbuf to the size of the received packet. */ + pbuf_realloc(priv->q, priv->recved); - LINK_STATS_INC(link.recv); + LINK_STATS_INC(link.recv); - LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n")); - t = priv->q; - priv->p = priv->q = NULL; - priv->i = priv->recved = 0; - return t; - } - continue; - case SLIP_ESC: - priv->state = SLIP_RECV_ESCAPE; - continue; + LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); + t = priv->q; + priv->p = priv->q = NULL; + priv->i = priv->recved = 0; + return t; } + return NULL; + case SLIP_ESC: + priv->state = SLIP_RECV_ESCAPE; + return NULL; + } /* end switch (c) */ + break; + case SLIP_RECV_ESCAPE: + /* un-escape END or ESC bytes, leave other bytes + (although that would be a protocol error) */ + switch (c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; break; - case SLIP_RECV_ESCAPE: - switch (c) { - case SLIP_ESC_END: - c = SLIP_END; - break; - case SLIP_ESC_ESC: - c = SLIP_ESC; - break; - } - priv->state = SLIP_RECV_NORMAL; - /* FALLTHROUGH */ } + priv->state = SLIP_RECV_NORMAL; + break; + } /* end switch (priv->state) */ + + /* byte received, packet not yet completely received */ + if (priv->p == NULL) { + /* allocate a new pbuf */ + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); + priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL); - /* byte received, packet not yet completely received */ if (priv->p == NULL) { - /* allocate a new pbuf */ - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); - priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL); - - if (priv->p == NULL) { - LINK_STATS_INC(link.drop); - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); - /* don't process any further since we got no pbuf to receive to */ - break; - } - - if (priv->q != NULL) { - /* 'chain' the pbuf to the existing chain */ - pbuf_cat(priv->q, priv->p); - } else { - /* p is the first pbuf in the chain */ - priv->q = priv->p; - } + LINK_STATS_INC(link.drop); + LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); + /* don't process any further since we got no pbuf to receive to */ + return NULL; } - /* this automatically drops bytes if > SLIP_MAX_SIZE */ - if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { - ((u8_t *)priv->p->payload)[priv->i] = c; - priv->recved++; - priv->i++; - if (priv->i >= priv->p->len) { - /* on to the next pbuf */ - priv->i = 0; - if (priv->p->next != NULL && priv->p->next->len > 0) { - /* p is a chain, on to the next in the chain */ - priv->p = priv->p->next; - } else { - /* p is a single pbuf, set it to NULL so next time a new - * pbuf is allocated */ - priv->p = NULL; - } - } + if (priv->q != NULL) { + /* 'chain' the pbuf to the existing chain */ + pbuf_cat(priv->q, priv->p); + } else { + /* p is the first pbuf in the chain */ + priv->q = priv->p; } } + /* this automatically drops bytes if > SLIP_MAX_SIZE */ + if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { + ((u8_t *)priv->p->payload)[priv->i] = c; + priv->recved++; + priv->i++; + if (priv->i >= priv->p->len) { + /* on to the next pbuf */ + priv->i = 0; + if (priv->p->next != NULL && priv->p->next->len > 0) { + /* p is a chain, on to the next in the chain */ + priv->p = priv->p->next; + } else { + /* p is a single pbuf, set it to NULL so next time a new + * pbuf is allocated */ + priv->p = NULL; + } + } + } return NULL; } -#if !NO_SYS +/** Like slipif_rxbyte, but passes completed packets to netif->input + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + */ +static void +slipif_rxbyte_input(struct netif *netif, u8_t c) +{ + struct pbuf *p; + p = slipif_rxbyte(netif, c); + if (p != NULL) { + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } +} + +#if SLIP_USE_RX_THREAD /** * The SLIP input thread. * @@ -266,20 +286,17 @@ slipif_input(struct netif *netif, u8_t block) static void slipif_loop_thread(void *nf) { - struct pbuf *p; + u8_t c; struct netif *netif = (struct netif *)nf; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; while (1) { - p = slipif_input(netif, SLIP_BLOCK); - if (p != NULL) { - if (netif->input(p, netif) != ERR_OK) { - pbuf_free(p); - p = NULL; - } + if (sio_read(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); } } } -#endif /* !NO_SYS */ +#endif /* SLIP_USE_RX_THREAD */ /** * SLIP netif initialization @@ -293,17 +310,20 @@ slipif_loop_thread(void *nf) * ERR_IF is serial line couldn't be opened * * @note netif->num must contain the number of the serial port to open - * (0 by default) + * (0 by default). If netif->state is != NULL, it is interpreted as an + * u8_t pointer pointing to the serial port number instead of netif->num. + * */ err_t slipif_init(struct netif *netif) { struct slipif_priv *priv; + u8_t sio_num; LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); /* Allocate private data */ - priv = mem_malloc(sizeof(struct slipif_priv)); + priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); if (!priv) { return ERR_MEM; } @@ -311,11 +331,20 @@ slipif_init(struct netif *netif) netif->name[0] = 's'; netif->name[1] = 'l'; netif->output = slipif_output; +#if LWIP_IPV6 + netif->output_ip6 = slipif_output; +#endif /* LWIP_IPV6 */ netif->mtu = SLIP_MAX_SIZE; netif->flags |= NETIF_FLAG_POINTTOPOINT; - /* Try to open the serial port (netif->num contains the port number). */ - priv->sd = sio_open(netif->num); + /* netif->state or netif->num contain the port number */ + if (netif->state != NULL) { + sio_num = *(u8_t*)netif->state; + } else { + sio_num = netif->num; + } + /* Try to open the serial port. */ + priv->sd = sio_open(sio_num); if (!priv->sd) { /* Opening the serial port failed. */ mem_free(priv); @@ -328,20 +357,20 @@ slipif_init(struct netif *netif) priv->state = SLIP_RECV_NORMAL; priv->i = 0; priv->recved = 0; +#if SLIP_RX_FROM_ISR + priv->rxpackets = NULL; +#endif netif->state = priv; - /* initialize the snmp variables and counters inside the struct netif - * ifSpeed: no assumption can be made without knowing more about the - * serial line! - */ - NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0); + /* initialize the snmp variables and counters inside the struct netif */ + NETIF_INIT_SNMP(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); -#if !NO_SYS +#if SLIP_USE_RX_THREAD /* Create a thread to poll the serial line. */ sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); -#endif +#endif /* SLIP_USE_RX_THREAD */ return ERR_OK; } @@ -353,19 +382,132 @@ slipif_init(struct netif *netif) void slipif_poll(struct netif *netif) { - struct pbuf *p; + u8_t c; struct slipif_priv *priv; LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); - priv = netif->state; + priv = (struct slipif_priv *)netif->state; - while ((p = slipif_input(netif, SLIP_DONTBLOCK)) != NULL) { - if (netif->input(p, netif) != ERR_OK) { - pbuf_free(p); - } + while (sio_tryread(priv->sd, &c, 1) > 0) { + slipif_rxbyte_input(netif, c); } } +#if SLIP_RX_FROM_ISR +/** + * Feeds the IP layer with incoming packets that were receive + * + * @param netif The lwip network interface structure for this slipif + */ +void +slipif_process_rxqueue(struct netif *netif) +{ + struct slipif_priv *priv; + SYS_ARCH_DECL_PROTECT(old_level); + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + priv = (struct slipif_priv *)netif->state; + + SYS_ARCH_PROTECT(old_level); + while (priv->rxpackets != NULL) { + struct pbuf *p = priv->rxpackets; +#if SLIP_RX_QUEUE + /* dequeue packet */ + struct pbuf *q = p; + while ((q->len != q->tot_len) && (q->next != NULL)) { + q = q->next; + } + priv->rxpackets = q->next; + q->next = NULL; +#else /* SLIP_RX_QUEUE */ + priv->rxpackets = NULL; +#endif /* SLIP_RX_QUEUE */ + SYS_ARCH_UNPROTECT(old_level); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + SYS_ARCH_PROTECT(old_level); + } +} + +/** Like slipif_rxbyte, but queues completed packets. + * + * @param netif The lwip network interface structure for this slipif + * @param data Received serial byte + */ +static void +slipif_rxbyte_enqueue(struct netif *netif, u8_t data) +{ + struct pbuf *p; + struct slipif_priv *priv = (struct slipif_priv *)netif->state; + SYS_ARCH_DECL_PROTECT(old_level); + + p = slipif_rxbyte(netif, data); + if (p != NULL) { + SYS_ARCH_PROTECT(old_level); + if (priv->rxpackets != NULL) { +#if SLIP_RX_QUEUE + /* queue multiple pbufs */ + struct pbuf *q = p; + while(q->next != NULL) { + q = q->next; + } + q->next = p; + } else { +#else /* SLIP_RX_QUEUE */ + pbuf_free(priv->rxpackets); + } + { +#endif /* SLIP_RX_QUEUE */ + priv->rxpackets = p; + } + SYS_ARCH_UNPROTECT(old_level); + } +} + +/** + * Process a received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + */ +void +slipif_received_byte(struct netif *netif, u8_t data) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + slipif_rxbyte_enqueue(netif, data); +} + +/** + * Process multiple received byte, completed packets are put on a queue that is + * fed into IP through slipif_process_rxqueue(). + * + * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. + * + * @param netif The lwip network interface structure for this slipif + * @param data received character + * @param len Number of received characters + */ +void +slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) +{ + u8_t i; + u8_t *rxdata = data; + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + + for (i = 0; i < len; i++, rxdata++) { + slipif_rxbyte_enqueue(netif, *rxdata); + } +} +#endif /* SLIP_RX_FROM_ISR */ + #endif /* LWIP_HAVE_SLIPIF */ From c5203ab5eadf46c66528ff17b05b20987f75117f Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 23 Oct 2011 17:31:03 +0200 Subject: [PATCH 131/151] fixed bug #34429: possible memory corruption with LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 --- CHANGELOG | 4 ++++ src/core/mem.c | 28 +++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1cba75a9..f5f553ce 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-10-23: Simon Goldschmidt + * mem.c: fixed bug #34429: possible memory corruption with + LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 + 2011-10-18: Simon Goldschmidt * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard error value diff --git a/src/core/mem.c b/src/core/mem.c index 2128a28e..1659a2c7 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -521,7 +521,7 @@ mem_malloc(mem_size_t size) sys_mutex_lock(&mem_mutex); LWIP_MEM_ALLOC_PROTECT(); #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* run as long as a mem_free disturbed mem_malloc */ + /* run as long as a mem_free disturbed mem_malloc or mem_trim */ do { local_mem_free_count = 0; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ @@ -535,12 +535,14 @@ mem_malloc(mem_size_t size) #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 0; LWIP_MEM_ALLOC_UNPROTECT(); - /* allow mem_free to run */ + /* allow mem_free or mem_trim to run */ LWIP_MEM_ALLOC_PROTECT(); if (mem_free_count != 0) { - local_mem_free_count = mem_free_count; + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem. */ + local_mem_free_count = 1; + break; } - mem_free_count = 0; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ if ((!mem->used) && @@ -584,15 +586,27 @@ mem_malloc(mem_size_t size) mem->used = 1; MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); } - +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +mem_malloc_adjust_lfree: +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ if (mem == lfree) { + struct mem *cur = lfree; /* Find next free block after mem and update lowest free pointer */ - while (lfree->used && lfree != ram_end) { + while (cur->used && cur != ram_end) { +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + mem_free_count = 0; LWIP_MEM_ALLOC_UNPROTECT(); /* prevent high interrupt latency... */ LWIP_MEM_ALLOC_PROTECT(); - lfree = (struct mem *)(void *)&ram[lfree->next]; + if (mem_free_count != 0) { + /* If mem_free or mem_trim have run, we have to restart since they + could have altered our current struct mem or lfree. */ + goto mem_malloc_adjust_lfree; + } +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + cur = (struct mem *)(void *)&ram[cur->next]; } + lfree = cur; LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); } LWIP_MEM_ALLOC_UNPROTECT(); From 78f030724671c70b209308502ab0e5f507301365 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 23 Oct 2011 17:38:23 +0200 Subject: [PATCH 132/151] Slipif: fixed IPv6 support --- src/netif/slipif.c | 47 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/netif/slipif.c b/src/netif/slipif.c index c7daa3b3..137ba89d 100644 --- a/src/netif/slipif.c +++ b/src/netif/slipif.c @@ -108,11 +108,10 @@ struct slipif_priv { * * @param netif the lwip network interface structure for this slipif * @param p the pbuf chaing packet to send - * @param ipaddr the ip address to send the packet to (not used for slipif) * @return always returns ERR_OK since the serial layer does not provide return values */ -err_t -slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) +static err_t +slipif_output(struct netif *netif, struct pbuf *p) { struct slipif_priv *priv; struct pbuf *q; @@ -123,8 +122,6 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); LWIP_ASSERT("p != NULL", (p != NULL)); - LWIP_UNUSED_ARG(ipaddr); - LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); priv = netif->state; @@ -158,6 +155,42 @@ slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) return ERR_OK; } +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chaing packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v4(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} + +#if LWIP_IPV6 +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chaing packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +static err_t +slipif_output_v6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr) +{ + LWIP_UNUSED_ARG(ipaddr); + return slipif_output(netif, p); +} +#endif /* LWIP_IPV6 */ + /** * Handle the incoming SLIP stream character by character * @@ -330,9 +363,9 @@ slipif_init(struct netif *netif) netif->name[0] = 's'; netif->name[1] = 'l'; - netif->output = slipif_output; + netif->output = slipif_output_v4; #if LWIP_IPV6 - netif->output_ip6 = slipif_output; + netif->output_ip6 = slipif_output_v6; #endif /* LWIP_IPV6 */ netif->mtu = SLIP_MAX_SIZE; netif->flags |= NETIF_FLAG_POINTTOPOINT; From 0fb07ba3287c1de402e98027a9f7d5d1c079b773 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 23 Oct 2011 18:10:46 +0200 Subject: [PATCH 133/151] - moved processing of refused_data to an own function (used from tcp_fasttmr and tcp_input); - improved readability of tcp_slowtmr by using defines to access keepalive variables --- src/core/tcp.c | 94 ++++++++++++++++++++----------------- src/core/tcp_in.c | 37 +++------------ src/include/lwip/tcp_impl.h | 1 + 3 files changed, 60 insertions(+), 72 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 3a03ac1e..1fa75153 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -66,6 +66,14 @@ #define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START) #endif +#if LWIP_TCP_KEEPALIVE +#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) +#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) +#else /* LWIP_TCP_KEEPALIVE */ +#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE +#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT +#endif /* LWIP_TCP_KEEPALIVE */ + const char * const tcp_state_str[] = { "CLOSED", "LISTEN", @@ -849,8 +857,9 @@ tcp_slowtmr(void) } } else { /* Increase the retransmission timer if it is running */ - if(pcb->rtime >= 0) + if(pcb->rtime >= 0) { ++pcb->rtime; + } if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { /* Time for a retransmission. */ @@ -897,14 +906,8 @@ tcp_slowtmr(void) if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { -#if LWIP_TCP_KEEPALIVE if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) - / TCP_SLOW_INTERVAL) -#else - if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) -#endif /* LWIP_TCP_KEEPALIVE */ + (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); @@ -913,15 +916,9 @@ tcp_slowtmr(void) ++pcb_remove; ++pcb_reset; } -#if LWIP_TCP_KEEPALIVE else if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) + (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) / TCP_SLOW_INTERVAL) -#else - else if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) - / TCP_SLOW_INTERVAL) -#endif /* LWIP_TCP_KEEPALIVE */ { tcp_keepalive(pcb); pcb->keep_cnt_sent++; @@ -1052,34 +1049,8 @@ tcp_fasttmr(void) struct tcp_pcb *next = pcb->next; /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { - /* Notify again application with data previously received. */ - err_t err; - u8_t refused_flags = pcb->refused_data->flags; - /* set pcb->refused_data to NULL in case the callback frees it and then - closes the pcb */ - struct pbuf *refused_data = pcb->refused_data; - pcb->refused_data = NULL; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); - TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); - if (err == ERR_OK) { - /* did refused_data include a FIN? If so, handle it now. */ - if (refused_flags & PBUF_FLAG_TCP_FIN) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - pcb = NULL; - } - } - } else if (err == ERR_ABRT) { - /* if err == ERR_ABRT, 'pcb' is already deallocated */ + if (tcp_process_refused_data(pcb) == ERR_ABRT) { pcb = NULL; - } else { - /* data is still refused */ - pcb->refused_data = refused_data; } } @@ -1095,6 +1066,45 @@ tcp_fasttmr(void) } } +/** Pass pcb->refused_data to the recv callback */ +err_t +tcp_process_refused_data(struct tcp_pcb *pcb) +{ + err_t err; + u8_t refused_flags = pcb->refused_data->flags; + /* set pcb->refused_data to NULL in case the callback frees it and then + closes the pcb */ + struct pbuf *refused_data = pcb->refused_data; + pcb->refused_data = NULL; + /* Notify again application with data previously received. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); + TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); + if (err == ERR_OK) { + /* did refused_data include a FIN? */ + if (refused_flags & PBUF_FLAG_TCP_FIN) { + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } + } + } else if (err == ERR_ABRT) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + /* Drop incoming packets because pcb is "full" (only if the incoming + segment contains data). */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); + return ERR_ABRT; + } else { + /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ + pcb->refused_data = refused_data; + } + return ERR_OK; +} + /** * Deallocates a list of TCP segments (tcp_seg structures). * diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 1824e92c..b2d9db2a 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -306,36 +306,13 @@ tcp_input(struct pbuf *p, struct netif *inp) /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { - u8_t refused_flags = pcb->refused_data->flags; - /* set pcb->refused_data to NULL in case the callback frees it and then - closes the pcb */ - struct pbuf *refused_data = pcb->refused_data; - pcb->refused_data = NULL; - /* Notify again application with data previously received. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); - TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); - if (err == ERR_OK) { - /* did refused_data include a FIN? */ - if (refused_flags & PBUF_FLAG_TCP_FIN) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - goto dropped; - } - } - } else if ((err == ERR_ABRT) || (tcplen > 0)) { - /* if err == ERR_ABRT, 'pcb' is already deallocated */ - /* Drop incoming packets because pcb is "full" (only if the incoming - segment contains data). */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); - goto dropped; - } else { - /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ - pcb->refused_data = refused_data; + if ((tcp_process_refused_data(pcb) == ERR_ABRT) || + ((pcb->refused_data != NULL) && (tcplen > 0))) { + /* pcb has been aborted or refused data is still refused and the new + segment contains data */ + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + goto aborted; } } tcp_input_pcb = pcb; diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 694583fa..bfda7f4a 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -72,6 +72,7 @@ void tcp_rexmit (struct tcp_pcb *pcb); void tcp_rexmit_rto (struct tcp_pcb *pcb); void tcp_rexmit_fast (struct tcp_pcb *pcb); u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); +err_t tcp_process_refused_data(struct tcp_pcb *pcb); /** * This is the Nagle algorithm: try to combine user data to send as few TCP From 2ce17a724aa84434c321f9a9716f09156975e18c Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Wed, 26 Oct 2011 14:31:48 -0600 Subject: [PATCH 134/151] Fix bug #34526: nd6_queue_packet() frees too much if out-of-memory Change-Id: Ib7ac0cb1b5a5389dd5449a908485493bd085ba9d --- src/core/ipv6/nd6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index 54290ef5..4ad05279 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -1543,10 +1543,11 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) if(copy_needed) { /* copy the whole packet into new pbufs */ p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); - if ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { + while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { /* Free oldest packet (as per RFC recommendation) */ r = neighbor_cache[neighbor_index].q; neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; nd6_free_q(r); p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); } @@ -1570,6 +1571,7 @@ nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) /* Free oldest packet (as per RFC recommendation) */ r = neighbor_cache[neighbor_index].q; neighbor_cache[neighbor_index].q = r->next; + r->next = NULL; nd6_free_q(r); new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); } From edcc859b589618128d67f1dc470562177833d9d6 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 28 Oct 2011 13:09:04 +0200 Subject: [PATCH 135/151] fixed bug #34638: Dead code in tcp_receive - pcb->dupacks --- CHANGELOG | 3 +++ src/core/tcp_in.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index f5f553ce..bbf80928 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,9 @@ HISTORY ++ Bugfixes: + 2011-10-28: Simon Goldschmidt + * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks + 2011-10-23: Simon Goldschmidt * mem.c: fixed bug #34429: possible memory corruption with LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index b2d9db2a..0dd2c904 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -938,8 +938,9 @@ tcp_receive(struct tcp_pcb *pcb) /* Clause 5 */ if (pcb->lastack == ackno) { found_dupack = 1; - if (pcb->dupacks + 1 > pcb->dupacks) + if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { ++pcb->dupacks; + } if (pcb->dupacks > 3) { /* Inflate the congestion window, but not if it means that the value overflows. */ From 21333d0f18b47aa8ebd65bdf72c54b5b258bd99f Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Fri, 28 Oct 2011 13:54:16 -0600 Subject: [PATCH 136/151] handle NULL when parsing IPv6 address (check for formatting) Change-Id: I42e1288689946c295e0bd1490a5eb4d8befb5877 --- src/core/ipv6/ip6_addr.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/core/ipv6/ip6_addr.c b/src/core/ipv6/ip6_addr.c index 6c047491..65d27980 100644 --- a/src/core/ipv6/ip6_addr.c +++ b/src/core/ipv6/ip6_addr.c @@ -91,11 +91,13 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) 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; + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } } current_block_index++; current_block_value = 0; @@ -110,7 +112,9 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) addr_index++; } else { - addr->addr[addr_index] = 0; + if (addr) { + addr->addr[addr_index] = 0; + } } current_block_index++; } @@ -126,16 +130,20 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) } } - if (current_block_index & 0x1) { - addr->addr[addr_index++] |= current_block_value; - } - else { - addr->addr[addr_index] = current_block_value << 16; + if (addr) { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } } /* convert to network byte order. */ - for (addr_index = 0; addr_index < 4; addr_index++) { - addr->addr[addr_index] = htonl(addr->addr[addr_index]); + if (addr) { + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = htonl(addr->addr[addr_index]); + } } if (current_block_index != 7) { @@ -143,7 +151,6 @@ ip6addr_aton(const char *cp, ip6_addr_t *addr) } return 1; - } /** From 09d1f55bce1996f7d1f5a411b3e3b68faa31b46d Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Fri, 28 Oct 2011 14:23:20 -0600 Subject: [PATCH 137/151] Conditional compilation in ppp.c according to PPP_ options. Change-Id: I466ce2b0114c9428f5e21bd0a09bb221f40bfc3e --- src/netif/ppp/ppp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/netif/ppp/ppp.c b/src/netif/ppp/ppp.c index 3838fcf2..73661346 100644 --- a/src/netif/ppp/ppp.c +++ b/src/netif/ppp/ppp.c @@ -172,7 +172,9 @@ typedef struct PPPControlRx_s { /** the rx file descriptor */ sio_fd_t fd; /** receive buffer - encoded data is stored here */ +#if PPP_INPROC_OWNTHREAD u_char rxbuf[PPPOS_RX_BUFSIZE]; +#endif /* The input packet. */ struct pbuf *inHead, *inTail; @@ -1737,6 +1739,7 @@ pppDrop(PPPControlRx *pcrx) snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif); } +#if !PPP_INPROC_OWNTHREAD /** Pass received raw characters to PPPoS to be decoded. This function is * thread-safe and can be called from a dedicated RX-thread or from a main-loop. * @@ -1749,6 +1752,7 @@ pppos_input(int pd, u_char* data, int len) { pppInProc(&pppControl[pd].rx, data, len); } +#endif /** * Process a received octet string. From b3ffa163152dc1ef70cec48ef1b87134844037e0 Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Fri, 28 Oct 2011 16:22:54 -0600 Subject: [PATCH 138/151] Use pppRecvWakeup only if PPP_INPROC_OWNTHREAD is defined. Change-Id: Ie800289eb5f6a64d0be1d38eab7154d4aa473d57 --- src/netif/ppp/ppp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/netif/ppp/ppp.c b/src/netif/ppp/ppp.c index 73661346..90eaf84b 100644 --- a/src/netif/ppp/ppp.c +++ b/src/netif/ppp/ppp.c @@ -174,7 +174,7 @@ typedef struct PPPControlRx_s { /** receive buffer - encoded data is stored here */ #if PPP_INPROC_OWNTHREAD u_char rxbuf[PPPOS_RX_BUFSIZE]; -#endif +#endif /* PPP_INPROC_OWNTHREAD */ /* The input packet. */ struct pbuf *inHead, *inTail; @@ -341,6 +341,7 @@ static u_char pppACCMMask[] = { 0x80 }; +#if PPP_INPROC_OWNTHREAD /** Wake up the task blocked in reading from serial line (if any) */ static void pppRecvWakeup(int pd) @@ -350,6 +351,7 @@ pppRecvWakeup(int pd) sio_read_abort(pppControl[pd].fd); } } +#endif /* PPP_INPROC_OWNTHREAD */ #endif /* PPPOS_SUPPORT */ void @@ -365,7 +367,9 @@ pppLinkTerminated(int pd) { #if PPPOS_SUPPORT PPPControl* pc; +#if PPP_INPROC_OWNTHREAD pppRecvWakeup(pd); +#endif /* PPP_INPROC_OWNTHREAD */ pc = &pppControl[pd]; PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); @@ -390,9 +394,9 @@ pppLinkDown(int pd) } else #endif /* PPPOE_SUPPORT */ { -#if PPPOS_SUPPORT +#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD pppRecvWakeup(pd); -#endif /* PPPOS_SUPPORT */ +#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD*/ } } @@ -576,7 +580,7 @@ pppOverSerialOpen(sio_fd_t fd, pppLinkStatusCB_fn linkStatusCB, void *linkStatus pppStart(pd); #if PPP_INPROC_OWNTHREAD sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); -#endif +#endif /* PPP_INPROC_OWNTHREAD */ } return pd; @@ -674,7 +678,9 @@ pppClose(int pd) pc->errCode = PPPERR_USER; /* This will leave us at PHASE_DEAD. */ pppStop(pd); +#if PPP_INPROC_OWNTHREAD pppRecvWakeup(pd); +#endif /* PPP_INPROC_OWNTHREAD */ #endif /* PPPOS_SUPPORT */ } From 7aa7c0f481fc679bae654c509364e2249d81e1fa Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sat, 29 Oct 2011 21:43:13 +0200 Subject: [PATCH 139/151] SEQ-comparing defines: cast parameters to u32_t for clarity --- src/include/lwip/tcp_impl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index bfda7f4a..9b745a0d 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -92,10 +92,10 @@ err_t tcp_process_refused_data(struct tcp_pcb *pcb); #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) -#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) -#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) -#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) -#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +#define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) /* is b<=a<=c? */ #if 0 /* see bug #10548 */ #define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) From d12e742373dff1d368b386649a4107d336661ed9 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 13 Nov 2011 17:06:19 +0100 Subject: [PATCH 140/151] Fixed bug #34733 Null pointer exception with SOCKET_DEBUG. --- src/api/sockets.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index d83847fd..3bc96f97 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -758,10 +758,15 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), SOCKETS_DEBUG, fromaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); - if (*fromlen > saddr.sa.sa_len) { - *fromlen = saddr.sa.sa_len; +#if SOCKETS_DEBUG + if (from && fromlen) +#endif /* SOCKETS_DEBUG */ + { + if (*fromlen > saddr.sa.sa_len) { + *fromlen = saddr.sa.sa_len; + } + MEMCPY(from, &saddr, *fromlen); } - MEMCPY(from, &saddr, *fromlen); } } From cb91705e037d9a51792971aa2b1df26354f972ee Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Thu, 17 Nov 2011 10:55:45 -0700 Subject: [PATCH 141/151] Generate ICMPv6 responses from a context other than input callback (e.g. timers in IPv6 reassembly). see bug #34846. Change-Id: I6b4d27c819291d8371c43288310d57c3f2c1c65f --- src/core/ipv6/icmp6.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index be725c2d..0c4dbbb0 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -257,7 +257,9 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) { struct pbuf *q; struct icmp6_hdr *icmp6hdr; - ip6_addr_t * reply_src; + ip6_addr_t *reply_src, *reply_dest; + struct ip6_hdr *ip6hdr; + struct netif *netif; /* ICMPv6 header + IPv6 header + data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, @@ -279,8 +281,29 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, IP6_HLEN + LWIP_ICMP6_DATASIZE); + /* Get the destination address and netif for this ICMP message. */ + if (ip_current_netif() != NULL) { + netif = ip_current_netif(); + reply_dest = ip6_current_src_addr(); + } + else { + /* We are not being called from input context, so we must determine + * addresses from the packet in question. reply_src is temporarily + * set to try and find the original netif where packet was accepted. */ + ip6hdr = (struct ip6_hdr *)p->payload; + reply_dest = &ip6hdr->src; + reply_src = &ip6hdr->dest; + netif = ip6_route(reply_src, reply_dest); + if (netif == NULL) { + /* drop */ + pbuf_free(q); + ICMP6_STATS_INC(icmp6.rterr); + return; + } + } + /* Select an address to use as source. */ - reply_src = ip6_select_source_address(ip_current_netif(), ip6_current_src_addr()); + reply_src = ip6_select_source_address(netif, reply_dest); if (reply_src == NULL) { /* drop */ pbuf_free(q); @@ -291,10 +314,10 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) /* calculate checksum */ icmp6hdr->chksum = 0; icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, - reply_src, ip6_current_src_addr()); + reply_src, reply_dest); ICMP6_STATS_INC(icmp6.xmit); - ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6); + ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(q); } From 440f31a4d33385582023d34fb806208bdb54b95f Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Thu, 17 Nov 2011 14:24:16 -0700 Subject: [PATCH 142/151] Add IPv6 timeouts to check for MEMP_NUM_SYS_TIMEOUT). Change-Id: Ic6a9493cde41652391b34a47e6003b9036f760de --- src/core/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/init.c b/src/core/init.c index 1d093fe8..d66e44a3 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -149,7 +149,7 @@ #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" #endif /* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)) +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))) #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" #endif #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) From 96d332e2349dd872b01cf5b9e98d70f285a4715a Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 22 Nov 2011 21:41:20 +0100 Subject: [PATCH 143/151] Fix icmp6_send_response: cannot assign (packed) ip6_addr_p_t* to ip6_addr_t* -> need to copy the packed address to an aligned address first --- src/core/ipv6/icmp6.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index 0c4dbbb0..fbfda5e7 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -258,6 +258,7 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) struct pbuf *q; struct icmp6_hdr *icmp6hdr; ip6_addr_t *reply_src, *reply_dest; + ip6_addr_t reply_src_local, reply_dest_local; struct ip6_hdr *ip6hdr; struct netif *netif; @@ -291,8 +292,11 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) * addresses from the packet in question. reply_src is temporarily * set to try and find the original netif where packet was accepted. */ ip6hdr = (struct ip6_hdr *)p->payload; - reply_dest = &ip6hdr->src; - reply_src = &ip6hdr->dest; + /* copy from packed address to aligned address */ + ip6_addr_copy(reply_dest_local, ip6hdr->src); + ip6_addr_copy(reply_src_local, ip6hdr->dest); + reply_dest = &reply_dest_local; + reply_src = &reply_src_local; netif = ip6_route(reply_src, reply_dest); if (netif == NULL) { /* drop */ From 08b497faead0e3f49f4e90991ef61bbe829c34cc Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 22 Nov 2011 21:44:28 +0100 Subject: [PATCH 144/151] fixed bug #34684: Clear the arp table cache when netif is brought down --- CHANGELOG | 4 ++++ src/core/netif.c | 5 +++++ src/include/netif/etharp.h | 1 + src/netif/etharp.c | 19 +++++++++++++++++-- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bbf80928..68b275c8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-11-22: Simon Goldschmidt + * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when + netif is brought down + 2011-10-28: Simon Goldschmidt * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks diff --git a/src/core/netif.c b/src/core/netif.c index c882eade..90bbff48 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -539,6 +539,11 @@ void netif_set_down(struct netif *netif) snmp_get_sysuptime(&netif->ts); #endif +#if LWIP_ARP + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_cleanup_netif(netif); + } +#endif /* LWIP_ARP */ NETIF_STATUS_CALLBACK(netif); } } diff --git a/src/include/netif/etharp.h b/src/include/netif/etharp.h index 2eda1488..92d57ae4 100644 --- a/src/include/netif/etharp.h +++ b/src/include/netif/etharp.h @@ -191,6 +191,7 @@ err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr); * nodes to update an entry in their ARP cache. * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ #define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) +void etharp_cleanup_netif(struct netif *netif); #if ETHARP_SUPPORT_STATIC_ENTRIES err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr); diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 8b333dd9..99187b4a 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -112,9 +112,7 @@ struct etharp_entry { struct pbuf *q; #endif /* ARP_QUEUEING */ ip_addr_t ipaddr; -#if LWIP_SNMP struct netif *netif; -#endif /* LWIP_SNMP */ struct eth_addr ethaddr; u8_t state; u8_t ctime; @@ -578,6 +576,23 @@ etharp_remove_static_entry(ip_addr_t *ipaddr) } #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +/** + * Remove all ARP table entries of the specified netif. + * + * @param netif points to a network interface + */ +void etharp_cleanup_netif(struct netif *netif) +{ + u8_t i; + + for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; + if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { + etharp_free_entry(i); + } + } +} + /** * Finds (stable) ethernet/IP address pair from ARP table * using interface and IP address index. From 988815579a26a8bf46c29538ae392f88c8719244 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 23 Nov 2011 20:58:19 +0100 Subject: [PATCH 145/151] fixed bug #34884: sys_msleep() body needs to be surrounded with '#ifndef sys_msleep' --- CHANGELOG | 4 ++++ src/core/sys.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 68b275c8..3d827ca7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-11-23: Simon Goldschmidt + * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with + '#ifndef sys_msleep' + 2011-11-22: Simon Goldschmidt * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when netif is brought down diff --git a/src/core/sys.c b/src/core/sys.c index d3a77deb..f1777372 100644 --- a/src/core/sys.c +++ b/src/core/sys.c @@ -45,6 +45,7 @@ #if !NO_SYS +#ifndef sys_msleep /** * Sleep for some ms. Timeouts are NOT processed while sleeping. * @@ -62,5 +63,6 @@ sys_msleep(u32_t ms) } } } +#endif /* sys_msleep */ #endif /* !NO_SYS */ From 14c766e750540160934796523f4fe9fefcbe8bb8 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 24 Nov 2011 21:11:11 +0100 Subject: [PATCH 146/151] fix for bug #34684 was wrong (netif for arp table entries was only set/reset with SNMP enabled) --- src/netif/etharp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 99187b4a..9183b847 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -191,9 +191,7 @@ etharp_free_entry(int i) #ifdef LWIP_DEBUG /* for debugging, clean out the complete entry */ arp_table[i].ctime = 0; -#if LWIP_SNMP arp_table[i].netif = NULL; -#endif /* LWIP_SNMP */ ip_addr_set_zero(&arp_table[i].ipaddr); arp_table[i].ethaddr = ethzero; #endif /* LWIP_DEBUG */ @@ -482,9 +480,7 @@ etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr } /* record network interface */ -#if LWIP_SNMP arp_table[i].netif = netif; -#endif /* LWIP_SNMP */ /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); From dd8729063c34c0073ae98190b0174bd045d240ca Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 25 Nov 2011 18:36:52 +0100 Subject: [PATCH 147/151] fixed bug #31177: tcp timers can corrupt tcp_active_pcbs in some cases --- CHANGELOG | 4 ++ src/core/tcp.c | 77 +++++++++++++++++++++++++++---------- src/core/tcp_in.c | 8 ++-- src/include/lwip/tcp.h | 1 + src/include/lwip/tcp_impl.h | 19 +++++++++ 5 files changed, 85 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3d827ca7..bfef4810 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -69,6 +69,10 @@ HISTORY ++ Bugfixes: + 2011-11-25: Simon Goldschmidt + * tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt + tcp_active_pcbs in some cases + 2011-11-23: Simon Goldschmidt * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with '#ifndef sys_msleep' diff --git a/src/core/tcp.c b/src/core/tcp.c index 1fa75153..e981d530 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -119,8 +119,11 @@ struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcb /** Only used for temporary storage. */ struct tcp_pcb *tcp_tmp_pcb; +u8_t tcp_active_pcbs_changed; + /** Timer counter to handle calling slow-timer from tcp_tmr() */ static u8_t tcp_timer; +static u8_t tcp_timer_ctr; static u16_t tcp_new_port(void); /** @@ -187,7 +190,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) /* TODO: to which state do we move now? */ /* move to TIME_WAIT since we close actively */ - TCP_RMV(&tcp_active_pcbs, pcb); + TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); @@ -219,7 +222,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) break; case SYN_SENT: err = ERR_OK; - tcp_pcb_remove(&tcp_active_pcbs, pcb); + TCP_PCB_REMOVE_ACTIVE(pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; snmp_inc_tcpattemptfails(); @@ -371,7 +374,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) errf = pcb->errf; #endif /* LWIP_CALLBACK_API */ errf_arg = pcb->callback_arg; - tcp_pcb_remove(&tcp_active_pcbs, pcb); + TCP_PCB_REMOVE_ACTIVE(pcb); if (pcb->unacked != NULL) { tcp_segs_free(pcb->unacked); } @@ -793,7 +796,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, if (old_local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } - TCP_REG(&tcp_active_pcbs, pcb); + TCP_REG_ACTIVE(pcb); snmp_inc_tcpactiveopens(); tcp_output(pcb); @@ -820,7 +823,9 @@ tcp_slowtmr(void) err = ERR_OK; ++tcp_ticks; + ++tcp_timer_ctr; +tcp_slowtmr_start: /* Steps through all of the active PCBs. */ prev = NULL; pcb = tcp_active_pcbs; @@ -832,6 +837,12 @@ tcp_slowtmr(void) LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); + if (pcb->last_timer == tcp_timer_ctr) { + /* skip this pcb, we have already processed it */ + pcb = pcb->next; + continue; + } + pcb->last_timer = tcp_timer_ctr; pcb_remove = 0; pcb_reset = 0; @@ -957,6 +968,8 @@ tcp_slowtmr(void) /* If the PCB should be removed, do it. */ if (pcb_remove) { struct tcp_pcb *pcb2; + tcp_err_fn err_fn; + void *err_arg; tcp_pcb_purge(pcb); /* Remove PCB from tcp_active_pcbs list. */ if (prev != NULL) { @@ -968,15 +981,22 @@ tcp_slowtmr(void) tcp_active_pcbs = pcb->next; } - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); if (pcb_reset) { tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); } + err_fn = pcb->errf; + err_arg = pcb->callback_arg; pcb2 = pcb; pcb = pcb->next; memp_free(MEMP_TCP_PCB, pcb2); + + tcp_active_pcbs_changed = 0; + TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } } else { /* get the 'next' element now and work with 'prev' below (in case of abort) */ prev = pcb; @@ -987,7 +1007,11 @@ tcp_slowtmr(void) if (prev->polltmr >= prev->pollinterval) { prev->polltmr = 0; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); + tcp_active_pcbs_changed = 0; TCP_EVENT_POLL(prev, err); + if (tcp_active_pcbs_changed) { + goto tcp_slowtmr_start; + } /* if err == ERR_ABRT, 'prev' is already deallocated */ if (err == ERR_OK) { tcp_output(prev); @@ -1043,26 +1067,38 @@ tcp_slowtmr(void) void tcp_fasttmr(void) { - struct tcp_pcb *pcb = tcp_active_pcbs; + struct tcp_pcb *pcb; + + ++tcp_timer_ctr; + +tcp_fasttmr_start: + pcb = tcp_active_pcbs; while(pcb != NULL) { - struct tcp_pcb *next = pcb->next; - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - if (tcp_process_refused_data(pcb) == ERR_ABRT) { - pcb = NULL; + if (pcb->last_timer != tcp_timer_ctr) { + struct tcp_pcb *next; + pcb->last_timer = tcp_timer_ctr; + /* send delayed ACKs */ + if (pcb->flags & TF_ACK_DELAY) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); + tcp_ack_now(pcb); + tcp_output(pcb); + pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } - } - /* send delayed ACKs */ - if (pcb && (pcb->flags & TF_ACK_DELAY)) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); - tcp_ack_now(pcb); - tcp_output(pcb); - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } + next = pcb->next; - pcb = next; + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + tcp_active_pcbs_changed = 0; + tcp_process_refused_data(pcb); + if (tcp_active_pcbs_changed) { + /* application callback has changed the pcb list: restart the loop */ + goto tcp_fasttmr_start; + } + } + pcb = next; + } } } @@ -1312,6 +1348,7 @@ tcp_alloc(u8_t prio) pcb->lastack = iss; pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; + pcb->last_timer = tcp_timer_ctr; pcb->polltmr = 0; diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 0dd2c904..6af07211 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -505,7 +505,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->so_options = pcb->so_options & SOF_INHERITED; /* Register the new PCB so that we can begin receiving segments for it. */ - TCP_REG(&tcp_active_pcbs, npcb); + TCP_REG_ACTIVE(npcb); /* Parse any options in the SYN. */ tcp_parseopt(npcb); @@ -755,7 +755,7 @@ tcp_process(struct tcp_pcb *pcb) ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_ack_now(pcb); tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); + TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } else { @@ -772,7 +772,7 @@ tcp_process(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_ack_now(pcb); tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); + TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } @@ -782,7 +782,7 @@ tcp_process(struct tcp_pcb *pcb) if (flags & TCP_ACK && ackno == pcb->snd_nxt) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_pcb_purge(pcb); - TCP_RMV(&tcp_active_pcbs, pcb); + TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 6af71583..4dc1df2a 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -191,6 +191,7 @@ struct tcp_pcb { /* Timers */ u8_t polltmr, pollinterval; + u8_t last_timer; u32_t tmr; /* receiver variables */ diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h index 9b745a0d..b068eef2 100644 --- a/src/include/lwip/tcp_impl.h +++ b/src/include/lwip/tcp_impl.h @@ -309,6 +309,7 @@ struct tcp_seg { /* Global variables: */ extern struct tcp_pcb *tcp_input_pcb; extern u32_t tcp_ticks; +extern u8_t tcp_active_pcbs_changed; /* The TCP PCB lists. */ union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ @@ -395,6 +396,24 @@ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ #endif /* LWIP_DEBUG */ +#define TCP_REG_ACTIVE(npcb) \ + do { \ + TCP_REG(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_RMV_ACTIVE(npcb) \ + do { \ + TCP_RMV(&tcp_active_pcbs, npcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + +#define TCP_PCB_REMOVE_ACTIVE(pcb) \ + do { \ + tcp_pcb_remove(&tcp_active_pcbs, pcb); \ + tcp_active_pcbs_changed = 1; \ + } while (0) + /* Internal functions: */ struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); From 85f8a59d7f7f1dc973b2dc70ba3d0237cd59d24e Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Mon, 28 Nov 2011 14:07:53 -0700 Subject: [PATCH 148/151] Added parenthesis to netif/ip6 macros. Change-Id: I32d7f28c9e106641e3d5be8342d2c884e166bb0e --- src/include/lwip/netif.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index a658e51b..322d2d0e 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -367,9 +367,9 @@ void netif_poll_all(void); #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)) +#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 */ From ce6fb83ef4e1e29f4e9244d69eaa6b249d88092d Mon Sep 17 00:00:00 2001 From: Ivan Delamer Date: Tue, 29 Nov 2011 12:49:43 -0700 Subject: [PATCH 149/151] bug #34846: time-exceeded was sometimes not sent to original fragment source, but to the sender of a packet fragment that triggered a buffer purge. Change-Id: I4bf20747bd900150491852649918a85cb7bf2aad --- src/core/ipv6/icmp6.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index fbfda5e7..dfe92107 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -283,14 +283,11 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) IP6_HLEN + LWIP_ICMP6_DATASIZE); /* Get the destination address and netif for this ICMP message. */ - if (ip_current_netif() != NULL) { - netif = ip_current_netif(); - reply_dest = ip6_current_src_addr(); - } - else { - /* We are not being called from input context, so we must determine - * addresses from the packet in question. reply_src is temporarily - * set to try and find the original netif where packet was accepted. */ + if ((ip_current_netif() == NULL) || + ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { + /* Special case, as ip6_current_xxx is either NULL, or points + * to a different packet than the one that expired. + * We must use the addresses that are stored in the expired packet. */ ip6hdr = (struct ip6_hdr *)p->payload; /* copy from packed address to aligned address */ ip6_addr_copy(reply_dest_local, ip6hdr->src); @@ -305,14 +302,18 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) return; } } + else { + netif = ip_current_netif(); + reply_dest = ip6_current_src_addr(); - /* Select an address to use as source. */ - reply_src = ip6_select_source_address(netif, reply_dest); - if (reply_src == NULL) { - /* drop */ - pbuf_free(q); - ICMP6_STATS_INC(icmp6.rterr); - return; + /* Select an address to use as source. */ + reply_src = ip6_select_source_address(netif, reply_dest); + if (reply_src == NULL) { + /* drop */ + pbuf_free(q); + ICMP6_STATS_INC(icmp6.rterr); + return; + } } /* calculate checksum */ From 5048a30fc748c06ddb9741a45e540411ef77c612 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Tue, 6 Dec 2011 21:21:44 +0100 Subject: [PATCH 150/151] Another fix for bug #32417 (debug assert that fires) --- src/core/tcp_out.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 49c9679a..1bbd587e 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -989,6 +989,9 @@ tcp_output(struct tcp_pcb *pcb) pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ tcp_output_segment(seg, pcb); snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { From 8114627d6a68641110f87ff434069631f537b67e Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 14 Dec 2011 21:42:51 +0100 Subject: [PATCH 151/151] Fixed typo in define check: LWIP_IPv6_FRAG -> LWIP_IPV6_FRAG --- src/include/lwip/memp_std.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/lwip/memp_std.h b/src/include/lwip/memp_std.h index 90679f6d..592a2824 100644 --- a/src/include/lwip/memp_std.h +++ b/src/include/lwip/memp_std.h @@ -47,7 +47,7 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), #if IP_REASSEMBLY LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") #endif /* IP_REASSEMBLY */ -#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG +#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 */