diff options
Diffstat (limited to 'net/sched/cls_u32.c')
| -rw-r--r-- | net/sched/cls_u32.c | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 07372f60bee3..b0c2a82178af 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/slab.h> | ||
| 34 | #include <linux/types.h> | 35 | #include <linux/types.h> |
| 35 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
| 36 | #include <linux/string.h> | 37 | #include <linux/string.h> |
| @@ -97,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re | |||
| 97 | { | 98 | { |
| 98 | struct { | 99 | struct { |
| 99 | struct tc_u_knode *knode; | 100 | struct tc_u_knode *knode; |
| 100 | u8 *ptr; | 101 | unsigned int off; |
| 101 | } stack[TC_U32_MAXDEPTH]; | 102 | } stack[TC_U32_MAXDEPTH]; |
| 102 | 103 | ||
| 103 | struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; | 104 | struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; |
| 104 | u8 *ptr = skb_network_header(skb); | 105 | unsigned int off = skb_network_offset(skb); |
| 105 | struct tc_u_knode *n; | 106 | struct tc_u_knode *n; |
| 106 | int sdepth = 0; | 107 | int sdepth = 0; |
| 107 | int off2 = 0; | 108 | int off2 = 0; |
| @@ -133,8 +134,16 @@ next_knode: | |||
| 133 | #endif | 134 | #endif |
| 134 | 135 | ||
| 135 | for (i = n->sel.nkeys; i>0; i--, key++) { | 136 | for (i = n->sel.nkeys; i>0; i--, key++) { |
| 137 | int toff = off + key->off + (off2 & key->offmask); | ||
| 138 | __be32 *data, _data; | ||
| 136 | 139 | ||
| 137 | if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { | 140 | if (skb_headroom(skb) + toff > INT_MAX) |
| 141 | goto out; | ||
| 142 | |||
| 143 | data = skb_header_pointer(skb, toff, 4, &_data); | ||
| 144 | if (!data) | ||
| 145 | goto out; | ||
| 146 | if ((*data ^ key->val) & key->mask) { | ||
| 138 | n = n->next; | 147 | n = n->next; |
| 139 | goto next_knode; | 148 | goto next_knode; |
| 140 | } | 149 | } |
| @@ -173,29 +182,45 @@ check_terminal: | |||
| 173 | if (sdepth >= TC_U32_MAXDEPTH) | 182 | if (sdepth >= TC_U32_MAXDEPTH) |
| 174 | goto deadloop; | 183 | goto deadloop; |
| 175 | stack[sdepth].knode = n; | 184 | stack[sdepth].knode = n; |
| 176 | stack[sdepth].ptr = ptr; | 185 | stack[sdepth].off = off; |
| 177 | sdepth++; | 186 | sdepth++; |
| 178 | 187 | ||
| 179 | ht = n->ht_down; | 188 | ht = n->ht_down; |
| 180 | sel = 0; | 189 | sel = 0; |
| 181 | if (ht->divisor) | 190 | if (ht->divisor) { |
| 182 | sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift); | 191 | __be32 *data, _data; |
| 183 | 192 | ||
| 193 | data = skb_header_pointer(skb, off + n->sel.hoff, 4, | ||
| 194 | &_data); | ||
| 195 | if (!data) | ||
| 196 | goto out; | ||
| 197 | sel = ht->divisor & u32_hash_fold(*data, &n->sel, | ||
| 198 | n->fshift); | ||
| 199 | } | ||
| 184 | if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) | 200 | if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) |
| 185 | goto next_ht; | 201 | goto next_ht; |
| 186 | 202 | ||
| 187 | if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { | 203 | if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { |
| 188 | off2 = n->sel.off + 3; | 204 | off2 = n->sel.off + 3; |
| 189 | if (n->sel.flags&TC_U32_VAROFFSET) | 205 | if (n->sel.flags & TC_U32_VAROFFSET) { |
| 190 | off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift; | 206 | __be16 *data, _data; |
| 207 | |||
| 208 | data = skb_header_pointer(skb, | ||
| 209 | off + n->sel.offoff, | ||
| 210 | 2, &_data); | ||
| 211 | if (!data) | ||
| 212 | goto out; | ||
| 213 | off2 += ntohs(n->sel.offmask & *data) >> | ||
| 214 | n->sel.offshift; | ||
| 215 | } | ||
| 191 | off2 &= ~3; | 216 | off2 &= ~3; |
| 192 | } | 217 | } |
| 193 | if (n->sel.flags&TC_U32_EAT) { | 218 | if (n->sel.flags&TC_U32_EAT) { |
| 194 | ptr += off2; | 219 | off += off2; |
| 195 | off2 = 0; | 220 | off2 = 0; |
| 196 | } | 221 | } |
| 197 | 222 | ||
| 198 | if (ptr < skb_tail_pointer(skb)) | 223 | if (off < skb->len) |
| 199 | goto next_ht; | 224 | goto next_ht; |
| 200 | } | 225 | } |
| 201 | 226 | ||
| @@ -203,14 +228,15 @@ check_terminal: | |||
| 203 | if (sdepth--) { | 228 | if (sdepth--) { |
| 204 | n = stack[sdepth].knode; | 229 | n = stack[sdepth].knode; |
| 205 | ht = n->ht_up; | 230 | ht = n->ht_up; |
| 206 | ptr = stack[sdepth].ptr; | 231 | off = stack[sdepth].off; |
| 207 | goto check_terminal; | 232 | goto check_terminal; |
| 208 | } | 233 | } |
| 234 | out: | ||
| 209 | return -1; | 235 | return -1; |
| 210 | 236 | ||
| 211 | deadloop: | 237 | deadloop: |
| 212 | if (net_ratelimit()) | 238 | if (net_ratelimit()) |
| 213 | printk("cls_u32: dead loop\n"); | 239 | printk(KERN_WARNING "cls_u32: dead loop\n"); |
| 214 | return -1; | 240 | return -1; |
| 215 | } | 241 | } |
| 216 | 242 | ||
| @@ -767,15 +793,15 @@ static struct tcf_proto_ops cls_u32_ops __read_mostly = { | |||
| 767 | 793 | ||
| 768 | static int __init init_u32(void) | 794 | static int __init init_u32(void) |
| 769 | { | 795 | { |
| 770 | printk("u32 classifier\n"); | 796 | pr_info("u32 classifier\n"); |
| 771 | #ifdef CONFIG_CLS_U32_PERF | 797 | #ifdef CONFIG_CLS_U32_PERF |
| 772 | printk(" Performance counters on\n"); | 798 | pr_info(" Performance counters on\n"); |
| 773 | #endif | 799 | #endif |
| 774 | #ifdef CONFIG_NET_CLS_IND | 800 | #ifdef CONFIG_NET_CLS_IND |
| 775 | printk(" input device check on \n"); | 801 | pr_info(" input device check on\n"); |
| 776 | #endif | 802 | #endif |
| 777 | #ifdef CONFIG_NET_CLS_ACT | 803 | #ifdef CONFIG_NET_CLS_ACT |
| 778 | printk(" Actions configured \n"); | 804 | pr_info(" Actions configured\n"); |
| 779 | #endif | 805 | #endif |
| 780 | return register_tcf_proto_ops(&cls_u32_ops); | 806 | return register_tcf_proto_ops(&cls_u32_ops); |
| 781 | } | 807 | } |
