--- zzzz-none-000/linux-3.10.107/include/net/inet_ecn.h 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/include/net/inet_ecn.h 2021-02-04 17:41:59.000000000 +0000 @@ -111,17 +111,31 @@ struct ipv6hdr; -static inline int IP6_ECN_set_ce(struct ipv6hdr *iph) +/* Note: + * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE, + * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE + * In IPv6 case, no checksum compensates the change in IPv6 header, + * so we have to update skb->csum. + */ +static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph) { + __be32 from, to; + if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) return 0; - *(__be32*)iph |= htonl(INET_ECN_CE << 20); + + from = *(__be32 *)iph; + to = from | htonl(INET_ECN_CE << 20); + net_hdr_word(iph) |= htonl(INET_ECN_CE << 20); + + if (skb->ip_summed == CHECKSUM_COMPLETE) + skb->csum = csum_add(csum_sub(skb->csum, from), to); return 1; } static inline void IP6_ECN_clear(struct ipv6hdr *iph) { - *(__be32*)iph &= ~htonl(INET_ECN_MASK << 20); + net_hdr_word(iph) &= ~htonl(INET_ECN_MASK << 20); } static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner) @@ -134,13 +148,15 @@ { switch (skb->protocol) { case cpu_to_be16(ETH_P_IP): - if (skb->network_header + sizeof(struct iphdr) <= skb->tail) + if (skb_network_header(skb) + sizeof(struct iphdr) <= + skb_tail_pointer(skb)) return IP_ECN_set_ce(ip_hdr(skb)); break; case cpu_to_be16(ETH_P_IPV6): - if (skb->network_header + sizeof(struct ipv6hdr) <= skb->tail) - return IP6_ECN_set_ce(ipv6_hdr(skb)); + if (skb_network_header(skb) + sizeof(struct ipv6hdr) <= + skb_tail_pointer(skb)) + return IP6_ECN_set_ce(skb, ipv6_hdr(skb)); break; } @@ -148,7 +164,7 @@ } /* - * RFC 6080 4.2 + * RFC 6040 4.2 * To decapsulate the inner header at the tunnel egress, a compliant * tunnel egress MUST set the outgoing ECN field to the codepoint at the * intersection of the appropriate arriving inner header (row) and outer