X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_ECN.c;h=706445426a6dfc4096d97e76d33cfe27a74ea665;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=f659ec3c92783047bb72ecea29807dce3aea5760;hpb=433e2af4175021d339b067f6e7ee0a4e4c4f7e2d;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index f659ec3c9..706445426 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -31,7 +31,7 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { u_int16_t diffs[2]; - if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) + if (!skb_make_writable(pskb, sizeof(struct iphdr))) return 0; diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF; @@ -43,7 +43,6 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) sizeof(diffs), (*pskb)->nh.iph->check ^0xFFFF)); - (*pskb)->nfcache |= NFC_ALTERED; } return 1; } @@ -52,44 +51,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 (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))) - return 0; + if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; - 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; - } + if ((*pskb)->ip_summed == CHECKSUM_HW && + skb_checksum_help(*pskb, inward)) + return 0; + + 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) + tcph->cwr = einfo->proto.tcp.cwr; + diffs[1] = ((u_int16_t *)tcph)[6]; + diffs[0] = diffs[0] ^ 0xFFFF; + + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) + tcph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + tcph->check^0xFFFF)); return 1; } @@ -117,12 +113,13 @@ target(struct sk_buff **pskb, static int checkentry(const char *tablename, - const struct ipt_entry *e, + const void *e_void, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) { const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; + const struct ipt_entry *e = e_void; if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) { printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n", @@ -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;