blob: 297b61b7296e7dd5f9150ea62d3faa89075929f6 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
fnm391fc2be2002-06-25 16:37:52 +00002 * Summary: ebt_vlan - IEEE 802.1Q extension module for userspace
fnm3f794d5a2002-06-14 17:28:13 +00003 *
fnm391fc2be2002-06-25 16:37:52 +00004 * Description: 802.1Q Virtual LAN match support module for ebtables project.
5 * Enables to match 802.1Q:
6 * 1) VLAN-tagged frames by VLAN numeric identifier (12 - bits field)
7 * 2) Priority-tagged frames by user_priority (3 bits field)
8 * 3) Encapsulated Frame by ethernet protocol type/length
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00009 *
10 * Authors:
11 * Bart De Schuymer <bart.de.schuymer@pandora.be>
fnm3f794d5a2002-06-14 17:28:13 +000012 * Nick Fedchik <nick@fedchik.org.ua>
13 * June, 2002
14 *
fnm391fc2be2002-06-25 16:37:52 +000015 * License: GNU GPL
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
fnm3f794d5a2002-06-14 17:28:13 +000030 *
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000031 */
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000032
fnm3f794d5a2002-06-14 17:28:13 +000033#include <stdio.h>
34#include <stdlib.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000035#include <string.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000036#include <getopt.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000037#include "../include/ebtables_u.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000038#include <linux/netfilter_bridge/ebt_vlan.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000039
fnm391fc2be2002-06-25 16:37:52 +000040#define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_
41#define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000042#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "! " : ""
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000043
fnm391fc2be2002-06-25 16:37:52 +000044#define VLAN_ID 0
45#define VLAN_PRIO 1
46#define VLAN_ENCAP 2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047static struct option opts[] = {
fnm391fc2be2002-06-25 16:37:52 +000048 {"vlan-id", required_argument, NULL, VLAN_ID},
49 {"vlan-prio", required_argument, NULL, VLAN_PRIO},
50 {"vlan-encap", required_argument, NULL, VLAN_ENCAP},
51 {NULL}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000052};
53
fnm391fc2be2002-06-25 16:37:52 +000054
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000055/*
fnm391fc2be2002-06-25 16:37:52 +000056 * Print out local help by "ebtables -h vlan"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 */
58static void print_help ()
59{
fnm391fc2be2002-06-25 16:37:52 +000060 printf ("802.1Q VLAN extension options:\n"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000061 "--vlan-id [!] id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n"
62 "--vlan-prio [!] prio : Priority-tagged frame user_priority, 0-7 (integer)\n"
63 "--vlan-encap [!] proto : Encapsulated protocol (hexadecimal)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000064}
65
66/*
67 * Initialization function
68 */
69static void init (struct ebt_entry_match *match)
70{
71 struct ebt_vlan_info *vlaninfo =
72 (struct ebt_vlan_info *) match->data;
73 /*
fnm391fc2be2002-06-25 16:37:52 +000074 * Set initial values
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000075 */
fnm391fc2be2002-06-25 16:37:52 +000076 vlaninfo->id = 1; /* Default VID for VLAN-tagged 802.1Q frames */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000077 vlaninfo->prio = 0;
fnm3f794d5a2002-06-14 17:28:13 +000078 vlaninfo->encap = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079 vlaninfo->invflags = 0;
80 vlaninfo->bitmask = 0;
81}
82
fnm3f794d5a2002-06-14 17:28:13 +000083/*
84 * option flags definition
85 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000086#define OPT_VLAN_ID 0x01
87#define OPT_VLAN_PRIO 0x02
fnm3f794d5a2002-06-14 17:28:13 +000088#define OPT_VLAN_ENCAP 0x04
89
fnm391fc2be2002-06-25 16:37:52 +000090/*
91 * Parse passed arguments values (ranges, flags, etc...)
92 * int c - parameter number from static struct option opts[]
93 * int argc - total amout of arguments (std argc value)
94 *
95 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000096static int
fnm391fc2be2002-06-25 16:37:52 +000097parse (int c,
98 char **argv,
99 int argc,
100 const struct ebt_u_entry *entry,
101 unsigned int *flags, struct ebt_entry_match **match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000102{
103 struct ebt_vlan_info *vlaninfo =
104 (struct ebt_vlan_info *) (*match)->data;
fnm3f794d5a2002-06-14 17:28:13 +0000105 unsigned long i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000106 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000107 uint16_t encap;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 switch (c) {
109 case VLAN_ID:
fnm3f794d5a2002-06-14 17:28:13 +0000110 /*
111 * ebtables.c:check_option(unsigned int *flags, unsigned int mask)
112 * checking for multiple usage of same option
113 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000114 check_option (flags, OPT_VLAN_ID);
115 /*
fnm3f794d5a2002-06-14 17:28:13 +0000116 * Check If we got inversed arg for vlan-id option,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000117 * otherwise unset inversion flag
118 */
119 if (check_inverse (optarg))
120 vlaninfo->invflags |= EBT_VLAN_ID;
121 /*
fnm3f794d5a2002-06-14 17:28:13 +0000122 * Check arg value presence
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000123 */
124 if (optind > argc)
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000125 print_error ("Missing VLAN ID argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126 /*
127 * Convert argv to long int,
128 * set *end to end of argv string,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000129 * base set 10 for decimal only
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000130 */
131 (unsigned short) i = strtol (argv[optind - 1], &end, 10);
132 /*
fnm3f794d5a2002-06-14 17:28:13 +0000133 * Check arg val range
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000134 */
fnm391fc2be2002-06-25 16:37:52 +0000135 if (i > 4094 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000136 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000137 ("Specified VLAN ID is out of range (0-4094)");
fnm3f794d5a2002-06-14 17:28:13 +0000138 /*
fnm391fc2be2002-06-25 16:37:52 +0000139 * Set up parameter value
fnm3f794d5a2002-06-14 17:28:13 +0000140 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000141 vlaninfo->id = i;
fnm3f794d5a2002-06-14 17:28:13 +0000142 /*
143 * Set up parameter presence flag
144 */
fnm391fc2be2002-06-25 16:37:52 +0000145 SET_BITMASK (EBT_VLAN_ID);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000146 break;
147
148 case VLAN_PRIO:
149 check_option (flags, OPT_VLAN_PRIO);
150 if (check_inverse (optarg))
151 vlaninfo->invflags |= EBT_VLAN_PRIO;
152 if (optind > argc)
153 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000154 ("Missing user_priority argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000155 /*
156 * Convert argv to long int,
157 * set *end to end of argv string,
158 * base set 10 for decimal only
159 */
fnm3f794d5a2002-06-14 17:28:13 +0000160 (unsigned char) i = strtol (argv[optind - 1], &end, 10);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000161 /*
162 * Check arg val range
163 */
fnm391fc2be2002-06-25 16:37:52 +0000164 if (i >= 8 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000165 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000166 ("Specified user_priority is out of range (0-7)");
fnm3f794d5a2002-06-14 17:28:13 +0000167 /*
168 * Set up parameter value
169 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000170 vlaninfo->prio = i;
fnm3f794d5a2002-06-14 17:28:13 +0000171 /*
172 * Set up parameter presence flag
173 */
fnm391fc2be2002-06-25 16:37:52 +0000174 SET_BITMASK (EBT_VLAN_PRIO);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000175 break;
176
fnm3f794d5a2002-06-14 17:28:13 +0000177 case VLAN_ENCAP:
178 check_option (flags, OPT_VLAN_ENCAP);
179 if (check_inverse (optarg))
180 vlaninfo->invflags |= EBT_VLAN_ENCAP;
181 if (optind > argc)
182 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000183 ("Missing encapsulated frame type argument value");
fnm3f794d5a2002-06-14 17:28:13 +0000184 /*
185 * Parameter can be decimal, hexadecimal, or string.
fnm391fc2be2002-06-25 16:37:52 +0000186 * Check arg val range (still raw area)
fnm3f794d5a2002-06-14 17:28:13 +0000187 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000188 (unsigned short) encap = strtol (argv[optind - 1], &end, 16);
189 if (*end == '\0' && (encap < ETH_ZLEN || encap > 0xFFFF))
fnm3f794d5a2002-06-14 17:28:13 +0000190 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000191 ("Specified encapsulated frame type is out of range");
fnm3f794d5a2002-06-14 17:28:13 +0000192 if (*end != '\0')
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000193 if (name_to_number (argv[optind - 1], &encap) == -1)
fnm3f794d5a2002-06-14 17:28:13 +0000194 print_error
195 ("Problem with the specified encapsulated"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000196 "protocol");
fnm3f794d5a2002-06-14 17:28:13 +0000197 /*
198 * Set up parameter value (network notation)
199 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000200 vlaninfo->encap = htons (encap);
fnm3f794d5a2002-06-14 17:28:13 +0000201 /*
202 * Set up parameter presence flag
203 */
fnm391fc2be2002-06-25 16:37:52 +0000204 SET_BITMASK (EBT_VLAN_ENCAP);
fnm3f794d5a2002-06-14 17:28:13 +0000205 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000206 default:
207 return 0;
208 }
209 return 1;
210}
211
212/*
fnm391fc2be2002-06-25 16:37:52 +0000213 * Final check - logical conditions
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000214 */
215static void
216final_check (const struct ebt_u_entry *entry,
217 const struct ebt_entry_match *match,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000218 const char *name, unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000219{
fnm391fc2be2002-06-25 16:37:52 +0000220
221 struct ebt_vlan_info *vlaninfo =
222 (struct ebt_vlan_info *) match->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000223 /*
Bart De Schuymer40573192002-08-29 16:48:36 +0000224 * Specified proto isn't 802.1Q?
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225 */
Bart De Schuymer40573192002-08-29 16:48:36 +0000226 if (entry->ethproto != ETH_P_8021Q ||
Bart De Schuymerb2632c52002-08-09 18:57:05 +0000227 entry->invflags & EBT_IPROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000228 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000229 ("For use 802.1Q extension the protocol must be specified as 802_1Q");
fnm391fc2be2002-06-25 16:37:52 +0000230 /*
fnm3cd338272002-11-09 13:27:31 +0000231 * Check if specified vlan-encap=0x8100 (802.1Q Frame)
232 * when vlan-encap specified.
233 */
234 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
235 if (vlaninfo->encap==htons(0x8100))
236 print_error
237 ("Encapsulated frame type can not be 802.1Q (0x8100)");
238 }
239
240 /*
fnm391fc2be2002-06-25 16:37:52 +0000241 * Check if specified vlan-id=0 (priority-tagged frame condition)
242 * when vlan-prio was specified.
243 */
244 if (GET_BITMASK (EBT_VLAN_PRIO)) {
245 if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID))
246 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000247 ("For use user_priority the specified vlan-id must be 0");
fnm391fc2be2002-06-25 16:37:52 +0000248 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000249}
250
251/*
252 * Print line when listing rules by ebtables -L
253 */
254static void
255print (const struct ebt_u_entry *entry,
256 const struct ebt_entry_match *match)
257{
258 struct ebt_vlan_info *vlaninfo =
259 (struct ebt_vlan_info *) match->data;
260
fnm391fc2be2002-06-25 16:37:52 +0000261 char ethertype_name[21];
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000262 /*
263 * Print VLAN ID if they are specified
264 */
fnm391fc2be2002-06-25 16:37:52 +0000265 if (GET_BITMASK (EBT_VLAN_ID)) {
266 printf ("--%s %s%d ",
267 opts[VLAN_ID].name,
268 INV_FLAG (EBT_VLAN_ID), vlaninfo->id);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269 }
270 /*
fnm391fc2be2002-06-25 16:37:52 +0000271 * Print user priority if they are specified
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000272 */
fnm391fc2be2002-06-25 16:37:52 +0000273 if (GET_BITMASK (EBT_VLAN_PRIO)) {
274 printf ("--%s %s%d ",
275 opts[VLAN_PRIO].name,
276 INV_FLAG (EBT_VLAN_PRIO), vlaninfo->prio);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000277 }
fnm3f794d5a2002-06-14 17:28:13 +0000278 /*
fnm391fc2be2002-06-25 16:37:52 +0000279 * Print encapsulated frame type if they are specified
fnm3f794d5a2002-06-14 17:28:13 +0000280 */
fnm391fc2be2002-06-25 16:37:52 +0000281 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
282 printf ("--%s %s",
283 opts[VLAN_ENCAP].name, INV_FLAG (EBT_VLAN_ENCAP));
284 bzero (ethertype_name, 21);
285 if (!number_to_name
286 (ntohs (vlaninfo->encap), ethertype_name)) {
287 printf ("%s ", ethertype_name);
288 } else {
289 printf ("%2.4X ", ntohs (vlaninfo->encap));
290 }
fnm3f794d5a2002-06-14 17:28:13 +0000291 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000292}
293
294
295static int
296compare (const struct ebt_entry_match *vlan1,
297 const struct ebt_entry_match *vlan2)
298{
299 struct ebt_vlan_info *vlaninfo1 =
300 (struct ebt_vlan_info *) vlan1->data;
301 struct ebt_vlan_info *vlaninfo2 =
302 (struct ebt_vlan_info *) vlan2->data;
303 /*
304 * Compare argc
305 */
306 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
307 return 0;
308 /*
309 * Compare inv flags
310 */
311 if (vlaninfo1->invflags != vlaninfo2->invflags)
312 return 0;
313 /*
314 * Compare VLAN ID if they are present
315 */
316 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
317 if (vlaninfo1->id != vlaninfo2->id)
318 return 0;
319 };
320 /*
321 * Compare VLAN Prio if they are present
322 */
323 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
324 if (vlaninfo1->prio != vlaninfo2->prio)
325 return 0;
326 };
fnm3f794d5a2002-06-14 17:28:13 +0000327 /*
328 * Compare VLAN Encap if they are present
329 */
330 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
331 if (vlaninfo1->encap != vlaninfo2->encap)
332 return 0;
333 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000334 return 1;
335}
336
337static struct ebt_u_match vlan_match = {
338 EBT_VLAN_MATCH,
339 sizeof (struct ebt_vlan_info),
340 print_help,
341 init,
342 parse,
343 final_check,
344 print,
345 compare,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000346 opts
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000347};
348
349static void _init (void) __attribute__ ((constructor));
350static void _init (void)
351{
352 register_match (&vlan_match);
353}