1/* 2 * Description: EBTables 802.1Q match extension kernelspace module. 3 * Authors: Nick Fedchik <nick@fedchik.org.ua> 4 * Bart De Schuymer <bdschuym@pandora.be> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21#include <linux/if_ether.h> 22#include <linux/if_vlan.h> 23#include <linux/module.h> 24#include <linux/moduleparam.h> 25#include <linux/netfilter_bridge/ebtables.h> 26#include <linux/netfilter_bridge/ebt_vlan.h> 27 28static int debug; 29#define MODULE_VERS "0.6" 30 31module_param(debug, int, 0); 32MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages"); 33MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>"); 34MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v" 35 MODULE_VERS); 36MODULE_LICENSE("GPL"); 37 38 39#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args) 40#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" 41#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ 42#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ 43#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return EBT_NOMATCH;} 44 45static int 46ebt_filter_vlan(const struct sk_buff *skb, 47 const struct net_device *in, 48 const struct net_device *out, 49 const void *data, unsigned int datalen) 50{ 51 struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; 52 struct vlan_hdr _frame, *fp; 53 54 unsigned short TCI; /* Whole TCI, given from parsed frame */ 55 unsigned short id; /* VLAN ID, given from frame TCI */ 56 unsigned char prio; /* user_priority, given from frame TCI */ 57 /* VLAN encapsulated Type/Length field, given from orig frame */ 58 __be16 encap; 59 60 fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame); 61 if (fp == NULL) 62 return EBT_NOMATCH; 63 64 /* Tag Control Information (TCI) consists of the following elements: 65 * - User_priority. The user_priority field is three bits in length, 66 * interpreted as a binary number. 67 * - Canonical Format Indicator (CFI). The Canonical Format Indicator 68 * (CFI) is a single bit flag value. Currently ignored. 69 * - VLAN Identifier (VID). The VID is encoded as 70 * an unsigned binary number. */ 71 TCI = ntohs(fp->h_vlan_TCI); 72 id = TCI & VLAN_VID_MASK; 73 prio = (TCI >> 13) & 0x7; 74 encap = fp->h_vlan_encapsulated_proto; 75 76 /* Checking VLAN Identifier (VID) */ 77 if (GET_BITMASK(EBT_VLAN_ID)) 78 EXIT_ON_MISMATCH(id, EBT_VLAN_ID); 79 80 /* Checking user_priority */ 81 if (GET_BITMASK(EBT_VLAN_PRIO)) 82 EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO); 83 84 /* Checking Encapsulated Proto (Length/Type) field */ 85 if (GET_BITMASK(EBT_VLAN_ENCAP)) 86 EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP); 87 88 return EBT_MATCH; 89} 90 91static int 92ebt_check_vlan(const char *tablename, 93 unsigned int hooknr, 94 const struct ebt_entry *e, void *data, unsigned int datalen) 95{ 96 struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; 97 98 /* Parameters buffer overflow check */ 99 if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) { 100 DEBUG_MSG 101 ("passed size %d is not eq to ebt_vlan_info (%Zd)\n", 102 datalen, sizeof(struct ebt_vlan_info)); 103 return -EINVAL; 104 } 105 106 /* Is it 802.1Q frame checked? */ 107 if (e->ethproto != htons(ETH_P_8021Q)) { 108 DEBUG_MSG 109 ("passed entry proto %2.4X is not 802.1Q (8100)\n", 110 (unsigned short) ntohs(e->ethproto)); 111 return -EINVAL; 112 } 113 114 /* Check for bitmask range 115 * True if even one bit is out of mask */ 116 if (info->bitmask & ~EBT_VLAN_MASK) { 117 DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", 118 info->bitmask, EBT_VLAN_MASK); 119 return -EINVAL; 120 } 121 122 /* Check for inversion flags range */ 123 if (info->invflags & ~EBT_VLAN_MASK) { 124 DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n", 125 info->invflags, EBT_VLAN_MASK); 126 return -EINVAL; 127 } 128 129 /* Reserved VLAN ID (VID) values 130 * ----------------------------- 131 * 0 - The null VLAN ID. 132 * 1 - The default Port VID (PVID) 133 * 0x0FFF - Reserved for implementation use. 134 * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */ 135 if (GET_BITMASK(EBT_VLAN_ID)) { 136 if (!!info->id) { /* if id!=0 => check vid range */ 137 if (info->id > VLAN_GROUP_ARRAY_LEN) { 138 DEBUG_MSG 139 ("id %d is out of range (1-4096)\n", 140 info->id); 141 return -EINVAL; 142 } 143 /* Note: This is valid VLAN-tagged frame point. 144 * Any value of user_priority are acceptable, 145 * but should be ignored according to 802.1Q Std. 146 * So we just drop the prio flag. */ 147 info->bitmask &= ~EBT_VLAN_PRIO; 148 } 149 /* Else, id=0 (null VLAN ID) => user_priority range (any?) */ 150 } 151 152 if (GET_BITMASK(EBT_VLAN_PRIO)) { 153 if ((unsigned char) info->prio > 7) { 154 DEBUG_MSG("prio %d is out of range (0-7)\n", 155 info->prio); 156 return -EINVAL; 157 } 158 } 159 /* Check for encapsulated proto range - it is possible to be 160 * any value for u_short range. 161 * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS */ 162 if (GET_BITMASK(EBT_VLAN_ENCAP)) { 163 if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) { 164 DEBUG_MSG 165 ("encap frame length %d is less than minimal\n", 166 ntohs(info->encap)); 167 return -EINVAL; 168 } 169 } 170 171 return 0; 172} 173 174static struct ebt_match filter_vlan = { 175 .name = EBT_VLAN_MATCH, 176 .match = ebt_filter_vlan, 177 .check = ebt_check_vlan, 178 .me = THIS_MODULE, 179}; 180 181static int __init ebt_vlan_init(void) 182{ 183 DEBUG_MSG("ebtables 802.1Q extension module v" 184 MODULE_VERS "\n"); 185 DEBUG_MSG("module debug=%d\n", !!debug); 186 return ebt_register_match(&filter_vlan); 187} 188 189static void __exit ebt_vlan_fini(void) 190{ 191 ebt_unregister_match(&filter_vlan); 192} 193 194module_init(ebt_vlan_init); 195module_exit(ebt_vlan_fini); 196