www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / kernel / linux / net / bridge / netfilter / ebt_ftos.c
1 /*
2  *  ebt_ftos
3  *
4  *      Authors:
5  *       Song Wang <songw@broadcom.com>
6  *
7  *  Feb, 2004
8  *
9  */
10
11 // The ftos target can be used in any chain
12 #include <linux/module.h>
13 #include <linux/skbuff.h>
14 #include <linux/ip.h>
15 #include <net/checksum.h>
16 #include <linux/if_vlan.h>
17 #include <linux/netfilter_bridge/ebtables.h>
18 #include <linux/netfilter_bridge/ebt_ftos_t.h>
19
20
21 static int ebt_target_ftos(struct sk_buff **pskb, unsigned int hooknr,
22    const struct net_device *in, const struct net_device *out,
23    const void *data, unsigned int datalen)
24 {
25         struct ebt_ftos_t_info *ftosinfo = (struct ebt_ftos_t_info *)data;
26         struct iphdr *iph;
27
28         /* if VLAN frame, we need to point to correct network header */
29         if ((*pskb)->protocol == __constant_htons(ETH_P_8021Q))
30                 iph = (struct iphdr *)((*pskb)->nh.raw + VLAN_HLEN);
31         else
32                 iph = (*pskb)->nh.iph;
33
34         if (iph->tos != ftosinfo->ftos) {
35                 /* Need to recalculate IP header checksum after altering TOS byte */
36                 u_int16_t diffs[2];
37
38                 /* raw socket (tcpdump) may have clone of incoming
39                    skb: don't disturb it --RR */
40                 if (skb_cloned(*pskb) && !(*pskb)->sk) {
41                         struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
42                         if (!nskb)
43                                 return NF_DROP;
44                         kfree_skb(*pskb);
45                         *pskb = nskb;
46                         if ((*pskb)->protocol == __constant_htons(ETH_P_8021Q))
47                                 iph = (struct iphdr *)((*pskb)->nh.raw + VLAN_HLEN);
48                         else
49                                 iph = (*pskb)->nh.iph;
50                 }
51
52
53                 diffs[0] = htons(iph->tos) ^ 0xFFFF;
54                 iph->tos = ftosinfo->ftos;
55                 diffs[1] = htons(iph->tos);
56                 iph->check = csum_fold(csum_partial((char *)diffs,
57                                                     sizeof(diffs),
58                                                     iph->check^0xFFFF));                
59                 (*pskb)->nfcache |= NFC_ALTERED;
60         }
61         return ftosinfo->target;
62 }
63
64 static int ebt_target_ftos_check(const char *tablename, unsigned int hookmask,
65    const struct ebt_entry *e, void *data, unsigned int datalen)
66 {
67         struct ebt_ftos_t_info *info = (struct ebt_ftos_t_info *)data;
68
69         if (datalen != sizeof(struct ebt_ftos_t_info))
70                 return -EINVAL;
71         if (BASE_CHAIN && info->target == EBT_RETURN)
72                 return -EINVAL;
73         CLEAR_BASE_CHAIN_BIT;
74         if (INVALID_TARGET)
75                 return -EINVAL;
76         return 0;
77 }
78
79 static struct ebt_target ftos_target =
80 {
81         .name           = EBT_FTOS_TARGET,
82         .target         = ebt_target_ftos,
83         .check          = ebt_target_ftos_check,
84         .me             = THIS_MODULE,
85 };
86
87 static int __init init(void)
88 {
89         return ebt_register_target(&ftos_target);
90 }
91
92 static void __exit fini(void)
93 {
94         ebt_unregister_target(&ftos_target);
95 }
96
97 module_init(init);
98 module_exit(fini);
99 MODULE_LICENSE("GPL");
100 MODULE_AUTHOR("Song Wang, songw@broadcom.com");
101 MODULE_DESCRIPTION("Target to overwrite the full TOS byte in IP header");