Import 2.2.5pre2
[davej-history.git] / net / sched / cls_fw.c
blob268ea9e8ccaa7fafcfee09f46385fdb7de3dd958
1 /*
2 * net/sched/cls_fw.c Classifier mapping ipchains' fwmark to traffic class.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 #include <linux/config.h>
13 #include <linux/module.h>
14 #include <asm/uaccess.h>
15 #include <asm/system.h>
16 #include <asm/bitops.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/socket.h>
23 #include <linux/sockios.h>
24 #include <linux/in.h>
25 #include <linux/errno.h>
26 #include <linux/interrupt.h>
27 #include <linux/if_ether.h>
28 #include <linux/inet.h>
29 #include <linux/netdevice.h>
30 #include <linux/etherdevice.h>
31 #include <linux/notifier.h>
32 #include <net/ip.h>
33 #include <net/route.h>
34 #include <linux/skbuff.h>
35 #include <net/sock.h>
36 #include <net/pkt_sched.h>
38 struct fw_head
40 struct fw_filter *ht[256];
43 struct fw_filter
45 struct fw_filter *next;
46 u32 id;
47 struct tcf_result res;
48 #ifdef CONFIG_NET_CLS_POLICE
49 struct tcf_police *police;
50 #endif
53 static __inline__ int fw_hash(u32 handle)
55 return handle&0xFF;
58 static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
59 struct tcf_result *res)
61 struct fw_head *head = (struct fw_head*)tp->root;
62 struct fw_filter *f;
63 #ifdef CONFIG_IP_FIREWALL
64 u32 id = skb->fwmark;
65 #else
66 u32 id = 0;
67 #endif
69 if (head == NULL)
70 goto old_method;
72 for (f=head->ht[fw_hash(id)]; f; f=f->next) {
73 if (f->id == id) {
74 *res = f->res;
75 #ifdef CONFIG_NET_CLS_POLICE
76 if (f->police)
77 return tcf_police(skb, f->police);
78 #endif
79 return 0;
82 return -1;
84 old_method:
85 if (id && (TC_H_MAJ(id) == 0 ||
86 !(TC_H_MAJ(id^tp->q->handle)))) {
87 res->classid = id;
88 res->class = 0;
89 return 0;
91 return -1;
94 static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
96 struct fw_head *head = (struct fw_head*)tp->root;
97 struct fw_filter *f;
99 if (head == NULL)
100 return 0;
102 for (f=head->ht[fw_hash(handle)]; f; f=f->next) {
103 if (f->id == handle)
104 return (unsigned long)f;
106 return 0;
109 static void fw_put(struct tcf_proto *tp, unsigned long f)
113 static int fw_init(struct tcf_proto *tp)
115 MOD_INC_USE_COUNT;
116 return 0;
119 static void fw_destroy(struct tcf_proto *tp)
121 struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
122 struct fw_filter *f;
123 int h;
125 if (head == NULL) {
126 MOD_DEC_USE_COUNT;
127 return;
130 for (h=0; h<256; h++) {
131 while ((f=head->ht[h]) != NULL) {
132 unsigned long cl;
133 head->ht[h] = f->next;
135 if ((cl = cls_set_class(&f->res.class, 0)) != 0)
136 tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
137 #ifdef CONFIG_NET_CLS_POLICE
138 tcf_police_release(f->police);
139 #endif
140 kfree(f);
143 kfree(head);
144 MOD_DEC_USE_COUNT;
147 static int fw_delete(struct tcf_proto *tp, unsigned long arg)
149 struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
150 struct fw_filter *f = (struct fw_filter*)arg;
151 struct fw_filter **fp;
153 if (head == NULL || f == NULL)
154 return -EINVAL;
156 for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {
157 if (*fp == f) {
158 unsigned long cl;
160 *fp = f->next;
161 synchronize_bh();
163 if ((cl = cls_set_class(&f->res.class, 0)) != 0)
164 tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
165 #ifdef CONFIG_NET_CLS_POLICE
166 tcf_police_release(f->police);
167 #endif
168 kfree(f);
169 return 0;
172 return -EINVAL;
175 static int fw_change(struct tcf_proto *tp, unsigned long base,
176 u32 handle,
177 struct rtattr **tca,
178 unsigned long *arg)
180 struct fw_head *head = (struct fw_head*)tp->root;
181 struct fw_filter *f;
182 struct rtattr *opt = tca[TCA_OPTIONS-1];
183 struct rtattr *tb[TCA_FW_MAX];
184 int err;
186 if (!opt)
187 return handle ? -EINVAL : 0;
189 if (rtattr_parse(tb, TCA_FW_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0)
190 return -EINVAL;
192 if ((f = (struct fw_filter*)*arg) != NULL) {
193 /* Node exists: adjust only classid */
195 if (f->id != handle && handle)
196 return -EINVAL;
197 if (tb[TCA_FW_CLASSID-1]) {
198 unsigned long cl;
200 f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
201 cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid);
202 cl = cls_set_class(&f->res.class, cl);
203 if (cl)
204 tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
206 #ifdef CONFIG_NET_CLS_POLICE
207 if (tb[TCA_FW_POLICE-1]) {
208 struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
210 police = xchg(&f->police, police);
211 synchronize_bh();
213 tcf_police_release(police);
215 #endif
216 return 0;
219 if (!handle)
220 return -EINVAL;
222 if (head == NULL) {
223 head = kmalloc(sizeof(struct fw_head), GFP_KERNEL);
224 if (head == NULL)
225 return -ENOBUFS;
226 memset(head, 0, sizeof(*head));
228 tp->root = head;
229 synchronize_bh();
232 f = kmalloc(sizeof(struct fw_filter), GFP_KERNEL);
233 if (f == NULL)
234 return -ENOBUFS;
235 memset(f, 0, sizeof(*f));
237 f->id = handle;
239 if (tb[TCA_FW_CLASSID-1]) {
240 err = -EINVAL;
241 if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != 4)
242 goto errout;
243 f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
244 cls_set_class(&f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
247 #ifdef CONFIG_NET_CLS_POLICE
248 if (tb[TCA_FW_POLICE-1])
249 f->police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
250 #endif
252 f->next = head->ht[fw_hash(handle)];
253 wmb();
254 head->ht[fw_hash(handle)] = f;
256 *arg = (unsigned long)f;
257 return 0;
259 errout:
260 if (f)
261 kfree(f);
262 return err;
265 static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
267 struct fw_head *head = (struct fw_head*)tp->root;
268 int h;
270 if (head == NULL)
271 arg->stop = 1;
273 if (arg->stop)
274 return;
276 for (h = 0; h <= 256; h++) {
277 struct fw_filter *f;
279 for (f = head->ht[h]; f; f = f->next) {
280 if (arg->count < arg->skip) {
281 arg->count++;
282 continue;
284 if (arg->fn(tp, (unsigned long)f, arg) < 0) {
285 arg->stop = 1;
286 break;
288 arg->count++;
293 #ifdef CONFIG_RTNETLINK
294 static int fw_dump(struct tcf_proto *tp, unsigned long fh,
295 struct sk_buff *skb, struct tcmsg *t)
297 struct fw_filter *f = (struct fw_filter*)fh;
298 unsigned char *b = skb->tail;
299 struct rtattr *rta;
301 if (f == NULL)
302 return skb->len;
304 t->tcm_handle = f->id;
306 if (!f->res.classid
307 #ifdef CONFIG_NET_CLS_POLICE
308 && !f->police
309 #endif
311 return skb->len;
313 rta = (struct rtattr*)b;
314 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
316 if (f->res.classid)
317 RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);
318 #ifdef CONFIG_NET_CLS_POLICE
319 if (f->police) {
320 struct rtattr * p_rta = (struct rtattr*)skb->tail;
322 RTA_PUT(skb, TCA_FW_POLICE, 0, NULL);
324 if (tcf_police_dump(skb, f->police) < 0)
325 goto rtattr_failure;
327 p_rta->rta_len = skb->tail - (u8*)p_rta;
329 #endif
331 rta->rta_len = skb->tail - b;
332 #ifdef CONFIG_NET_CLS_POLICE
333 if (f->police) {
334 RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), &f->police->stats);
336 #endif
337 return skb->len;
339 rtattr_failure:
340 skb_trim(skb, b - skb->data);
341 return -1;
343 #endif
346 struct tcf_proto_ops cls_fw_ops = {
347 NULL,
348 "fw",
349 fw_classify,
350 fw_init,
351 fw_destroy,
353 fw_get,
354 fw_put,
355 fw_change,
356 fw_delete,
357 fw_walk,
358 #ifdef CONFIG_RTNETLINK
359 fw_dump
360 #else
361 NULL
362 #endif
365 #ifdef MODULE
366 int init_module(void)
368 return register_tcf_proto_ops(&cls_fw_ops);
371 void cleanup_module(void)
373 unregister_tcf_proto_ops(&cls_fw_ops);
375 #endif