bridge: Verify that a vlan is allowed to egress on given port
[linux-2.6-microblaze.git] / net / bridge / br_vlan.c
1 #include <linux/kernel.h>
2 #include <linux/netdevice.h>
3 #include <linux/rtnetlink.h>
4 #include <linux/slab.h>
5
6 #include "br_private.h"
7
8 static int __vlan_add(struct net_port_vlans *v, u16 vid)
9 {
10         int err;
11
12         if (test_bit(vid, v->vlan_bitmap))
13                 return -EEXIST;
14
15         if (v->port_idx && vid) {
16                 struct net_device *dev = v->parent.port->dev;
17
18                 /* Add VLAN to the device filter if it is supported.
19                  * Stricly speaking, this is not necessary now, since devices
20                  * are made promiscuous by the bridge, but if that ever changes
21                  * this code will allow tagged traffic to enter the bridge.
22                  */
23                 if (dev->features & NETIF_F_HW_VLAN_FILTER) {
24                         err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
25                         if (err)
26                                 return err;
27                 }
28         }
29
30         set_bit(vid, v->vlan_bitmap);
31         return 0;
32 }
33
34 static int __vlan_del(struct net_port_vlans *v, u16 vid)
35 {
36         if (!test_bit(vid, v->vlan_bitmap))
37                 return -EINVAL;
38
39         if (v->port_idx && vid) {
40                 struct net_device *dev = v->parent.port->dev;
41
42                 if (dev->features & NETIF_F_HW_VLAN_FILTER)
43                         dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
44         }
45
46         clear_bit(vid, v->vlan_bitmap);
47         if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
48                 if (v->port_idx)
49                         rcu_assign_pointer(v->parent.port->vlan_info, NULL);
50                 else
51                         rcu_assign_pointer(v->parent.br->vlan_info, NULL);
52                 kfree_rcu(v, rcu);
53         }
54         return 0;
55 }
56
57 static void __vlan_flush(struct net_port_vlans *v)
58 {
59         bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN);
60         if (v->port_idx)
61                 rcu_assign_pointer(v->parent.port->vlan_info, NULL);
62         else
63                 rcu_assign_pointer(v->parent.br->vlan_info, NULL);
64         kfree_rcu(v, rcu);
65 }
66
67 /* Called under RCU */
68 bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
69                         struct sk_buff *skb)
70 {
71         u16 vid;
72
73         /* If VLAN filtering is disabled on the bridge, all packets are
74          * permitted.
75          */
76         if (!br->vlan_enabled)
77                 return true;
78
79         /* If there are no vlan in the permitted list, all packets are
80          * rejected.
81          */
82         if (!v)
83                 return false;
84
85         br_vlan_get_tag(skb, &vid);
86         if (test_bit(vid, v->vlan_bitmap))
87                 return true;
88
89         return false;
90 }
91
92 /* Called under RCU. */
93 bool br_allowed_egress(struct net_bridge *br,
94                        const struct net_port_vlans *v,
95                        const struct sk_buff *skb)
96 {
97         u16 vid;
98
99         if (!br->vlan_enabled)
100                 return true;
101
102         if (!v)
103                 return false;
104
105         br_vlan_get_tag(skb, &vid);
106         if (test_bit(vid, v->vlan_bitmap))
107                 return true;
108
109         return false;
110 }
111
112 /* Must be protected by RTNL */
113 int br_vlan_add(struct net_bridge *br, u16 vid)
114 {
115         struct net_port_vlans *pv = NULL;
116         int err;
117
118         ASSERT_RTNL();
119
120         pv = rtnl_dereference(br->vlan_info);
121         if (pv)
122                 return __vlan_add(pv, vid);
123
124         /* Create port vlan infomration
125          */
126         pv = kzalloc(sizeof(*pv), GFP_KERNEL);
127         if (!pv)
128                 return -ENOMEM;
129
130         pv->parent.br = br;
131         err = __vlan_add(pv, vid);
132         if (err)
133                 goto out;
134
135         rcu_assign_pointer(br->vlan_info, pv);
136         return 0;
137 out:
138         kfree(pv);
139         return err;
140 }
141
142 /* Must be protected by RTNL */
143 int br_vlan_delete(struct net_bridge *br, u16 vid)
144 {
145         struct net_port_vlans *pv;
146
147         ASSERT_RTNL();
148
149         pv = rtnl_dereference(br->vlan_info);
150         if (!pv)
151                 return -EINVAL;
152
153         __vlan_del(pv, vid);
154         return 0;
155 }
156
157 void br_vlan_flush(struct net_bridge *br)
158 {
159         struct net_port_vlans *pv;
160
161         ASSERT_RTNL();
162
163         pv = rtnl_dereference(br->vlan_info);
164         if (!pv)
165                 return;
166
167         __vlan_flush(pv);
168 }
169
170 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
171 {
172         if (!rtnl_trylock())
173                 return restart_syscall();
174
175         if (br->vlan_enabled == val)
176                 goto unlock;
177
178         br->vlan_enabled = val;
179
180 unlock:
181         rtnl_unlock();
182         return 0;
183 }
184
185 /* Must be protected by RTNL */
186 int nbp_vlan_add(struct net_bridge_port *port, u16 vid)
187 {
188         struct net_port_vlans *pv = NULL;
189         int err;
190
191         ASSERT_RTNL();
192
193         pv = rtnl_dereference(port->vlan_info);
194         if (pv)
195                 return __vlan_add(pv, vid);
196
197         /* Create port vlan infomration
198          */
199         pv = kzalloc(sizeof(*pv), GFP_KERNEL);
200         if (!pv) {
201                 err = -ENOMEM;
202                 goto clean_up;
203         }
204
205         pv->port_idx = port->port_no;
206         pv->parent.port = port;
207         err = __vlan_add(pv, vid);
208         if (err)
209                 goto clean_up;
210
211         rcu_assign_pointer(port->vlan_info, pv);
212         return 0;
213
214 clean_up:
215         kfree(pv);
216         return err;
217 }
218
219 /* Must be protected by RTNL */
220 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
221 {
222         struct net_port_vlans *pv;
223
224         ASSERT_RTNL();
225
226         pv = rtnl_dereference(port->vlan_info);
227         if (!pv)
228                 return -EINVAL;
229
230         return __vlan_del(pv, vid);
231 }
232
233 void nbp_vlan_flush(struct net_bridge_port *port)
234 {
235         struct net_port_vlans *pv;
236
237         ASSERT_RTNL();
238
239         pv = rtnl_dereference(port->vlan_info);
240         if (!pv)
241                 return;
242
243         __vlan_flush(pv);
244 }