7224 lines · 175.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * 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> * *	Fixes: *	Vitaly E. Lavrov		RTA_OK arithmetic was wrong. */ #include <linux/bitops.h>#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/if_bridge.h>#include <linux/if_vlan.h>#include <linux/pci.h>#include <linux/etherdevice.h>#include <linux/bpf.h> #include <linux/uaccess.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/tcp.h>#include <net/sock.h>#include <net/pkt_sched.h>#include <net/fib_rules.h>#include <net/rtnetlink.h>#include <net/net_namespace.h>#include <net/netdev_lock.h>#include <net/devlink.h>#if IS_ENABLED(CONFIG_IPV6)#include <net/addrconf.h>#endif#include <linux/dpll.h> #include "dev.h" #define RTNL_MAX_TYPE		50#define RTNL_SLAVE_MAX_TYPE	45 struct rtnl_link {	rtnl_doit_func		doit;	rtnl_dumpit_func	dumpit;	struct module		*owner;	unsigned int		flags;	struct rcu_head		rcu;}; static DEFINE_MUTEX(rtnl_mutex); void rtnl_lock(void){	mutex_lock(&rtnl_mutex);}EXPORT_SYMBOL(rtnl_lock); int rtnl_lock_interruptible(void){	return mutex_lock_interruptible(&rtnl_mutex);} int rtnl_lock_killable(void){	return mutex_lock_killable(&rtnl_mutex);} static struct sk_buff *defer_kfree_skb_list;void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail){	if (head && tail) {		tail->next = defer_kfree_skb_list;		defer_kfree_skb_list = head;	}}EXPORT_SYMBOL(rtnl_kfree_skbs); void __rtnl_unlock(void){	struct sk_buff *head = defer_kfree_skb_list; 	defer_kfree_skb_list = NULL; 	/* Ensure that we didn't actually add any TODO item when __rtnl_unlock()	 * is used. In some places, e.g. in cfg80211, we have code that will do	 * something like	 *   rtnl_lock()	 *   wiphy_lock()	 *   ...	 *   rtnl_unlock()	 *	 * and because netdev_run_todo() acquires the RTNL for items on the list	 * we could cause a situation such as this:	 * Thread 1			Thread 2	 *				  rtnl_lock()	 *				  unregister_netdevice()	 *				  __rtnl_unlock()	 * rtnl_lock()	 * wiphy_lock()	 * rtnl_unlock()	 *   netdev_run_todo()	 *     __rtnl_unlock()	 *	 *     // list not empty now	 *     // because of thread 2	 *				  rtnl_lock()	 *     while (!list_empty(...))	 *       rtnl_lock()	 *				  wiphy_lock()	 * **** DEADLOCK ****	 *	 * However, usage of __rtnl_unlock() is rare, and so we can ensure that	 * it's not used in cases where something is added to do the list.	 */	WARN_ON(!list_empty(&net_todo_list)); 	mutex_unlock(&rtnl_mutex); 	while (head) {		struct sk_buff *next = head->next; 		kfree_skb(head);		cond_resched();		head = next;	}} void rtnl_unlock(void){	/* This fellow will unlock it for us. */	netdev_run_todo();}EXPORT_SYMBOL(rtnl_unlock); int rtnl_trylock(void){	return mutex_trylock(&rtnl_mutex);}EXPORT_SYMBOL(rtnl_trylock); int rtnl_is_locked(void){	return mutex_is_locked(&rtnl_mutex);}EXPORT_SYMBOL(rtnl_is_locked); bool refcount_dec_and_rtnl_lock(refcount_t *r){	return refcount_dec_and_mutex_lock(r, &rtnl_mutex);}EXPORT_SYMBOL(refcount_dec_and_rtnl_lock); #ifdef CONFIG_PROVE_LOCKINGbool lockdep_rtnl_is_held(void){	return lockdep_is_held(&rtnl_mutex);}EXPORT_SYMBOL(lockdep_rtnl_is_held);#endif /* #ifdef CONFIG_PROVE_LOCKING */ #ifdef CONFIG_DEBUG_NET_SMALL_RTNLvoid __rtnl_net_lock(struct net *net){	ASSERT_RTNL(); 	mutex_lock(&net->rtnl_mutex);}EXPORT_SYMBOL(__rtnl_net_lock); void __rtnl_net_unlock(struct net *net){	ASSERT_RTNL(); 	mutex_unlock(&net->rtnl_mutex);}EXPORT_SYMBOL(__rtnl_net_unlock); void rtnl_net_lock(struct net *net){	rtnl_lock();	__rtnl_net_lock(net);}EXPORT_SYMBOL(rtnl_net_lock); void rtnl_net_unlock(struct net *net){	__rtnl_net_unlock(net);	rtnl_unlock();}EXPORT_SYMBOL(rtnl_net_unlock); int rtnl_net_trylock(struct net *net){	int ret = rtnl_trylock(); 	if (ret)		__rtnl_net_lock(net); 	return ret;}EXPORT_SYMBOL(rtnl_net_trylock); int rtnl_net_lock_killable(struct net *net){	int ret = rtnl_lock_killable(); 	if (!ret)		__rtnl_net_lock(net); 	return ret;} static int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b){	if (net_eq(net_a, net_b))		return 0; 	/* always init_net first */	if (net_eq(net_a, &init_net))		return -1; 	if (net_eq(net_b, &init_net))		return 1; 	/* otherwise lock in ascending order */	return net_a < net_b ? -1 : 1;} int rtnl_net_lock_cmp_fn(const struct lockdep_map *a, const struct lockdep_map *b){	const struct net *net_a, *net_b; 	net_a = container_of(a, struct net, rtnl_mutex.dep_map);	net_b = container_of(b, struct net, rtnl_mutex.dep_map); 	return rtnl_net_cmp_locks(net_a, net_b);} bool rtnl_net_is_locked(struct net *net){	return rtnl_is_locked() && mutex_is_locked(&net->rtnl_mutex);}EXPORT_SYMBOL(rtnl_net_is_locked); bool lockdep_rtnl_net_is_held(struct net *net){	return lockdep_rtnl_is_held() && lockdep_is_held(&net->rtnl_mutex);}EXPORT_SYMBOL(lockdep_rtnl_net_is_held);#elsestatic int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b){	/* No need to swap */	return -1;}#endif struct rtnl_nets {	/* ->newlink() needs to freeze 3 netns at most;	 * 2 for the new device, 1 for its peer.	 */	struct net *net[3];	unsigned char len;}; static void rtnl_nets_init(struct rtnl_nets *rtnl_nets){	memset(rtnl_nets, 0, sizeof(*rtnl_nets));} static void rtnl_nets_destroy(struct rtnl_nets *rtnl_nets){	int i; 	for (i = 0; i < rtnl_nets->len; i++) {		put_net(rtnl_nets->net[i]);		rtnl_nets->net[i] = NULL;	} 	rtnl_nets->len = 0;} /** * rtnl_nets_add - Add netns to be locked before ->newlink(). * * @rtnl_nets: rtnl_nets pointer passed to ->get_peer_net(). * @net: netns pointer with an extra refcnt held. * * The extra refcnt is released in rtnl_nets_destroy(). */static void rtnl_nets_add(struct rtnl_nets *rtnl_nets, struct net *net){	int i; 	DEBUG_NET_WARN_ON_ONCE(rtnl_nets->len == ARRAY_SIZE(rtnl_nets->net)); 	for (i = 0; i < rtnl_nets->len; i++) {		switch (rtnl_net_cmp_locks(rtnl_nets->net[i], net)) {		case 0:			put_net(net);			return;		case 1:			swap(rtnl_nets->net[i], net);		}	} 	rtnl_nets->net[i] = net;	rtnl_nets->len++;} static void rtnl_nets_lock(struct rtnl_nets *rtnl_nets){	int i; 	rtnl_lock(); 	for (i = 0; i < rtnl_nets->len; i++)		__rtnl_net_lock(rtnl_nets->net[i]);} static void rtnl_nets_unlock(struct rtnl_nets *rtnl_nets){	int i; 	for (i = 0; i < rtnl_nets->len; i++)		__rtnl_net_unlock(rtnl_nets->net[i]); 	rtnl_unlock();} static struct rtnl_link __rcu *__rcu *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1]; 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 struct rtnl_link *rtnl_get_link(int protocol, int msgtype){	struct rtnl_link __rcu **tab; 	if (protocol >= ARRAY_SIZE(rtnl_msg_handlers))		protocol = PF_UNSPEC; 	tab = rcu_dereference_rtnl(rtnl_msg_handlers[protocol]);	if (!tab)		tab = rcu_dereference_rtnl(rtnl_msg_handlers[PF_UNSPEC]); 	return rcu_dereference_rtnl(tab[msgtype]);} static int rtnl_register_internal(struct module *owner,				  int protocol, int msgtype,				  rtnl_doit_func doit, rtnl_dumpit_func dumpit,				  unsigned int flags){	struct rtnl_link *link, *old;	struct rtnl_link __rcu **tab;	int msgindex;	int ret = -ENOBUFS; 	BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);	msgindex = rtm_msgindex(msgtype); 	rtnl_lock();	tab = rtnl_dereference(rtnl_msg_handlers[protocol]);	if (tab == NULL) {		tab = kcalloc(RTM_NR_MSGTYPES, sizeof(void *), GFP_KERNEL);		if (!tab)			goto unlock; 		/* ensures we see the 0 stores */		rcu_assign_pointer(rtnl_msg_handlers[protocol], tab);	} 	old = rtnl_dereference(tab[msgindex]);	if (old) {		link = kmemdup(old, sizeof(*old), GFP_KERNEL);		if (!link)			goto unlock;	} else {		link = kzalloc_obj(*link);		if (!link)			goto unlock;	} 	WARN_ON(link->owner && link->owner != owner);	link->owner = owner; 	WARN_ON(doit && link->doit && link->doit != doit);	if (doit)		link->doit = doit;	WARN_ON(dumpit && link->dumpit && link->dumpit != dumpit);	if (dumpit)		link->dumpit = dumpit; 	WARN_ON(rtnl_msgtype_kind(msgtype) != RTNL_KIND_DEL &&		(flags & RTNL_FLAG_BULK_DEL_SUPPORTED));	link->flags |= flags; 	/* publish protocol:msgtype */	rcu_assign_pointer(tab[msgindex], link);	ret = 0;	if (old)		kfree_rcu(old, rcu);unlock:	rtnl_unlock();	return ret;} /** * 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. */static int rtnl_unregister(int protocol, int msgtype){	struct rtnl_link __rcu **tab;	struct rtnl_link *link;	int msgindex; 	BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);	msgindex = rtm_msgindex(msgtype); 	rtnl_lock();	tab = rtnl_dereference(rtnl_msg_handlers[protocol]);	if (!tab) {		rtnl_unlock();		return -ENOENT;	} 	link = rcu_replace_pointer_rtnl(tab[msgindex], NULL);	rtnl_unlock(); 	kfree_rcu(link, rcu); 	return 0;} /** * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol * @protocol : Protocol family or PF_UNSPEC * * Identical to calling rtnl_unregister() for all registered message types * of a certain protocol family. */void rtnl_unregister_all(int protocol){	struct rtnl_link __rcu **tab;	struct rtnl_link *link;	int msgindex; 	BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); 	rtnl_lock();	tab = rcu_replace_pointer_rtnl(rtnl_msg_handlers[protocol], NULL);	if (!tab) {		rtnl_unlock();		return;	}	for (msgindex = 0; msgindex < RTM_NR_MSGTYPES; msgindex++) {		link = rcu_replace_pointer_rtnl(tab[msgindex], NULL);		kfree_rcu(link, rcu);

Lines 1–500 of 7224.