linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / netfilter / xt_MARK.c
1 /* This is a module which is used for setting the NFMARK field of an skb. */
2
3 /* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/ip.h>
13 #include <net/checksum.h>
14
15 #include <linux/netfilter/x_tables.h>
16 #include <linux/netfilter/xt_MARK.h>
17
18 MODULE_LICENSE("GPL");
19 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
20 MODULE_DESCRIPTION("ip[6]tables MARK modification module");
21 MODULE_ALIAS("ipt_MARK");
22 MODULE_ALIAS("ip6t_MARK");
23
24 static unsigned int
25 target_v0(struct sk_buff **pskb,
26           const struct net_device *in,
27           const struct net_device *out,
28           unsigned int hooknum,
29           const void *targinfo,
30           void *userinfo)
31 {
32         const struct xt_mark_target_info *markinfo = targinfo;
33
34         if((*pskb)->nfmark != markinfo->mark)
35                 (*pskb)->nfmark = markinfo->mark;
36
37         return XT_CONTINUE;
38 }
39
40 static unsigned int
41 target_v1(struct sk_buff **pskb,
42           const struct net_device *in,
43           const struct net_device *out,
44           unsigned int hooknum,
45           const void *targinfo,
46           void *userinfo)
47 {
48         const struct xt_mark_target_info_v1 *markinfo = targinfo;
49         int mark = 0;
50
51         switch (markinfo->mode) {
52         case XT_MARK_SET:
53                 mark = markinfo->mark;
54                 break;
55                 
56         case XT_MARK_AND:
57                 mark = (*pskb)->nfmark & markinfo->mark;
58                 break;
59                 
60         case XT_MARK_OR:
61                 mark = (*pskb)->nfmark | markinfo->mark;
62                 break;
63         }
64
65         if((*pskb)->nfmark != mark)
66                 (*pskb)->nfmark = mark;
67
68         return XT_CONTINUE;
69 }
70
71
72 static int
73 checkentry_v0(const char *tablename,
74               const void *entry,
75               void *targinfo,
76               unsigned int targinfosize,
77               unsigned int hook_mask)
78 {
79         struct xt_mark_target_info *markinfo = targinfo;
80
81         if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
82                 printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
83                        targinfosize,
84                        XT_ALIGN(sizeof(struct xt_mark_target_info)));
85                 return 0;
86         }
87
88         if (strcmp(tablename, "mangle") != 0) {
89                 printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
90                 return 0;
91         }
92
93         if (markinfo->mark > 0xffffffff) {
94                 printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
95                 return 0;
96         }
97
98         return 1;
99 }
100
101 static int
102 checkentry_v1(const char *tablename,
103               const void *entry,
104               void *targinfo,
105               unsigned int targinfosize,
106               unsigned int hook_mask)
107 {
108         struct xt_mark_target_info_v1 *markinfo = targinfo;
109
110         if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
111                 printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
112                        targinfosize,
113                        XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
114                 return 0;
115         }
116
117         if (strcmp(tablename, "mangle") != 0) {
118                 printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
119                 return 0;
120         }
121
122         if (markinfo->mode != XT_MARK_SET
123             && markinfo->mode != XT_MARK_AND
124             && markinfo->mode != XT_MARK_OR) {
125                 printk(KERN_WARNING "MARK: unknown mode %u\n",
126                        markinfo->mode);
127                 return 0;
128         }
129
130         if (markinfo->mark > 0xffffffff) {
131                 printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
132                 return 0;
133         }
134
135         return 1;
136 }
137
138 static struct xt_target ipt_mark_reg_v0 = {
139         .name           = "MARK",
140         .target         = target_v0,
141         .checkentry     = checkentry_v0,
142         .me             = THIS_MODULE,
143         .revision       = 0,
144 };
145
146 static struct xt_target ipt_mark_reg_v1 = {
147         .name           = "MARK",
148         .target         = target_v1,
149         .checkentry     = checkentry_v1,
150         .me             = THIS_MODULE,
151         .revision       = 1,
152 };
153
154 static struct xt_target ip6t_mark_reg_v0 = {
155         .name           = "MARK",
156         .target         = target_v0,
157         .checkentry     = checkentry_v0,
158         .me             = THIS_MODULE,
159         .revision       = 0,
160 };
161
162 static int __init init(void)
163 {
164         int err;
165
166         err = xt_register_target(AF_INET, &ipt_mark_reg_v0);
167         if (err)
168                 return err;
169
170         err = xt_register_target(AF_INET, &ipt_mark_reg_v1);
171         if (err)
172                 xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
173
174         err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0);
175         if (err) {
176                 xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
177                 xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
178         }
179
180         return err;
181 }
182
183 static void __exit fini(void)
184 {
185         xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
186         xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
187         xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0);
188 }
189
190 module_init(init);
191 module_exit(fini);