Commit 6a80208e authored by Rusty Russell's avatar Rusty Russell Committed by Linus Torvalds

[PATCH] More ECN Fixes: make writable before writing

Patrick McHardy spotted this, on top of previous fix.  I neatened it.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 03b6d0ef
...@@ -52,44 +52,41 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) ...@@ -52,44 +52,41 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
static inline int static inline int
set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) 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]; u_int16_t diffs[2];
/* Not enought header? */ /* Not enought header? */
th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
sizeof(_tcph), &_tcph); sizeof(_tcph), &_tcph);
if (th == NULL) if (!tcph)
return 0; return 0;
diffs[0] = ((u_int16_t *)th)[6]; if (!(einfo->operation & IPT_ECN_OP_SET_ECE
if (einfo->operation & IPT_ECN_OP_SET_ECE) || tcph->ece == einfo->proto.tcp.ece)
th->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) if (einfo->operation & IPT_ECN_OP_SET_CWR)
th->cwr = einfo->proto.tcp.cwr; tcph->cwr = einfo->proto.tcp.cwr;
diffs[1] = ((u_int16_t *)th)[6]; diffs[1] = ((u_int16_t *)tcph)[6];
diffs[0] = diffs[0] ^ 0xFFFF;
/* Only mangle if it's changed. */
if (diffs[0] != diffs[1]) { if ((*pskb)->ip_summed != CHECKSUM_HW)
diffs[0] = diffs[0] ^ 0xFFFF; tcph->check = csum_fold(csum_partial((char *)diffs,
if (!skb_ip_make_writable(pskb, sizeof(diffs),
(*pskb)->nh.iph->ihl*4+sizeof(_tcph))) tcph->check^0xFFFF));
else
if (skb_checksum_help(*pskb, inward))
return 0; return 0;
(*pskb)->nfcache |= NFC_ALTERED;
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;
}
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment