/* Return 0 if there was an error. */
static inline int
-set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
+set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
{
struct tcphdr tcph;
u_int16_t diffs[2];
if (!skb_ip_make_writable(pskb,
(*pskb)->nh.iph->ihl*4+sizeof(tcph)))
return 0;
- tcph.check = csum_fold(csum_partial((char *)diffs,
- sizeof(diffs),
- tcph.check^0xFFFF));
+ if ((*pskb)->ip_summed != CHECKSUM_HW)
+ tcph.check = csum_fold(csum_partial((char *)diffs,
+ sizeof(diffs),
+ tcph.check^0xFFFF));
memcpy((*pskb)->data + (*pskb)->nh.iph->ihl*4,
&tcph, sizeof(tcph));
+ if ((*pskb)->ip_summed == CHECKSUM_HW)
+ if (skb_checksum_help(pskb, inward))
+ return 0;
(*pskb)->nfcache |= NFC_ALTERED;
}
return 1;
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
&& (*pskb)->nh.iph->protocol == IPPROTO_TCP)
- if (!set_ect_tcp(pskb, einfo))
+ if (!set_ect_tcp(pskb, einfo, (out == NULL)))
return NF_DROP;
return IPT_CONTINUE;