aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_fw.c')
-rw-r--r--net/sched/cls_fw.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index e6973d9b686d..e54acc6bcccd 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -50,6 +50,7 @@
50struct fw_head 50struct fw_head
51{ 51{
52 struct fw_filter *ht[HTSIZE]; 52 struct fw_filter *ht[HTSIZE];
53 u32 mask;
53}; 54};
54 55
55struct fw_filter 56struct fw_filter
@@ -101,7 +102,7 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
101 struct fw_filter *f; 102 struct fw_filter *f;
102 int r; 103 int r;
103#ifdef CONFIG_NETFILTER 104#ifdef CONFIG_NETFILTER
104 u32 id = skb->nfmark; 105 u32 id = skb->nfmark & head->mask;
105#else 106#else
106 u32 id = 0; 107 u32 id = 0;
107#endif 108#endif
@@ -209,7 +210,9 @@ static int
209fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, 210fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
210 struct rtattr **tb, struct rtattr **tca, unsigned long base) 211 struct rtattr **tb, struct rtattr **tca, unsigned long base)
211{ 212{
213 struct fw_head *head = (struct fw_head *)tp->root;
212 struct tcf_exts e; 214 struct tcf_exts e;
215 u32 mask;
213 int err; 216 int err;
214 217
215 err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map); 218 err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map);
@@ -232,6 +235,15 @@ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
232 } 235 }
233#endif /* CONFIG_NET_CLS_IND */ 236#endif /* CONFIG_NET_CLS_IND */
234 237
238 if (tb[TCA_FW_MASK-1]) {
239 if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
240 goto errout;
241 mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
242 if (mask != head->mask)
243 goto errout;
244 } else if (head->mask != 0xFFFFFFFF)
245 goto errout;
246
235 tcf_exts_change(tp, &f->exts, &e); 247 tcf_exts_change(tp, &f->exts, &e);
236 248
237 return 0; 249 return 0;
@@ -267,9 +279,17 @@ static int fw_change(struct tcf_proto *tp, unsigned long base,
267 return -EINVAL; 279 return -EINVAL;
268 280
269 if (head == NULL) { 281 if (head == NULL) {
282 u32 mask = 0xFFFFFFFF;
283 if (tb[TCA_FW_MASK-1]) {
284 if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
285 return -EINVAL;
286 mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
287 }
288
270 head = kzalloc(sizeof(struct fw_head), GFP_KERNEL); 289 head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
271 if (head == NULL) 290 if (head == NULL)
272 return -ENOBUFS; 291 return -ENOBUFS;
292 head->mask = mask;
273 293
274 tcf_tree_lock(tp); 294 tcf_tree_lock(tp);
275 tp->root = head; 295 tp->root = head;
@@ -330,6 +350,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
330static int fw_dump(struct tcf_proto *tp, unsigned long fh, 350static int fw_dump(struct tcf_proto *tp, unsigned long fh,
331 struct sk_buff *skb, struct tcmsg *t) 351 struct sk_buff *skb, struct tcmsg *t)
332{ 352{
353 struct fw_head *head = (struct fw_head *)tp->root;
333 struct fw_filter *f = (struct fw_filter*)fh; 354 struct fw_filter *f = (struct fw_filter*)fh;
334 unsigned char *b = skb->tail; 355 unsigned char *b = skb->tail;
335 struct rtattr *rta; 356 struct rtattr *rta;
@@ -351,6 +372,8 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh,
351 if (strlen(f->indev)) 372 if (strlen(f->indev))
352 RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev); 373 RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev);
353#endif /* CONFIG_NET_CLS_IND */ 374#endif /* CONFIG_NET_CLS_IND */
375 if (head->mask != 0xFFFFFFFF)
376 RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask);
354 377
355 if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) 378 if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)
356 goto rtattr_failure; 379 goto rtattr_failure;