diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-06-05 07:32:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-06-05 07:32:21 -0700 |
commit | ed7dc1dfbcef301407a1e3138a49dc94e5a19d0a (patch) | |
tree | 2aef7400d404774f0f8a30b6eefb0690a09ec24c /net/sched/cls_u32.c | |
parent | 7926e0bfbbc5ff81ddad0fda831eef7060e40997 (diff) | |
parent | ca7335948e294faf8adf65f2c95ca18ea78540db (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (30 commits)
X25: remove duplicated #include
tcp: use correct net ns in cookie_v4_check()
rps: tcp: fix rps_sock_flow_table table updates
ppp_generic: fix multilink fragment sizes
syncookies: remove Kconfig text line about disabled-by-default
ixgbe: only check pfc bits in hang logic if pfc is enabled
net: check for refcount if pop a stacked dst_entry
ixgbe: return IXGBE_ERR_RAR_INDEX when out of range
act_pedit: access skb->data safely
sfc: Store port number in net_device::dev_id
epic100: Test __BIG_ENDIAN instead of (non-existent) CONFIG_BIG_ENDIAN
tehuti: return -EFAULT on copy_to_user errors
isdn/kcapi: return -EFAULT on copy_from_user errors
e1000e: change logical negate to bitwise
sfc: Get port number from CS_PORT_NUM, not PCI function number
cls_u32: use skb_header_pointer() to dereference data safely
TCP: tcp_hybla: Fix integer overflow in slow start increment
act_nat: fix the wrong checksum when addr isn't in old_addr/mask
net/fec: fix pm to survive to suspend/resume
korina: count RX DMA OVR as rx_fifo_error
...
Diffstat (limited to 'net/sched/cls_u32.c')
-rw-r--r-- | net/sched/cls_u32.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 96275422c619..4f522143811e 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -98,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re { struct { struct tc_u_knode *knode; - u8 *ptr; + unsigned int off; } stack[TC_U32_MAXDEPTH]; struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; - u8 *ptr = skb_network_header(skb); + unsigned int off = skb_network_offset(skb); struct tc_u_knode *n; int sdepth = 0; int off2 = 0; @@ -134,8 +134,14 @@ next_knode: #endif for (i = n->sel.nkeys; i>0; i--, key++) { - - if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { + unsigned int toff; + __be32 *data, _data; + + toff = off + key->off + (off2 & key->offmask); + data = skb_header_pointer(skb, toff, 4, &_data); + if (!data) + goto out; + if ((*data ^ key->val) & key->mask) { n = n->next; goto next_knode; } @@ -174,29 +180,45 @@ check_terminal: if (sdepth >= TC_U32_MAXDEPTH) goto deadloop; stack[sdepth].knode = n; - stack[sdepth].ptr = ptr; + stack[sdepth].off = off; sdepth++; ht = n->ht_down; sel = 0; - if (ht->divisor) - sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift); - + if (ht->divisor) { + __be32 *data, _data; + + data = skb_header_pointer(skb, off + n->sel.hoff, 4, + &_data); + if (!data) + goto out; + sel = ht->divisor & u32_hash_fold(*data, &n->sel, + n->fshift); + } if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) goto next_ht; if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { off2 = n->sel.off + 3; - if (n->sel.flags&TC_U32_VAROFFSET) - off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift; + if (n->sel.flags & TC_U32_VAROFFSET) { + __be16 *data, _data; + + data = skb_header_pointer(skb, + off + n->sel.offoff, + 2, &_data); + if (!data) + goto out; + off2 += ntohs(n->sel.offmask & *data) >> + n->sel.offshift; + } off2 &= ~3; } if (n->sel.flags&TC_U32_EAT) { - ptr += off2; + off += off2; off2 = 0; } - if (ptr < skb_tail_pointer(skb)) + if (off < skb->len) goto next_ht; } @@ -204,9 +226,10 @@ check_terminal: if (sdepth--) { n = stack[sdepth].knode; ht = n->ht_up; - ptr = stack[sdepth].ptr; + off = stack[sdepth].off; goto check_terminal; } +out: return -1; deadloop: |