blob: 580fa71188eb5a4931b771f3bf4a4dcbeff65f5e [file] [log] [blame]
/*
* Summary: ebt_vlan - 802.1 Q match extension module for userspace
*
* Description:802.1 Q Virtual LAN match support module for ebtables project.
* Enable to match 802.1 Q VLAN tagged frames by VLAN numeric
* identifier (12 - bits field) and user_priority (3 bits field)
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
* Nick Fedchik <nick@fedchik.org.ua>
* June, 2002
*
* License: GPL
*
*/
#include <getopt.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netfilter_bridge/ebtables.h>
#include "../include/ebtables_u.h"
#define VLAN_ID '1'
#define VLAN_PRIO '2'
#define VLAN_ENCAP '3'
static struct option opts[] = {
{"vlan-id", required_argument, 0, VLAN_ID},
{"vlan-prio", required_argument, 0, VLAN_PRIO},
{"vlan-encap", required_argument, 0, VLAN_ENCAP},
{0}
};
/*
* Print out local help by ebtables -h vlan
*/
static void print_help ()
{
printf ("802.1Q VLAN options:\n"
"--vlan-id [!] id : VLAN ID 1-4094 (integer)\n"
"--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n"
"--vlan-encap [!] proto : VLAN Encapsulated Protocol (integer or string as in /etc/ethertypes)\n");
}
/*
* Initialization function
*/
static void init (struct ebt_entry_match *match)
{
struct ebt_vlan_info *vlaninfo =
(struct ebt_vlan_info *) match->data;
/*
* Just clean initial values
*/
vlaninfo->id = 0;
vlaninfo->prio = 0;
vlaninfo->encap = 0;
vlaninfo->invflags = 0;
vlaninfo->bitmask = 0;
}
/*
* option flags definition
*/
#define OPT_VLAN_ID 0x01
#define OPT_VLAN_PRIO 0x02
#define OPT_VLAN_ENCAP 0x04
static int
parse (int c, char **argv, int argc,
const struct ebt_u_entry *entry, unsigned int *flags,
struct ebt_entry_match **match)
{
struct ebt_vlan_info *vlaninfo =
(struct ebt_vlan_info *) (*match)->data;
unsigned long i;
char *end;
switch (c) {
case VLAN_ID:
/*
* ebtables.c:check_option(unsigned int *flags, unsigned int mask)
* checking for multiple usage of same option
*/
check_option (flags, OPT_VLAN_ID);
/*
* Check If we got inversed arg for vlan-id option,
* otherwise unset inversion flag
*/
if (check_inverse (optarg))
vlaninfo->invflags |= EBT_VLAN_ID;
/*
* Check arg value presence
*/
if (optind > argc)
print_error ("Missing VLAN ID argument\n");
/*
* Convert argv to long int,
* set *end to end of argv string,
* base set 10 for decimal only
*/
(unsigned short) i = strtol (argv[optind - 1], &end, 10);
/*
* Check arg val range
*/
if (i < 1 || i >= 4094 || *end != '\0') {
i = 0;
print_error
("Problem with specified VLAN ID range\n");
}
/*
* Set up parameter value
*/
vlaninfo->id = i;
/*
* Set up parameter presence flag
*/
vlaninfo->bitmask |= EBT_VLAN_ID;
break;
case VLAN_PRIO:
check_option (flags, OPT_VLAN_PRIO);
if (check_inverse (optarg))
vlaninfo->invflags |= EBT_VLAN_PRIO;
if (optind > argc)
print_error
("Missing VLAN Priority level argument\n");
/*
* Convert argv to long int,
* set *end to end of argv string,
* base set 10 for decimal only
*/
(unsigned char) i = strtol (argv[optind - 1], &end, 10);
/*
* Check arg val range
*/
if (i >= 8 || *end != '\0') {
i = 0;
print_error
("Problem with specified VLAN Priority range\n");
}
/*
* Set up parameter value
*/
vlaninfo->prio = i;
/*
* Set up parameter presence flag
*/
vlaninfo->bitmask |= EBT_VLAN_PRIO;
break;
case VLAN_ENCAP:
check_option (flags, OPT_VLAN_ENCAP);
if (check_inverse (optarg))
vlaninfo->invflags |= EBT_VLAN_ENCAP;
if (optind > argc)
print_error
("Missing VLAN Encapsulated Protocol argument\n");
/*
* Parameter can be decimal, hexadecimal, or string.
* Check arg val range
*/
(unsigned short) i = strtol (argv[optind - 1], &end, 16);
if (*end == '\0' && (i < 0 || i > 0xFFFF))
print_error
("Problem with the specified encapsulated protocol");
if (*end != '\0')
if (name_to_protocol (argv[optind - 1]) == -1)
print_error
("Problem with the specified encapsulated"
"protocol");
/*
* Set up parameter value (network notation)
*/
vlaninfo->encap = htons (i);
/*
* Set up parameter presence flag
*/
vlaninfo->bitmask |= EBT_VLAN_ENCAP;
break;
default:
return 0;
}
return 1;
}
/*
* Final check
*/
static void
final_check (const struct ebt_u_entry *entry,
const struct ebt_entry_match *match,
const char *name, unsigned int hook)
{
/*
* Is any proto supplied there? Or specified proto isn't 802.1Q?
*/
if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q)
print_error
("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n");
}
/*
* Print line when listing rules by ebtables -L
*/
static void
print (const struct ebt_u_entry *entry,
const struct ebt_entry_match *match)
{
struct ebt_vlan_info *vlaninfo =
(struct ebt_vlan_info *) match->data;
/*
* Print VLAN ID if they are specified
*/
if (vlaninfo->bitmask & EBT_VLAN_ID) {
printf ("vlan id: %s%d, ",
vlaninfo->invflags & EBT_VLAN_ID ? "!" : "",
vlaninfo->id);
}
/*
* Print VLAN priority if they are specified
*/
if (vlaninfo->bitmask & EBT_VLAN_PRIO) {
printf ("vlan prio: %s%d, ",
vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "",
vlaninfo->prio);
}
/*
* Print VLAN encapsulated protocol if they are specified
*/
if (vlaninfo->bitmask & EBT_VLAN_ENCAP) {
printf ("vlan encap: %s%2.4X, ",
vlaninfo->invflags & EBT_VLAN_ENCAP ? "!" : "",
ntohs (vlaninfo->encap));
}
}
static int
compare (const struct ebt_entry_match *vlan1,
const struct ebt_entry_match *vlan2)
{
struct ebt_vlan_info *vlaninfo1 =
(struct ebt_vlan_info *) vlan1->data;
struct ebt_vlan_info *vlaninfo2 =
(struct ebt_vlan_info *) vlan2->data;
/*
* Compare argc
*/
if (vlaninfo1->bitmask != vlaninfo2->bitmask)
return 0;
/*
* Compare inv flags
*/
if (vlaninfo1->invflags != vlaninfo2->invflags)
return 0;
/*
* Compare VLAN ID if they are present
*/
if (vlaninfo1->bitmask & EBT_VLAN_ID) {
if (vlaninfo1->id != vlaninfo2->id)
return 0;
};
/*
* Compare VLAN Prio if they are present
*/
if (vlaninfo1->bitmask & EBT_VLAN_PRIO) {
if (vlaninfo1->prio != vlaninfo2->prio)
return 0;
};
/*
* Compare VLAN Encap if they are present
*/
if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) {
if (vlaninfo1->encap != vlaninfo2->encap)
return 0;
};
return 1;
}
static struct ebt_u_match vlan_match = {
EBT_VLAN_MATCH,
sizeof (struct ebt_vlan_info),
print_help,
init,
parse,
final_check,
print,
compare,
opts,
};
static void _init (void) __attribute__ ((constructor));
static void _init (void)
{
register_match (&vlan_match);
}