blob: 2379f9771eafcc6275948be242bf3b539515565a [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
fnm3f794d5a2002-06-14 17:28:13 +00002 * Summary: ebt_vlan - 802.1 Q match extension module for userspace
3 *
4 * Description:802.1 Q Virtual LAN match support module for ebtables project.
5 * Enable to match 802.1 Q VLAN tagged frames by VLAN numeric
6 * identifier (12 - bits field) and user_priority (3 bits field)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00007 *
8 * Authors:
9 * Bart De Schuymer <bart.de.schuymer@pandora.be>
fnm3f794d5a2002-06-14 17:28:13 +000010 * Nick Fedchik <nick@fedchik.org.ua>
11 * June, 2002
12 *
13 * License: GPL
14 *
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000015 */
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000016
fnm3f794d5a2002-06-14 17:28:13 +000017#include <stdio.h>
18#include <stdlib.h>
fnm3f794d5a2002-06-14 17:28:13 +000019#include <sys/socket.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000020#include <netinet/in.h>
21#include <string.h>
fnm3f794d5a2002-06-14 17:28:13 +000022#include <linux/netfilter_bridge/ebtables.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000023#include <getopt.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000024#include "../include/ebtables_u.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000025#include <linux/netfilter_bridge/ebt_vlan.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000026
27#define VLAN_ID '1'
28#define VLAN_PRIO '2'
fnm3f794d5a2002-06-14 17:28:13 +000029#define VLAN_ENCAP '3'
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000030
31static struct option opts[] = {
32 {"vlan-id", required_argument, 0, VLAN_ID},
33 {"vlan-prio", required_argument, 0, VLAN_PRIO},
fnm3f794d5a2002-06-14 17:28:13 +000034 {"vlan-encap", required_argument, 0, VLAN_ENCAP},
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000035 {0}
36};
37
38/*
fnm3f794d5a2002-06-14 17:28:13 +000039 * Print out local help by ebtables -h vlan
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040 */
41static void print_help ()
42{
43 printf ("802.1Q VLAN options:\n"
fnm3f794d5a2002-06-14 17:28:13 +000044 "--vlan-id [!] id : VLAN ID 1-4094 (integer)\n"
45 "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n"
46 "--vlan-encap [!] proto : VLAN Encapsulated Protocol (integer or string as in /etc/ethertypes)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047}
48
49/*
50 * Initialization function
51 */
52static void init (struct ebt_entry_match *match)
53{
54 struct ebt_vlan_info *vlaninfo =
55 (struct ebt_vlan_info *) match->data;
56 /*
57 * Just clean initial values
58 */
59 vlaninfo->id = 0;
60 vlaninfo->prio = 0;
fnm3f794d5a2002-06-14 17:28:13 +000061 vlaninfo->encap = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000062 vlaninfo->invflags = 0;
63 vlaninfo->bitmask = 0;
64}
65
fnm3f794d5a2002-06-14 17:28:13 +000066/*
67 * option flags definition
68 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000069#define OPT_VLAN_ID 0x01
70#define OPT_VLAN_PRIO 0x02
fnm3f794d5a2002-06-14 17:28:13 +000071#define OPT_VLAN_ENCAP 0x04
72
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000073static int
74parse (int c, char **argv, int argc,
75 const struct ebt_u_entry *entry, unsigned int *flags,
76 struct ebt_entry_match **match)
77{
78 struct ebt_vlan_info *vlaninfo =
79 (struct ebt_vlan_info *) (*match)->data;
fnm3f794d5a2002-06-14 17:28:13 +000080 unsigned long i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000081 char *end;
82
83 switch (c) {
84 case VLAN_ID:
fnm3f794d5a2002-06-14 17:28:13 +000085 /*
86 * ebtables.c:check_option(unsigned int *flags, unsigned int mask)
87 * checking for multiple usage of same option
88 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000089 check_option (flags, OPT_VLAN_ID);
90 /*
fnm3f794d5a2002-06-14 17:28:13 +000091 * Check If we got inversed arg for vlan-id option,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000092 * otherwise unset inversion flag
93 */
94 if (check_inverse (optarg))
95 vlaninfo->invflags |= EBT_VLAN_ID;
96 /*
fnm3f794d5a2002-06-14 17:28:13 +000097 * Check arg value presence
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000098 */
99 if (optind > argc)
100 print_error ("Missing VLAN ID argument\n");
101 /*
102 * Convert argv to long int,
103 * set *end to end of argv string,
104 * base set 10 for decimal only
105 */
106 (unsigned short) i = strtol (argv[optind - 1], &end, 10);
107 /*
fnm3f794d5a2002-06-14 17:28:13 +0000108 * Check arg val range
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 */
fnm3f794d5a2002-06-14 17:28:13 +0000110 if (i < 1 || i >= 4094 || *end != '\0') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111 i = 0;
112 print_error
113 ("Problem with specified VLAN ID range\n");
114 }
fnm3f794d5a2002-06-14 17:28:13 +0000115 /*
116 * Set up parameter value
117 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000118 vlaninfo->id = i;
fnm3f794d5a2002-06-14 17:28:13 +0000119 /*
120 * Set up parameter presence flag
121 */
122 vlaninfo->bitmask |= EBT_VLAN_ID;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123 break;
124
125 case VLAN_PRIO:
126 check_option (flags, OPT_VLAN_PRIO);
127 if (check_inverse (optarg))
128 vlaninfo->invflags |= EBT_VLAN_PRIO;
129 if (optind > argc)
130 print_error
131 ("Missing VLAN Priority level argument\n");
132 /*
133 * Convert argv to long int,
134 * set *end to end of argv string,
135 * base set 10 for decimal only
136 */
fnm3f794d5a2002-06-14 17:28:13 +0000137 (unsigned char) i = strtol (argv[optind - 1], &end, 10);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000138 /*
139 * Check arg val range
140 */
141 if (i >= 8 || *end != '\0') {
142 i = 0;
143 print_error
144 ("Problem with specified VLAN Priority range\n");
145 }
fnm3f794d5a2002-06-14 17:28:13 +0000146 /*
147 * Set up parameter value
148 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000149 vlaninfo->prio = i;
fnm3f794d5a2002-06-14 17:28:13 +0000150 /*
151 * Set up parameter presence flag
152 */
153 vlaninfo->bitmask |= EBT_VLAN_PRIO;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000154 break;
155
fnm3f794d5a2002-06-14 17:28:13 +0000156 case VLAN_ENCAP:
157 check_option (flags, OPT_VLAN_ENCAP);
158 if (check_inverse (optarg))
159 vlaninfo->invflags |= EBT_VLAN_ENCAP;
160 if (optind > argc)
161 print_error
162 ("Missing VLAN Encapsulated Protocol argument\n");
163 /*
164 * Parameter can be decimal, hexadecimal, or string.
165 * Check arg val range
166 */
167 (unsigned short) i = strtol (argv[optind - 1], &end, 16);
168 if (*end == '\0' && (i < 0 || i > 0xFFFF))
169 print_error
170 ("Problem with the specified encapsulated protocol");
171 if (*end != '\0')
172 if (name_to_protocol (argv[optind - 1]) == -1)
173 print_error
174 ("Problem with the specified encapsulated"
175 "protocol");
176 /*
177 * Set up parameter value (network notation)
178 */
179 vlaninfo->encap = htons (i);
180 /*
181 * Set up parameter presence flag
182 */
183 vlaninfo->bitmask |= EBT_VLAN_ENCAP;
184 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000185 default:
186 return 0;
187 }
188 return 1;
189}
190
191/*
192 * Final check
193 */
194static void
195final_check (const struct ebt_u_entry *entry,
196 const struct ebt_entry_match *match,
197 const char *name, unsigned int hook)
198{
199 /*
200 * Is any proto supplied there? Or specified proto isn't 802.1Q?
201 */
202 if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
203 print_error
204 ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n");
205}
206
207/*
208 * Print line when listing rules by ebtables -L
209 */
210static void
211print (const struct ebt_u_entry *entry,
212 const struct ebt_entry_match *match)
213{
214 struct ebt_vlan_info *vlaninfo =
215 (struct ebt_vlan_info *) match->data;
216
217 /*
218 * Print VLAN ID if they are specified
219 */
220 if (vlaninfo->bitmask & EBT_VLAN_ID) {
221 printf ("vlan id: %s%d, ",
222 vlaninfo->invflags & EBT_VLAN_ID ? "!" : "",
223 vlaninfo->id);
224 }
225 /*
226 * Print VLAN priority if they are specified
227 */
228 if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
229 printf ("vlan prio: %s%d, ",
230 vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "",
231 vlaninfo->prio);
232 }
fnm3f794d5a2002-06-14 17:28:13 +0000233 /*
234 * Print VLAN encapsulated protocol if they are specified
235 */
236 if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
237 printf ("vlan encap: %s%2.4X, ",
238 vlaninfo->invflags & EBT_VLAN_ENCAP ? "!" : "",
239 ntohs (vlaninfo->encap));
240 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000241}
242
243
244static int
245compare (const struct ebt_entry_match *vlan1,
246 const struct ebt_entry_match *vlan2)
247{
248 struct ebt_vlan_info *vlaninfo1 =
249 (struct ebt_vlan_info *) vlan1->data;
250 struct ebt_vlan_info *vlaninfo2 =
251 (struct ebt_vlan_info *) vlan2->data;
252 /*
253 * Compare argc
254 */
255 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
256 return 0;
257 /*
258 * Compare inv flags
259 */
260 if (vlaninfo1->invflags != vlaninfo2->invflags)
261 return 0;
262 /*
263 * Compare VLAN ID if they are present
264 */
265 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
266 if (vlaninfo1->id != vlaninfo2->id)
267 return 0;
268 };
269 /*
270 * Compare VLAN Prio if they are present
271 */
272 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
273 if (vlaninfo1->prio != vlaninfo2->prio)
274 return 0;
275 };
fnm3f794d5a2002-06-14 17:28:13 +0000276 /*
277 * Compare VLAN Encap if they are present
278 */
279 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
280 if (vlaninfo1->encap != vlaninfo2->encap)
281 return 0;
282 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000283 return 1;
284}
285
286static struct ebt_u_match vlan_match = {
287 EBT_VLAN_MATCH,
288 sizeof (struct ebt_vlan_info),
289 print_help,
290 init,
291 parse,
292 final_check,
293 print,
294 compare,
295 opts,
296};
297
298static void _init (void) __attribute__ ((constructor));
299static void _init (void)
300{
301 register_match (&vlan_match);
302}