Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 135177
b: refs/heads/master
c: f9ac30f
h: refs/heads/master
i:
  135175: 409d383
v: v3
  • Loading branch information
Eric Biederman authored and David S. Miller committed Mar 13, 2009
1 parent d24c474 commit 1c29015
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b0832a2961022a076c812384435b5f0290b3fc91
refs/heads/master: f9ac30f080d23ef0a2d4a1b7c6806c9a21c0f324
73 changes: 60 additions & 13 deletions trunk/drivers/net/macvlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,47 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
return NULL;
}

static void macvlan_hash_add(struct macvlan_dev *vlan)
{
struct macvlan_port *port = vlan->port;
const unsigned char *addr = vlan->dev->dev_addr;

hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
}

static void macvlan_hash_del(struct macvlan_dev *vlan)
{
hlist_del_rcu(&vlan->hlist);
synchronize_rcu();
}

static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
const unsigned char *addr)
{
macvlan_hash_del(vlan);
/* Now that we are unhashed it is safe to change the device
* address without confusing packet delivery.
*/
memcpy(vlan->dev->dev_addr, addr, ETH_ALEN);
macvlan_hash_add(vlan);
}

static int macvlan_addr_busy(const struct macvlan_port *port,
const unsigned char *addr)
{
/* Test to see if the specified multicast address is
* currently in use by the underlying device or
* another macvlan.
*/
if (memcmp(port->dev->dev_addr, addr, ETH_ALEN) == 0)
return 1;

if (macvlan_hash_lookup(port, addr))
return 1;

return 0;
}

static void macvlan_broadcast(struct sk_buff *skb,
const struct macvlan_port *port)
{
Expand Down Expand Up @@ -184,10 +225,13 @@ static const struct header_ops macvlan_hard_header_ops = {
static int macvlan_open(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
struct net_device *lowerdev = vlan->lowerdev;
int err;

err = -EBUSY;
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
goto out;

err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
if (err < 0)
goto out;
Expand All @@ -196,8 +240,7 @@ static int macvlan_open(struct net_device *dev)
if (err < 0)
goto del_unicast;
}

hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
macvlan_hash_add(vlan);
return 0;

del_unicast:
Expand All @@ -217,8 +260,7 @@ static int macvlan_stop(struct net_device *dev)

dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);

hlist_del_rcu(&vlan->hlist);
synchronize_rcu();
macvlan_hash_del(vlan);
return 0;
}

Expand All @@ -232,16 +274,21 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;

if (!(dev->flags & IFF_UP))
goto out;
if (!(dev->flags & IFF_UP)) {
/* Just copy in the new address */
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
} else {
/* Rehash and update the device filters */
if (macvlan_addr_busy(vlan->port, addr->sa_data))
return -EBUSY;

err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN);
if (err < 0)
return err;
dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN)))
return err;

out:
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);

macvlan_hash_change_addr(vlan, addr->sa_data);
}
return 0;
}

Expand Down

0 comments on commit 1c29015

Please sign in to comment.