blob: ab2ce0923f7c7ccea2307cdcea512b2dd1a3b075 [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 Schuymerc1939b12002-11-20 19:41:54 +000038#include "../include/ethernetdb.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000039#include <linux/netfilter_bridge/ebt_vlan.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040
fnm391fc2be2002-06-25 16:37:52 +000041#define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_
42#define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000043#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "! " : ""
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000044
fnm391fc2be2002-06-25 16:37:52 +000045#define VLAN_ID 0
46#define VLAN_PRIO 1
47#define VLAN_ENCAP 2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000048static struct option opts[] = {
fnm391fc2be2002-06-25 16:37:52 +000049 {"vlan-id", required_argument, NULL, VLAN_ID},
50 {"vlan-prio", required_argument, NULL, VLAN_PRIO},
51 {"vlan-encap", required_argument, NULL, VLAN_ENCAP},
52 {NULL}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000053};
54
fnm391fc2be2002-06-25 16:37:52 +000055
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000056/*
fnm391fc2be2002-06-25 16:37:52 +000057 * Print out local help by "ebtables -h vlan"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000058 */
59static void print_help ()
60{
fnm391fc2be2002-06-25 16:37:52 +000061 printf ("802.1Q VLAN extension options:\n"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000062 "--vlan-id [!] id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n"
63 "--vlan-prio [!] prio : Priority-tagged frame user_priority, 0-7 (integer)\n"
64 "--vlan-encap [!] proto : Encapsulated protocol (hexadecimal)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000065}
66
67/*
68 * Initialization function
69 */
70static void init (struct ebt_entry_match *match)
71{
72 struct ebt_vlan_info *vlaninfo =
73 (struct ebt_vlan_info *) match->data;
74 /*
fnm391fc2be2002-06-25 16:37:52 +000075 * Set initial values
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000076 */
fnm391fc2be2002-06-25 16:37:52 +000077 vlaninfo->id = 1; /* Default VID for VLAN-tagged 802.1Q frames */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000078 vlaninfo->prio = 0;
fnm3f794d5a2002-06-14 17:28:13 +000079 vlaninfo->encap = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 vlaninfo->invflags = 0;
81 vlaninfo->bitmask = 0;
82}
83
fnm3f794d5a2002-06-14 17:28:13 +000084/*
85 * option flags definition
86 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000087#define OPT_VLAN_ID 0x01
88#define OPT_VLAN_PRIO 0x02
fnm3f794d5a2002-06-14 17:28:13 +000089#define OPT_VLAN_ENCAP 0x04
90
fnm391fc2be2002-06-25 16:37:52 +000091/*
92 * Parse passed arguments values (ranges, flags, etc...)
93 * int c - parameter number from static struct option opts[]
94 * int argc - total amout of arguments (std argc value)
95 *
96 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000097static int
fnm391fc2be2002-06-25 16:37:52 +000098parse (int c,
99 char **argv,
100 int argc,
101 const struct ebt_u_entry *entry,
102 unsigned int *flags, struct ebt_entry_match **match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000103{
104 struct ebt_vlan_info *vlaninfo =
105 (struct ebt_vlan_info *) (*match)->data;
fnm3f794d5a2002-06-14 17:28:13 +0000106 unsigned long i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000107 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000108 uint16_t encap;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 switch (c) {
110 case VLAN_ID:
fnm3f794d5a2002-06-14 17:28:13 +0000111 /*
112 * ebtables.c:check_option(unsigned int *flags, unsigned int mask)
113 * checking for multiple usage of same option
114 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000115 check_option (flags, OPT_VLAN_ID);
116 /*
fnm3f794d5a2002-06-14 17:28:13 +0000117 * Check If we got inversed arg for vlan-id option,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000118 * otherwise unset inversion flag
119 */
120 if (check_inverse (optarg))
121 vlaninfo->invflags |= EBT_VLAN_ID;
122 /*
fnm3f794d5a2002-06-14 17:28:13 +0000123 * Check arg value presence
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000124 */
125 if (optind > argc)
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000126 print_error ("Missing VLAN ID argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127 /*
128 * Convert argv to long int,
129 * set *end to end of argv string,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000130 * base set 10 for decimal only
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000131 */
132 (unsigned short) i = strtol (argv[optind - 1], &end, 10);
133 /*
fnm3f794d5a2002-06-14 17:28:13 +0000134 * Check arg val range
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135 */
fnm391fc2be2002-06-25 16:37:52 +0000136 if (i > 4094 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000138 ("Specified VLAN ID is out of range (0-4094)");
fnm3f794d5a2002-06-14 17:28:13 +0000139 /*
fnm391fc2be2002-06-25 16:37:52 +0000140 * Set up parameter value
fnm3f794d5a2002-06-14 17:28:13 +0000141 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000142 vlaninfo->id = i;
fnm3f794d5a2002-06-14 17:28:13 +0000143 /*
144 * Set up parameter presence flag
145 */
fnm391fc2be2002-06-25 16:37:52 +0000146 SET_BITMASK (EBT_VLAN_ID);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000147 break;
148
149 case VLAN_PRIO:
150 check_option (flags, OPT_VLAN_PRIO);
151 if (check_inverse (optarg))
152 vlaninfo->invflags |= EBT_VLAN_PRIO;
153 if (optind > argc)
154 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000155 ("Missing user_priority argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000156 /*
157 * Convert argv to long int,
158 * set *end to end of argv string,
159 * base set 10 for decimal only
160 */
fnm3f794d5a2002-06-14 17:28:13 +0000161 (unsigned char) i = strtol (argv[optind - 1], &end, 10);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000162 /*
163 * Check arg val range
164 */
fnm391fc2be2002-06-25 16:37:52 +0000165 if (i >= 8 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000166 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000167 ("Specified user_priority is out of range (0-7)");
fnm3f794d5a2002-06-14 17:28:13 +0000168 /*
169 * Set up parameter value
170 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000171 vlaninfo->prio = i;
fnm3f794d5a2002-06-14 17:28:13 +0000172 /*
173 * Set up parameter presence flag
174 */
fnm391fc2be2002-06-25 16:37:52 +0000175 SET_BITMASK (EBT_VLAN_PRIO);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000176 break;
177
fnm3f794d5a2002-06-14 17:28:13 +0000178 case VLAN_ENCAP:
179 check_option (flags, OPT_VLAN_ENCAP);
180 if (check_inverse (optarg))
181 vlaninfo->invflags |= EBT_VLAN_ENCAP;
182 if (optind > argc)
183 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000184 ("Missing encapsulated frame type argument value");
fnm3f794d5a2002-06-14 17:28:13 +0000185 /*
186 * Parameter can be decimal, hexadecimal, or string.
fnm391fc2be2002-06-25 16:37:52 +0000187 * Check arg val range (still raw area)
fnm3f794d5a2002-06-14 17:28:13 +0000188 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000189 (unsigned short) encap = strtol (argv[optind - 1], &end, 16);
190 if (*end == '\0' && (encap < ETH_ZLEN || encap > 0xFFFF))
fnm3f794d5a2002-06-14 17:28:13 +0000191 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000192 ("Specified encapsulated frame type is out of range");
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000193 if (*end != '\0') {
194 struct ethertypeent *ent;
195
196 ent = getethertypebyname(argv[optind - 1]);
197 if (!ent)
fnm3f794d5a2002-06-14 17:28:13 +0000198 print_error
199 ("Problem with the specified encapsulated"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000200 "protocol");
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000201 encap = ent->e_ethertype;
202 }
fnm3f794d5a2002-06-14 17:28:13 +0000203 /*
204 * Set up parameter value (network notation)
205 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000206 vlaninfo->encap = htons (encap);
fnm3f794d5a2002-06-14 17:28:13 +0000207 /*
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000208 * Set up parameter presence flag
fnm3f794d5a2002-06-14 17:28:13 +0000209 */
fnm391fc2be2002-06-25 16:37:52 +0000210 SET_BITMASK (EBT_VLAN_ENCAP);
fnm3f794d5a2002-06-14 17:28:13 +0000211 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000212 default:
213 return 0;
214 }
215 return 1;
216}
217
218/*
fnm391fc2be2002-06-25 16:37:52 +0000219 * Final check - logical conditions
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000220 */
221static void
222final_check (const struct ebt_u_entry *entry,
223 const struct ebt_entry_match *match,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000224 const char *name, unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225{
fnm391fc2be2002-06-25 16:37:52 +0000226
227 struct ebt_vlan_info *vlaninfo =
228 (struct ebt_vlan_info *) match->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000229 /*
Bart De Schuymer40573192002-08-29 16:48:36 +0000230 * Specified proto isn't 802.1Q?
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000231 */
Bart De Schuymer40573192002-08-29 16:48:36 +0000232 if (entry->ethproto != ETH_P_8021Q ||
Bart De Schuymerb2632c52002-08-09 18:57:05 +0000233 entry->invflags & EBT_IPROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000234 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000235 ("For use 802.1Q extension the protocol must be specified as 802_1Q");
fnm391fc2be2002-06-25 16:37:52 +0000236 /*
fnm3cd338272002-11-09 13:27:31 +0000237 * Check if specified vlan-encap=0x8100 (802.1Q Frame)
238 * when vlan-encap specified.
239 */
240 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
241 if (vlaninfo->encap==htons(0x8100))
242 print_error
243 ("Encapsulated frame type can not be 802.1Q (0x8100)");
244 }
245
246 /*
fnm391fc2be2002-06-25 16:37:52 +0000247 * Check if specified vlan-id=0 (priority-tagged frame condition)
248 * when vlan-prio was specified.
249 */
250 if (GET_BITMASK (EBT_VLAN_PRIO)) {
251 if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID))
252 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000253 ("For use user_priority the specified vlan-id must be 0");
fnm391fc2be2002-06-25 16:37:52 +0000254 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000255}
256
257/*
258 * Print line when listing rules by ebtables -L
259 */
260static void
261print (const struct ebt_u_entry *entry,
262 const struct ebt_entry_match *match)
263{
264 struct ebt_vlan_info *vlaninfo =
265 (struct ebt_vlan_info *) match->data;
266
267 /*
268 * Print VLAN ID if they are specified
269 */
fnm391fc2be2002-06-25 16:37:52 +0000270 if (GET_BITMASK (EBT_VLAN_ID)) {
271 printf ("--%s %s%d ",
272 opts[VLAN_ID].name,
273 INV_FLAG (EBT_VLAN_ID), vlaninfo->id);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000274 }
275 /*
fnm391fc2be2002-06-25 16:37:52 +0000276 * Print user priority if they are specified
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000277 */
fnm391fc2be2002-06-25 16:37:52 +0000278 if (GET_BITMASK (EBT_VLAN_PRIO)) {
279 printf ("--%s %s%d ",
280 opts[VLAN_PRIO].name,
281 INV_FLAG (EBT_VLAN_PRIO), vlaninfo->prio);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000282 }
fnm3f794d5a2002-06-14 17:28:13 +0000283 /*
fnm391fc2be2002-06-25 16:37:52 +0000284 * Print encapsulated frame type if they are specified
fnm3f794d5a2002-06-14 17:28:13 +0000285 */
fnm391fc2be2002-06-25 16:37:52 +0000286 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000287 struct ethertypeent *ent;
288
fnm391fc2be2002-06-25 16:37:52 +0000289 printf ("--%s %s",
290 opts[VLAN_ENCAP].name, INV_FLAG (EBT_VLAN_ENCAP));
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000291 ent = getethertypebynumber(ntohs(vlaninfo->encap));
292 if (!ent)
fnm391fc2be2002-06-25 16:37:52 +0000293 printf ("%2.4X ", ntohs (vlaninfo->encap));
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000294 else
295 printf ("%s ", ent->e_name);
fnm3f794d5a2002-06-14 17:28:13 +0000296 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000297}
298
299
300static int
301compare (const struct ebt_entry_match *vlan1,
302 const struct ebt_entry_match *vlan2)
303{
304 struct ebt_vlan_info *vlaninfo1 =
305 (struct ebt_vlan_info *) vlan1->data;
306 struct ebt_vlan_info *vlaninfo2 =
307 (struct ebt_vlan_info *) vlan2->data;
308 /*
309 * Compare argc
310 */
311 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
312 return 0;
313 /*
314 * Compare inv flags
315 */
316 if (vlaninfo1->invflags != vlaninfo2->invflags)
317 return 0;
318 /*
319 * Compare VLAN ID if they are present
320 */
321 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
322 if (vlaninfo1->id != vlaninfo2->id)
323 return 0;
324 };
325 /*
326 * Compare VLAN Prio if they are present
327 */
328 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
329 if (vlaninfo1->prio != vlaninfo2->prio)
330 return 0;
331 };
fnm3f794d5a2002-06-14 17:28:13 +0000332 /*
333 * Compare VLAN Encap if they are present
334 */
335 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
336 if (vlaninfo1->encap != vlaninfo2->encap)
337 return 0;
338 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339 return 1;
340}
341
342static struct ebt_u_match vlan_match = {
343 EBT_VLAN_MATCH,
344 sizeof (struct ebt_vlan_info),
345 print_help,
346 init,
347 parse,
348 final_check,
349 print,
350 compare,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000351 opts
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000352};
353
354static void _init (void) __attribute__ ((constructor));
355static void _init (void)
356{
357 register_match (&vlan_match);
358}