diff options
author | Patrick McHardy <kaber@trash.net> | 2007-07-11 19:42:31 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 19:45:36 -0700 |
commit | 0e06877c6fdbc67b1132be895f995acd1ff30135 (patch) | |
tree | ddaba8cddc8a95d23ee18f812c6aba67dd9b1c6f | |
parent | 2d85cba2b272a5201a60966a65a4f8c0bcc0bb71 (diff) |
[RTNETLINK]: rtnl_link: allow specifying initial device address
Drivers need to validate the initial addresses in their netlink attribute
validation function or manually reject them if they can't support this.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/dummy.c | 12 | ||||
-rw-r--r-- | drivers/net/ifb.c | 12 | ||||
-rw-r--r-- | net/8021q/vlan.c | 8 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 7 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 9 |
5 files changed, 44 insertions, 4 deletions
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 373ff700404..756a6bcb038 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -84,9 +84,21 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + static struct rtnl_link_ops dummy_link_ops __read_mostly = { .kind = "dummy", .setup = dummy_setup, + .validate = dummy_validate, }; /* Number of dummy devices to be set up by this module. */ diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index c8e7c8f6ba3..f5c3598e59a 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -221,10 +221,22 @@ static int ifb_open(struct net_device *dev) return 0; } +static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + static struct rtnl_link_ops ifb_link_ops __read_mostly = { .kind = "ifb", .priv_size = sizeof(struct ifb_private), .setup = ifb_setup, + .validate = ifb_validate, }; /* Number of ifb devices to be set up by this module. */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 34c1d0b241c..abb9900edb3 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -324,8 +324,10 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); - memcpy(dev->broadcast, real_dev->broadcast, real_dev->addr_len); - memcpy(dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); + if (is_zero_ether_addr(dev->dev_addr)) + memcpy(dev->dev_addr, real_dev->dev_addr, dev->addr_len); + if (is_zero_ether_addr(dev->broadcast)) + memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->hard_header = real_dev->hard_header; @@ -373,6 +375,8 @@ void vlan_setup(struct net_device *new_dev) new_dev->set_multicast_list = vlan_dev_set_multicast_list; new_dev->destructor = free_netdev; new_dev->do_ioctl = vlan_dev_ioctl; + + memset(new_dev->broadcast, 0, sizeof(ETH_ALEN)); } static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 844c7e43d0f..6cdd1e015e2 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -41,6 +41,13 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) u16 id; int err; + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + if (!data) return -EINVAL; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 7b6b1639674..864cbdf31ed 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1032,8 +1032,7 @@ replay: if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change) return -EOPNOTSUPP; - if (tb[IFLA_ADDRESS] || tb[IFLA_BROADCAST] || tb[IFLA_MAP] || - tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) + if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) return -EOPNOTSUPP; if (!ops) { @@ -1065,6 +1064,12 @@ replay: if (tb[IFLA_MTU]) dev->mtu = nla_get_u32(tb[IFLA_MTU]); + if (tb[IFLA_ADDRESS]) + memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), + nla_len(tb[IFLA_ADDRESS])); + if (tb[IFLA_BROADCAST]) + memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), + nla_len(tb[IFLA_BROADCAST])); if (tb[IFLA_TXQLEN]) dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); if (tb[IFLA_WEIGHT]) |