blob: 6714c82d4d1acf056d7cc7a7b2143779fc134fcd [file] [log] [blame]
Bart De Schuymerff587202005-02-08 20:02:28 +00001/* ebt_vlan
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00002 *
3 * Authors:
Bart De Schuymerff587202005-02-08 20:02:28 +00004 * Bart De Schuymer <bdschuym@pandora.be>
fnm3f794d5a2002-06-14 17:28:13 +00005 * Nick Fedchik <nick@fedchik.org.ua>
Bart De Schuymerff587202005-02-08 20:02:28 +00006 *
fnm3f794d5a2002-06-14 17:28:13 +00007 * June, 2002
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00008 */
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +00009
fnm3f794d5a2002-06-14 17:28:13 +000010#include <stdio.h>
11#include <stdlib.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000012#include <string.h>
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000013#include <getopt.h>
fnm38e011e62002-11-21 10:32:04 +000014#include <ctype.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000015#include "../include/ebtables_u.h"
Bart De Schuymerc1939b12002-11-20 19:41:54 +000016#include "../include/ethernetdb.h"
Bart De Schuymere4b1fdf2002-06-16 09:20:22 +000017#include <linux/netfilter_bridge/ebt_vlan.h>
fnm38e011e62002-11-21 10:32:04 +000018#include <linux/if_ether.h>
19
fnm38e011e62002-11-21 10:32:04 +000020#define NAME_VLAN_ID "id"
21#define NAME_VLAN_PRIO "prio"
22#define NAME_VLAN_ENCAP "encap"
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000023
Bart De Schuymerff587202005-02-08 20:02:28 +000024#define VLAN_ID '1'
25#define VLAN_PRIO '2'
26#define VLAN_ENCAP '3'
fnm38e011e62002-11-21 10:32:04 +000027
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000028static struct option opts[] = {
Bart De Schuymerff587202005-02-08 20:02:28 +000029 {"vlan-id" , required_argument, NULL, VLAN_ID},
30 {"vlan-prio" , required_argument, NULL, VLAN_PRIO},
31 {"vlan-encap", required_argument, NULL, VLAN_ENCAP},
32 { 0 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000033};
34
fnm38e011e62002-11-21 10:32:04 +000035/*
36 * option inverse flags definition
37 */
38#define OPT_VLAN_ID 0x01
39#define OPT_VLAN_PRIO 0x02
40#define OPT_VLAN_ENCAP 0x04
41#define OPT_VLAN_FLAGS (OPT_VLAN_ID | OPT_VLAN_PRIO | OPT_VLAN_ENCAP)
42
43struct ethertypeent *ethent;
fnm391fc2be2002-06-25 16:37:52 +000044
fnm38e011e62002-11-21 10:32:04 +000045static void print_help()
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000046{
Bart De Schuymerff587202005-02-08 20:02:28 +000047 printf(
48"vlan options:\n"
49"--vlan-id [!] id : vlan-tagged frame identifier, 0,1-4096 (integer)\n"
50"--vlan-prio [!] prio : Priority-tagged frame's user priority, 0-7 (integer)\n"
51"--vlan-encap [!] encap : Encapsulated frame protocol (hexadecimal or name)\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000052}
53
fnm38e011e62002-11-21 10:32:04 +000054static void init(struct ebt_entry_match *match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000055{
Bart De Schuymerff587202005-02-08 20:02:28 +000056 struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 vlaninfo->invflags = 0;
58 vlaninfo->bitmask = 0;
59}
60
Bart De Schuymer2f0d7482003-06-04 06:23:49 +000061
Bart De Schuymerff587202005-02-08 20:02:28 +000062static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
63 unsigned int *flags, struct ebt_entry_match **match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000064{
Bart De Schuymerff587202005-02-08 20:02:28 +000065 struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000066 char *end;
fnm38e011e62002-11-21 10:32:04 +000067 struct ebt_vlan_info local;
68
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000069 switch (c) {
70 case VLAN_ID:
Bart De Schuymerff587202005-02-08 20:02:28 +000071 ebt_check_option2(flags, OPT_VLAN_ID);
72 if (ebt_check_inverse2(optarg))
73 vlaninfo->invflags |= EBT_VLAN_ID;
74 local.id = strtoul(optarg, &end, 10);
75 if (local.id > 4094 || *end != '\0')
76 ebt_print_error2("Invalid --vlan-id range ('%s')", optarg);
fnm38e011e62002-11-21 10:32:04 +000077 vlaninfo->id = local.id;
Bart De Schuymerff587202005-02-08 20:02:28 +000078 vlaninfo->bitmask |= EBT_VLAN_ID;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000079 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080 case VLAN_PRIO:
Bart De Schuymerff587202005-02-08 20:02:28 +000081 ebt_check_option2(flags, OPT_VLAN_PRIO);
82 if (ebt_check_inverse2(optarg))
83 vlaninfo->invflags |= EBT_VLAN_PRIO;
84 local.prio = strtoul(optarg, &end, 10);
85 if (local.prio >= 8 || *end != '\0')
86 ebt_print_error2("Invalid --vlan-prio range ('%s')", optarg);
fnm38e011e62002-11-21 10:32:04 +000087 vlaninfo->prio = local.prio;
Bart De Schuymerff587202005-02-08 20:02:28 +000088 vlaninfo->bitmask |= EBT_VLAN_PRIO;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000089 break;
fnm3f794d5a2002-06-14 17:28:13 +000090 case VLAN_ENCAP:
Bart De Schuymerff587202005-02-08 20:02:28 +000091 ebt_check_option2(flags, OPT_VLAN_ENCAP);
92 if (ebt_check_inverse2(optarg))
93 vlaninfo->invflags |= EBT_VLAN_ENCAP;
94 local.encap = strtoul(optarg, &end, 16);
Bart De Schuymerc1939b12002-11-20 19:41:54 +000095 if (*end != '\0') {
Bart De Schuymerff587202005-02-08 20:02:28 +000096 ethent = getethertypebyname(optarg);
fnm38e011e62002-11-21 10:32:04 +000097 if (ethent == NULL)
Bart De Schuymerff587202005-02-08 20:02:28 +000098 ebt_print_error("Unknown --vlan-encap value ('%s')", optarg);
fnm38e011e62002-11-21 10:32:04 +000099 local.encap = ethent->e_ethertype;
Bart De Schuymerc1939b12002-11-20 19:41:54 +0000100 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000101 if (local.encap < ETH_ZLEN)
102 ebt_print_error2("Invalid --vlan-encap range ('%s')", optarg);
fnm38e011e62002-11-21 10:32:04 +0000103 vlaninfo->encap = htons(local.encap);
Bart De Schuymerff587202005-02-08 20:02:28 +0000104 vlaninfo->bitmask |= EBT_VLAN_ENCAP;
fnm3f794d5a2002-06-14 17:28:13 +0000105 break;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000106 default:
107 return 0;
fnm38e011e62002-11-21 10:32:04 +0000108
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109 }
110 return 1;
111}
112
Bart De Schuymerff587202005-02-08 20:02:28 +0000113static void final_check(const struct ebt_u_entry *entry,
114 const struct ebt_entry_match *match,
115 const char *name, unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000116{
fnm38e011e62002-11-21 10:32:04 +0000117 if (entry->ethproto != ETH_P_8021Q || entry->invflags & EBT_IPROTO)
Bart De Schuymerff587202005-02-08 20:02:28 +0000118 ebt_print_error("For vlan filtering the protocol must be specified as 802_1Q");
fnm3cd338272002-11-09 13:27:31 +0000119
Bart De Schuymerff587202005-02-08 20:02:28 +0000120 /* Check if specified vlan-id=0 (priority-tagged frame condition)
121 * when vlan-prio was specified. */
122 /* I see no reason why a user should be prohibited to match on a perhaps impossible situation <BDS>
123 if (vlaninfo->bitmask & EBT_VLAN_PRIO &&
124 vlaninfo->id && vlaninfo->bitmask & EBT_VLAN_ID)
125 ebt_print_error("When setting --vlan-prio the specified --vlan-id must be 0");*/
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000126}
127
Bart De Schuymerff587202005-02-08 20:02:28 +0000128static void print(const struct ebt_u_entry *entry,
129 const struct ebt_entry_match *match)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000130{
Bart De Schuymerff587202005-02-08 20:02:28 +0000131 struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000132
Bart De Schuymerff587202005-02-08 20:02:28 +0000133 if (vlaninfo->bitmask & EBT_VLAN_ID) {
134 printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000136 if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
137 printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000138 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000139 if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
140 printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : "");
fnm38e011e62002-11-21 10:32:04 +0000141 ethent = getethertypebynumber(ntohs(vlaninfo->encap));
142 if (ethent != NULL) {
143 printf("%s ", ethent->e_name);
144 } else {
145 printf("%4.4X ", ntohs(vlaninfo->encap));
146 }
fnm3f794d5a2002-06-14 17:28:13 +0000147 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148}
149
Bart De Schuymerff587202005-02-08 20:02:28 +0000150static int compare(const struct ebt_entry_match *vlan1,
151 const struct ebt_entry_match *vlan2)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000152{
Bart De Schuymerff587202005-02-08 20:02:28 +0000153 struct ebt_vlan_info *vlaninfo1 = (struct ebt_vlan_info *) vlan1->data;
154 struct ebt_vlan_info *vlaninfo2 = (struct ebt_vlan_info *) vlan2->data;
155
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000156 if (vlaninfo1->bitmask != vlaninfo2->bitmask)
157 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000158 if (vlaninfo1->invflags != vlaninfo2->invflags)
159 return 0;
Bart De Schuymerff587202005-02-08 20:02:28 +0000160 if (vlaninfo1->bitmask & EBT_VLAN_ID &&
161 vlaninfo1->id != vlaninfo2->id)
162 return 0;
163 if (vlaninfo1->bitmask & EBT_VLAN_PRIO &&
164 vlaninfo1->prio != vlaninfo2->prio)
165 return 0;
166 if (vlaninfo1->bitmask & EBT_VLAN_ENCAP &&
167 vlaninfo1->encap != vlaninfo2->encap)
168 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000169 return 1;
170}
171
172static struct ebt_u_match vlan_match = {
Bart De Schuymerfbdebad2008-02-03 19:58:44 +0000173 .name = "vlan",
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000174 .size = sizeof(struct ebt_vlan_info),
175 .help = print_help,
176 .init = init,
177 .parse = parse,
178 .final_check = final_check,
179 .print = print,
180 .compare = compare,
181 .extra_ops = opts,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000182};
183
Bart De Schuymer64182a32004-01-21 20:39:54 +0000184void _init(void)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000185{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000186 ebt_register_match(&vlan_match);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000187}