Index: api/netbuf.c =================================================================== RCS file: /sources/lwip/lwip/src/api/netbuf.c,v retrieving revision 1.7 diff -u -r1.7 netbuf.c --- api/netbuf.c 22 May 2010 21:11:02 -0000 1.7 +++ api/netbuf.c 9 Dec 2010 19:29:18 -0000 @@ -61,7 +61,11 @@ 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 @@ #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; Index: api/api_msg.c =================================================================== RCS file: /sources/lwip/lwip/src/api/api_msg.c,v retrieving revision 1.153 diff -u -r1.153 api_msg.c --- api/api_msg.c 30 Jun 2010 08:33:14 -0000 1.153 +++ api/api_msg.c 9 Dec 2010 19:29:18 -0000 @@ -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 @@ buf->p = q; buf->ptr = q; - ip_addr_copy(buf->addr, *ip_current_src_addr()); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&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; @@ -173,9 +182,29 @@ } 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*)ip_current_header()) + IP6_HLEN); +#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 */ @@ -183,7 +212,7 @@ #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 */ @@ -481,7 +510,15 @@ 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; @@ -491,17 +528,33 @@ #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 ( +#if LWIP_IPV6 + (msg->conn->type==NETCONN_UDPLITE_IPV6) || +#endif /* LWIP_IPV6 */ + (msg->conn->type==NETCONN_UDPLITE)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); } #endif /* LWIP_UDPLITE */ - if (msg->conn->type==NETCONN_UDPNOCHKSUM) { + if ( +#if LWIP_IPV6 + (msg->conn->type==NETCONN_UDPNOCHKSUM_IPV6) || +#endif /* LWIP_IPV6 */ + (msg->conn->type==NETCONN_UDPNOCHKSUM)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); } udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); @@ -509,7 +562,15 @@ #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; @@ -674,7 +735,7 @@ 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() */ @@ -732,7 +793,7 @@ 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); @@ -818,7 +879,7 @@ (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", @@ -936,7 +997,7 @@ 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); @@ -1055,7 +1116,7 @@ } 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); @@ -1112,29 +1173,62 @@ 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; @@ -1159,7 +1253,7 @@ #if LWIP_TCP msg->err = ERR_OK; if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { + if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { #if TCP_LISTEN_BACKLOG if (msg->conn->pcb.tcp->state == LISTEN) { tcp_accepted(msg->conn->pcb.tcp); @@ -1316,7 +1410,7 @@ 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 */ @@ -1369,8 +1463,20 @@ 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)) { @@ -1425,9 +1531,9 @@ /* @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; @@ -1452,7 +1558,7 @@ 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 @@ -1468,10 +1574,24 @@ 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) @@ -1485,7 +1605,7 @@ } TCPIP_APIMSG_ACK(msg); } -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** Index: api/api_lib.c =================================================================== RCS file: /sources/lwip/lwip/src/api/api_lib.c,v retrieving revision 1.114 diff -u -r1.114 api_lib.c --- api/api_lib.c 24 Jun 2010 19:33:14 -0000 1.114 +++ api/api_lib.c 9 Dec 2010 19:29:18 -0000 @@ -366,7 +366,7 @@ #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 @@ -426,7 +426,7 @@ netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) { LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && - netconn_type(conn) == NETCONN_TCP, return ERR_ARG;); + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); return netconn_recv_data(conn, (void **)new_buf); } @@ -453,7 +453,7 @@ 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 */ @@ -473,7 +473,11 @@ 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; @@ -499,7 +503,7 @@ void netconn_recved(struct netconn *conn, u32_t length) { - 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. */ @@ -527,7 +531,15 @@ 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); } @@ -578,7 +590,7 @@ 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; } @@ -651,7 +663,7 @@ 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. * @@ -683,7 +695,7 @@ NETCONN_SET_SAFE_ERR(conn, err); return err; } -#endif /* LWIP_IGMP */ +#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** Index: include/lwip/api_msg.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/api_msg.h,v retrieving revision 1.43 diff -u -r1.43 api_msg.h --- include/lwip/api_msg.h 24 Jun 2010 19:33:14 -0000 1.43 +++ include/lwip/api_msg.h 9 Dec 2010 19:29:23 -0000 @@ -97,14 +97,14 @@ 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; @@ -153,9 +153,9 @@ 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); Index: include/lwip/netif.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/netif.h,v retrieving revision 1.58 diff -u -r1.58 netif.h --- include/lwip/netif.h 15 Feb 2010 19:53:46 -0000 1.58 +++ include/lwip/netif.h 9 Dec 2010 19:29:23 -0000 @@ -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 @@ #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_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 @@ /** 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 @@ 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 @@ * 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 @@ /** 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; @@ -212,6 +258,11 @@ 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 a 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 @@ #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 Index: include/lwip/raw.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/raw.h,v retrieving revision 1.16 diff -u -r1.16 raw.h --- include/lwip/raw.h 4 Feb 2010 18:47:48 -0000 1.16 +++ include/lwip/raw.h 9 Dec 2010 19:29:24 -0000 @@ -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 @@ 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 @@ 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 @@ 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. */ Index: include/lwip/tcp_impl.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/tcp_impl.h,v retrieving revision 1.9 diff -u -r1.9 tcp_impl.h --- include/lwip/tcp_impl.h 16 May 2010 15:57:45 -0000 1.9 +++ include/lwip/tcp_impl.h 9 Dec 2010 19:29:24 -0000 @@ -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" { @@ -430,6 +432,11 @@ 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); @@ -438,6 +445,9 @@ #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 *ip6addr); +#endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if LWIP_CALLBACK_API Index: include/lwip/udp.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/udp.h,v retrieving revision 1.32 diff -u -r1.32 udp.h --- include/lwip/udp.h 12 Jul 2010 09:34:11 -0000 1.32 +++ include/lwip/udp.h 9 Dec 2010 19:29:24 -0000 @@ -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 @@ 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 @@ #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 @@ #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 Index: include/lwip/netbuf.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/netbuf.h,v retrieving revision 1.8 diff -u -r1.8 netbuf.h --- include/lwip/netbuf.h 22 May 2010 21:11:03 -0000 1.8 +++ include/lwip/netbuf.h 9 Dec 2010 19:29:23 -0000 @@ -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 @@ /** 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 @@ #endif /* LWIP_CHECKSUM_ON_COPY */ u16_t toport_chksum; #if LWIP_NETBUF_RECVINFO - ip_addr_t toaddr; + union { + ip_addr_t toaddr; + NETBUF_IP6 + } toaddr; #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ }; @@ -81,12 +94,12 @@ #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 @@ (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 Index: include/lwip/api.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/api.h,v retrieving revision 1.69 diff -u -r1.69 api.h --- include/lwip/api.h 24 Jun 2010 19:33:14 -0000 1.69 +++ include/lwip/api.h 9 Dec 2010 19:29:23 -0000 @@ -78,18 +78,31 @@ /* 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) /** 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 +124,13 @@ 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; @@ -236,13 +249,25 @@ 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) Index: include/lwip/tcp.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/tcp.h,v retrieving revision 1.103 diff -u -r1.103 tcp.h --- include/lwip/tcp.h 13 Mar 2010 15:04:08 -0000 1.103 +++ include/lwip/tcp.h 9 Dec 2010 19:29:24 -0000 @@ -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 @@ 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 } Index: include/lwip/memp_std.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/memp_std.h,v retrieving revision 1.17 diff -u -r1.17 memp_std.h --- include/lwip/memp_std.h 25 Jun 2010 18:59:29 -0000 1.17 +++ include/lwip/memp_std.h 9 Dec 2010 19:29:23 -0000 @@ -91,6 +91,15 @@ 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_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. * Index: include/lwip/pbuf.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/pbuf.h,v retrieving revision 1.39 diff -u -r1.39 pbuf.h --- include/lwip/pbuf.h 12 Jul 2010 09:34:11 -0000 1.39 +++ include/lwip/pbuf.h 9 Dec 2010 19:29:24 -0000 @@ -45,7 +45,11 @@ #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, Index: include/lwip/opt.h =================================================================== RCS file: /sources/lwip/lwip/src/include/lwip/opt.h,v retrieving revision 1.164 diff -u -r1.164 opt.h --- include/lwip/opt.h 24 Jun 2010 20:27:49 -0000 1.164 +++ include/lwip/opt.h 9 Dec 2010 19:29:24 -0000 @@ -1778,6 +1778,231 @@ /* --------------------------------------- + ---------- 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 1 +#endif + +/** + * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) + */ +#ifndef LWIP_ICMP6 +#define LWIP_ICMP6 1 +#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 1 +#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 0 +#endif + +/** + * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address + * is being resolved. + */ +#ifndef LWIP_ND6_QUEUEING +#define LWIP_ND6_QUEUEING 1 +#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 + */ +#ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME +#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 //ms +#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_TIMERS==1: Allow Router Advertisement messages to update + * Reachable time and retransmission timers. + */ +#ifndef LWIP_ND6_ALLOW_RA_TIMERS +#define LWIP_ND6_ALLOW_RA_TIMERS 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 1 +#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 1 +#endif + +/* + --------------------------------------- ---------- Debugging options ---------- --------------------------------------- */ Index: core/timers.c =================================================================== RCS file: /sources/lwip/lwip/src/core/timers.c,v retrieving revision 1.16 diff -u -r1.16 timers.c --- core/timers.c 29 Jun 2010 19:55:21 -0000 1.16 +++ core/timers.c 9 Dec 2010 19:29:21 -0000 @@ -56,7 +56,12 @@ #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" - +#if LWIP_IPV6 +#include "lwip/nd6.h" +#endif /* LWIP_IPV6 */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ /** The one and only timeout list */ static struct sys_timeo *next_timeout; @@ -217,6 +222,38 @@ } #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_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 +276,12 @@ #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_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 */ Index: core/udp.c =================================================================== RCS file: /sources/lwip/lwip/src/core/udp.c,v retrieving revision 1.129 diff -u -r1.129 udp.c --- core/udp.c 12 Jul 2010 14:10:28 -0000 1.129 +++ core/udp.c 9 Dec 2010 19:29:22 -0000 @@ -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" @@ -86,7 +90,6 @@ 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_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 @@ udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ +#if LWIP_IPV6 + broadcast = (ip_current_header() != NULL) && ip_addr_isbroadcast(¤t_iphdr_dest, inp); +#else /* LWIP_IPV6 */ broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); +#endif /* LWIP_IPV6 */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); @@ -143,8 +147,12 @@ /* 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), ¤t_iphdr_src)))) { pcb = inp->dhcp->pcb; } } @@ -165,22 +173,35 @@ 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)); + ip4_addr1_16(&pcb->local_ip.ip4), ip4_addr2_16(&pcb->local_ip.ip4), + ip4_addr3_16(&pcb->local_ip.ip4), ip4_addr4_16(&pcb->local_ip.ip4), pcb->local_port, + ip4_addr1_16(&pcb->remote_ip.ip4), ip4_addr2_16(&pcb->remote_ip.ip4), + ip4_addr3_16(&pcb->remote_ip.ip4), ip4_addr4_16(&pcb->remote_ip.ip4), 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), ¤t_iphdr_dest) || #if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || + ip_addr_ismulticast(¤t_iphdr_dest) || #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 +213,18 @@ /* 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), ¤t_iphdr_src)))))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -215,10 +246,26 @@ } /* 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, ¤t_iphdr_dest))) { 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,6 +284,21 @@ goto end; } } +#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, ¤t_iphdr_src, ¤t_iphdr_dest, IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, @@ -253,6 +315,21 @@ { #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,7 +354,11 @@ 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(¤t_iphdr_dest)) && ((pcb->so_options & SOF_REUSEADDR) != 0)) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ @@ -287,18 +368,26 @@ 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), ¤t_iphdr_dest) || #if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || + ip_addr_ismulticast(¤t_iphdr_dest) || #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) { @@ -311,7 +400,15 @@ 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); +#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); + } } } } @@ -325,9 +422,17 @@ } #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 +441,30 @@ } 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 && +#if LWIP_IPV6 + !ip6_addr_ismulticast(ip6_current_dest_addr()) && +#endif /* LWIP_IPV6 */ !ip_addr_ismulticast(¤t_iphdr_dest)) { /* move payload pointer back to ip header */ - pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); + pbuf_header(p, (IPH_HL(ip_current_header()) * 4) + UDP_HLEN); LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); - icmp_dest_unreach(p, ICMP_DUR_PORT); - } +#if LWIP_IPV6 && LWIP_ICMP6 + if (ip6_current_header() != NULL) { + icmp6_dest_unreach(p, ICMP6_DUR_PORT); + } + else +#endif /* LWIP_IPV6 && LWIP_ICMP6 */ + { +#if LWIP_ICMP + 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 +499,7 @@ 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 +510,7 @@ 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,11 +551,25 @@ 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)); + } + else { + netif = ip6_route((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) { @@ -494,7 +626,11 @@ #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 +640,7 @@ /* 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; @@ -542,20 +678,60 @@ /* 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 */ @@ -566,7 +742,7 @@ 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)); @@ -593,31 +769,64 @@ } 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 */ - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; +#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 */ + + /* 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*/ @@ -627,20 +836,21 @@ 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' */ @@ -649,14 +859,48 @@ } 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*/ @@ -728,9 +972,20 @@ #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)); @@ -739,7 +994,15 @@ } } - 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) { @@ -776,8 +1039,8 @@ } 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), + ip4_addr1_16(&pcb->local_ip.ip4), ip4_addr2_16(&pcb->local_ip.ip4), + ip4_addr3_16(&pcb->local_ip.ip4), ip4_addr4_16(&pcb->local_ip.ip4), pcb->local_port)); return ERR_OK; } @@ -804,38 +1067,51 @@ struct udp_pcb *ipcb; if (pcb->local_port == 0) { - err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); + err_t err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port); if (err != ERR_OK) { return err; } } - ip_addr_set(&pcb->remote_ip, ipaddr); +#if LWIP_IPV6 + if (pcb->isipv6) { + ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_set(&pcb->remote_ip.ip4, ipaddr); + } pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; /** TODO: this functionality belongs in upper layers */ #ifdef LWIP_UDP_TODO - /* Nail down local IP for netconn_addr()/getsockname() */ - if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { - struct netif *netif; - - if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } - /** 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; +#if LWIP_IPV6 + if (pcb->isipv6) +#endif /* LWIP_IPV6 */ + { + /* Nail down local IP for netconn_addr()/getsockname() */ + if (ip_addr_isany(&pcb->local_ip.ip4) && !ip_addr_isany(&pcb->remote_ip.ip4)) { + struct netif *netif; + + if ((netif = ip_route(&(pcb->remote_ip.ip4))) == NULL) { + LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.ip4.addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + /** TODO: this will bind the udp pcb locally, to the interface which + is used to route output packets to the remote address. However, we + might want to accept incoming packets on any interface! */ + pcb->local_ip.ip4 = netif->ip_addr; + } else if (ip_addr_isany(&pcb->remote_ip.ip4)) { + pcb->local_ip.ip4.addr = 0; + } } #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), + ip4_addr1_16(&pcb->local_ip.ip4), ip4_addr2_16(&pcb->local_ip.ip4), + ip4_addr3_16(&pcb->local_ip.ip4), ip4_addr4_16(&pcb->local_ip.ip4), pcb->local_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ @@ -860,7 +1136,15 @@ 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; @@ -879,7 +1163,7 @@ udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ - pcb->recv = recv; + pcb->recv.ip4 = recv; pcb->recv_arg = recv_arg; } @@ -939,6 +1223,28 @@ 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. Index: core/netif.c =================================================================== RCS file: /sources/lwip/lwip/src/core/netif.c,v retrieving revision 1.90 diff -u -r1.90 netif.c --- core/netif.c 15 Mar 2010 09:47:43 -0000 1.90 +++ core/netif.c 9 Dec 2010 19:29:20 -0000 @@ -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 @@ 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 @@ 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 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 @@ #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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } #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 */ Index: core/tcp_in.c =================================================================== RCS file: /sources/lwip/lwip/src/core/tcp_in.c,v retrieving revision 1.145 diff -u -r1.145 tcp_in.c --- core/tcp_in.c 22 May 2010 21:11:02 -0000 1.145 +++ core/tcp_in.c 9 Dec 2010 19:29:21 -0000 @@ -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; @@ -105,15 +110,14 @@ 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 @@ } /* 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(¤t_iphdr_dest, inp) || + ip_addr_ismulticast(¤t_iphdr_dest)))) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); @@ -134,6 +144,25 @@ } #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(), + IPH_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 @@ 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 @@ 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), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip.ip4), ¤t_iphdr_dest)))) { /* 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 @@ 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), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip.ip4), ¤t_iphdr_dest)))) { /* 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 @@ 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), ¤t_iphdr_dest)) { + /* 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), ¤t_iphdr_dest) || + ip_addr_isany(&(lpcb->local_ip.ip4))) { + /* found a match */ + break; + } } #endif /* SO_REUSE */ } @@ -414,9 +492,19 @@ 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); } @@ -449,9 +537,19 @@ /* 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 @@ -473,9 +571,19 @@ 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, current_ip6hdr_dest); + ip6_addr_copy(npcb->remote_ip.ip6, current_ip6hdr_src); + } + else +#endif /* LWIP_IPV6 */ + { + ip_addr_copy(npcb->local_ip.ip4, current_iphdr_dest); + ip_addr_copy(npcb->remote_ip.ip4, current_iphdr_src); + } 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; @@ -496,7 +604,15 @@ /* 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->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(); @@ -538,8 +654,17 @@ 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) { @@ -636,7 +761,15 @@ 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->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 @@ -672,8 +805,17 @@ /* 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: @@ -715,8 +857,17 @@ } } 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 */ @@ -1018,6 +1169,13 @@ 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; @@ -1338,6 +1496,13 @@ /* 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); Index: core/tcp.c =================================================================== RCS file: /sources/lwip/lwip/src/core/tcp.c,v retrieving revision 1.133 diff -u -r1.133 tcp.c --- core/tcp.c 12 Jul 2010 09:49:00 -0000 1.133 +++ core/tcp.c 9 Dec 2010 19:29:21 -0000 @@ -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 @@ /* 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); @@ -316,8 +328,8 @@ 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 */ @@ -335,10 +347,10 @@ } 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 */ @@ -355,12 +367,20 @@ 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); } } @@ -431,18 +451,40 @@ ((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); @@ -497,7 +539,15 @@ 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; } @@ -517,7 +567,16 @@ 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); + } TCP_RMV(&tcp_bound_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); #if LWIP_CALLBACK_API @@ -651,23 +710,55 @@ 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)); + 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); } if (pcb->local_port == 0) { @@ -684,8 +775,18 @@ 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; } @@ -706,7 +807,15 @@ 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, (ip6_addr_t*)ipaddr); + } + else +#endif /* LWIP_IPV6 */ + { + pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); + } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; @@ -844,8 +953,8 @@ #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))); + ip4_addr1_16(&pcb->remote_ip.ip4), ip4_addr2_16(&pcb->remote_ip.ip4), + ip4_addr3_16(&pcb->remote_ip.ip4), ip4_addr4_16(&pcb->remote_ip.ip4))); ++pcb_remove; ++pcb_reset; @@ -909,8 +1018,17 @@ 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->next; @@ -1255,6 +1373,27 @@ 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. @@ -1365,8 +1504,18 @@ 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); @@ -1481,6 +1630,35 @@ } 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 *ip6addr) +{ + 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(ip6addr); + mtu = nd6_get_destination_mtu(ip6addr, 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* Index: core/init.c =================================================================== RCS file: /sources/lwip/lwip/src/core/init.c,v retrieving revision 1.56 diff -u -r1.56 init.c --- core/init.c 24 Jun 2010 20:27:49 -0000 1.56 +++ core/init.c 9 Dec 2010 19:29:20 -0000 @@ -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. @@ -296,6 +299,13 @@ #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(); Index: core/memp.c =================================================================== RCS file: /sources/lwip/lwip/src/core/memp.c,v retrieving revision 1.69 diff -u -r1.69 memp.c --- core/memp.c 16 May 2010 14:34:16 -0000 1.69 +++ core/memp.c 9 Dec 2010 19:29:20 -0000 @@ -58,6 +58,12 @@ #include "lwip/snmp_msg.h" #include "lwip/dns.h" #include "netif/ppp_oe.h" +#if LWIP_ND6_QUEUEING +#include "lwip/nd6.h" +#endif /* LWIP_ND6_QUEUEING */ +#if LWIP_IPV6_MLD +#include "lwip/mld6.h" +#endif /* LWIP_IPV6_MLD */ #include Index: core/tcp_out.c =================================================================== RCS file: /sources/lwip/lwip/src/core/tcp_out.c,v retrieving revision 1.111 diff -u -r1.111 tcp_out.c --- core/tcp_out.c 16 May 2010 15:57:44 -0000 1.111 +++ core/tcp_out.c 9 Dec 2010 19:29:21 -0000 @@ -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 @@ -869,17 +872,34 @@ } #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; @@ -1084,12 +1104,30 @@ /* 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->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); } /* Set retransmission timer running if it is not currently enabled */ @@ -1115,14 +1153,24 @@ 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", @@ -1130,9 +1178,19 @@ } /* 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); @@ -1150,20 +1208,46 @@ #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*/ + } } /** @@ -1223,6 +1307,65 @@ 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 * @@ -1355,8 +1498,8 @@ 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))); + ip4_addr1_16(&pcb->remote_ip.ip4), ip4_addr2_16(&pcb->remote_ip.ip4), + ip4_addr3_16(&pcb->remote_ip.ip4), ip4_addr4_16(&pcb->remote_ip.ip4))); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); @@ -1369,19 +1512,41 @@ } 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 + 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*/ + 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, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); + 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, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); + ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ + } pbuf_free(p); @@ -1410,8 +1575,8 @@ 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))); + ip4_addr1_16(&pcb->remote_ip.ip4), ip4_addr2_16(&pcb->remote_ip.ip4), + ip4_addr3_16(&pcb->remote_ip.ip4), ip4_addr4_16(&pcb->remote_ip.ip4))); LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: tcp_ticks %"U32_F @@ -1446,19 +1611,41 @@ *((char *)p->payload + TCP_HLEN) = *(char *)seg->dataptr; } +#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); Index: core/raw.c =================================================================== RCS file: /sources/lwip/lwip/src/core/raw.c,v retrieving revision 1.29 diff -u -r1.29 raw.c --- core/raw.c 22 May 2010 21:11:02 -0000 1.29 +++ core/raw.c 9 Dec 2010 19:29:20 -0000 @@ -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 @@ 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 @@ /* 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), ¤t_iphdr_dest))))) { #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(¤t_iphdr_dest, 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 @@ 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 @@ 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 @@ 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 @@ 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 */ @@ -231,6 +310,19 @@ } } +#if LWIP_IPV6 + if (pcb->isipv6) { + if ((netif = ip6_route((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))); @@ -242,29 +334,62 @@ } #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*/ @@ -287,7 +412,13 @@ 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); } /** @@ -349,4 +480,28 @@ 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 */ Index: include/ipv4/lwip/ip.h =================================================================== RCS file: /sources/lwip/lwip/src/include/ipv4/lwip/ip.h,v retrieving revision 1.41 diff -u -r1.41 ip.h --- include/ipv4/lwip/ip.h 22 May 2010 21:11:02 -0000 1.41 +++ include/ipv4/lwip/ip.h 9 Dec 2010 19:29:23 -0000 @@ -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 @@ #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 */ \ Index: include/ipv6/lwip/ip_addr.h =================================================================== RCS file: include/ipv6/lwip/ip_addr.h diff -N include/ipv6/lwip/ip_addr.h --- include/ipv6/lwip/ip_addr.h 7 Sep 2007 23:02:02 -0000 1.9 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -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__ */ Index: include/ipv6/lwip/ip.h =================================================================== RCS file: include/ipv6/lwip/ip.h diff -N include/ipv6/lwip/ip.h --- include/ipv6/lwip/ip.h 5 May 2009 17:50:42 -0000 1.14 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -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__ */ - - Index: include/ipv6/lwip/icmp.h =================================================================== RCS file: include/ipv6/lwip/icmp.h diff -N include/ipv6/lwip/icmp.h --- include/ipv6/lwip/icmp.h 7 Sep 2007 23:02:02 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -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__ */ - Index: include/ipv6/lwip/inet.h =================================================================== RCS file: include/ipv6/lwip/inet.h diff -N include/ipv6/lwip/inet.h --- include/ipv6/lwip/inet.h 7 Sep 2007 23:02:02 -0000 1.8 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -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__ */ - Index: include/netif/etharp.h =================================================================== RCS file: /sources/lwip/lwip/src/include/netif/etharp.h,v retrieving revision 1.51 diff -u -r1.51 etharp.h --- include/netif/etharp.h 16 May 2010 16:26:12 -0000 1.51 +++ include/netif/etharp.h 9 Dec 2010 19:29:25 -0000 @@ -139,6 +139,7 @@ #define ETHTYPE_VLAN 0x8100 #define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ #define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHTYPE_IPV6 0x86dd /** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables * or known to be 32-bit aligned within the protocol header. */ Index: core/ipv4/inet_chksum.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv4/inet_chksum.c,v retrieving revision 1.19 diff -u -r1.19 inet_chksum.c --- core/ipv4/inet_chksum.c 15 Mar 2010 10:44:19 -0000 1.19 +++ core/ipv4/inet_chksum.c 9 Dec 2010 19:29:22 -0000 @@ -60,6 +60,7 @@ # ifndef LWIP_CHKSUM_ALGORITHM # define LWIP_CHKSUM_ALGORITHM 2 # endif +u16_t lwip_standard_chksum(void *dataptr, int len); // prototype #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 @@ * @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 @@ * 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; Index: core/ipv4/icmp.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv4/icmp.c,v retrieving revision 1.53 diff -u -r1.53 icmp.c --- core/ipv4/icmp.c 22 May 2010 21:11:02 -0000 1.53 +++ core/ipv4/icmp.c 9 Dec 2010 19:29:22 -0000 @@ -87,10 +87,9 @@ 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; } Index: core/ipv4/igmp.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv4/igmp.c,v retrieving revision 1.43 diff -u -r1.43 igmp.c --- core/ipv4/igmp.c 12 Jul 2010 09:34:17 -0000 1.43 +++ core/ipv4/igmp.c 9 Dec 2010 19:29:22 -0000 @@ -382,14 +382,13 @@ /** * 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_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 @@ } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); + ip_addr_debug_print(IGMP_DEBUG, &(current_header->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); + ip_addr_debug_print(IGMP_DEBUG, &(current_header->dest)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); /* Now calculate and check the checksum */ Index: core/ipv4/ip.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv4/ip.c,v retrieving revision 1.104 diff -u -r1.104 ip.c --- core/ipv4/ip.c 12 Jul 2010 09:34:11 -0000 1.104 +++ core/ipv4/ip.c 9 Dec 2010 19:29:22 -0000 @@ -496,23 +496,27 @@ 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 */ Index: core/ipv6/ip6_addr.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv6/ip6_addr.c,v retrieving revision 1.12 diff -u -r1.12 ip6_addr.c --- core/ipv6/ip6_addr.c 7 Sep 2007 23:02:01 -0000 1.12 +++ core/ipv6/ip6_addr.c 9 Dec 2010 19:29:23 -0000 @@ -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,212 @@ * * 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) -{ - return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) && - (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) && - (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) && - (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3])); - -} +#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip6_addr.h" +#include "lwip/def.h" + +/* used by IP6_ADDR_ANY in ip6_addr.h */ +const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } }; -u8_t -ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2) +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) +#endif + +/** + * Check whether "cp" is a valid ascii representation + * of an IPv6 address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * + * @param cp IPv6 address in ascii represenation (e.g. "FF01::1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ip6addr_aton(const char *cp, ip6_addr_t *addr) { - return(addr1->addr[0] == addr2->addr[0] && - addr1->addr[1] == addr2->addr[1] && - addr1->addr[2] == addr2->addr[2] && - addr1->addr[3] == addr2->addr[3]); + u32_t addr_index, zero_blocks, current_block_index, current_block_value; + const char * s; + + // count the number of colons, to count the number of blocks in a "::" sequence + // zero_blocks may be 1 even if there are no :: sequences + zero_blocks = 8; + for (s = cp; *s != 0; s++) { + if (*s == ':') + zero_blocks--; + else if (!isxdigit(*s)) + break; + } + + // parse each block + addr_index = 0; + current_block_index = 0; + current_block_value = 0; + for (s = cp; *s != 0; s++) { + if (*s == ':') { + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + current_block_index++; + current_block_value = 0; + if (current_block_index > 7) { + return 0; // address too long! + } + if (s[1] == ':') { + s++; + // "::" found, set zeros + while (zero_blocks-- > 0) { + if (current_block_index & 0x1) { + addr_index++; + } + else { + addr->addr[addr_index] = 0; + } + current_block_index++; + } + } + } + else if (isxdigit(*s)) { + // add current digit + current_block_value = (current_block_value << 4) + + (isdigit(*s) ? *s - '0' : + 10 + (islower(*s) ? *s - 'a' : *s - 'A')); + } + else { + // unexpected digit, space? CRLF? + break; + } + } + + if (current_block_index & 0x1) { + addr->addr[addr_index++] |= current_block_value; + } + else { + addr->addr[addr_index] = current_block_value << 16; + } + + /* convert to network byte order. */ + for (addr_index = 0; addr_index < 4; addr_index++) { + addr->addr[addr_index] = htonl(addr->addr[addr_index]); + } + + if (current_block_index != 7) { + return 0; + } + + return 1; + } -void -ip_addr_set(struct ip_addr *dest, struct ip_addr *src) +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * represenation of addr + */ +char * +ip6addr_ntoa(const ip6_addr_t *addr) { - SMEMCPY(dest, src, sizeof(struct ip_addr)); - /* dest->addr[0] = src->addr[0]; - dest->addr[1] = src->addr[1]; - dest->addr[2] = src->addr[2]; - dest->addr[3] = src->addr[3];*/ + static char str[40]; + return ip6addr_ntoa_r(addr, str, 40); } -u8_t -ip_addr_isany(struct ip_addr *addr) +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip6 address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) { - if (addr == NULL) return 1; - return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0); + u32_t current_block_index, current_block_value; + s32_t zero_flag, i; + + i = 0; + zero_flag = 0; // used to indicate a zero chain for "::' + + for (current_block_index = 0; current_block_index < 8; current_block_index++) { + // get the current 16-bit block + current_block_value = htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + if (current_block_value == 0) { + // generate empty block "::" + if (!zero_flag) { + if (current_block_index > 0) { + zero_flag = 1; + buf[i++] = ':'; + if (i >= buflen) return NULL; + } + } + } + else { + if (current_block_index > 0) { + buf[i++] = ':'; + if (i >= buflen) return NULL; + } + + if ((current_block_value & 0xf000) == 0) { + zero_flag = 1; + } + else { + buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); + if (i >= buflen) return NULL; + } + + if (((current_block_value & 0xf00) == 0) && (zero_flag)) { + // do nothing + } + else { + buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); + if (i >= buflen) return NULL; + } + + if (((current_block_value & 0xf0) == 0) && (zero_flag)) { + // do nothing + } + else { + buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); + if (i >= buflen) return NULL; + } + + buf[i++] = xchar((current_block_value & 0xf)); + if (i >= buflen) return NULL; + + zero_flag = 0; + } + } + + buf[i] = 0; + + return buf; } +#endif /* LWIP_IPV6 */ Index: core/ipv6/ip6.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv6/ip6.c,v retrieving revision 1.21 diff -u -r1.21 ip6.c --- core/ipv6/ip6.c 21 Feb 2010 11:35:22 -0000 1.21 +++ core/ipv6/ip6.c 9 Dec 2010 19:29:22 -0000 @@ -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,722 @@ * * 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/icmp6.h" +#include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp_impl.h" - -#include "lwip/stats.h" +#include "lwip/dhcp6.h" +#include "lwip/nd6.h" +#include "lwip/mld6.h" #include "arch/perf.h" -/* ip_init: - * - * Initializes the IP layer. - */ -void -ip_init(void) -{ -} +/** Header of the input IPv6 packet currently being processed. */ +const struct ip6_hdr *current_ip6_header; +/** Source IPv6 address of current_header */ +ip6_addr_t current_ip6hdr_src; +/** Destination IPv6 address of current_header */ +ip6_addr_t current_ip6hdr_dest; + -/* ip_route: + +/** + * Finds the appropriate network interface for a given IPv6 address. It searches the + * list of network interfaces linearly. A match is found if the network ID of one of + * the IPv6 addresses of the network interface equals the network ID of the IPv6 address + * given to the function. + * + * @todo this routing function needs to be improved dramatically for it to work properly + * with more than 1 netif!!! * - * 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. + * @param dest the destination IPv6 address for which to find the route + * @return the netif on which to send to reach dest */ - struct netif * -ip_route(struct ip_addr *dest) +ip6_route(struct ip6_addr *dest) { struct netif *netif; + u8_t i; 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; + } } } + /* no matching netif found, use default netif */ return netif_default; } -/* ip_forward: - * - * 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. +/** + * Select the best IPv6 source address for a given destination + * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior + * is assumed. + * + * @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) { + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip6_addr_islinklocal(ip6_current_dest_addr())) { + LWIP_DEBUGF(IP_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); + goto return_noroute; + } - 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); - return; + /* Find network interface where to forward this IP packet to. */ + netif = ip6_route(ip6_current_dest_addr()); + if (netif == NULL) { + LWIP_DEBUGF(IP_DEBUG, ("ip6_forward: no route.\n")); +#if LWIP_ICMP6 + /* Don't send ICMP messages in response to ICMP messages */ + if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { + icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); + } +#endif /* LWIP_ICMP6 */ + goto return_noroute; } - /* Decrement TTL and send ICMP if ttl == 0. */ - if (--iphdr->hoplim == 0) { -#if LWIP_ICMP + /* Do not forward packets onto the same network interface on which + * they arrived. */ + if (netif == inp) { + LWIP_DEBUGF(IP_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); + goto return_noroute; + } + + /* decrement HL */ + IP6H_HL_SET(iphdr, IP6H_HL(iphdr) - 1); + /* send ICMP6 if HL == 0 */ + if (IP6H_HL(iphdr) == 0) { +#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_time_exceeded(p, ICMP6_TE_HL); } -#endif /* LWIP_ICMP */ - pbuf_free(p); +#endif /* LWIP_ICMP6 */ return; } - /* Incremental update of the IP checksum. */ - /* if (iphdr->chksum >= htons(0xffff - 0x100)) { - iphdr->chksum += htons(0x100) + 1; - } else { - iphdr->chksum += htons(0x100); - }*/ - - - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to ")); -#if IP_DEBUG - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); -#endif /* IP_DEBUG */ - LWIP_DEBUGF(IP_DEBUG, ("\n")); - - IP_STATS_INC(ip.fw); - IP_STATS_INC(ip.xmit); - - PERF_STOP("ip_forward"); - - netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); + PERF_STOP("ip6_forward"); + /* transmit pbuf on chosen interface */ + netif->output_ip6(netif, p, ip6_current_dest_addr()); + return; +return_noroute: + // TODO debug info + ; } +#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; - - - PERF_START; - -#if IP_DEBUG - ip_debug_print(p); -#endif /* IP_DEBUG */ - - - IP_STATS_INC(ip.recv); + u8_t nexth; + u16_t hlen; /* the current header length */ + u16_t hlen_tot; /* the total header length */ + u8_t i; +#if IP_ACCEPT_LINK_LAYER_ADDRESSING + int check_ip_src=1; +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ /* 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(IP_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; + return ERR_OK; } - /* is this packet for us? */ - for(netif = netif_list; netif != NULL; netif = netif->next) { -#if IP_DEBUG - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr ")); - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("\n")); -#endif /* IP_DEBUG */ - if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) { - break; + /* 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(IP_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(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IP (len %"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); + 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); + + /* 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))) { + goto netif_found; // exit outer loop + } + } + } + if (first) { + first = 0; + netif = netif_list; + } else { + netif = netif->next; + } + if (netif == inp) { + netif = netif->next; + } + } while(netif != NULL); +netif_found: + ; + } + + /* "::" 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 */ + pbuf_free(p); + ip6_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + return ERR_OK; + } + /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ -#if IP_FORWARD - ip_forward(p, iphdr); -#endif + LWIP_DEBUGF(IP_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); + } else +#endif /* LWIP_IPV6_FORWARD */ + { + /* TODO snmp errors */ + } pbuf_free(p); - return; - } + ip6_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + return ERR_OK; + } + + /* Save next header type. */ + nexth = IP6H_NEXTH(ip6hdr); + + /* Init header length. */ + hlen = hlen_tot = 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: + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload) + 1); + hlen_tot += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 header (len %"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_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + return ERR_OK; + } - pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len)); + pbuf_header(p, -hlen); + break; + case IP6_NEXTH_DESTOPTS: + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload) + 1); + hlen_tot += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 header (len %"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_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + return ERR_OK; + } - /* 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 */ + pbuf_header(p, -hlen); + break; + case IP6_NEXTH_ROUTING: + /* Get next header type. */ + nexth = *((u8_t *)p->payload); + + /* Get the header length. */ + hlen = 8 * (1 + *((u8_t *)p->payload) + 1); + hlen_tot += hlen; + + /* Skip over this header. */ + if (hlen > p->len) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("IPv6 header (len %"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_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + return ERR_OK; + } - if(pbuf_header(p, -IP_HLEN)) { - LWIP_ASSERT("Can't move over header in packet", 0); - return; + pbuf_header(p, -hlen); + break; +#if LWIP_IPV6_REASS + case IP6_NEXTH_FRAGMENT: + // TODO + break; +#endif + default: + goto options_done; + break; + } } +options_done: - 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; + /* p points to IPv6 header again. */ + pbuf_header(p, hlen_tot); + + /* current pointers. */ + current_netif = inp; + current_ip6_header = ip6hdr; + + /* send to upper layers */ +#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, -hlen_tot); + udp_input(p, inp); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case IP6_NEXTH_TCP: + /* Point to payload. */ + pbuf_header(p, -hlen_tot); + tcp_input(p, inp); + break; +#endif /* LWIP_TCP */ +#if LWIP_ICMP6 + case IP6_NEXTH_ICMP6: + /* Point to payload. */ + pbuf_header(p, -hlen_tot); + icmp6_input(p, inp); + break; #endif /* LWIP_ICMP */ - default: -#if LWIP_ICMP - /* send ICMP destination protocol unreachable */ - icmp_dest_unreach(p, ICMP_DUR_PROTO); + default: +#if LWIP_ICMP6 + /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ + if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && + (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { + icmp6_param_problem(p, ICMP6_PP_HEADER, 0); /* TODO use correct pointer value */ + } #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); + pbuf_free(p); + break; + } } - PERF_STOP("ip_input"); + + current_netif = NULL; + current_ip6_header = NULL; + ip6_addr_set_any(¤t_ip6hdr_src); + ip6_addr_set_any(¤t_ip6hdr_dest); + + return ERR_OK; } -/* ip_output_if: - * - * 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. +/** + * 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. + * + * @param p the packet to send (p->payload points to the data, e.g. next + protocol header; if dest == IP_HDRINCL, p already includes an + IPv6 header and p->payload points to that IPv6 header) + * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an + * IP address of the netif is selected and used as source address. + * if src == NULL, IP6_ADDR_ANY is used as source) + * @param dest the destination IPv6 address to send the packet to + * @param hl the Hop Limit value to be set in the IPv6 header + * @param tc the Traffic Class value to be set in the IPv6 header + * @param nexth the Next Header to be set in the IPv6 header + * @param netif the netif on which to send this packet + * @return ERR_OK if the packet was sent OK + * ERR_BUF if p doesn't have enough space for IPv6/LINK headers + * returns errors returned by netif->output */ - err_t -ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, - u8_t proto, struct netif *netif) +ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) { - struct ip_hdr *iphdr; - - PERF_START; + struct ip6_hdr *ip6hdr; + ip6_addr_t dest_addr; - 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); + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + + /* Should the IPv6 header be generated or is it already included in p? */ + if (dest != IP6_HDRINCL) { + /* generate IPv6 header */ + if (pbuf_header(p, IP6_HLEN)) { + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IPv6 header in pbuf\n")); - return ERR_BUF; - } - LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); + return ERR_BUF; + } - iphdr = p->payload; + ip6hdr = (struct ip6_hdr *)p->payload; + LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", + (p->len >= sizeof(struct ip6_hdr))); + IP6H_HL_SET(ip6hdr, hl); + IP6H_NEXTH_SET(ip6hdr, nexth); - if (dest != IP_HDRINCL) { - LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n")); - iphdr->hoplim = ttl; - iphdr->nexthdr = proto; - iphdr->len = htons(p->tot_len - IP_HLEN); - ip_addr_set(&(iphdr->dest), dest); + /* dest cannot be NULL here */ + ip6_addr_copy(ip6hdr->dest, *dest); - iphdr->v = 6; + IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); + IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); - if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); - } else { - ip_addr_set(&(iphdr->src), src); + if (src == NULL) { + src = IP6_ADDR_ANY; + } + else if (ip6_addr_isany(src)) { + src = ip6_select_source_address(netif, dest); + if ((src == NULL) || ip6_addr_isany(src)) { + /* No appropriate source address was found for this packet. */ + 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; + } + +#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 > netif->mtu)) { + return ip6_frag(p, netif, dest); } +#endif /* LWIP_IPV6_FRAG */ - IP_STATS_INC(ip.xmit); - - LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len)); -#if IP_DEBUG - ip_debug_print(p); -#endif /* IP_DEBUG */ - - PERF_STOP("ip_output_if"); - return netif->output(netif, p, dest); + LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); + 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. + * + * @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 * - * Simple interface to ip_output_if. It finds the outgoing network interface and - * calls upon ip_output_if to do the actual work. + * @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(dest)) == NULL) { + 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(dest)) == NULL) { 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; + + /* Move pointer to make room for hop-by-hop options header. */ + if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) { + return ERR_BUF; + } - 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")); + 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 */ + + +#endif /* LWIP_IPV6 */ Index: core/ipv6/inet6.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv6/inet6.c,v retrieving revision 1.1 diff -u -r1.1 inet6.c --- core/ipv6/inet6.c 16 Nov 2007 19:31:12 -0000 1.1 +++ core/ipv6/inet6.c 9 Dec 2010 19:29:22 -0000 @@ -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 * - */ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/inet.h" - -/* chksum: - * - * Sums up all 16 bit words in a memory portion. Also includes any odd byte. - * This function is used by the other checksum functions. * - * For now, this is not optimized. Must be optimized for the particular processor - * arcitecture on which it is to run. Preferebly coded in assembler. + * Please coordinate changes and requests with Ivan Delamer + * */ -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; +#include "lwip/opt.h" -} +#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - */ +#include "lwip/def.h" +#include "lwip/inet6.h" -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 */ Index: core/ipv6/icmp6.c =================================================================== RCS file: /sources/lwip/lwip/src/core/ipv6/icmp6.c,v retrieving revision 1.20 diff -u -r1.20 icmp6.c --- core/ipv6/icmp6.c 28 Nov 2007 21:21:06 -0000 1.20 +++ core/ipv6/icmp6.c 9 Dec 2010 19:29:22 -0000 @@ -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,255 @@ * * 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/stats.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 + +#ifndef LWIP_ICMP6_DATASIZE +#define LWIP_ICMP6_DATASIZE 8 +#endif +#if LWIP_ICMP6_DATASIZE == 0 +#define LWIP_ICMP6_DATASIZE 8 +#endif -void -icmp_input(struct pbuf *p, struct netif *inp) -{ - u8_t type; - struct icmp_echo_hdr *iecho; - struct ip_hdr *iphdr; - struct ip_addr tmpaddr; +/* Forward declarations */ +static void icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data); - ICMP_STATS_INC(icmp.recv); - /* TODO: check length before accessing payload! */ +/** + * Process an input ICMPv6 message. Called by ip6_input. + * + * Will generate a reply for echo requests. Other messages are forwarded + * to nd6_input, or mld6_input. + * + * @param p the mld packet, p->payload pointing to the icmpv6 header + * @param inp the netif on which this packet was received + */ +void +icmp6_input(struct pbuf *p, struct netif *inp) +{ + struct icmp6_hdr *icmp6hdr; + struct pbuf * r; + ip6_addr_t * reply_src; + + /* Check that ICMPv6 header fits in payload */ + if (p->len < sizeof(struct icmp6_hdr)) { + /* drop short packets */ + pbuf_free(p); + return; + } - type = ((u8_t *)p->payload)[0]; + icmp6hdr = (struct icmp6_hdr *)p->payload; - switch (type) { - case ICMP6_ECHO: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); +#if LWIP_ICMP6_CHECKSUM_CHECK + if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(), + IP6_NEXTH_ICMP6, p->tot_len) != 0) { + /* Checksum failed */ + pbuf_free(p); + return; + } +#endif /* LWIP_ICMP6_CHECKSUM_CHECK */ - if (p->tot_len < sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); + switch (icmp6hdr->type) { + case ICMP6_TYPE_NA: /* Neighbor advertisement */ + case ICMP6_TYPE_NS: /* Neighbor solicitation */ + case ICMP6_TYPE_RA: /* Router advertisement */ + case ICMP6_TYPE_RD: /* Redirect */ + case ICMP6_TYPE_PTB: /* Packet too big */ + nd6_input(p, inp); + return; + break; + case ICMP6_TYPE_RS: +#if LWIP_IPV6_FORWARD + /* TODO */ +#endif + break; + case ICMP6_TYPE_MLQ: + case ICMP6_TYPE_MLR: + case ICMP6_TYPE_MLD: +#if LWIP_IPV6_MLD + mld6_input(p, inp); + return; +#endif + break; + case ICMP6_TYPE_EREQ: +#if !LWIP_MULTICAST_PING + /* multicast destination address? */ + if (ip6_addr_ismulticast(ip6_current_dest_addr())) { + /* drop */ + pbuf_free(p); + return; + } +#endif /* LWIP_MULTICAST_PING */ + /* Allocate reply. */ + r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); + if (r == NULL) { + /* drop */ pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); return; } - iecho = p->payload; - iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN); - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.chkerr); - /* return;*/ + + /* Copy echo request. */ + if (pbuf_copy(r, p) != ERR_OK) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + return; } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len)); - ip_addr_set(&tmpaddr, &(iphdr->src)); - ip_addr_set(&(iphdr->src), &(iphdr->dest)); - ip_addr_set(&(iphdr->dest), &tmpaddr); - iecho->type = ICMP6_ER; - /* adjust the checksum */ - if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) { - iecho->chksum += htons(ICMP6_ECHO << 8) + 1; - } else { - iecho->chksum += htons(ICMP6_ECHO << 8); + + /* Determine reply source IPv6 address. */ + reply_src = ip6_select_source_address(inp, ip6_current_src_addr()); + if (reply_src == NULL) { + /* drop */ + pbuf_free(p); + pbuf_free(r); + return; } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.xmit); - /* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ - ip_output_if (p, &(iphdr->src), IP_HDRINCL, - iphdr->hoplim, IP_PROTO_ICMP, inp); + /* Set fields in reply. */ + ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + reply_src, ip6_current_src_addr(), + IP6_NEXTH_ICMP6, r->tot_len); + + /* Send reply. */ + ip6_output_if(r, reply_src, ip6_current_src_addr(), + LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); + pbuf_free(r); + break; default: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type)); - ICMP_STATS_INC(icmp.proterr); - ICMP_STATS_INC(icmp.drop); + break; } pbuf_free(p); } + +/** + * Send an icmpv6 'destination unreachable' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the unreachable type + */ void -icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) +icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) { - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_dur_hdr *idur; - - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (8 + IP_HLEN + 8))); - - iphdr = p->payload; - - idur = q->payload; - idur->type = (u8_t)ICMP6_DUR; - idur->icode = (u8_t)t; - - SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8); + icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0); +} - /* calculate checksum */ - idur->chksum = 0; - idur->chksum = inet_chksum(idur, q->len); - ICMP_STATS_INC(icmp.xmit); +/** + * Send an icmpv6 'packet too big' packet. + * + * @param p the input packet for which the 'packet too big' should be sent, + * p->payload pointing to the IPv6 header + * @param mtu the maximum mtu that we can accept + */ +void +icmp6_packet_too_big(struct pbuf *p, u32_t mtu) +{ + icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu); +} - ip_output(q, NULL, - (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); - pbuf_free(q); +/** + * Send an icmpv6 'time exceeded' packet. + * + * @param p the input packet for which the 'unreachable' should be sent, + * p->payload pointing to the IPv6 header + * @param c ICMPv6 code for the time exceeded type + */ +void +icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) +{ + icmp6_send_response(p, ICMP6_TYPE_TE, c, 0); } +/** + * Send an icmpv6 'parameter problem' packet. + * + * @param p the input packet for which the 'param problem' should be sent, + * p->payload pointing to the IP header + * @param c ICMPv6 code for the param problem type + * @param pointer the pointer to the byte where the parameter is found + */ void -icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) +icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) { - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_te_hdr *tehdr; + icmp6_send_response(p, ICMP6_TYPE_PP, c, pointer); +} - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); +/** + * Send an ICMPv6 packet in response to an incoming packet. + * + * @param p the input packet for which the response should be sent, + * p->payload pointing to the IPv6 header + * @param type Type of the ICMPv6 header + * @param code Code of the ICMPv6 header + * @param data Additional 32-bit parameter in the ICMPv6 header + */ +static void +icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data) +{ + struct pbuf *q; + struct icmp6_hdr *icmp6hdr; + ip6_addr_t * reply_src; - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ + /* ICMPv6 header + IPv6 header + data */ + q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, + PBUF_RAM); if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); 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); + 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); + + 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 */ Index: netif/etharp.c =================================================================== RCS file: /sources/lwip/lwip/src/netif/etharp.c,v retrieving revision 1.173 diff -u -r1.173 etharp.c --- netif/etharp.c 22 May 2010 21:11:03 -0000 1.173 +++ netif/etharp.c 9 Dec 2010 19:29:25 -0000 @@ -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" @@ -1268,6 +1269,19 @@ 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); Index: netif/ethernetif.c =================================================================== RCS file: /sources/lwip/lwip/src/netif/ethernetif.c,v retrieving revision 1.52 diff -u -r1.52 ethernetif.c --- netif/ethernetif.c 9 Oct 2009 20:16:26 -0000 1.52 +++ netif/ethernetif.c 9 Dec 2010 19:29:25 -0000 @@ -54,6 +54,7 @@ #include #include #include "netif/etharp.h" +#include "netif/ethip6.h" #include "netif/ppp_oe.h" /* Define those to better describe your network interface. */ @@ -239,6 +240,7 @@ 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 @@ * 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]); Index: core/ipv6/nd6.c =================================================================== RCS file: core/ipv6/nd6.c diff -N core/ipv6/nd6.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/ipv6/nd6.c 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,1608 @@ +/** + * @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 + + +/* 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_select_router(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); + +#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 +#define ND6_SEND_FLAG_EMPTY_SRC 0x02 +#define ND6_SEND_FLAG_ALLNODES_DEST 0x04 +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; + + 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); + return; + } + + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)(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); + 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); + 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 *)(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); + 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); + 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); + 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); + 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_TIMERS + retrans_timer = ra_hdr->retrans_timer; + reachable_time = ra_hdr->reachable_time; +#endif /* LWIP_ND6_ALLOW_RA_TIMERS */ + + /* 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); + return; + } + + /* Process each option. */ + while (p->tot_len > 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) { + /* TODO enable/disable this through #if */ + inp->mtu = mtu_opt->mtu; + } + 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)); + + i = nd6_get_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) && + (inp->ip6_autoconfig_enabled)) { + /* TODO Use this prefix to generate IPv6 addresses. */ + } +#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. */ + 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); + 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 *)(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); + return; + } + + icmp6hdr = (struct icmp6_hdr *)p->payload; + ip6hdr = (struct ip6_hdr *)(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: + 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; + 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].invalidation_timer -= ND6_TMR_INTERVAL / 1000; + } + } + + + /* 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); + /* TODO leave group if DAD fails. */ + } +#endif /* LWIP_IPV6_MLD */ + /* Send a NS for this address. */ + nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_EMPTY_SRC | 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 (flags & ND6_SEND_FLAG_EMPTY_SRC) { + src_addr = IP6_ADDR_ANY; + } else { + /* Use link-local address as source address. */ + src_addr = &(netif->ip6_addr[0]); + /* TODO: Select a source address to use with this NS message? */ + /*src_addr = ip6_select_source_address(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address));*/ + } + + /* 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); + } + return; + } + + /* Set fields. */ + ns_hdr = (struct ns_header *)p->payload; + lladdr_opt = (struct lladdr_option *)(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 <= 6 ? 1 : 2; // TODO what if larger than 2? + 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. */ + ip6_output_if(p, (flags & ND6_SEND_FLAG_EMPTY_SRC) ? 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); + } + return; + } + + /* Set fields. */ + na_hdr = (struct na_header *)p->payload; + lladdr_opt = (struct lladdr_option *)(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 <= 6 ? 1 : 2; // TODO what if larger than 2? + 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. */ + 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); + } + 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 *)(p->payload + sizeof(struct rs_header)); + lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; + lladdr_opt->length = netif->hwaddr_len <= 6 ? 1 : 2; // TODO what if larger than 2? + 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. */ + 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 + */ +static 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!! */ + (void)netif; /* TODO match router to the netif!! */ + + /* 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) && + (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) && + (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) { + 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; + (void)netif; /* TODO match router to the netif!! */ + + /* Look for router. */ + for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { + if ((default_router_list[i].neighbor_entry != NULL) && + 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_cmp(&(prefix_list[i].prefix), prefix)) && + (prefix_list[i].netif == netif)) { + return 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); + 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. */ + } 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. */ + } 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; + + /* 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) { + 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 ... */ + struct nd6_q_entry *new_entry; + /* allocate a new nd6 queue entry */ + 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 */ + struct nd6_q_entry *r; + 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; + } + 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; + } + 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 */ Index: include/ipv6/lwip/ip6_chksum.h =================================================================== RCS file: include/ipv6/lwip/ip6_chksum.h diff -N include/ipv6/lwip/ip6_chksum.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/ip6_chksum.h 1 Jan 1970 00:00:00 -0000 @@ -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, u32_t proto_len); +u16_t ip6_chksum_pseudo_partial(struct pbuf *p, + ip6_addr_t *src, ip6_addr_t *dest, + u8_t proto, u32_t proto_len, u16_t chksum_len); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_CHKSUM_H__ */ Index: include/ipv6/lwip/inet6.h =================================================================== RCS file: include/ipv6/lwip/inet6.h diff -N include/ipv6/lwip/inet6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/inet6.h 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,65 @@ +/** + * @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" + +#ifdef __cplusplus +extern "C" { +#endif + + + // TODO everything!!!! + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_INET6_H__ */ + Index: netif/ethip6.c =================================================================== RCS file: netif/ethip6.c diff -N netif/ethip6.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ netif/ethip6.c 1 Jan 1970 00:00:00 -0000 @@ -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 "netif/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 */ Index: core/ipv6/ip6_chksum.c =================================================================== RCS file: core/ipv6/ip6_chksum.c diff -N core/ipv6/ip6_chksum.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/ipv6/ip6_chksum.c 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,183 @@ +/** + * @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); +# ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 2 +# endif +#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, u32_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((u16_t)(proto_len & 0xffff)); + acc += (u32_t)htons((u16_t)((proto_len >> 16) & 0xffff)); + + /* 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, u32_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((u16_t)(proto_len & 0xffff)); + acc += (u32_t)htons((u16_t)((proto_len >> 16) & 0xffff)); + + /* 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 */ Index: include/ipv6/lwip/icmp6.h =================================================================== RCS file: include/ipv6/lwip/icmp6.h diff -N include/ipv6/lwip/icmp6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/icmp6.h 1 Jan 1970 00:00:00 -0000 @@ -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__ */ Index: include/netif/ethip6.h =================================================================== RCS file: include/netif/ethip6.h diff -N include/netif/ethip6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/netif/ethip6.h 1 Jan 1970 00:00:00 -0000 @@ -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__ */ Index: include/ipv6/lwip/ip6_addr.h =================================================================== RCS file: include/ipv6/lwip/ip6_addr.h diff -N include/ipv6/lwip/ip6_addr.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/ip6_addr.h 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,263 @@ +/** + * @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 + + +/** 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(0xff010000UL)) && \ + ((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(0xff010000UL)) && \ + ((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) + + +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__ */ Index: core/ipv6/mld6.c =================================================================== RCS file: core/ipv6/mld6.c diff -N core/ipv6/mld6.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/ipv6/mld6.c 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,562 @@ +/** + * @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 + + +/* + * MLD constants + */ +#define MLD6_HL 1 +#define MLD6_JOIN_DELAYING_MEMBER_TMR (500) // milliseconds + +#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); + } + 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; + + /* Check that mld header fits in packet. */ + if (p->len < sizeof(struct mld_header)) { + // TODO debug message + pbuf_free(p); + 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))) { + /* 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. */ + 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. */ + 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: + 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_send(group, ICMP6_TYPE_MLR); + mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR); + } + + /* 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_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_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); + } + return; + } + + /* Move to make room for Hop-by-hop options header. */ + if (pbuf_header(p, -IP6_HBH_HLEN)) { + pbuf_free(p); + 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. */ + 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 */ Index: include/ipv6/lwip/ip6.h =================================================================== RCS file: include/ipv6/lwip/ip6.h diff -N include/ipv6/lwip/ip6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/ip6.h 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,193 @@ +/** + * @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 _hl); + /* 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 + + +#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_HL(hdr) ((hdr)->_hl) + +#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_HL_SET(hdr, hl) (hdr)->_hl = (u8_t)(hl) + + + +/** Header of the input IPv6 packet currently being processed. */ +extern const struct ip6_hdr *current_ip6_header; +/** 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 *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) +/** 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) + + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IPV6 */ + +#endif /* __LWIP_IP6_H__ */ Index: core/ipv6/dhcp6.c =================================================================== RCS file: core/ipv6/dhcp6.c diff -N core/ipv6/dhcp6.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/ipv6/dhcp6.c 1 Jan 1970 00:00:00 -0000 @@ -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 */ Index: include/ipv6/lwip/nd6.h =================================================================== RCS file: include/ipv6/lwip/nd6.h diff -N include/ipv6/lwip/nd6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/nd6.h 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,361 @@ +/** + * @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; +}; + +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); +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__ */ Index: include/ipv6/lwip/dhcp6.h =================================================================== RCS file: include/ipv6/lwip/dhcp6.h diff -N include/ipv6/lwip/dhcp6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/dhcp6.h 1 Jan 1970 00:00:00 -0000 @@ -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 +}; + +#endif /* LWIP_IPV6_DHCP6 */ + +#endif /* __LWIP_IP6_DHCP6_H__ */ Index: include/ipv6/lwip/mld6.h =================================================================== RCS file: include/ipv6/lwip/mld6.h diff -N include/ipv6/lwip/mld6.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/ipv6/lwip/mld6.h 1 Jan 1970 00:00:00 -0000 @@ -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__ */