1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/if_ether.h>
21#include <linux/if_vlan.h>
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/netfilter/x_tables.h>
25#include <linux/netfilter_bridge/ebtables.h>
26#include <linux/netfilter_bridge/ebt_vlan.h>
27
28#define MODULE_VERS "0.6"
29
30MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
31MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match");
32MODULE_LICENSE("GPL");
33
34#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
35#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return false; }
36
37static bool
38ebt_vlan_mt(const struct sk_buff *skb, struct xt_action_param *par)
39{
40 const struct ebt_vlan_info *info = par->matchinfo;
41
42 unsigned short TCI;
43 unsigned short id;
44 unsigned char prio;
45
46 __be16 encap;
47
48 if (skb_vlan_tag_present(skb)) {
49 TCI = skb_vlan_tag_get(skb);
50 encap = skb->protocol;
51 } else {
52 const struct vlan_hdr *fp;
53 struct vlan_hdr _frame;
54
55 fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
56 if (fp == NULL)
57 return false;
58
59 TCI = ntohs(fp->h_vlan_TCI);
60 encap = fp->h_vlan_encapsulated_proto;
61 }
62
63
64
65
66
67
68
69
70 id = TCI & VLAN_VID_MASK;
71 prio = (TCI >> 13) & 0x7;
72
73
74 if (GET_BITMASK(EBT_VLAN_ID))
75 EXIT_ON_MISMATCH(id, EBT_VLAN_ID);
76
77
78 if (GET_BITMASK(EBT_VLAN_PRIO))
79 EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO);
80
81
82 if (GET_BITMASK(EBT_VLAN_ENCAP))
83 EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
84
85 return true;
86}
87
88static int ebt_vlan_mt_check(const struct xt_mtchk_param *par)
89{
90 struct ebt_vlan_info *info = par->matchinfo;
91 const struct ebt_entry *e = par->entryinfo;
92
93
94 if (e->ethproto != htons(ETH_P_8021Q)) {
95 pr_debug("passed entry proto %2.4X is not 802.1Q (8100)\n",
96 ntohs(e->ethproto));
97 return -EINVAL;
98 }
99
100
101
102 if (info->bitmask & ~EBT_VLAN_MASK) {
103 pr_debug("bitmask %2X is out of mask (%2X)\n",
104 info->bitmask, EBT_VLAN_MASK);
105 return -EINVAL;
106 }
107
108
109 if (info->invflags & ~EBT_VLAN_MASK) {
110 pr_debug("inversion flags %2X is out of mask (%2X)\n",
111 info->invflags, EBT_VLAN_MASK);
112 return -EINVAL;
113 }
114
115
116
117
118
119
120
121 if (GET_BITMASK(EBT_VLAN_ID)) {
122 if (!!info->id) {
123 if (info->id > VLAN_N_VID) {
124 pr_debug("id %d is out of range (1-4096)\n",
125 info->id);
126 return -EINVAL;
127 }
128
129
130
131
132 info->bitmask &= ~EBT_VLAN_PRIO;
133 }
134
135 }
136
137 if (GET_BITMASK(EBT_VLAN_PRIO)) {
138 if ((unsigned char) info->prio > 7) {
139 pr_debug("prio %d is out of range (0-7)\n",
140 info->prio);
141 return -EINVAL;
142 }
143 }
144
145
146
147 if (GET_BITMASK(EBT_VLAN_ENCAP)) {
148 if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
149 pr_debug("encap frame length %d is less than "
150 "minimal\n", ntohs(info->encap));
151 return -EINVAL;
152 }
153 }
154
155 return 0;
156}
157
158static struct xt_match ebt_vlan_mt_reg __read_mostly = {
159 .name = "vlan",
160 .revision = 0,
161 .family = NFPROTO_BRIDGE,
162 .match = ebt_vlan_mt,
163 .checkentry = ebt_vlan_mt_check,
164 .matchsize = sizeof(struct ebt_vlan_info),
165 .me = THIS_MODULE,
166};
167
168static int __init ebt_vlan_init(void)
169{
170 pr_debug("ebtables 802.1Q extension module v" MODULE_VERS "\n");
171 return xt_register_match(&ebt_vlan_mt_reg);
172}
173
174static void __exit ebt_vlan_fini(void)
175{
176 xt_unregister_match(&ebt_vlan_mt_reg);
177}
178
179module_init(ebt_vlan_init);
180module_exit(ebt_vlan_fini);
181