/* * 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 * Nick Fedchik * June, 2002 * * License: GPL * */ #include #include #include #include #include #include #include "../include/ebtables_u.h" #include #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_mask, unsigned int time) { /* * 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); }