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#ifdef	HNDCTF
18#include <net/netfilter/nf_conntrack.h>
19#endif
20
21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
23MODULE_DESCRIPTION("ip[6]tables MARK modification module");
24MODULE_ALIAS("ipt_MARK");
25MODULE_ALIAS("ip6t_MARK");
26
27static unsigned int
28target_v0(struct sk_buff **pskb,
29	  const struct net_device *in,
30	  const struct net_device *out,
31	  unsigned int hooknum,
32	  const struct xt_target *target,
33	  const void *targinfo)
34{
35	const struct xt_mark_target_info *markinfo = targinfo;
36
37	(*pskb)->mark = markinfo->mark;
38	return XT_CONTINUE;
39}
40
41static unsigned int
42target_v1(struct sk_buff **pskb,
43	  const struct net_device *in,
44	  const struct net_device *out,
45	  unsigned int hooknum,
46	  const struct xt_target *target,
47	  const void *targinfo)
48{
49	const struct xt_mark_target_info_v1 *markinfo = targinfo;
50	int mark = 0;
51
52	switch (markinfo->mode) {
53	case XT_MARK_SET:
54		mark = markinfo->mark;
55#ifdef	HNDCTF
56	{
57		enum ip_conntrack_info ctinfo;
58		struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo);
59		ct->ctf_flags |= CTF_FLAGS_EXCLUDED;
60	}
61#endif	/* HNDCTF */
62		break;
63
64	case XT_MARK_AND:
65		mark = (*pskb)->mark & markinfo->mark;
66		break;
67
68	case XT_MARK_OR:
69		mark = (*pskb)->mark | markinfo->mark;
70		break;
71	}
72
73	(*pskb)->mark = mark;
74	return XT_CONTINUE;
75}
76
77
78static int
79checkentry_v0(const char *tablename,
80	      const void *entry,
81	      const struct xt_target *target,
82	      void *targinfo,
83	      unsigned int hook_mask)
84{
85	struct xt_mark_target_info *markinfo = targinfo;
86
87	if (markinfo->mark > 0xffffffff) {
88		printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
89		return 0;
90	}
91	return 1;
92}
93
94static int
95checkentry_v1(const char *tablename,
96	      const void *entry,
97	      const struct xt_target *target,
98	      void *targinfo,
99	      unsigned int hook_mask)
100{
101	struct xt_mark_target_info_v1 *markinfo = targinfo;
102
103	if (markinfo->mode != XT_MARK_SET
104	    && markinfo->mode != XT_MARK_AND
105	    && markinfo->mode != XT_MARK_OR) {
106		printk(KERN_WARNING "MARK: unknown mode %u\n",
107		       markinfo->mode);
108		return 0;
109	}
110	if (markinfo->mark > 0xffffffff) {
111		printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
112		return 0;
113	}
114	return 1;
115}
116
117#ifdef CONFIG_COMPAT
118struct compat_xt_mark_target_info_v1 {
119	compat_ulong_t	mark;
120	u_int8_t	mode;
121	u_int8_t	__pad1;
122	u_int16_t	__pad2;
123};
124
125static void compat_from_user_v1(void *dst, void *src)
126{
127	struct compat_xt_mark_target_info_v1 *cm = src;
128	struct xt_mark_target_info_v1 m = {
129		.mark	= cm->mark,
130		.mode	= cm->mode,
131	};
132	memcpy(dst, &m, sizeof(m));
133}
134
135static int compat_to_user_v1(void __user *dst, void *src)
136{
137	struct xt_mark_target_info_v1 *m = src;
138	struct compat_xt_mark_target_info_v1 cm = {
139		.mark	= m->mark,
140		.mode	= m->mode,
141	};
142	return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
143}
144#endif /* CONFIG_COMPAT */
145
146static struct xt_target xt_mark_target[] = {
147	{
148		.name		= "MARK",
149		.family		= AF_INET,
150		.revision	= 0,
151		.checkentry	= checkentry_v0,
152		.target		= target_v0,
153		.targetsize	= sizeof(struct xt_mark_target_info),
154		.table		= "mangle",
155		.me		= THIS_MODULE,
156	},
157	{
158		.name		= "MARK",
159		.family		= AF_INET,
160		.revision	= 1,
161		.checkentry	= checkentry_v1,
162		.target		= target_v1,
163		.targetsize	= sizeof(struct xt_mark_target_info_v1),
164#ifdef CONFIG_COMPAT
165		.compatsize	= sizeof(struct compat_xt_mark_target_info_v1),
166		.compat_from_user = compat_from_user_v1,
167		.compat_to_user	= compat_to_user_v1,
168#endif
169		.table		= "mangle",
170		.me		= THIS_MODULE,
171	},
172	{
173		.name		= "MARK",
174		.family		= AF_INET6,
175		.revision	= 0,
176		.checkentry	= checkentry_v0,
177		.target		= target_v0,
178		.targetsize	= sizeof(struct xt_mark_target_info),
179		.table		= "mangle",
180		.me		= THIS_MODULE,
181	},
182};
183
184static int __init xt_mark_init(void)
185{
186	return xt_register_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target));
187}
188
189static void __exit xt_mark_fini(void)
190{
191	xt_unregister_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target));
192}
193
194module_init(xt_mark_init);
195module_exit(xt_mark_fini);
196