コード例 #1
0
static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct net_device *dev;
	int err, send_addr_notify = 0, modified = 0;
	struct nlattr *tb[IFLA_MAX+1];
	char ifname[IFNAMSIZ];

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
	if (err < 0)
		goto errout;

	if (tb[IFLA_IFNAME])
		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
	else
		ifname[0] = '\0';

	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 (dev == NULL) {
		err = -ENODEV;
		goto errout;
	}

	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 ifmap k_map;

		if (!dev->set_config) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		u_map = nla_data(tb[IFLA_MAP]);
		k_map.mem_start = (unsigned long) u_map->mem_start;
		k_map.mem_end = (unsigned long) u_map->mem_end;
		k_map.base_addr = (unsigned short) u_map->base_addr;
		k_map.irq = (unsigned char) u_map->irq;
		k_map.dma = (unsigned char) u_map->dma;
		k_map.port = (unsigned char) u_map->port;

		err = dev->set_config(dev, &k_map);
		if (err < 0)
			goto errout_dev;

		modified = 1;
	}

	if (tb[IFLA_ADDRESS]) {
		struct sockaddr *sa;
		int len;

		if (!dev->set_mac_address) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		len = sizeof(sa_family_t) + dev->addr_len;
		sa = kmalloc(len, GFP_KERNEL);
		if (!sa) {
			err = -ENOMEM;
			goto errout_dev;
		}
		sa->sa_family = dev->type;
		memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
		       dev->addr_len);
		err = dev->set_mac_address(dev, sa);
		kfree(sa);
		if (err)
			goto errout_dev;
		send_addr_notify = 1;
		modified = 1;
	}

	if (tb[IFLA_MTU]) {
		err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

	/*
	 * Interface selected by interface index but interface
	 * name provided implies that a name change has been
	 * requested.
	 */
	if (ifm->ifi_index >= 0 && ifname[0]) {
		err = dev_change_name(dev, ifname);
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

#ifdef CONFIG_NET_WIRELESS_RTNETLINK
	if (tb[IFLA_WIRELESS]) {
		/* Call Wireless Extensions.
		 * Various stuff checked in there... */
		err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]),
					     nla_len(tb[IFLA_WIRELESS]));
		if (err < 0)
			goto errout_dev;
	}
#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;

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)
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

	dev_put(dev);
errout:
	return err;
}
コード例 #2
0
static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
    struct ifinfomsg  *ifm = NLMSG_DATA(nlh);
    struct rtattr    **ida = arg;
    struct net_device *dev;
    int err, send_addr_notify = 0;

    if (ifm->ifi_index >= 0)
        dev = dev_get_by_index(ifm->ifi_index);
    else if (ida[IFLA_IFNAME - 1]) {
        char ifname[IFNAMSIZ];

        if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
                           IFNAMSIZ) >= IFNAMSIZ)
            return -EINVAL;
        dev = dev_get_by_name(ifname);
    } else
        return -EINVAL;

    if (!dev)
        return -ENODEV;

    err = -EINVAL;

    if (ifm->ifi_flags)
        dev_change_flags(dev, ifm->ifi_flags);

    if (ida[IFLA_MAP - 1]) {
        struct rtnl_link_ifmap *u_map;
        struct ifmap k_map;

        if (!dev->set_config) {
            err = -EOPNOTSUPP;
            goto out;
        }

        if (!netif_device_present(dev)) {
            err = -ENODEV;
            goto out;
        }

        if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
            goto out;

        u_map = RTA_DATA(ida[IFLA_MAP - 1]);

        k_map.mem_start = (unsigned long) u_map->mem_start;
        k_map.mem_end = (unsigned long) u_map->mem_end;
        k_map.base_addr = (unsigned short) u_map->base_addr;
        k_map.irq = (unsigned char) u_map->irq;
        k_map.dma = (unsigned char) u_map->dma;
        k_map.port = (unsigned char) u_map->port;

        err = dev->set_config(dev, &k_map);

        if (err)
            goto out;
    }

    if (ida[IFLA_ADDRESS - 1]) {
        struct sockaddr *sa;
        int len;

        if (!dev->set_mac_address) {
            err = -EOPNOTSUPP;
            goto out;
        }
        if (!netif_device_present(dev)) {
            err = -ENODEV;
            goto out;
        }
        if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
            goto out;

        len = sizeof(sa_family_t) + dev->addr_len;
        sa = kmalloc(len, GFP_KERNEL);
        if (!sa) {
            err = -ENOMEM;
            goto out;
        }
        sa->sa_family = dev->type;
        memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]),
               dev->addr_len);
        err = dev->set_mac_address(dev, sa);
        kfree(sa);
        if (err)
            goto out;
        send_addr_notify = 1;
    }

    if (ida[IFLA_BROADCAST - 1]) {
        if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len))
            goto out;
        memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]),
               dev->addr_len);
        send_addr_notify = 1;
    }

    if (ida[IFLA_MTU - 1]) {
        if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
            goto out;
        err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));

        if (err)
            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);
        if (err)
            goto out;
    }

#ifdef CONFIG_NET_WIRELESS_RTNETLINK
    if (ida[IFLA_WIRELESS - 1]) {

        /* Call Wireless Extensions.
         * Various stuff checked in there... */
        err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
        if (err)
            goto out;
    }
#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */

    err = 0;

out:
    if (send_addr_notify)
        call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

    dev_put(dev);
    return err;
}