X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_ECN.c;h=ada9911118e9a7ec2ee841db8b3f250e48bfb71c;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=120109cd294db678e9e47014075d9e69fe8cc1ae;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 120109cd2..ada991111 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -52,44 +52,41 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) static inline int set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) { - struct tcphdr _tcph, *th; + struct tcphdr _tcph, *tcph; u_int16_t diffs[2]; /* Not enought header? */ - th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, - sizeof(_tcph), &_tcph); - if (th == NULL) + tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, + sizeof(_tcph), &_tcph); + if (!tcph) return 0; - diffs[0] = ((u_int16_t *)th)[6]; - if (einfo->operation & IPT_ECN_OP_SET_ECE) - th->ece = einfo->proto.tcp.ece; + if (!(einfo->operation & IPT_ECN_OP_SET_ECE + || tcph->ece == einfo->proto.tcp.ece) + && (!(einfo->operation & IPT_ECN_OP_SET_CWR + || tcph->cwr == einfo->proto.tcp.cwr))) + return 1; + + if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; + diffs[0] = ((u_int16_t *)tcph)[6]; + if (einfo->operation & IPT_ECN_OP_SET_ECE) + tcph->ece = einfo->proto.tcp.ece; if (einfo->operation & IPT_ECN_OP_SET_CWR) - th->cwr = einfo->proto.tcp.cwr; - diffs[1] = ((u_int16_t *)&th)[6]; - - /* Only mangle if it's changed. */ - if (diffs[0] != diffs[1]) { - diffs[0] = diffs[0] ^ 0xFFFF; - if (!skb_ip_make_writable(pskb, - (*pskb)->nh.iph->ihl*4+sizeof(_tcph))) + tcph->cwr = einfo->proto.tcp.cwr; + diffs[1] = ((u_int16_t *)tcph)[6]; + diffs[0] = diffs[0] ^ 0xFFFF; + + if ((*pskb)->ip_summed != CHECKSUM_HW) + tcph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + tcph->check^0xFFFF)); + else + if (skb_checksum_help(*pskb, inward)) return 0; - - if (th != &_tcph) - memcpy(&_tcph, th, sizeof(_tcph)); - - 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; - } + (*pskb)->nfcache |= NFC_ALTERED; return 1; } @@ -148,7 +145,7 @@ checkentry(const char *tablename, } if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) - && e->ip.proto != IPPROTO_TCP) { + && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) { printk(KERN_WARNING "ECN: cannot use TCP operations on a " "non-tcp rule\n"); return 0;