static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct netlink_ext_ack *extack)
{
	struct net *net = sock_net(skb->sk);
	struct net_device *dev = NULL;
	int idxattr = 0, prividx = 0;
	struct if_stats_msg *ifsm;
	struct sk_buff *nskb;
	u32 filter_mask;
	int err;

	if (nlmsg_len(nlh) < sizeof(*ifsm))
		return -EINVAL;

	ifsm = nlmsg_data(nlh);
	if (ifsm->ifindex > 0)
		dev = __dev_get_by_index(net, ifsm->ifindex);
	else
		return -EINVAL;

	if (!dev)
		return -ENODEV;

	filter_mask = ifsm->filter_mask;
	if (!filter_mask)
		return -EINVAL;

	nskb = nlmsg_new(if_nlmsg_stats_size(dev, filter_mask), GFP_KERNEL);
	if (!nskb)
		return -ENOBUFS;

	err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS,
				  NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
				  0, filter_mask, &idxattr, &prividx);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_stats_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
	} else {
		err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
	}

	return err;
}
static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct netlink_ext_ack *extack)
{
	struct net *net = sock_net(skb->sk);
	struct net_device *dev = NULL;
	int idxattr = 0, prividx = 0;
	struct if_stats_msg *ifsm;
	struct sk_buff *nskb;
	u32 filter_mask;
	int err;

	if (nlmsg_len(nlh) < sizeof(*ifsm))
		return -EINVAL;

	ifsm = nlmsg_data(nlh);
	if (ifsm->ifindex > 0)
		dev = __dev_get_by_index(net, ifsm->ifindex);
	else
		return -EINVAL;

	if (!dev)
		return -ENODEV;

	filter_mask = ifsm->filter_mask;
	if (!filter_mask)
		return -EINVAL;

	nskb = nlmsg_new(if_nlmsg_stats_size(dev, filter_mask), GFP_KERNEL);
	if (!nskb)
		return -ENOBUFS;

	err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS,
				  NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
				  0, filter_mask, &idxattr, &prividx);
	if (err < 0) {
		 
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
	} else {
		err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
	}

	return err;
}