import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / net / ipv4 / netfilter / ipt_ecn.c
1 /* IP tables module for matching the value of the IPv4 and TCP ECN bits
2  *
3  * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
4  *
5  * (C) 2002 by Harald Welte <laforge@gnumonks.org>
6  *
7  * This software is distributed under the terms GNU GPL v2
8  */
9
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/tcp.h>
13
14 #include <linux/netfilter_ipv4/ip_tables.h>
15 #include <linux/netfilter_ipv4/ipt_ecn.h>
16
17 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
18 MODULE_DESCRIPTION("IP tables ECN matching module");
19 MODULE_LICENSE("GPL");
20
21 static inline int match_ip(const struct sk_buff *skb,
22                            const struct iphdr *iph,
23                            const struct ipt_ecn_info *einfo)
24 {
25         return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
26 }
27
28 static inline int match_tcp(const struct sk_buff *skb,
29                             const struct iphdr *iph,
30                             const struct ipt_ecn_info *einfo)
31 {
32         struct tcphdr *tcph = (void *)iph + iph->ihl*4;
33
34         if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
35                 if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
36                         if (tcph->ece == 1)
37                                 return 0;
38                 } else {
39                         if (tcph->ece == 0)
40                                 return 0;
41                 }
42         }
43
44         if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
45                 if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
46                         if (tcph->cwr == 1)
47                                 return 0;
48                 } else {
49                         if (tcph->cwr == 0)
50                                 return 0;
51                 }
52         }
53
54         return 1;
55 }
56
57 static int match(const struct sk_buff *skb, const struct net_device *in,
58                  const struct net_device *out, const void *matchinfo,
59                  int offset, const void *hdr, u_int16_t datalen,
60                  int *hotdrop)
61 {
62         const struct ipt_ecn_info *info = matchinfo;
63         const struct iphdr *iph = skb->nh.iph;
64
65         if (info->operation & IPT_ECN_OP_MATCH_IP)
66                 if (!match_ip(skb, iph, info))
67                         return 0;
68
69         if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
70                 if (iph->protocol != IPPROTO_TCP)
71                         return 0;
72                 if (!match_tcp(skb, iph, info))
73                         return 0;
74         }
75
76         return 1;
77 }
78
79 static int checkentry(const char *tablename, const struct ipt_ip *ip,
80                       void *matchinfo, unsigned int matchsize,
81                       unsigned int hook_mask)
82 {
83         const struct ipt_ecn_info *info = matchinfo;
84
85         if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
86                 return 0;
87
88         if (info->operation & IPT_ECN_OP_MATCH_MASK)
89                 return 0;
90
91         if (info->invert & IPT_ECN_OP_MATCH_MASK)
92                 return 0;
93
94         if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
95             && ip->proto != IPPROTO_TCP) {
96                 printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
97                        " non-tcp packets\n");
98                 return 0;
99         }
100
101         return 1;
102 }
103
104 static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
105                 &checkentry, NULL, THIS_MODULE };
106
107 static int __init init(void)
108 {
109         return ipt_register_match(&ecn_match);
110 }
111
112 static void __exit fini(void)
113 {
114         ipt_unregister_match(&ecn_match);
115 }
116
117 module_init(init);
118 module_exit(fini);