blob: 382961f3feef95a57ae7da573067d514d41dd024 [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 /*
231 * Check if specified vlan-id=0 (priority-tagged frame condition)
232 * when vlan-prio was specified.
233 */
234 if (GET_BITMASK (EBT_VLAN_PRIO)) {
235 if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID))
236 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000237 ("For use user_priority the specified vlan-id must be 0");
fnm391fc2be2002-06-25 16:37:52 +0000238 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000239}
240
241/*
242 * Print line when listing rules by ebtables -L
243 */
244static void
245print (const struct ebt_u_entry *entry,
246 const struct ebt_entry_match *match)
247{
248 struct ebt_vlan_info *vlaninfo =
249 (struct ebt_vlan_info *) match->data;
250
fnm391fc2be2002-06-25 16:37:52 +0000251 char ethertype_name[21];
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000252 /*
253 * Print VLAN ID if they are specified
254 */
fnm391fc2be2002-06-25 16:37:52 +0000255 if (GET_BITMASK (EBT_VLAN_ID)) {
256 printf ("--%s %s%d ",
257 opts[VLAN_ID].name,
258 INV_FLAG (EBT_VLAN_ID), vlaninfo->id);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000259 }
260 /*
fnm391fc2be2002-06-25 16:37:52 +0000261 * Print user priority if they are specified
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000262 */
fnm391fc2be2002-06-25 16:37:52 +0000263 if (GET_BITMASK (EBT_VLAN_PRIO)) {
264 printf ("--%s %s%d ",
265 opts[VLAN_PRIO].name,
266 INV_FLAG (EBT_VLAN_PRIO), vlaninfo->prio);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000267 }
fnm3f794d5a2002-06-14 17:28:13 +0000268 /*
fnm391fc2be2002-06-25 16:37:52 +0000269 * Print encapsulated frame type if they are specified
fnm3f794d5a2002-06-14 17:28:13 +0000270 */
fnm391fc2be2002-06-25 16:37:52 +0000271 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
272 printf ("--%s %s",
273 opts[VLAN_ENCAP].name, INV_FLAG (EBT_VLAN_ENCAP));
274 bzero (ethertype_name, 21);
275 if (!number_to_name
276 (ntohs (vlaninfo->encap), ethertype_name)) {
277 printf ("%s ", ethertype_name);
278 } else {
279 printf ("%2.4X ", ntohs (vlaninfo->encap));
280 }
fnm3f794d5a2002-06-14 17:28:13 +0000281 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000282}
283
284
285static int
286compare (const struct ebt_entry_match *vlan1,
287 const struct ebt_entry_match *vlan2)
288{
289 struct ebt_vlan_info *vlaninfo1 =
290 (struct ebt_vlan_info *) vlan1->data;
291 struct ebt_vlan_info *vlaninfo2 =
292 (struct ebt_vlan_info *) vlan2->data;
293 /*
294 * Compare argc
295 */
296 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
297 return 0;
298 /*
299 * Compare inv flags
300 */
301 if (vlaninfo1->invflags != vlaninfo2->invflags)
302 return 0;
303 /*
304 * Compare VLAN ID if they are present
305 */
306 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
307 if (vlaninfo1->id != vlaninfo2->id)
308 return 0;
309 };
310 /*
311 * Compare VLAN Prio if they are present
312 */
313 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
314 if (vlaninfo1->prio != vlaninfo2->prio)
315 return 0;
316 };
fnm3f794d5a2002-06-14 17:28:13 +0000317 /*
318 * Compare VLAN Encap if they are present
319 */
320 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
321 if (vlaninfo1->encap != vlaninfo2->encap)
322 return 0;
323 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000324 return 1;
325}
326
327static struct ebt_u_match vlan_match = {
328 EBT_VLAN_MATCH,
329 sizeof (struct ebt_vlan_info),
330 print_help,
331 init,
332 parse,
333 final_check,
334 print,
335 compare,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000336 opts
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000337};
338
339static void _init (void) __attribute__ ((constructor));
340static void _init (void)
341{
342 register_match (&vlan_match);
343}