⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtnetlink.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		Routing netlink socket interface: protocol independent part. * * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * *	Fixes: *	Vitaly E. Lavrov		RTA_OK arithmetics was wrong. */#include <linux/errno.h>#include <linux/module.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/capability.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/security.h>#include <linux/mutex.h>#include <linux/if_addr.h>#include <linux/nsproxy.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/string.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <net/ip.h>#include <net/protocol.h>#include <net/arp.h>#include <net/route.h>#include <net/udp.h>#include <net/sock.h>#include <net/pkt_sched.h>#include <net/fib_rules.h>#include <net/rtnetlink.h>struct rtnl_link{	rtnl_doit_func		doit;	rtnl_dumpit_func	dumpit;};static DEFINE_MUTEX(rtnl_mutex);static struct sock *rtnl;void rtnl_lock(void){	mutex_lock(&rtnl_mutex);}void __rtnl_unlock(void){	mutex_unlock(&rtnl_mutex);}void rtnl_unlock(void){	mutex_unlock(&rtnl_mutex);	netdev_run_todo();}int rtnl_trylock(void){	return mutex_trylock(&rtnl_mutex);}int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len){	memset(tb, 0, sizeof(struct rtattr*)*maxattr);	while (RTA_OK(rta, len)) {		unsigned flavor = rta->rta_type;		if (flavor && flavor <= maxattr)			tb[flavor-1] = rta;		rta = RTA_NEXT(rta, len);	}	return 0;}int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,				 struct rtattr *rta, int len){	if (RTA_PAYLOAD(rta) < len)		return -1;	if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {		rta = RTA_DATA(rta) + RTA_ALIGN(len);		return rtattr_parse_nested(tb, maxattr, rta);	}	memset(tb, 0, sizeof(struct rtattr *) * maxattr);	return 0;}static struct rtnl_link *rtnl_msg_handlers[NPROTO];static inline int rtm_msgindex(int msgtype){	int msgindex = msgtype - RTM_BASE;	/*	 * msgindex < 0 implies someone tried to register a netlink	 * control code. msgindex >= RTM_NR_MSGTYPES may indicate that	 * the message type has not been added to linux/rtnetlink.h	 */	BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES);	return msgindex;}static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex){	struct rtnl_link *tab;	tab = rtnl_msg_handlers[protocol];	if (tab == NULL || tab[msgindex].doit == NULL)		tab = rtnl_msg_handlers[PF_UNSPEC];	return tab ? tab[msgindex].doit : NULL;}static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex){	struct rtnl_link *tab;	tab = rtnl_msg_handlers[protocol];	if (tab == NULL || tab[msgindex].dumpit == NULL)		tab = rtnl_msg_handlers[PF_UNSPEC];	return tab ? tab[msgindex].dumpit : NULL;}/** * __rtnl_register - Register a rtnetlink message type * @protocol: Protocol family or PF_UNSPEC * @msgtype: rtnetlink message type * @doit: Function pointer called for each request message * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message * * Registers the specified function pointers (at least one of them has * to be non-NULL) to be called whenever a request message for the * specified protocol family and message type is received. * * The special protocol family PF_UNSPEC may be used to define fallback * function pointers for the case when no entry for the specific protocol * family exists. * * Returns 0 on success or a negative error code. */int __rtnl_register(int protocol, int msgtype,		    rtnl_doit_func doit, rtnl_dumpit_func dumpit){	struct rtnl_link *tab;	int msgindex;	BUG_ON(protocol < 0 || protocol >= NPROTO);	msgindex = rtm_msgindex(msgtype);	tab = rtnl_msg_handlers[protocol];	if (tab == NULL) {		tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);		if (tab == NULL)			return -ENOBUFS;		rtnl_msg_handlers[protocol] = tab;	}	if (doit)		tab[msgindex].doit = doit;	if (dumpit)		tab[msgindex].dumpit = dumpit;	return 0;}EXPORT_SYMBOL_GPL(__rtnl_register);/** * rtnl_register - Register a rtnetlink message type * * Identical to __rtnl_register() but panics on failure. This is useful * as failure of this function is very unlikely, it can only happen due * to lack of memory when allocating the chain to store all message * handlers for a protocol. Meant for use in init functions where lack * of memory implies no sense in continueing. */void rtnl_register(int protocol, int msgtype,		   rtnl_doit_func doit, rtnl_dumpit_func dumpit){	if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)		panic("Unable to register rtnetlink message handler, "		      "protocol = %d, message type = %d\n",		      protocol, msgtype);}EXPORT_SYMBOL_GPL(rtnl_register);/** * rtnl_unregister - Unregister a rtnetlink message type * @protocol: Protocol family or PF_UNSPEC * @msgtype: rtnetlink message type * * Returns 0 on success or a negative error code. */int rtnl_unregister(int protocol, int msgtype){	int msgindex;	BUG_ON(protocol < 0 || protocol >= NPROTO);	msgindex = rtm_msgindex(msgtype);	if (rtnl_msg_handlers[protocol] == NULL)		return -ENOENT;	rtnl_msg_handlers[protocol][msgindex].doit = NULL;	rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;	return 0;}EXPORT_SYMBOL_GPL(rtnl_unregister);/** * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol * @protocol : Protocol family or PF_UNSPEC * * Identical to calling rtnl_unregster() for all registered message types * of a certain protocol family. */void rtnl_unregister_all(int protocol){	BUG_ON(protocol < 0 || protocol >= NPROTO);	kfree(rtnl_msg_handlers[protocol]);	rtnl_msg_handlers[protocol] = NULL;}EXPORT_SYMBOL_GPL(rtnl_unregister_all);static LIST_HEAD(link_ops);/** * __rtnl_link_register - Register rtnl_link_ops with rtnetlink. * @ops: struct rtnl_link_ops * to register * * The caller must hold the rtnl_mutex. This function should be used * by drivers that create devices during module initialization. It * must be called before registering the devices. * * Returns 0 on success or a negative error code. */int __rtnl_link_register(struct rtnl_link_ops *ops){	if (!ops->dellink)		ops->dellink = unregister_netdevice;	list_add_tail(&ops->list, &link_ops);	return 0;}EXPORT_SYMBOL_GPL(__rtnl_link_register);/** * rtnl_link_register - Register rtnl_link_ops with rtnetlink. * @ops: struct rtnl_link_ops * to register * * Returns 0 on success or a negative error code. */int rtnl_link_register(struct rtnl_link_ops *ops){	int err;	rtnl_lock();	err = __rtnl_link_register(ops);	rtnl_unlock();	return err;}EXPORT_SYMBOL_GPL(rtnl_link_register);/** * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. * @ops: struct rtnl_link_ops * to unregister * * The caller must hold the rtnl_mutex. */void __rtnl_link_unregister(struct rtnl_link_ops *ops){	struct net_device *dev, *n;	struct net *net;	for_each_net(net) {restart:		for_each_netdev_safe(net, dev, n) {			if (dev->rtnl_link_ops == ops) {				ops->dellink(dev);				goto restart;			}		}	}	list_del(&ops->list);}EXPORT_SYMBOL_GPL(__rtnl_link_unregister);/** * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. * @ops: struct rtnl_link_ops * to unregister */void rtnl_link_unregister(struct rtnl_link_ops *ops){	rtnl_lock();	__rtnl_link_unregister(ops);	rtnl_unlock();}EXPORT_SYMBOL_GPL(rtnl_link_unregister);static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind){	const struct rtnl_link_ops *ops;	list_for_each_entry(ops, &link_ops, list) {		if (!strcmp(ops->kind, kind))			return ops;	}	return NULL;}static size_t rtnl_link_get_size(const struct net_device *dev){	const struct rtnl_link_ops *ops = dev->rtnl_link_ops;	size_t size;	if (!ops)		return 0;	size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */	       nlmsg_total_size(strlen(ops->kind) + 1);	 /* IFLA_INFO_KIND */	if (ops->get_size)		/* IFLA_INFO_DATA + nested data */		size += nlmsg_total_size(sizeof(struct nlattr)) +			ops->get_size(dev);	if (ops->get_xstats_size)		size += ops->get_xstats_size(dev);	/* IFLA_INFO_XSTATS */	return size;}static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev){	const struct rtnl_link_ops *ops = dev->rtnl_link_ops;	struct nlattr *linkinfo, *data;	int err = -EMSGSIZE;	linkinfo = nla_nest_start(skb, IFLA_LINKINFO);	if (linkinfo == NULL)		goto out;	if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)		goto err_cancel_link;	if (ops->fill_xstats) {		err = ops->fill_xstats(skb, dev);		if (err < 0)			goto err_cancel_link;	}	if (ops->fill_info) {		data = nla_nest_start(skb, IFLA_INFO_DATA);		if (data == NULL)			goto err_cancel_link;		err = ops->fill_info(skb, dev);		if (err < 0)			goto err_cancel_data;		nla_nest_end(skb, data);	}	nla_nest_end(skb, linkinfo);	return 0;err_cancel_data:	nla_nest_cancel(skb, data);err_cancel_link:	nla_nest_cancel(skb, linkinfo);out:	return err;}static const int rtm_min[RTM_NR_FAMILIES] ={	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)),	[RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),	[RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)),	[RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),	[RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)),	[RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)),	[RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)),	[RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)),	[RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),	[RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),};static const int rta_max[RTM_NR_FAMILIES] ={	[RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX,	[RTM_FAM(RTM_NEWADDR)]      = IFA_MAX,	[RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX,	[RTM_FAM(RTM_NEWRULE)]      = FRA_MAX,	[RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX,	[RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX,	[RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX,	[RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,};void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data){	struct rtattr *rta;	int size = RTA_LENGTH(attrlen);	rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));	rta->rta_type = attrtype;	rta->rta_len = size;	memcpy(RTA_DATA(rta), data, attrlen);	memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);}size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size){	size_t ret = RTA_PAYLOAD(rta);	char *src = RTA_DATA(rta);	if (ret > 0 && src[ret - 1] == '\0')		ret--;	if (size > 0) {		size_t len = (ret >= size) ? size - 1 : ret;		memset(dest, 0, size);		memcpy(dest, src, len);	}	return ret;}int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo){	int err = 0;	NETLINK_CB(skb).dst_group = group;	if (echo)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -