예제 #1
0
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct sk_buff *nskb;
	char *iw_buf = NULL, *iw = NULL;
	int iw_buf_len = 0;
	int err;

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

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index >= 0) {
		dev = dev_get_by_index(ifm->ifi_index);
		if (dev == NULL)
			return -ENODEV;
	} else
		return -EINVAL;


#ifdef CONFIG_NET_WIRELESS_RTNETLINK
	if (tb[IFLA_WIRELESS]) {
		/* Call Wireless Extensions. We need to know the size before
		 * we can alloc. Various stuff checked in there... */
		err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]),
					     nla_len(tb[IFLA_WIRELESS]),
					     &iw_buf, &iw_buf_len);
		if (err < 0)
			goto errout;

		iw += IW_EV_POINT_OFF;
	}
#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */

	nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL);
	if (nskb == NULL) {
		err = -ENOBUFS;
		goto errout;
	}

	err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
			       NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
		goto errout;
	}
	err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
	kfree(iw_buf);
	dev_put(dev);

	return err;
}
예제 #2
0
void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
{
	struct sk_buff *skb;
	int err = -ENOBUFS;

	skb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL);
	if (skb == NULL)
		goto errout;

	err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size() */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(skb);
		goto errout;
	}
	err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
errout:
	if (err < 0)
		rtnl_set_sk_err(RTNLGRP_LINK, err);
}
예제 #3
0
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct sk_buff *nskb;
	int err;

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

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index > 0) {
		dev = dev_get_by_index(ifm->ifi_index);
		if (dev == NULL)
			return -ENODEV;
	} else
		return -EINVAL;

	nskb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL);
	if (nskb == NULL) {
		err = -ENOBUFS;
		goto errout;
	}

	err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
			       nlh->nlmsg_seq, 0, 0);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
		goto errout;
	}
	err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
	dev_put(dev);

	return err;
}
예제 #4
0
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
			    int type, u32 pid, u32 seq, u32 change,
			    unsigned int flags)
{
	struct ifinfomsg *ifm;
	struct nlmsghdr *nlh;

	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
	if (nlh == NULL)
		return -EMSGSIZE;

	ifm = nlmsg_data(nlh);
	ifm->ifi_family = AF_UNSPEC;
	ifm->__ifi_pad = 0;
	ifm->ifi_type = dev->type;
	ifm->ifi_index = dev->ifindex;
	ifm->ifi_flags = dev_get_flags(dev);
	ifm->ifi_change = change;

	NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
	NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len);
	NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight);
	NLA_PUT_U8(skb, IFLA_OPERSTATE,
		   netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
	NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
	NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);

	if (dev->ifindex != dev->iflink)
		NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);

	if (dev->master)
		NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);

	if (dev->qdisc_sleeping)
		NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc_sleeping->ops->id);

	if (1) {
		struct rtnl_link_ifmap map = {
			.mem_start   = dev->mem_start,
			.mem_end     = dev->mem_end,
			.base_addr   = dev->base_addr,
			.irq         = dev->irq,
			.dma         = dev->dma,
			.port        = dev->if_port,
		};
		NLA_PUT(skb, IFLA_MAP, sizeof(map), &map);
	}

	if (dev->addr_len) {
		NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
		NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
	}

	if (dev->get_stats) {
		struct net_device_stats *stats = dev->get_stats(dev);
		if (stats) {
			struct nlattr *attr;

			attr = nla_reserve(skb, IFLA_STATS,
					   sizeof(struct rtnl_link_stats));
			if (attr == NULL)
				goto nla_put_failure;

			copy_rtnl_link_stats(nla_data(attr), stats);
		}
	}

	return nlmsg_end(skb, nlh);

nla_put_failure:
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
}

static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
{
	int idx;
	int s_idx = cb->args[0];
	struct net_device *dev;

	idx = 0;
	for_each_netdev(dev) {
		if (idx < s_idx)
			goto cont;
		if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
				     NETLINK_CB(cb->skb).pid,
				     cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
			break;
cont:
		idx++;
	}
	cb->args[0] = idx;

	return skb->len;
}