mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 13:41:55 +00:00
[NET]: Convert link modification to new netlink api
Transforms do_setlink() into rtnl_setlink() using the new netlink api. A warning message printed to the console is added in the event that a change request fails while part of the change request has been comitted already. The ioctl() based nature of net devices makes it almost impossible to move on to atomic netlink operations without obsoleting some of the functionality. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1823730fbc
commit
da5e0494c5
@ -336,52 +336,69 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c
|
|||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = {
|
||||||
|
[IFLA_IFNAME] = { .type = NLA_STRING },
|
||||||
|
[IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
|
||||||
|
[IFLA_MTU] = { .type = NLA_U32 },
|
||||||
|
[IFLA_TXQLEN] = { .type = NLA_U32 },
|
||||||
|
[IFLA_WEIGHT] = { .type = NLA_U32 },
|
||||||
|
[IFLA_OPERSTATE] = { .type = NLA_U8 },
|
||||||
|
[IFLA_LINKMODE] = { .type = NLA_U8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
||||||
{
|
{
|
||||||
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
|
struct ifinfomsg *ifm;
|
||||||
struct rtattr **ida = arg;
|
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
int err, send_addr_notify = 0;
|
int err, send_addr_notify = 0, modified = 0;
|
||||||
|
struct nlattr *tb[IFLA_MAX+1];
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
if (ifm->ifi_index >= 0)
|
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
|
||||||
dev = dev_get_by_index(ifm->ifi_index);
|
if (err < 0)
|
||||||
else if (ida[IFLA_IFNAME - 1]) {
|
goto errout;
|
||||||
char ifname[IFNAMSIZ];
|
|
||||||
|
|
||||||
if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
|
if (tb[IFLA_IFNAME] &&
|
||||||
IFNAMSIZ) >= IFNAMSIZ)
|
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ) >= IFNAMSIZ)
|
||||||
return -EINVAL;
|
|
||||||
dev = dev_get_by_name(ifname);
|
|
||||||
} else
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
ifm = nlmsg_data(nlh);
|
||||||
|
if (ifm->ifi_index >= 0)
|
||||||
|
dev = dev_get_by_index(ifm->ifi_index);
|
||||||
|
else if (tb[IFLA_IFNAME])
|
||||||
|
dev = dev_get_by_name(ifname);
|
||||||
|
else
|
||||||
|
goto errout;
|
||||||
|
|
||||||
if (ifm->ifi_flags)
|
if (dev == NULL) {
|
||||||
dev_change_flags(dev, ifm->ifi_flags);
|
err = -ENODEV;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
if (ida[IFLA_MAP - 1]) {
|
if (tb[IFLA_ADDRESS] &&
|
||||||
|
nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
|
||||||
|
goto errout_dev;
|
||||||
|
|
||||||
|
if (tb[IFLA_BROADCAST] &&
|
||||||
|
nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
|
||||||
|
goto errout_dev;
|
||||||
|
|
||||||
|
if (tb[IFLA_MAP]) {
|
||||||
struct rtnl_link_ifmap *u_map;
|
struct rtnl_link_ifmap *u_map;
|
||||||
struct ifmap k_map;
|
struct ifmap k_map;
|
||||||
|
|
||||||
if (!dev->set_config) {
|
if (!dev->set_config) {
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto out;
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!netif_device_present(dev)) {
|
if (!netif_device_present(dev)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto out;
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
u_map = RTA_DATA(ida[IFLA_MAP - 1]);
|
|
||||||
|
|
||||||
|
u_map = nla_data(tb[IFLA_MAP]);
|
||||||
k_map.mem_start = (unsigned long) u_map->mem_start;
|
k_map.mem_start = (unsigned long) u_map->mem_start;
|
||||||
k_map.mem_end = (unsigned long) u_map->mem_end;
|
k_map.mem_end = (unsigned long) u_map->mem_end;
|
||||||
k_map.base_addr = (unsigned short) u_map->base_addr;
|
k_map.base_addr = (unsigned short) u_map->base_addr;
|
||||||
@ -390,119 +407,111 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
|||||||
k_map.port = (unsigned char) u_map->port;
|
k_map.port = (unsigned char) u_map->port;
|
||||||
|
|
||||||
err = dev->set_config(dev, &k_map);
|
err = dev->set_config(dev, &k_map);
|
||||||
|
if (err < 0)
|
||||||
|
goto errout_dev;
|
||||||
|
|
||||||
if (err)
|
modified = 1;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ida[IFLA_ADDRESS - 1]) {
|
if (tb[IFLA_ADDRESS]) {
|
||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!dev->set_mac_address) {
|
if (!dev->set_mac_address) {
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto out;
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!netif_device_present(dev)) {
|
if (!netif_device_present(dev)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto out;
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
len = sizeof(sa_family_t) + dev->addr_len;
|
len = sizeof(sa_family_t) + dev->addr_len;
|
||||||
sa = kmalloc(len, GFP_KERNEL);
|
sa = kmalloc(len, GFP_KERNEL);
|
||||||
if (!sa) {
|
if (!sa) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
sa->sa_family = dev->type;
|
sa->sa_family = dev->type;
|
||||||
memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]),
|
memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
|
||||||
dev->addr_len);
|
dev->addr_len);
|
||||||
err = dev->set_mac_address(dev, sa);
|
err = dev->set_mac_address(dev, sa);
|
||||||
kfree(sa);
|
kfree(sa);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto errout_dev;
|
||||||
send_addr_notify = 1;
|
send_addr_notify = 1;
|
||||||
|
modified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ida[IFLA_BROADCAST - 1]) {
|
if (tb[IFLA_MTU]) {
|
||||||
if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len))
|
err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
|
||||||
goto out;
|
if (err < 0)
|
||||||
memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]),
|
goto errout_dev;
|
||||||
dev->addr_len);
|
modified = 1;
|
||||||
send_addr_notify = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ida[IFLA_MTU - 1]) {
|
/*
|
||||||
if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
|
* Interface selected by interface index but interface
|
||||||
goto out;
|
* name provided implies that a name change has been
|
||||||
err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));
|
* requested.
|
||||||
|
*/
|
||||||
if (err)
|
if (ifm->ifi_index >= 0 && ifname[0]) {
|
||||||
goto out;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ida[IFLA_TXQLEN - 1]) {
|
|
||||||
if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ida[IFLA_WEIGHT - 1]) {
|
|
||||||
if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ida[IFLA_OPERSTATE - 1]) {
|
|
||||||
if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ida[IFLA_LINKMODE - 1]) {
|
|
||||||
if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
write_lock_bh(&dev_base_lock);
|
|
||||||
dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
|
|
||||||
write_unlock_bh(&dev_base_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
|
|
||||||
char ifname[IFNAMSIZ];
|
|
||||||
|
|
||||||
if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
|
|
||||||
IFNAMSIZ) >= IFNAMSIZ)
|
|
||||||
goto out;
|
|
||||||
err = dev_change_name(dev, ifname);
|
err = dev_change_name(dev, ifname);
|
||||||
if (err)
|
if (err < 0)
|
||||||
goto out;
|
goto errout_dev;
|
||||||
|
modified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
|
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
|
||||||
if (ida[IFLA_WIRELESS - 1]) {
|
if (tb[IFLA_WIRELESS]) {
|
||||||
|
|
||||||
/* Call Wireless Extensions.
|
/* Call Wireless Extensions.
|
||||||
* Various stuff checked in there... */
|
* Various stuff checked in there... */
|
||||||
err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
|
err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]),
|
||||||
if (err)
|
nla_len(tb[IFLA_WIRELESS]));
|
||||||
goto out;
|
if (err < 0)
|
||||||
|
goto errout_dev;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
|
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
|
||||||
|
|
||||||
|
if (tb[IFLA_BROADCAST]) {
|
||||||
|
nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
|
||||||
|
send_addr_notify = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ifm->ifi_flags)
|
||||||
|
dev_change_flags(dev, ifm->ifi_flags);
|
||||||
|
|
||||||
|
if (tb[IFLA_TXQLEN])
|
||||||
|
dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
|
||||||
|
|
||||||
|
if (tb[IFLA_WEIGHT])
|
||||||
|
dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
|
||||||
|
|
||||||
|
if (tb[IFLA_OPERSTATE])
|
||||||
|
set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
|
||||||
|
|
||||||
|
if (tb[IFLA_LINKMODE]) {
|
||||||
|
write_lock_bh(&dev_base_lock);
|
||||||
|
dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
|
||||||
|
write_unlock_bh(&dev_base_lock);
|
||||||
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
out:
|
errout_dev:
|
||||||
|
if (err < 0 && modified && net_ratelimit())
|
||||||
|
printk(KERN_WARNING "A link change request failed with "
|
||||||
|
"some changes comitted already. Interface %s may "
|
||||||
|
"have been left with an inconsistent configuration, "
|
||||||
|
"please check.\n", dev->name);
|
||||||
|
|
||||||
if (send_addr_notify)
|
if (send_addr_notify)
|
||||||
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
|
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
|
||||||
|
|
||||||
dev_put(dev);
|
dev_put(dev);
|
||||||
|
errout:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,7 +762,7 @@ static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
|
|||||||
.doit = do_getlink,
|
.doit = do_getlink,
|
||||||
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
|
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
|
||||||
.dumpit = rtnetlink_dump_ifinfo },
|
.dumpit = rtnetlink_dump_ifinfo },
|
||||||
[RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
|
[RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink },
|
||||||
[RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
|
[RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
|
||||||
[RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
|
[RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
|
||||||
[RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
|
[RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add },
|
||||||
|
Loading…
Reference in New Issue
Block a user