diff --git a/CHANGELOG b/CHANGELOG index f86f5d9b..c217efb9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -100,6 +100,10 @@ HISTORY ++ Bugfixes: + 2014-04-06: Simon Goldschmidt + * dhcp.c, ip4.c/.h, ip6.c/.h, udp.c/.h, ip.h: Fixed bug #41787 DHCP Discovery + is invalid when an IP is set to thet netif. + 2014-03-14: Simon Goldschmidt * tcp_out.c: Fixed bug #36153 TCP Cheksum error if LWIP_CHECKSUM_ON_COPY=1 diff --git a/src/core/dhcp.c b/src/core/dhcp.c index 4c605212..32307461 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -317,7 +317,7 @@ dhcp_select(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* send broadcast to any DHCP server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); } else { @@ -845,7 +845,7 @@ dhcp_decline(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* per section 4.4.4, broadcast DECLINE messages */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); } else { @@ -895,7 +895,7 @@ dhcp_discover(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 48d2a391..2f1da5b8 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -655,6 +655,43 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { +#endif /* IP_OPTIONS_SEND */ + ip_addr_t *src_used = src; + if (dest != IP_HDRINCL) { + if (ip_addr_isany(src)) { + src_used = &netif->ip_addr; + } + } + +#if IP_OPTIONS_SEND + return ip_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif, + ip_options, optlen); +#else /* IP_OPTIONS_SEND */ + return ip_output_if_src(p, src_used, dest, ttl, tos, proto, netif); +#endif /* IP_OPTIONS_SEND */ +} + +/** + * Same as ip_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip_output_if_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, + u8_t proto, struct netif *netif) +{ +#if IP_OPTIONS_SEND + return ip_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); +} + +/** + * Same as ip_output_if_opt() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t ip_output_if_opt_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen) +{ #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; ip_addr_t dest_addr; @@ -741,8 +778,8 @@ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, #endif /* CHECKSUM_GEN_IP_INLINE */ ++ip_id; - if (ip_addr_isany(src)) { - ip_addr_copy(iphdr->src, netif->ip_addr); + if (src == NULL) { + ip_addr_copy(iphdr->src, ip_addr_any); } else { /* src cannot be NULL here */ ip_addr_copy(iphdr->src, *src); diff --git a/src/core/ipv6/ip6.c b/src/core/ipv6/ip6.c index 5ab51848..fa786e99 100644 --- a/src/core/ipv6/ip6.c +++ b/src/core/ipv6/ip6.c @@ -744,6 +744,29 @@ err_t 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) +{ + ip6_addr_t *src_used = src; + if (dest != IP_HDRINCL) { + if (src != NULL && ip6_addr_isany(src)) { + src = ip6_select_source_address(netif, dest); + if ((src == NULL) || ip6_addr_isany(src)) { + /* No appropriate source address was found for this packet. */ + LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); + IP6_STATS_INC(ip6.rterr); + return ERR_RTE; + } + } + return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif); +} + +/** + * Same as ip6_output_if() but 'src' address is not replaced by netif address + * when it is 'any'. + */ +err_t +ip6_output_if_src(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, + u8_t hl, u8_t tc, + u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; @@ -777,15 +800,6 @@ ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, if (src == NULL) { src = IP6_ADDR_ANY; } - else if (ip6_addr_isany(src)) { - src = ip6_select_source_address(netif, dest); - if ((src == NULL) || ip6_addr_isany(src)) { - /* No appropriate source address was found for this packet. */ - LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); - IP6_STATS_INC(ip6.rterr); - return ERR_RTE; - } - } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); diff --git a/src/core/udp.c b/src/core/udp.c index 986e6992..a7b24466 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -626,8 +626,65 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t chksum) { #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ - struct udp_hdr *udphdr; ip_addr_t *src_ip; + + /* PCB local address is IP_ANY_ADDR? */ +#if LWIP_IPV6 + if (PCB_ISIPV6(pcb)) { + if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { + src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); + if (src_ip == NULL) { + /* No suitable source address was found. */ + return ERR_RTE; + } + } else { + /* use UDP PCB local IPv6 address as source address, if still valid. */ + if (netif_get_ip6_addr_match(netif, ipX_2_ip6(&pcb->local_ip)) < 0) { + /* Address isn't valid anymore. */ + return ERR_RTE; + } + src_ip = ipX_2_ip(&pcb->local_ip); + } + } + else +#endif /* LWIP_IPV6 */ + if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { + /* use outgoing network interface IP address as source address */ + src_ip = &(netif->ip_addr); + } else { + /* check if UDP PCB local IP address is correct + * this could be an old address if netif->ip_addr has changed */ + if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) { + /* local_ip doesn't match, drop the packet */ + return ERR_VAL; + } + /* use UDP PCB local IP address as source address */ + src_ip = ipX_2_ip(&(pcb->local_ip)); + } +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); +#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ +} + +/** Same as udp_sendto_if(), but with source address */ +err_t +udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, ip_addr_t *src_ip) +{ +#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP + return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); +} + +/** Same as udp_sendto_if_src(), but with checksum */ +err_t +udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum, ip_addr_t *src_ip) +{ +#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ + struct udp_hdr *udphdr; err_t err; struct pbuf *q; /* q will be sent down the stack */ u8_t ip_proto; @@ -704,57 +761,6 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, } #endif /* LWIP_IGMP */ - - /* PCB local address is IP_ANY_ADDR? */ -#if LWIP_IPV6 - if (PCB_ISIPV6(pcb)) { - if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { - src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); - if (src_ip == NULL) { - /* No suitable source address was found. */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - /* p is still referenced by the caller, and will live on */ - } - return ERR_RTE; - } - } else { - /* use UDP PCB local IPv6 address as source address, if still valid. */ - if (netif_get_ip6_addr_match(netif, ipX_2_ip6(&pcb->local_ip)) < 0) { - /* Address isn't valid anymore. */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - /* p is still referenced by the caller, and will live on */ - } - return ERR_RTE; - } - src_ip = ipX_2_ip(&pcb->local_ip); - } - } - else -#endif /* LWIP_IPV6 */ - if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* check if UDP PCB local IP address is correct - * this could be an old address if netif->ip_addr has changed */ - if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) { - /* local_ip doesn't match, drop the packet */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; - /* p is still referenced by the caller, and will live on */ - } - return ERR_VAL; - } - /* use UDP PCB local IP address as source address */ - src_ip = ipX_2_ip(&(pcb->local_ip)); - } - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); #if LWIP_UDPLITE @@ -840,7 +846,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); /* output to IP */ NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); - err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); + err = ipX_output_if_src(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* TODO: must this be increased even if error occured? */ diff --git a/src/include/ipv4/lwip/ip4.h b/src/include/ipv4/lwip/ip4.h index 04b5b8a6..e1728357 100644 --- a/src/include/ipv4/lwip/ip4.h +++ b/src/include/ipv4/lwip/ip4.h @@ -117,8 +117,9 @@ err_t ip_input(struct pbuf *p, struct netif *inp); err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto); err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, - struct netif *netif); + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); +err_t ip_output_if_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); #if LWIP_NETIF_HWADDRHINT err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); @@ -127,6 +128,9 @@ err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen); +err_t ip_output_if_opt_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, + u16_t optlen); #endif /* IP_OPTIONS_SEND */ #define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL) diff --git a/src/include/ipv6/lwip/ip6.h b/src/include/ipv6/lwip/ip6.h index ac32ceec..5ab61c3c 100644 --- a/src/include/ipv6/lwip/ip6.h +++ b/src/include/ipv6/lwip/ip6.h @@ -169,6 +169,8 @@ err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr * 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); +err_t ip6_output_if_src(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); diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index a0cd1d4d..5d34e9bc 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -213,6 +213,10 @@ extern struct ip_globals ip_data; ((isipv6) ? \ ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ ip_output_if(p, (src), (dest), ttl, tos, proto, netif)) +#define ipX_output_if_src(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ((isipv6) ? \ + ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ + ip_output_if_src(p, (src), (dest), ttl, tos, proto, netif)) #define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ ((isipv6) ? \ ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \ @@ -231,6 +235,8 @@ extern struct ip_globals ip_data; ip_output(p, src, dest, ttl, tos, proto) #define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ ip_output_if(p, src, dest, ttl, tos, proto, netif) +#define ipX_output_if_src(isipv6, p, src, dest, ttl, tos, proto, netif) \ + ip_output_if_src(p, src, dest, ttl, tos, proto, netif) #define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) #define ipX_route(isipv6, src, dest) \ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 14d5c0ae..93c72b79 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -156,6 +156,9 @@ void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif); +err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, ip_addr_t *src_ip); err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port); err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); @@ -170,6 +173,9 @@ err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum); err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum); +err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, + u8_t have_chksum, u16_t chksum, ip_addr_t *src_ip); #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ #define udp_flags(pcb) ((pcb)->flags)