diff --git a/CHANGELOG b/CHANGELOG index 6fbaa783..45b96d1e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,10 @@ HISTORY ++ New features: + 2015-09-01: Simon Goldschmidt + * task #12178: hardware checksum capabilities can be configured per netif + (use NETIF_SET_CHECKSUM_CTRL() in your netif's init function) + 2015-08-30: Simon Goldschmidt * PBUF_REF with "custom" pbufs is now supported for RX pbufs (see pcapif in contrib for an example, LWIP_SUPPORT_CUSTOM_PBUF is required) diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index db08f510..0d669605 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -133,12 +133,14 @@ icmp_input(struct pbuf *p, struct netif *inp) goto lenerr; } #if CHECKSUM_CHECK_ICMP - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); - pbuf_free(p); - ICMP_STATS_INC(icmp.chkerr); - snmp_inc_icmpinerrors(); - return; + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP) { + if (inet_chksum_pbuf(p) != 0) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); + pbuf_free(p); + ICMP_STATS_INC(icmp.chkerr); + snmp_inc_icmpinerrors(); + return; + } } #endif #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN @@ -193,12 +195,19 @@ icmp_input(struct pbuf *p, struct netif *inp) ip4_addr_copy(iphdr->dest, *ip4_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); #if CHECKSUM_GEN_ICMP - /* adjust the checksum */ - if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; - } else { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8); + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP) { + /* adjust the checksum */ + if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; + } else { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8); + } } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + iecho->chksum = 0; + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ #else /* CHECKSUM_GEN_ICMP */ iecho->chksum = 0; #endif /* CHECKSUM_GEN_ICMP */ @@ -207,7 +216,9 @@ icmp_input(struct pbuf *p, struct netif *inp) IPH_TTL_SET(iphdr, ICMP_TTL); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + } #endif /* CHECKSUM_GEN_IP */ ICMP_STATS_INC(icmp.xmit); @@ -293,6 +304,7 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) /* we can use the echo header here */ struct icmp_echo_hdr *icmphdr; ip4_addr_t iphdr_src; + struct netif *netif; /* ICMP header + IP header + 8 bytes of data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, @@ -321,18 +333,23 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); - /* calculate checksum */ - icmphdr->chksum = 0; + netif = ip4_route(&iphdr_src); + if (netif != NULL) { + /* calculate checksum */ + icmphdr->chksum = 0; #if CHECKSUM_GEN_ICMP - icmphdr->chksum = inet_chksum(icmphdr, q->len); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP) { + icmphdr->chksum = inet_chksum(icmphdr, q->len); + } #endif - ICMP_STATS_INC(icmp.xmit); - /* increase number of messages attempted to send */ - snmp_inc_icmpoutmsgs(); - /* increase number of destination unreachable messages attempted to send */ - snmp_inc_icmpouttimeexcds(); - ip4_addr_copy(iphdr_src, iphdr->src); - ip4_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP); + ICMP_STATS_INC(icmp.xmit); + /* increase number of messages attempted to send */ + snmp_inc_icmpoutmsgs(); + /* increase number of destination unreachable messages attempted to send */ + snmp_inc_icmpouttimeexcds(); + ip4_addr_copy(iphdr_src, iphdr->src); + ip4_output_if(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP, netif); + } pbuf_free(q); } diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index ebe066d3..c4ca61cd 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -63,8 +63,13 @@ /** Set this to 0 in the rare case of wanting to call an extra function to * generate the IP checksum (in contrast to calculating it on-the-fly). */ #ifndef LWIP_INLINE_IP_CHKSUM +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define LWIP_INLINE_IP_CHKSUM 0 +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ #define LWIP_INLINE_IP_CHKSUM 1 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ #endif + #if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP #define CHECKSUM_GEN_IP_INLINE 1 #else @@ -178,7 +183,7 @@ ip4_route(const ip4_addr_t *dest) if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) || ip4_addr_isany_val(*netif_ip4_addr(netif_default))) { - /* No matching netif found an default netif is not usable. + /* No matching netif found and default netif is not usable. If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); @@ -443,16 +448,18 @@ ip4_input(struct pbuf *p, struct netif *inp) /* verify checksum */ #if CHECKSUM_CHECK_IP - if (inet_chksum(iphdr, iphdr_hlen) != 0) { + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) { + if (inet_chksum(iphdr, iphdr_hlen) != 0) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); - ip4_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.chkerr); - IP_STATS_INC(ip.drop); - snmp_inc_ipinhdrerrors(); - return ERR_OK; + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, + ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); + ip4_debug_print(p); + pbuf_free(p); + IP_STATS_INC(ip.chkerr); + IP_STATS_INC(ip.drop); + snmp_inc_ipinhdrerrors(); + return ERR_OK; + } } #endif @@ -597,7 +604,7 @@ ip4_input(struct pbuf *p, struct netif *inp) /* packet consists of multiple fragments? */ if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ - LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", + LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip4_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip4_reass(p); @@ -889,12 +896,21 @@ err_t ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_add chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); chk_sum = (chk_sum >> 16) + chk_sum; chk_sum = ~chk_sum; - iphdr->_chksum = (u16_t)chk_sum; /* network order */ + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + iphdr->_chksum = (u16_t)chk_sum; /* network order */ + } +#if LWIP_CHECKSUM_CTRL_PER_NETIF + else { + IPH_CHKSUM_SET(iphdr, 0); + } +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ #else /* CHECKSUM_GEN_IP_INLINE */ IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); -#endif + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); + } +#endif /* CHECKSUM_GEN_IP */ #endif /* CHECKSUM_GEN_IP_INLINE */ } else { /* IP header already included in p */ diff --git a/src/core/ipv4/ip_frag.c b/src/core/ipv4/ip_frag.c index 80f5b50d..7e933aca 100644 --- a/src/core/ipv4/ip_frag.c +++ b/src/core/ipv4/ip_frag.c @@ -320,7 +320,7 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) prev->next = ipr->next; } - /* now we can free the ip_reass struct */ + /* now we can free the ip_reassdata struct */ memp_free(MEMP_REASSDATA, ipr); } @@ -494,7 +494,7 @@ ip4_reass(struct pbuf *p) fraghdr = (struct ip_hdr*)p->payload; if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n")); IPFRAG_STATS_INC(ip_frag.err); goto nullreturn; } @@ -511,7 +511,7 @@ ip4_reass(struct pbuf *p) #endif /* IP_REASS_FREE_OLDEST */ { /* No datagram could be freed and still too many pbufs enqueued */ - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); IPFRAG_STATS_INC(ip_frag.memerr); /* @todo: send ICMP time exceeded here? */ @@ -527,7 +527,7 @@ ip4_reass(struct pbuf *p) in the reassembly buffer. If so, we proceed with copying the fragment into the buffer. */ if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", + LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n", ntohs(IPH_ID(fraghdr)))); IPFRAG_STATS_INC(ip_frag.cachehit); break; @@ -563,7 +563,7 @@ ip4_reass(struct pbuf *p) ipr->flags |= IP_REASS_FLAG_LASTFRAG; ipr->datagram_len = offset + len; LWIP_DEBUGF(IP_REASS_DEBUG, - ("ip_reass: last fragment seen, total len %"S16_F"\n", + ("ip4_reass: last fragment seen, total len %"S16_F"\n", ipr->datagram_len)); } /* find the right place to insert this pbuf */ @@ -583,9 +583,11 @@ ip4_reass(struct pbuf *p) IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); IPH_OFFSET_SET(fraghdr, 0); IPH_CHKSUM_SET(fraghdr, 0); - /* @todo: do we need to set calculate the correct checksum? */ + /* @todo: do we need to set/calculate the correct checksum? */ #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); + } #endif /* CHECKSUM_GEN_IP */ p = ipr->p; @@ -625,7 +627,7 @@ ip4_reass(struct pbuf *p) return NULL; nullreturn: - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); + LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n")); IPFRAG_STATS_INC(ip_frag.drop); pbuf_free(p); return NULL; @@ -831,7 +833,9 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) { + IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); + } #endif /* CHECKSUM_GEN_IP */ #if IP_FRAG_USES_STATIC_BUF @@ -841,7 +845,7 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest) /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then - * free it.A PBUF_ROM style pbuf for which pbuf_header + * free it. A PBUF_ROM style pbuf for which pbuf_header * worked would make things simpler. */ header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); diff --git a/src/core/ipv6/icmp6.c b/src/core/ipv6/icmp6.c index 9b6f1e05..d2c40f15 100644 --- a/src/core/ipv6/icmp6.c +++ b/src/core/ipv6/icmp6.c @@ -97,13 +97,15 @@ icmp6_input(struct pbuf *p, struct netif *inp) icmp6hdr = (struct icmp6_hdr *)p->payload; #if CHECKSUM_CHECK_ICMP6 - if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), - ip6_current_dest_addr()) != 0) { - /* Checksum failed */ - pbuf_free(p); - ICMP6_STATS_INC(icmp6.chkerr); - ICMP6_STATS_INC(icmp6.drop); - return; + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { + if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), + ip6_current_dest_addr()) != 0) { + /* Checksum failed */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.chkerr); + ICMP6_STATS_INC(icmp6.drop); + return; + } } #endif /* CHECKSUM_CHECK_ICMP6 */ @@ -180,8 +182,10 @@ icmp6_input(struct pbuf *p, struct netif *inp) ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; #if CHECKSUM_GEN_ICMP6 - ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, - IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { + ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, + IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); + } #endif /* CHECKSUM_GEN_ICMP6 */ /* Send reply. */ @@ -330,8 +334,10 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) /* calculate checksum */ icmp6hdr->chksum = 0; #if CHECKSUM_GEN_ICMP6 - icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, - reply_src, reply_dest); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, + reply_src, reply_dest); + } #endif /* CHECKSUM_GEN_ICMP6 */ ICMP6_STATS_INC(icmp6.xmit); diff --git a/src/core/ipv6/mld6.c b/src/core/ipv6/mld6.c index e7b7daea..66eba712 100644 --- a/src/core/ipv6/mld6.c +++ b/src/core/ipv6/mld6.c @@ -569,8 +569,10 @@ mld6_send(struct mld_group *group, u8_t type) ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); #if CHECKSUM_GEN_ICMP6 - mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, - src_addr, &(group->group_address)); + IF__NETIF_CHECKSUM_ENABLED(group->netif, NETIF_CHECKSUM_GEN_ICMP6) { + mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, + src_addr, &(group->group_address)); + } #endif /* CHECKSUM_GEN_ICMP6 */ /* Add hop-by-hop headers options: router alert with MLD value. */ diff --git a/src/core/ipv6/nd6.c b/src/core/ipv6/nd6.c index f8497f99..5f22a022 100644 --- a/src/core/ipv6/nd6.c +++ b/src/core/ipv6/nd6.c @@ -878,8 +878,10 @@ nd6_send_ns(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags) } #if CHECKSUM_GEN_ICMP6 - ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - target_addr); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + target_addr); + } #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ @@ -954,8 +956,10 @@ nd6_send_na(struct netif * netif, const ip6_addr_t * target_addr, u8_t flags) } #if CHECKSUM_GEN_ICMP6 - na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - dest_addr); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + dest_addr); + } #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ @@ -1023,8 +1027,10 @@ nd6_send_rs(struct netif * netif) } #if CHECKSUM_GEN_ICMP6 - rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, - &multicast_address); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { + rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, + &multicast_address); + } #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ diff --git a/src/core/netif.c b/src/core/netif.c index 0ea74f0c..668196f5 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -205,6 +205,7 @@ netif_add(struct netif *netif, } netif->output_ip6 = netif_null_output_ip6; #endif /* LWIP_IPV6 */ + NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 49615515..d718014a 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -111,9 +111,6 @@ tcp_input(struct pbuf *p, struct netif *inp) #endif /* SO_REUSE */ u8_t hdrlen; err_t err; -#if CHECKSUM_CHECK_TCP - u16_t chksum; -#endif /* CHECKSUM_CHECK_TCP */ LWIP_UNUSED_ARG(inp); @@ -147,15 +144,17 @@ tcp_input(struct pbuf *p, struct netif *inp) } #if CHECKSUM_CHECK_TCP - /* Verify TCP checksum. */ - chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - ip_current_src_addr(), ip_current_dest_addr()); - if (chksum != 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - chksum)); - tcp_debug_print(tcphdr); - TCP_STATS_INC(tcp.chkerr); - goto dropped; + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { + /* Verify TCP checksum. */ + u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + ip_current_src_addr(), ip_current_dest_addr()); + if (chksum != 0) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", + chksum)); + tcp_debug_print(tcphdr); + TCP_STATS_INC(tcp.chkerr); + goto dropped; + } } #endif /* CHECKSUM_CHECK_TCP */ diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 01fbc6a0..567942ed 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -898,6 +898,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) err_t err; struct pbuf *p; u8_t optlen = 0; + struct netif *netif; #if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP struct tcp_hdr *tcphdr; #endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ @@ -928,19 +929,23 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) if (pcb->flags & TF_TIMESTAMP) { tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); } -#endif - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &pcb->local_ip, &pcb->remote_ip); #endif -#if LWIP_NETIF_HWADDRHINT - err = ip_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, - IP_PROTO_TCP, &pcb->addr_hint); -#else /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, - IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ + + netif = ip_route(PCB_ISIPV6(pcb), &pcb->remote_ip, &pcb->local_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } +#endif + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, + pcb->ttl, pcb->tos, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + } pbuf_free(p); if (err != ERR_OK) { @@ -1128,6 +1133,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) err_t err; u16_t len; u32_t *opts; + struct netif *netif; /** @bug Exclude retransmitted segments from this count. */ snmp_inc_tcpoutsegs(); @@ -1184,13 +1190,16 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) pcb->rtime = 0; } - /* If we don't have a local IP address, we get one by - calling ip_route(). */ + netif = ip_route(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + return ERR_RTE; + } + + /* If we don't have a local IP address, we get one from netif */ if (ip_addr_isany(&pcb->local_ip)) { - struct netif *netif; - ip_addr_t *local_ip; - ip_route_get_local_ip(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip, &pcb->local_ip); - if ((netif == NULL) || (local_ip == NULL)) { + ip_addr_t *local_ip = ip_netif_get_local_ip(PCB_ISIPV6(pcb), netif, + &pcb->remote_ip, &pcb->local_ip); + if (local_ip == NULL) { return ERR_RTE; } #if !LWIP_IPV4 || !LWIP_IPV6 @@ -1216,8 +1225,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) seg->p->payload = seg->tcphdr; seg->tcphdr->chksum = 0; +#if CHECKSUM_GEN_TCP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { #if TCP_CHECKSUM_ON_COPY - { u32_t acc; #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK u16_t chksum_slow = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, @@ -1246,22 +1256,18 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) seg->tcphdr->chksum = chksum_slow; } #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ - } #else /* TCP_CHECKSUM_ON_COPY */ -#if CHECKSUM_GEN_TCP - seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, - seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); -#endif /* CHECKSUM_GEN_TCP */ + seg->tcphdr->chksum = ip_chksum_pseudo(seg->p, IP_PROTO_TCP, + seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CHECKSUM_ON_COPY */ +#endif /* CHECKSUM_GEN_TCP */ + } TCP_STATS_INC(tcp.xmit); -#if LWIP_NETIF_HWADDRHINT - err = ip_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, - pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); -#else /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - pcb->tos, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + pcb->tos, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); return err; } @@ -1292,6 +1298,7 @@ tcp_rst(u32_t seqno, u32_t ackno, { struct pbuf *p; struct tcp_hdr *tcphdr; + struct netif *netif; 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")); @@ -1317,12 +1324,17 @@ tcp_rst(u32_t seqno, u32_t ackno, TCP_STATS_INC(tcp.xmit); snmp_inc_tcpoutrsts(); + netif = ip_route(IP_IS_V6(remote_ip), local_ip, remote_ip); + if (netif != NULL) { #if CHECKSUM_GEN_TCP - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - local_ip, remote_ip); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + local_ip, remote_ip); + } #endif - /* Send output with hardcoded TTL/HL since we have no access to the pcb */ - ip_output(IP_IS_V6(remote_ip), p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); + /* Send output with hardcoded TTL/HL since we have no access to the pcb */ + ip_output_if(IP_IS_V6(remote_ip), p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP, netif); + } pbuf_free(p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); } @@ -1469,9 +1481,7 @@ tcp_keepalive(struct tcp_pcb *pcb) { err_t err; struct pbuf *p; -#if CHECKSUM_GEN_TCP - struct tcp_hdr *tcphdr; -#endif /* CHECKSUM_GEN_TCP */ + struct netif *netif; LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip); @@ -1486,23 +1496,25 @@ tcp_keepalive(struct tcp_pcb *pcb) ("tcp_keepalive: could not allocate memory for pbuf\n")); return ERR_MEM; } + netif = ip_route(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { #if CHECKSUM_GEN_TCP - tcphdr = (struct tcp_hdr *)p->payload; - - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &pcb->local_ip, &pcb->remote_ip); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + struct tcp_hdr *tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } #endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - err = ip_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, - pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint); -#else /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ + TCP_STATS_INC(tcp.xmit); + /* Send output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_TCP, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + } pbuf_free(p); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F" err %d.\n", @@ -1528,6 +1540,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) struct tcp_seg *seg; u16_t len; u8_t is_fin; + struct netif *netif; LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip); @@ -1571,19 +1584,23 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); } + netif = ip_route(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip); + if (netif == NULL) { + err = ERR_RTE; + } else { #if CHECKSUM_GEN_TCP - tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, - &pcb->local_ip, &pcb->remote_ip); + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) { + tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, + &pcb->local_ip, &pcb->remote_ip); + } #endif - TCP_STATS_INC(tcp.xmit); + TCP_STATS_INC(tcp.xmit); - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - err = ip_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, - 0, IP_PROTO_TCP, &pcb->addr_hint); -#else /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ + /* Send output to IP */ + NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); + err = ip_output_if(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, + 0, IP_PROTO_TCP, netif); + } pbuf_free(p); diff --git a/src/core/udp.c b/src/core/udp.c index 6215c314..c18255af 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -325,34 +325,36 @@ udp_input(struct pbuf *p, struct netif *inp) if (for_us) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if CHECKSUM_CHECK_UDP + IF__NETIF_CHECKSUM_ENABLED(inp, CHECKSUM_CHECK_UDP) { #if LWIP_UDPLITE - if (ip_current_header_proto() == IP_PROTO_UDPLITE) { - /* Do the UDP Lite checksum */ - u16_t chklen = ntohs(udphdr->len); - if (chklen < sizeof(struct udp_hdr)) { - if (chklen == 0) { - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet (See RFC 3828 chap. 3.1) */ - chklen = p->tot_len; - } else { - /* At least the UDP-Lite header must be covered by the - checksum! (Again, see RFC 3828 chap. 3.1) */ + if (ip_current_header_proto() == IP_PROTO_UDPLITE) { + /* Do the UDP Lite checksum */ + u16_t chklen = ntohs(udphdr->len); + if (chklen < sizeof(struct udp_hdr)) { + if (chklen == 0) { + /* For UDP-Lite, checksum length of 0 means checksum + over the complete packet (See RFC 3828 chap. 3.1) */ + chklen = p->tot_len; + } else { + /* At least the UDP-Lite header must be covered by the + checksum! (Again, see RFC 3828 chap. 3.1) */ + goto chkerr; + } + } + if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, + p->tot_len, chklen, + ip_current_src_addr(), ip_current_dest_addr()) != 0) { goto chkerr; } - } - if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, - p->tot_len, chklen, - ip_current_src_addr(), ip_current_dest_addr()) != 0) { - goto chkerr; - } - } else + } else #endif /* LWIP_UDPLITE */ - { - if (udphdr->chksum != 0) { - if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, - ip_current_src_addr(), - ip_current_dest_addr()) != 0) { - goto chkerr; + { + if (udphdr->chksum != 0) { + if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, + ip_current_src_addr(), + ip_current_dest_addr()) != 0) { + goto chkerr; + } } } } @@ -804,24 +806,26 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d udphdr->len = htons(chklen_hdr); /* calculate checksum */ #if CHECKSUM_GEN_UDP + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { #if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - chklen = UDP_HLEN; - } + if (have_chksum) { + chklen = UDP_HLEN; + } #endif /* LWIP_CHECKSUM_ON_COPY */ - udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, - q->tot_len, chklen, src_ip, dst_ip); + udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, + q->tot_len, chklen, src_ip, dst_ip); #if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - acc = udphdr->chksum + (u16_t)~(chksum); - udphdr->chksum = FOLD_U32T(acc); - } + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } #endif /* LWIP_CHECKSUM_ON_COPY */ - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udphdr->chksum == 0x0000) { + udphdr->chksum = 0xffff; + } } #endif /* CHECKSUM_GEN_UDP */ @@ -833,28 +837,30 @@ udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *d udphdr->len = htons(q->tot_len); /* calculate checksum */ #if CHECKSUM_GEN_UDP - /* Checksum is mandatory over IPv6. */ - if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - u16_t udpchksum; + IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { + /* Checksum is mandatory over IPv6. */ + if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { + u16_t udpchksum; #if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, - q->tot_len, UDP_HLEN, src_ip, dst_ip); - acc = udpchksum + (u16_t)~(chksum); - udpchksum = FOLD_U32T(acc); - } else + if (have_chksum) { + u32_t acc; + udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, + q->tot_len, UDP_HLEN, src_ip, dst_ip); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else #endif /* LWIP_CHECKSUM_ON_COPY */ - { - udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, - src_ip, dst_ip); - } + { + udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, + src_ip, dst_ip); + } - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udpchksum == 0x0000) { - udpchksum = 0xffff; + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; } - udphdr->chksum = udpchksum; } #endif /* CHECKSUM_GEN_UDP */ ip_proto = IP_PROTO_UDP; diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index 188b29ef..6c01faf0 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -98,6 +98,21 @@ extern "C" { * Set by the netif driver in its init function. */ #define NETIF_FLAG_MLD6 0x40U +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_CHECKSUM_GEN_IP 0x0001 +#define NETIF_CHECKSUM_GEN_UDP 0x0002 +#define NETIF_CHECKSUM_GEN_TCP 0x0004 +#define NETIF_CHECKSUM_GEN_ICMP 0x0008 +#define NETIF_CHECKSUM_GEN_ICMP6 0x0010 +#define NETIF_CHECKSUM_CHECK_IP 0x0100 +#define NETIF_CHECKSUM_CHECK_UDP 0x0200 +#define NETIF_CHECKSUM_CHECK_TCP 0x0400 +#define NETIF_CHECKSUM_CHECK_ICMP 0x0800 +#define NETIF_CHECKSUM_CHECK_ICMP6 0x1000 +#define NETIF_CHECKSUM_ENABLE_ALL 0xFFFF +#define NETIF_CHECKSUM_DISABLE_ALL 0x0000 +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + struct netif; /** Function prototype for netif init functions. Set up flags and output/linkoutput @@ -240,6 +255,9 @@ struct netif { /* the hostname for this netif, NULL is a valid value */ char* hostname; #endif /* LWIP_NETIF_HOSTNAME */ +#if LWIP_CHECKSUM_CTRL_PER_NETIF + u16_t chksum_flags; +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/ /** maximum transfer unit (in bytes) */ u16_t mtu; /** number of bytes used in hwaddr */ @@ -292,12 +310,21 @@ struct netif { #endif /* ENABLE_LOOPBACK */ }; +#if LWIP_CHECKSUM_CTRL_PER_NETIF +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ + (netif)->chksum_flags = chksumflags; } while(0) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) if (((netif) == NULL) || (((netif)->chksum_flags & (chksumflag)) != 0)) +#else /* LWIP_CHECKSUM_CTRL_PER_NETIF */ +#define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) +#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag) +#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */ + #if LWIP_SNMP -#define NETIF_INIT_SNMP(netif, type, speed) \ +#define NETIF_INIT_SNMP(netif, type, speed) do { \ /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ - (netif)->link_type = (type); \ + (netif)->link_type = (type); \ /* your link speed here (units: bits per second) */ \ - (netif)->link_speed = (speed); \ + (netif)->link_speed = (speed);\ (netif)->ts = 0; \ (netif)->ifinoctets = 0; \ (netif)->ifinucastpkts = 0; \ @@ -306,7 +333,7 @@ struct netif { (netif)->ifoutoctets = 0; \ (netif)->ifoutucastpkts = 0; \ (netif)->ifoutnucastpkts = 0; \ - (netif)->ifoutdiscards = 0 + (netif)->ifoutdiscards = 0; } while(0) #else /* LWIP_SNMP */ #define NETIF_INIT_SNMP(netif, type, speed) #endif /* LWIP_SNMP */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 4e1588a1..4dbf143f 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -2443,6 +2443,16 @@ ---------- Checksum options ---------- -------------------------------------- */ + +/** + * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled + * per netif. + * ATTENTION: if enabled, the CHECKSUM_GEN_* and CHECKSUM_CHECK_* defines must be enabled! + */ +#ifndef LWIP_CHECKSUM_CTRL_PER_NETIF +#define LWIP_CHECKSUM_CTRL_PER_NETIF 0 +#endif + /** * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. */