]> Pileus Git - ~andy/linux/blob - net/bridge/br_vlan.c
209464ef5242729904dd1cbd7c77204bb16f7e50
[~andy/linux] / 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 /* Must be protected by RTNL */
68 int br_vlan_add(struct net_bridge *br, u16 vid)
69 {
70         struct net_port_vlans *pv = NULL;
71         int err;
72
73         ASSERT_RTNL();
74
75         pv = rtnl_dereference(br->vlan_info);
76         if (pv)
77                 return __vlan_add(pv, vid);
78
79         /* Create port vlan infomration
80          */
81         pv = kzalloc(sizeof(*pv), GFP_KERNEL);
82         if (!pv)
83                 return -ENOMEM;
84
85         pv->parent.br = br;
86         err = __vlan_add(pv, vid);
87         if (err)
88                 goto out;
89
90         rcu_assign_pointer(br->vlan_info, pv);
91         return 0;
92 out:
93         kfree(pv);
94         return err;
95 }
96
97 /* Must be protected by RTNL */
98 int br_vlan_delete(struct net_bridge *br, u16 vid)
99 {
100         struct net_port_vlans *pv;
101
102         ASSERT_RTNL();
103
104         pv = rtnl_dereference(br->vlan_info);
105         if (!pv)
106                 return -EINVAL;
107
108         __vlan_del(pv, vid);
109         return 0;
110 }
111
112 void br_vlan_flush(struct net_bridge *br)
113 {
114         struct net_port_vlans *pv;
115
116         ASSERT_RTNL();
117
118         pv = rtnl_dereference(br->vlan_info);
119         if (!pv)
120                 return;
121
122         __vlan_flush(pv);
123 }
124
125 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
126 {
127         if (!rtnl_trylock())
128                 return restart_syscall();
129
130         if (br->vlan_enabled == val)
131                 goto unlock;
132
133         br->vlan_enabled = val;
134
135 unlock:
136         rtnl_unlock();
137         return 0;
138 }
139
140 /* Must be protected by RTNL */
141 int nbp_vlan_add(struct net_bridge_port *port, u16 vid)
142 {
143         struct net_port_vlans *pv = NULL;
144         int err;
145
146         ASSERT_RTNL();
147
148         pv = rtnl_dereference(port->vlan_info);
149         if (pv)
150                 return __vlan_add(pv, vid);
151
152         /* Create port vlan infomration
153          */
154         pv = kzalloc(sizeof(*pv), GFP_KERNEL);
155         if (!pv) {
156                 err = -ENOMEM;
157                 goto clean_up;
158         }
159
160         pv->port_idx = port->port_no;
161         pv->parent.port = port;
162         err = __vlan_add(pv, vid);
163         if (err)
164                 goto clean_up;
165
166         rcu_assign_pointer(port->vlan_info, pv);
167         return 0;
168
169 clean_up:
170         kfree(pv);
171         return err;
172 }
173
174 /* Must be protected by RTNL */
175 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
176 {
177         struct net_port_vlans *pv;
178
179         ASSERT_RTNL();
180
181         pv = rtnl_dereference(port->vlan_info);
182         if (!pv)
183                 return -EINVAL;
184
185         return __vlan_del(pv, vid);
186 }
187
188 void nbp_vlan_flush(struct net_bridge_port *port)
189 {
190         struct net_port_vlans *pv;
191
192         ASSERT_RTNL();
193
194         pv = rtnl_dereference(port->vlan_info);
195         if (!pv)
196                 return;
197
198         __vlan_flush(pv);
199 }