aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/macvlan.c73
1 files changed, 60 insertions, 13 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index b5241fc0f51..70d3ef4a2c5 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -60,6 +60,47 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
60 return NULL; 60 return NULL;
61} 61}
62 62
63static void macvlan_hash_add(struct macvlan_dev *vlan)
64{
65 struct macvlan_port *port = vlan->port;
66 const unsigned char *addr = vlan->dev->dev_addr;
67
68 hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
69}
70
71static void macvlan_hash_del(struct macvlan_dev *vlan)
72{
73 hlist_del_rcu(&vlan->hlist);
74 synchronize_rcu();
75}
76
77static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
78 const unsigned char *addr)
79{
80 macvlan_hash_del(vlan);
81 /* Now that we are unhashed it is safe to change the device
82 * address without confusing packet delivery.
83 */
84 memcpy(vlan->dev->dev_addr, addr, ETH_ALEN);
85 macvlan_hash_add(vlan);
86}
87
88static int macvlan_addr_busy(const struct macvlan_port *port,
89 const unsigned char *addr)
90{
91 /* Test to see if the specified multicast address is
92 * currently in use by the underlying device or
93 * another macvlan.
94 */
95 if (memcmp(port->dev->dev_addr, addr, ETH_ALEN) == 0)
96 return 1;
97
98 if (macvlan_hash_lookup(port, addr))
99 return 1;
100
101 return 0;
102}
103
63static void macvlan_broadcast(struct sk_buff *skb, 104static void macvlan_broadcast(struct sk_buff *skb,
64 const struct macvlan_port *port) 105 const struct macvlan_port *port)
65{ 106{
@@ -184,10 +225,13 @@ static const struct header_ops macvlan_hard_header_ops = {
184static int macvlan_open(struct net_device *dev) 225static int macvlan_open(struct net_device *dev)
185{ 226{
186 struct macvlan_dev *vlan = netdev_priv(dev); 227 struct macvlan_dev *vlan = netdev_priv(dev);
187 struct macvlan_port *port = vlan->port;
188 struct net_device *lowerdev = vlan->lowerdev; 228 struct net_device *lowerdev = vlan->lowerdev;
189 int err; 229 int err;
190 230
231 err = -EBUSY;
232 if (macvlan_addr_busy(vlan->port, dev->dev_addr))
233 goto out;
234
191 err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN); 235 err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
192 if (err < 0) 236 if (err < 0)
193 goto out; 237 goto out;
@@ -196,8 +240,7 @@ static int macvlan_open(struct net_device *dev)
196 if (err < 0) 240 if (err < 0)
197 goto del_unicast; 241 goto del_unicast;
198 } 242 }
199 243 macvlan_hash_add(vlan);
200 hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
201 return 0; 244 return 0;
202 245
203del_unicast: 246del_unicast:
@@ -217,8 +260,7 @@ static int macvlan_stop(struct net_device *dev)
217 260
218 dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); 261 dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
219 262
220 hlist_del_rcu(&vlan->hlist); 263 macvlan_hash_del(vlan);
221 synchronize_rcu();
222 return 0; 264 return 0;
223} 265}
224 266
@@ -232,16 +274,21 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
232 if (!is_valid_ether_addr(addr->sa_data)) 274 if (!is_valid_ether_addr(addr->sa_data))
233 return -EADDRNOTAVAIL; 275 return -EADDRNOTAVAIL;
234 276
235 if (!(dev->flags & IFF_UP)) 277 if (!(dev->flags & IFF_UP)) {
236 goto out; 278 /* Just copy in the new address */
279 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
280 } else {
281 /* Rehash and update the device filters */
282 if (macvlan_addr_busy(vlan->port, addr->sa_data))
283 return -EBUSY;
237 284
238 err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN); 285 if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN)))
239 if (err < 0) 286 return err;
240 return err;
241 dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
242 287
243out: 288 dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
244 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); 289
290 macvlan_hash_change_addr(vlan, addr->sa_data);
291 }
245 return 0; 292 return 0;
246} 293}
247 294