finally in sync with archive
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ipt_FTOS.c
1 /* Set TOS field in header to any value
2  *
3  * (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
4  *
5  * This software is distributed under GNU GPL v2, 1991
6  * 
7  * ipt_FTOS.c borrowed heavily from ipt_TOS.c  11/09/2000
8  * 
9  * Updated 3/4/02 - added in Rusty's skb_clone fix 
10  *                - added MODULE Political License
11  *                - redid checksum routine somewhat
12 */
13
14 #include <linux/module.h>
15 #include <linux/skbuff.h>
16 #include <linux/ip.h>
17 #include <net/checksum.h>
18
19 #include <linux/netfilter_ipv4/ip_tables.h>
20 #include <linux/netfilter_ipv4/ipt_FTOS.h>
21
22 static unsigned int
23 target(struct sk_buff **pskb,
24        unsigned int hooknum,
25        const struct net_device *in,
26        const struct net_device *out,
27        const void *targinfo,
28        void *userinfo)
29 {
30         struct iphdr *iph = (*pskb)->nh.iph;
31         const struct ipt_FTOS_info *ftosinfo = targinfo;
32
33         if ((iph->tos & IPTOS_TOS_MASK) != ftosinfo->ftos) {
34                 u_int16_t diffs[2];
35
36                 /* raw socket (tcpdump) may have clone of incoming
37                    skb: don't disturb it --RR */
38                 if (skb_cloned(*pskb) && !(*pskb)->sk) {
39                         struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
40                         if (!nskb)
41                                 return NF_DROP;
42                         kfree_skb(*pskb);
43                         *pskb = nskb;
44                         iph = (*pskb)->nh.iph;
45                 }
46
47                 diffs[0] = htons(iph->tos) ^ 0xFFFF;
48                 iph->tos = ftosinfo->ftos;
49                 diffs[1] = htons(iph->tos);
50                 iph->check = csum_fold(csum_partial((char *)diffs,
51                                                     sizeof(diffs),
52                                                     iph->check^0xFFFF));
53                 (*pskb)->nfcache |= NFC_ALTERED;
54         }
55         return IPT_CONTINUE;
56 }
57
58 static int
59 checkentry(const char *tablename,
60            const struct ipt_entry *e,
61            void *targinfo,
62            unsigned int targinfosize,
63            unsigned int hook_mask)
64 {
65         const u_int8_t ftos = ((struct ipt_FTOS_info *)targinfo)->ftos;
66
67         if (targinfosize != IPT_ALIGN(sizeof(struct ipt_FTOS_info))) {
68                 printk(KERN_WARNING "FTOS: targinfosize %u != %Zu\n",
69                        targinfosize,
70                        IPT_ALIGN(sizeof(struct ipt_FTOS_info)));
71                 return 0;
72         }
73
74         if (strcmp(tablename, "mangle") != 0) {
75                 printk(KERN_WARNING "FTOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
76                 return 0;
77         }
78
79         return 1;
80 }
81
82 #if defined(CONFIG_MIPS_BRCM)
83 static struct ipt_target ipt_ftos_reg = {
84         .name           = "FTOS",
85         .target         = target,
86         .checkentry     = checkentry,
87         .me             = THIS_MODULE,
88 };
89 #else
90 static struct ipt_target ipt_ftos_reg
91 = { { NULL, NULL }, "FTOS", target, checkentry, NULL, THIS_MODULE };
92 #endif
93
94 static int __init init(void)
95 {
96         if (ipt_register_target(&ipt_ftos_reg))
97                 return -EINVAL;
98
99         return 0;
100 }
101
102 static void __exit fini(void)
103 {
104         ipt_unregister_target(&ipt_ftos_reg);
105 }
106
107 module_init(init);
108 module_exit(fini);
109 MODULE_LICENSE("GPL");