blob: 76077cb248219faec5fc625526e8e8f865442a7c [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>
fnm3f794d5a2002-06-14 17:28:13 +000035#include <sys/socket.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000036#include <netinet/in.h>
37#include <string.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000038#include <getopt.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000039#include "../include/ebtables_u.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000040#include <linux/netfilter_bridge/ebt_vlan.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000041
fnm391fc2be2002-06-25 16:37:52 +000042#define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_
43#define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000044#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "! " : ""
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000045
fnm391fc2be2002-06-25 16:37:52 +000046#define VLAN_ID 0
47#define VLAN_PRIO 1
48#define VLAN_ENCAP 2
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049static struct option opts[] = {
fnm391fc2be2002-06-25 16:37:52 +000050 {"vlan-id", required_argument, NULL, VLAN_ID},
51 {"vlan-prio", required_argument, NULL, VLAN_PRIO},
52 {"vlan-encap", required_argument, NULL, VLAN_ENCAP},
53 {NULL}
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000054};
55
fnm391fc2be2002-06-25 16:37:52 +000056
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057/*
fnm391fc2be2002-06-25 16:37:52 +000058 * Print out local help by "ebtables -h vlan"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000059 */
60static void print_help ()
61{
fnm391fc2be2002-06-25 16:37:52 +000062 printf ("802.1Q VLAN extension options:\n"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +000063 "--vlan-id [!] id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n"
64 "--vlan-prio [!] prio : Priority-tagged frame user_priority, 0-7 (integer)\n"
65 "--vlan-encap [!] proto : Encapsulated protocol (hexadecimal)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000066}
67
68/*
69 * Initialization function
70 */
71static void init (struct ebt_entry_match *match)
72{
73 struct ebt_vlan_info *vlaninfo =
74 (struct ebt_vlan_info *) match->data;
75 /*
fnm391fc2be2002-06-25 16:37:52 +000076 * Set initial values
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000077 */
fnm391fc2be2002-06-25 16:37:52 +000078 vlaninfo->id = 1; /* Default VID for VLAN-tagged 802.1Q frames */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079 vlaninfo->prio = 0;
fnm3f794d5a2002-06-14 17:28:13 +000080 vlaninfo->encap = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000081 vlaninfo->invflags = 0;
82 vlaninfo->bitmask = 0;
83}
84
fnm3f794d5a2002-06-14 17:28:13 +000085/*
86 * option flags definition
87 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000088#define OPT_VLAN_ID 0x01
89#define OPT_VLAN_PRIO 0x02
fnm3f794d5a2002-06-14 17:28:13 +000090#define OPT_VLAN_ENCAP 0x04
91
fnm391fc2be2002-06-25 16:37:52 +000092/*
93 * Parse passed arguments values (ranges, flags, etc...)
94 * int c - parameter number from static struct option opts[]
95 * int argc - total amout of arguments (std argc value)
96 *
97 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000098static int
fnm391fc2be2002-06-25 16:37:52 +000099parse (int c,
100 char **argv,
101 int argc,
102 const struct ebt_u_entry *entry,
103 unsigned int *flags, struct ebt_entry_match **match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000104{
105 struct ebt_vlan_info *vlaninfo =
106 (struct ebt_vlan_info *) (*match)->data;
fnm3f794d5a2002-06-14 17:28:13 +0000107 unsigned long i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 char *end;
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000109 __u16 encap;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000110 switch (c) {
111 case VLAN_ID:
fnm3f794d5a2002-06-14 17:28:13 +0000112 /*
113 * ebtables.c:check_option(unsigned int *flags, unsigned int mask)
114 * checking for multiple usage of same option
115 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116 check_option (flags, OPT_VLAN_ID);
117 /*
fnm3f794d5a2002-06-14 17:28:13 +0000118 * Check If we got inversed arg for vlan-id option,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000119 * otherwise unset inversion flag
120 */
121 if (check_inverse (optarg))
122 vlaninfo->invflags |= EBT_VLAN_ID;
123 /*
fnm3f794d5a2002-06-14 17:28:13 +0000124 * Check arg value presence
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125 */
126 if (optind > argc)
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000127 print_error ("Missing VLAN ID argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000128 /*
129 * Convert argv to long int,
130 * set *end to end of argv string,
131 * base set 10 for decimal only
132 */
133 (unsigned short) i = strtol (argv[optind - 1], &end, 10);
134 /*
fnm3f794d5a2002-06-14 17:28:13 +0000135 * Check arg val range
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000136 */
fnm391fc2be2002-06-25 16:37:52 +0000137 if (i > 4094 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000138 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000139 ("Specified VLAN ID is out of range (0-4094)");
fnm3f794d5a2002-06-14 17:28:13 +0000140 /*
fnm391fc2be2002-06-25 16:37:52 +0000141 * Set up parameter value
fnm3f794d5a2002-06-14 17:28:13 +0000142 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143 vlaninfo->id = i;
fnm3f794d5a2002-06-14 17:28:13 +0000144 /*
145 * Set up parameter presence flag
146 */
fnm391fc2be2002-06-25 16:37:52 +0000147 SET_BITMASK (EBT_VLAN_ID);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148 break;
149
150 case VLAN_PRIO:
151 check_option (flags, OPT_VLAN_PRIO);
152 if (check_inverse (optarg))
153 vlaninfo->invflags |= EBT_VLAN_PRIO;
154 if (optind > argc)
155 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000156 ("Missing user_priority argument value");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000157 /*
158 * Convert argv to long int,
159 * set *end to end of argv string,
160 * base set 10 for decimal only
161 */
fnm3f794d5a2002-06-14 17:28:13 +0000162 (unsigned char) i = strtol (argv[optind - 1], &end, 10);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000163 /*
164 * Check arg val range
165 */
fnm391fc2be2002-06-25 16:37:52 +0000166 if (i >= 8 || *end != '\0')
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000167 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000168 ("Specified user_priority is out of range (0-7)");
fnm3f794d5a2002-06-14 17:28:13 +0000169 /*
170 * Set up parameter value
171 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000172 vlaninfo->prio = i;
fnm3f794d5a2002-06-14 17:28:13 +0000173 /*
174 * Set up parameter presence flag
175 */
fnm391fc2be2002-06-25 16:37:52 +0000176 SET_BITMASK (EBT_VLAN_PRIO);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000177 break;
178
fnm3f794d5a2002-06-14 17:28:13 +0000179 case VLAN_ENCAP:
180 check_option (flags, OPT_VLAN_ENCAP);
181 if (check_inverse (optarg))
182 vlaninfo->invflags |= EBT_VLAN_ENCAP;
183 if (optind > argc)
184 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000185 ("Missing encapsulated frame type argument value");
fnm3f794d5a2002-06-14 17:28:13 +0000186 /*
187 * Parameter can be decimal, hexadecimal, or string.
fnm391fc2be2002-06-25 16:37:52 +0000188 * Check arg val range (still raw area)
fnm3f794d5a2002-06-14 17:28:13 +0000189 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000190 (unsigned short) encap = strtol (argv[optind - 1], &end, 16);
191 if (*end == '\0' && (encap < ETH_ZLEN || encap > 0xFFFF))
fnm3f794d5a2002-06-14 17:28:13 +0000192 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000193 ("Specified encapsulated frame type is out of range");
fnm3f794d5a2002-06-14 17:28:13 +0000194 if (*end != '\0')
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000195 if (name_to_number (argv[optind - 1], &encap) == -1)
fnm3f794d5a2002-06-14 17:28:13 +0000196 print_error
197 ("Problem with the specified encapsulated"
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000198 "protocol");
fnm3f794d5a2002-06-14 17:28:13 +0000199 /*
200 * Set up parameter value (network notation)
201 */
Bart De Schuymer4e0ea922002-06-26 18:58:17 +0000202 vlaninfo->encap = htons (encap);
fnm3f794d5a2002-06-14 17:28:13 +0000203 /*
204 * Set up parameter presence flag
205 */
fnm391fc2be2002-06-25 16:37:52 +0000206 SET_BITMASK (EBT_VLAN_ENCAP);
fnm3f794d5a2002-06-14 17:28:13 +0000207 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000208 default:
209 return 0;
210 }
211 return 1;
212}
213
214/*
fnm391fc2be2002-06-25 16:37:52 +0000215 * Final check - logical conditions
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000216 */
217static void
218final_check (const struct ebt_u_entry *entry,
219 const struct ebt_entry_match *match,
fnm391fc2be2002-06-25 16:37:52 +0000220 const char *name, unsigned int hook, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000221{
fnm391fc2be2002-06-25 16:37:52 +0000222
223 struct ebt_vlan_info *vlaninfo =
224 (struct ebt_vlan_info *) match->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225 /*
fnm391fc2be2002-06-25 16:37:52 +0000226 * Is any proto param specified there? Or specified proto isn't 802.1Q?
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000227 */
228 if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
229 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000230 ("For use 802.1Q extension the protocol must be specified as 802_1Q");
fnm391fc2be2002-06-25 16:37:52 +0000231 /*
232 * Check if specified vlan-id=0 (priority-tagged frame condition)
233 * when vlan-prio was specified.
234 */
235 if (GET_BITMASK (EBT_VLAN_PRIO)) {
236 if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID))
237 print_error
Bart De Schuymer2ab59ea2002-07-24 10:14:02 +0000238 ("For use user_priority the specified vlan-id must be 0");
fnm391fc2be2002-06-25 16:37:52 +0000239 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000240}
241
242/*
243 * Print line when listing rules by ebtables -L
244 */
245static void
246print (const struct ebt_u_entry *entry,
247 const struct ebt_entry_match *match)
248{
249 struct ebt_vlan_info *vlaninfo =
250 (struct ebt_vlan_info *) match->data;
251
fnm391fc2be2002-06-25 16:37:52 +0000252 char ethertype_name[21];
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000253 /*
254 * Print VLAN ID if they are specified
255 */
fnm391fc2be2002-06-25 16:37:52 +0000256 if (GET_BITMASK (EBT_VLAN_ID)) {
257 printf ("--%s %s%d ",
258 opts[VLAN_ID].name,
259 INV_FLAG (EBT_VLAN_ID), vlaninfo->id);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260 }
261 /*
fnm391fc2be2002-06-25 16:37:52 +0000262 * Print user priority if they are specified
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 */
fnm391fc2be2002-06-25 16:37:52 +0000264 if (GET_BITMASK (EBT_VLAN_PRIO)) {
265 printf ("--%s %s%d ",
266 opts[VLAN_PRIO].name,
267 INV_FLAG (EBT_VLAN_PRIO), vlaninfo->prio);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000268 }
fnm3f794d5a2002-06-14 17:28:13 +0000269 /*
fnm391fc2be2002-06-25 16:37:52 +0000270 * Print encapsulated frame type if they are specified
fnm3f794d5a2002-06-14 17:28:13 +0000271 */
fnm391fc2be2002-06-25 16:37:52 +0000272 if (GET_BITMASK (EBT_VLAN_ENCAP)) {
273 printf ("--%s %s",
274 opts[VLAN_ENCAP].name, INV_FLAG (EBT_VLAN_ENCAP));
275 bzero (ethertype_name, 21);
276 if (!number_to_name
277 (ntohs (vlaninfo->encap), ethertype_name)) {
278 printf ("%s ", ethertype_name);
279 } else {
280 printf ("%2.4X ", ntohs (vlaninfo->encap));
281 }
fnm3f794d5a2002-06-14 17:28:13 +0000282 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000283}
284
285
286static int
287compare (const struct ebt_entry_match *vlan1,
288 const struct ebt_entry_match *vlan2)
289{
290 struct ebt_vlan_info *vlaninfo1 =
291 (struct ebt_vlan_info *) vlan1->data;
292 struct ebt_vlan_info *vlaninfo2 =
293 (struct ebt_vlan_info *) vlan2->data;
294 /*
295 * Compare argc
296 */
297 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
298 return 0;
299 /*
300 * Compare inv flags
301 */
302 if (vlaninfo1->invflags != vlaninfo2->invflags)
303 return 0;
304 /*
305 * Compare VLAN ID if they are present
306 */
307 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
308 if (vlaninfo1->id != vlaninfo2->id)
309 return 0;
310 };
311 /*
312 * Compare VLAN Prio if they are present
313 */
314 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
315 if (vlaninfo1->prio != vlaninfo2->prio)
316 return 0;
317 };
fnm3f794d5a2002-06-14 17:28:13 +0000318 /*
319 * Compare VLAN Encap if they are present
320 */
321 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
322 if (vlaninfo1->encap != vlaninfo2->encap)
323 return 0;
324 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000325 return 1;
326}
327
328static struct ebt_u_match vlan_match = {
329 EBT_VLAN_MATCH,
330 sizeof (struct ebt_vlan_info),
331 print_help,
332 init,
333 parse,
334 final_check,
335 print,
336 compare,
337 opts,
338};
339
340static void _init (void) __attribute__ ((constructor));
341static void _init (void)
342{
343 register_match (&vlan_match);
344}