netfilter: change return types of match functions for ebtables extensions
[safe/jmp/linux-2.6] / net / bridge / netfilter / ebt_vlan.c
1 /*
2  * Description: EBTables 802.1Q match extension kernelspace module.
3  * Authors: Nick Fedchik <nick@fedchik.org.ua>
4  *          Bart De Schuymer <bdschuym@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <linux/if_ether.h>
22 #include <linux/if_vlan.h>
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/netfilter/x_tables.h>
26 #include <linux/netfilter_bridge/ebtables.h>
27 #include <linux/netfilter_bridge/ebt_vlan.h>
28
29 static int debug;
30 #define MODULE_VERS "0.6"
31
32 module_param(debug, int, 0);
33 MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
34 MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
35 MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match");
36 MODULE_LICENSE("GPL");
37
38
39 #define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
40 #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
41 #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return false; }
42
43 static bool
44 ebt_filter_vlan(const struct sk_buff *skb,
45                 const struct net_device *in,
46                 const struct net_device *out,
47                 const void *data, unsigned int datalen)
48 {
49         const struct ebt_vlan_info *info = data;
50         const struct vlan_hdr *fp;
51         struct vlan_hdr _frame;
52
53         unsigned short TCI;     /* Whole TCI, given from parsed frame */
54         unsigned short id;      /* VLAN ID, given from frame TCI */
55         unsigned char prio;     /* user_priority, given from frame TCI */
56         /* VLAN encapsulated Type/Length field, given from orig frame */
57         __be16 encap;
58
59         fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
60         if (fp == NULL)
61                 return false;
62
63         /* Tag Control Information (TCI) consists of the following elements:
64          * - User_priority. The user_priority field is three bits in length,
65          * interpreted as a binary number.
66          * - Canonical Format Indicator (CFI). The Canonical Format Indicator
67          * (CFI) is a single bit flag value. Currently ignored.
68          * - VLAN Identifier (VID). The VID is encoded as
69          * an unsigned binary number. */
70         TCI = ntohs(fp->h_vlan_TCI);
71         id = TCI & VLAN_VID_MASK;
72         prio = (TCI >> 13) & 0x7;
73         encap = fp->h_vlan_encapsulated_proto;
74
75         /* Checking VLAN Identifier (VID) */
76         if (GET_BITMASK(EBT_VLAN_ID))
77                 EXIT_ON_MISMATCH(id, EBT_VLAN_ID);
78
79         /* Checking user_priority */
80         if (GET_BITMASK(EBT_VLAN_PRIO))
81                 EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO);
82
83         /* Checking Encapsulated Proto (Length/Type) field */
84         if (GET_BITMASK(EBT_VLAN_ENCAP))
85                 EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
86
87         return true;
88 }
89
90 static bool
91 ebt_check_vlan(const char *tablename,
92                unsigned int hooknr,
93                const struct ebt_entry *e, void *data, unsigned int datalen)
94 {
95         struct ebt_vlan_info *info = data;
96
97         /* Is it 802.1Q frame checked? */
98         if (e->ethproto != htons(ETH_P_8021Q)) {
99                 DEBUG_MSG
100                     ("passed entry proto %2.4X is not 802.1Q (8100)\n",
101                      (unsigned short) ntohs(e->ethproto));
102                 return false;
103         }
104
105         /* Check for bitmask range
106          * True if even one bit is out of mask */
107         if (info->bitmask & ~EBT_VLAN_MASK) {
108                 DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
109                           info->bitmask, EBT_VLAN_MASK);
110                 return false;
111         }
112
113         /* Check for inversion flags range */
114         if (info->invflags & ~EBT_VLAN_MASK) {
115                 DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
116                           info->invflags, EBT_VLAN_MASK);
117                 return false;
118         }
119
120         /* Reserved VLAN ID (VID) values
121          * -----------------------------
122          * 0 - The null VLAN ID.
123          * 1 - The default Port VID (PVID)
124          * 0x0FFF - Reserved for implementation use.
125          * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */
126         if (GET_BITMASK(EBT_VLAN_ID)) {
127                 if (!!info->id) { /* if id!=0 => check vid range */
128                         if (info->id > VLAN_GROUP_ARRAY_LEN) {
129                                 DEBUG_MSG
130                                     ("id %d is out of range (1-4096)\n",
131                                      info->id);
132                                 return false;
133                         }
134                         /* Note: This is valid VLAN-tagged frame point.
135                          * Any value of user_priority are acceptable,
136                          * but should be ignored according to 802.1Q Std.
137                          * So we just drop the prio flag. */
138                         info->bitmask &= ~EBT_VLAN_PRIO;
139                 }
140                 /* Else, id=0 (null VLAN ID)  => user_priority range (any?) */
141         }
142
143         if (GET_BITMASK(EBT_VLAN_PRIO)) {
144                 if ((unsigned char) info->prio > 7) {
145                         DEBUG_MSG("prio %d is out of range (0-7)\n",
146                              info->prio);
147                         return false;
148                 }
149         }
150         /* Check for encapsulated proto range - it is possible to be
151          * any value for u_short range.
152          * if_ether.h:  ETH_ZLEN        60   -  Min. octets in frame sans FCS */
153         if (GET_BITMASK(EBT_VLAN_ENCAP)) {
154                 if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
155                         DEBUG_MSG
156                             ("encap frame length %d is less than minimal\n",
157                              ntohs(info->encap));
158                         return false;
159                 }
160         }
161
162         return true;
163 }
164
165 static struct ebt_match filter_vlan __read_mostly = {
166         .name           = EBT_VLAN_MATCH,
167         .match          = ebt_filter_vlan,
168         .check          = ebt_check_vlan,
169         .matchsize      = XT_ALIGN(sizeof(struct ebt_vlan_info)),
170         .me             = THIS_MODULE,
171 };
172
173 static int __init ebt_vlan_init(void)
174 {
175         DEBUG_MSG("ebtables 802.1Q extension module v"
176                   MODULE_VERS "\n");
177         DEBUG_MSG("module debug=%d\n", !!debug);
178         return ebt_register_match(&filter_vlan);
179 }
180
181 static void __exit ebt_vlan_fini(void)
182 {
183         ebt_unregister_match(&filter_vlan);
184 }
185
186 module_init(ebt_vlan_init);
187 module_exit(ebt_vlan_fini);