blob: 06708da5cdfeda5927edf55f3ea111b8710fec55 [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>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000022#include <getopt.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000023#include "../include/ebtables_u.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000024#include <linux/netfilter_bridge/ebt_vlan.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000025
26#define VLAN_ID '1'
27#define VLAN_PRIO '2'
fnm3f794d5a2002-06-14 17:28:13 +000028#define VLAN_ENCAP '3'
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000029
30static struct option opts[] = {
31 {"vlan-id", required_argument, 0, VLAN_ID},
32 {"vlan-prio", required_argument, 0, VLAN_PRIO},
fnm3f794d5a2002-06-14 17:28:13 +000033 {"vlan-encap", required_argument, 0, VLAN_ENCAP},
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034 {0}
35};
36
37/*
fnm3f794d5a2002-06-14 17:28:13 +000038 * Print out local help by ebtables -h vlan
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000039 */
40static void print_help ()
41{
42 printf ("802.1Q VLAN options:\n"
fnm3f794d5a2002-06-14 17:28:13 +000043 "--vlan-id [!] id : VLAN ID 1-4094 (integer)\n"
44 "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n"
45 "--vlan-encap [!] proto : VLAN Encapsulated Protocol (integer or string as in /etc/ethertypes)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000046}
47
48/*
49 * Initialization function
50 */
51static void init (struct ebt_entry_match *match)
52{
53 struct ebt_vlan_info *vlaninfo =
54 (struct ebt_vlan_info *) match->data;
55 /*
56 * Just clean initial values
57 */
58 vlaninfo->id = 0;
59 vlaninfo->prio = 0;
fnm3f794d5a2002-06-14 17:28:13 +000060 vlaninfo->encap = 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000061 vlaninfo->invflags = 0;
62 vlaninfo->bitmask = 0;
63}
64
fnm3f794d5a2002-06-14 17:28:13 +000065/*
66 * option flags definition
67 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000068#define OPT_VLAN_ID 0x01
69#define OPT_VLAN_PRIO 0x02
fnm3f794d5a2002-06-14 17:28:13 +000070#define OPT_VLAN_ENCAP 0x04
71
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000072static int
73parse (int c, char **argv, int argc,
74 const struct ebt_u_entry *entry, unsigned int *flags,
75 struct ebt_entry_match **match)
76{
77 struct ebt_vlan_info *vlaninfo =
78 (struct ebt_vlan_info *) (*match)->data;
fnm3f794d5a2002-06-14 17:28:13 +000079 unsigned long i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 char *end;
81
82 switch (c) {
83 case VLAN_ID:
fnm3f794d5a2002-06-14 17:28:13 +000084 /*
85 * ebtables.c:check_option(unsigned int *flags, unsigned int mask)
86 * checking for multiple usage of same option
87 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000088 check_option (flags, OPT_VLAN_ID);
89 /*
fnm3f794d5a2002-06-14 17:28:13 +000090 * Check If we got inversed arg for vlan-id option,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000091 * otherwise unset inversion flag
92 */
93 if (check_inverse (optarg))
94 vlaninfo->invflags |= EBT_VLAN_ID;
95 /*
fnm3f794d5a2002-06-14 17:28:13 +000096 * Check arg value presence
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000097 */
98 if (optind > argc)
99 print_error ("Missing VLAN ID argument\n");
100 /*
101 * Convert argv to long int,
102 * set *end to end of argv string,
103 * base set 10 for decimal only
104 */
105 (unsigned short) i = strtol (argv[optind - 1], &end, 10);
106 /*
fnm3f794d5a2002-06-14 17:28:13 +0000107 * Check arg val range
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 */
fnm3f794d5a2002-06-14 17:28:13 +0000109 if (i < 1 || i >= 4094 || *end != '\0') {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000110 i = 0;
111 print_error
112 ("Problem with specified VLAN ID range\n");
113 }
fnm3f794d5a2002-06-14 17:28:13 +0000114 /*
115 * Set up parameter value
116 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000117 vlaninfo->id = i;
fnm3f794d5a2002-06-14 17:28:13 +0000118 /*
119 * Set up parameter presence flag
120 */
121 vlaninfo->bitmask |= EBT_VLAN_ID;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000122 break;
123
124 case VLAN_PRIO:
125 check_option (flags, OPT_VLAN_PRIO);
126 if (check_inverse (optarg))
127 vlaninfo->invflags |= EBT_VLAN_PRIO;
128 if (optind > argc)
129 print_error
130 ("Missing VLAN Priority level argument\n");
131 /*
132 * Convert argv to long int,
133 * set *end to end of argv string,
134 * base set 10 for decimal only
135 */
fnm3f794d5a2002-06-14 17:28:13 +0000136 (unsigned char) i = strtol (argv[optind - 1], &end, 10);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137 /*
138 * Check arg val range
139 */
140 if (i >= 8 || *end != '\0') {
141 i = 0;
142 print_error
143 ("Problem with specified VLAN Priority range\n");
144 }
fnm3f794d5a2002-06-14 17:28:13 +0000145 /*
146 * Set up parameter value
147 */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148 vlaninfo->prio = i;
fnm3f794d5a2002-06-14 17:28:13 +0000149 /*
150 * Set up parameter presence flag
151 */
152 vlaninfo->bitmask |= EBT_VLAN_PRIO;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000153 break;
154
fnm3f794d5a2002-06-14 17:28:13 +0000155 case VLAN_ENCAP:
156 check_option (flags, OPT_VLAN_ENCAP);
157 if (check_inverse (optarg))
158 vlaninfo->invflags |= EBT_VLAN_ENCAP;
159 if (optind > argc)
160 print_error
161 ("Missing VLAN Encapsulated Protocol argument\n");
162 /*
163 * Parameter can be decimal, hexadecimal, or string.
164 * Check arg val range
165 */
166 (unsigned short) i = strtol (argv[optind - 1], &end, 16);
167 if (*end == '\0' && (i < 0 || i > 0xFFFF))
168 print_error
169 ("Problem with the specified encapsulated protocol");
170 if (*end != '\0')
171 if (name_to_protocol (argv[optind - 1]) == -1)
172 print_error
173 ("Problem with the specified encapsulated"
174 "protocol");
175 /*
176 * Set up parameter value (network notation)
177 */
178 vlaninfo->encap = htons (i);
179 /*
180 * Set up parameter presence flag
181 */
182 vlaninfo->bitmask |= EBT_VLAN_ENCAP;
183 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000184 default:
185 return 0;
186 }
187 return 1;
188}
189
190/*
191 * Final check
192 */
193static void
194final_check (const struct ebt_u_entry *entry,
195 const struct ebt_entry_match *match,
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000196 const char *name, unsigned int hook_mask)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000197{
198 /*
199 * Is any proto supplied there? Or specified proto isn't 802.1Q?
200 */
201 if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
202 print_error
203 ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n");
204}
205
206/*
207 * Print line when listing rules by ebtables -L
208 */
209static void
210print (const struct ebt_u_entry *entry,
211 const struct ebt_entry_match *match)
212{
213 struct ebt_vlan_info *vlaninfo =
214 (struct ebt_vlan_info *) match->data;
215
216 /*
217 * Print VLAN ID if they are specified
218 */
219 if (vlaninfo->bitmask & EBT_VLAN_ID) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000220 printf ("--vlan-id %s %d, ",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000221 vlaninfo->invflags & EBT_VLAN_ID ? "!" : "",
222 vlaninfo->id);
223 }
224 /*
225 * Print VLAN priority if they are specified
226 */
227 if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000228 printf ("--vlan-prio %s %d, ",
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000229 vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "",
230 vlaninfo->prio);
231 }
fnm3f794d5a2002-06-14 17:28:13 +0000232 /*
233 * Print VLAN encapsulated protocol if they are specified
234 */
235 if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000236 printf ("--vlan-encap %s %2.4X, ",
fnm3f794d5a2002-06-14 17:28:13 +0000237 vlaninfo->invflags & EBT_VLAN_ENCAP ? "!" : "",
238 ntohs (vlaninfo->encap));
239 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000240}
241
242
243static int
244compare (const struct ebt_entry_match *vlan1,
245 const struct ebt_entry_match *vlan2)
246{
247 struct ebt_vlan_info *vlaninfo1 =
248 (struct ebt_vlan_info *) vlan1->data;
249 struct ebt_vlan_info *vlaninfo2 =
250 (struct ebt_vlan_info *) vlan2->data;
251 /*
252 * Compare argc
253 */
254 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
255 return 0;
256 /*
257 * Compare inv flags
258 */
259 if (vlaninfo1->invflags != vlaninfo2->invflags)
260 return 0;
261 /*
262 * Compare VLAN ID if they are present
263 */
264 if (vlaninfo1->bitmask & EBT_VLAN_ID) {
265 if (vlaninfo1->id != vlaninfo2->id)
266 return 0;
267 };
268 /*
269 * Compare VLAN Prio if they are present
270 */
271 if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
272 if (vlaninfo1->prio != vlaninfo2->prio)
273 return 0;
274 };
fnm3f794d5a2002-06-14 17:28:13 +0000275 /*
276 * Compare VLAN Encap if they are present
277 */
278 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
279 if (vlaninfo1->encap != vlaninfo2->encap)
280 return 0;
281 };
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000282 return 1;
283}
284
285static struct ebt_u_match vlan_match = {
286 EBT_VLAN_MATCH,
287 sizeof (struct ebt_vlan_info),
288 print_help,
289 init,
290 parse,
291 final_check,
292 print,
293 compare,
294 opts,
295};
296
297static void _init (void) __attribute__ ((constructor));
298static void _init (void)
299{
300 register_match (&vlan_match);
301}