27d03f396117a77a0ec38697e49bd1a20f8517f5
[linux-2.6.git] / net / netfilter / xt_MARK.c
1 /*
2  *      xt_MARK - Netfilter module to modify the NFMARK field of an skb
3  *
4  *      (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
5  *      Copyright © CC Computer Consultants GmbH, 2007 - 2008
6  *      Jan Engelhardt <jengelh@computergmbh.de>
7  *
8  *      This program is free software; you can redistribute it and/or modify
9  *      it under the terms of the GNU General Public License version 2 as
10  *      published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <linux/ip.h>
16 #include <net/checksum.h>
17
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter/xt_MARK.h>
20
21 MODULE_LICENSE("GPL");
22 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
23 MODULE_DESCRIPTION("Xtables: packet mark modification");
24 MODULE_ALIAS("ipt_MARK");
25 MODULE_ALIAS("ip6t_MARK");
26
27 static unsigned int
28 mark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par)
29 {
30         const struct xt_mark_target_info *markinfo = par->targinfo;
31
32         skb->mark = markinfo->mark;
33         return XT_CONTINUE;
34 }
35
36 static unsigned int
37 mark_tg_v1(struct sk_buff *skb, const struct xt_target_param *par)
38 {
39         const struct xt_mark_target_info_v1 *markinfo = par->targinfo;
40         int mark = 0;
41
42         switch (markinfo->mode) {
43         case XT_MARK_SET:
44                 mark = markinfo->mark;
45                 break;
46
47         case XT_MARK_AND:
48                 mark = skb->mark & markinfo->mark;
49                 break;
50
51         case XT_MARK_OR:
52                 mark = skb->mark | markinfo->mark;
53                 break;
54         }
55
56         skb->mark = mark;
57         return XT_CONTINUE;
58 }
59
60 static unsigned int
61 mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
62 {
63         const struct xt_mark_tginfo2 *info = par->targinfo;
64
65         skb->mark = (skb->mark & ~info->mask) ^ info->mark;
66         return XT_CONTINUE;
67 }
68
69 static bool
70 mark_tg_check_v0(const char *tablename, const void *entry,
71                  const struct xt_target *target, void *targinfo,
72                  unsigned int hook_mask)
73 {
74         const struct xt_mark_target_info *markinfo = targinfo;
75
76         if (markinfo->mark > 0xffffffff) {
77                 printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
78                 return false;
79         }
80         return true;
81 }
82
83 static bool
84 mark_tg_check_v1(const char *tablename, const void *entry,
85                  const struct xt_target *target, void *targinfo,
86                  unsigned int hook_mask)
87 {
88         const struct xt_mark_target_info_v1 *markinfo = targinfo;
89
90         if (markinfo->mode != XT_MARK_SET
91             && markinfo->mode != XT_MARK_AND
92             && markinfo->mode != XT_MARK_OR) {
93                 printk(KERN_WARNING "MARK: unknown mode %u\n",
94                        markinfo->mode);
95                 return false;
96         }
97         if (markinfo->mark > 0xffffffff) {
98                 printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
99                 return false;
100         }
101         return true;
102 }
103
104 #ifdef CONFIG_COMPAT
105 struct compat_xt_mark_target_info {
106         compat_ulong_t  mark;
107 };
108
109 static void mark_tg_compat_from_user_v0(void *dst, void *src)
110 {
111         const struct compat_xt_mark_target_info *cm = src;
112         struct xt_mark_target_info m = {
113                 .mark   = cm->mark,
114         };
115         memcpy(dst, &m, sizeof(m));
116 }
117
118 static int mark_tg_compat_to_user_v0(void __user *dst, void *src)
119 {
120         const struct xt_mark_target_info *m = src;
121         struct compat_xt_mark_target_info cm = {
122                 .mark   = m->mark,
123         };
124         return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
125 }
126
127 struct compat_xt_mark_target_info_v1 {
128         compat_ulong_t  mark;
129         u_int8_t        mode;
130         u_int8_t        __pad1;
131         u_int16_t       __pad2;
132 };
133
134 static void mark_tg_compat_from_user_v1(void *dst, void *src)
135 {
136         const struct compat_xt_mark_target_info_v1 *cm = src;
137         struct xt_mark_target_info_v1 m = {
138                 .mark   = cm->mark,
139                 .mode   = cm->mode,
140         };
141         memcpy(dst, &m, sizeof(m));
142 }
143
144 static int mark_tg_compat_to_user_v1(void __user *dst, void *src)
145 {
146         const struct xt_mark_target_info_v1 *m = src;
147         struct compat_xt_mark_target_info_v1 cm = {
148                 .mark   = m->mark,
149                 .mode   = m->mode,
150         };
151         return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
152 }
153 #endif /* CONFIG_COMPAT */
154
155 static struct xt_target mark_tg_reg[] __read_mostly = {
156         {
157                 .name           = "MARK",
158                 .family         = NFPROTO_IPV4,
159                 .revision       = 0,
160                 .checkentry     = mark_tg_check_v0,
161                 .target         = mark_tg_v0,
162                 .targetsize     = sizeof(struct xt_mark_target_info),
163 #ifdef CONFIG_COMPAT
164                 .compatsize     = sizeof(struct compat_xt_mark_target_info),
165                 .compat_from_user = mark_tg_compat_from_user_v0,
166                 .compat_to_user = mark_tg_compat_to_user_v0,
167 #endif
168                 .table          = "mangle",
169                 .me             = THIS_MODULE,
170         },
171         {
172                 .name           = "MARK",
173                 .family         = NFPROTO_IPV4,
174                 .revision       = 1,
175                 .checkentry     = mark_tg_check_v1,
176                 .target         = mark_tg_v1,
177                 .targetsize     = sizeof(struct xt_mark_target_info_v1),
178 #ifdef CONFIG_COMPAT
179                 .compatsize     = sizeof(struct compat_xt_mark_target_info_v1),
180                 .compat_from_user = mark_tg_compat_from_user_v1,
181                 .compat_to_user = mark_tg_compat_to_user_v1,
182 #endif
183                 .table          = "mangle",
184                 .me             = THIS_MODULE,
185         },
186         {
187                 .name           = "MARK",
188                 .family         = NFPROTO_IPV6,
189                 .revision       = 0,
190                 .checkentry     = mark_tg_check_v0,
191                 .target         = mark_tg_v0,
192                 .targetsize     = sizeof(struct xt_mark_target_info),
193 #ifdef CONFIG_COMPAT
194                 .compatsize     = sizeof(struct compat_xt_mark_target_info),
195                 .compat_from_user = mark_tg_compat_from_user_v0,
196                 .compat_to_user = mark_tg_compat_to_user_v0,
197 #endif
198                 .table          = "mangle",
199                 .me             = THIS_MODULE,
200         },
201         {
202                 .name           = "MARK",
203                 .family         = NFPROTO_IPV6,
204                 .revision       = 1,
205                 .checkentry     = mark_tg_check_v1,
206                 .target         = mark_tg_v1,
207                 .targetsize     = sizeof(struct xt_mark_target_info_v1),
208 #ifdef CONFIG_COMPAT
209                 .compatsize     = sizeof(struct compat_xt_mark_target_info_v1),
210                 .compat_from_user = mark_tg_compat_from_user_v1,
211                 .compat_to_user = mark_tg_compat_to_user_v1,
212 #endif
213                 .table          = "mangle",
214                 .me             = THIS_MODULE,
215         },
216         {
217                 .name           = "MARK",
218                 .revision       = 2,
219                 .family         = NFPROTO_UNSPEC,
220                 .target         = mark_tg,
221                 .targetsize     = sizeof(struct xt_mark_tginfo2),
222                 .me             = THIS_MODULE,
223         },
224 };
225
226 static int __init mark_tg_init(void)
227 {
228         return xt_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
229 }
230
231 static void __exit mark_tg_exit(void)
232 {
233         xt_unregister_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
234 }
235
236 module_init(mark_tg_init);
237 module_exit(mark_tg_exit);