162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NETLINK      Kernel-user communication protocol.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * 		Authors:	Alan Cox <alan@lxorguk.ukuu.org.uk>
662306a36Sopenharmony_ci * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
762306a36Sopenharmony_ci * 				Patrick McHardy <kaber@trash.net>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
1062306a36Sopenharmony_ci *                               added netlink_proto_exit
1162306a36Sopenharmony_ci * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br>
1262306a36Sopenharmony_ci * 				 use nlk_sk, as sk->protinfo is on a diet 8)
1362306a36Sopenharmony_ci * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org>
1462306a36Sopenharmony_ci * 				 - inc module use count of module that owns
1562306a36Sopenharmony_ci * 				   the kernel socket in case userspace opens
1662306a36Sopenharmony_ci * 				   socket of same protocol
1762306a36Sopenharmony_ci * 				 - remove all module support, since netlink is
1862306a36Sopenharmony_ci * 				   mandatory if CONFIG_NET=y these days
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/bpf.h>
2462306a36Sopenharmony_ci#include <linux/capability.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/filter.h>
2762306a36Sopenharmony_ci#include <linux/init.h>
2862306a36Sopenharmony_ci#include <linux/signal.h>
2962306a36Sopenharmony_ci#include <linux/sched.h>
3062306a36Sopenharmony_ci#include <linux/errno.h>
3162306a36Sopenharmony_ci#include <linux/string.h>
3262306a36Sopenharmony_ci#include <linux/stat.h>
3362306a36Sopenharmony_ci#include <linux/socket.h>
3462306a36Sopenharmony_ci#include <linux/un.h>
3562306a36Sopenharmony_ci#include <linux/fcntl.h>
3662306a36Sopenharmony_ci#include <linux/termios.h>
3762306a36Sopenharmony_ci#include <linux/sockios.h>
3862306a36Sopenharmony_ci#include <linux/net.h>
3962306a36Sopenharmony_ci#include <linux/fs.h>
4062306a36Sopenharmony_ci#include <linux/slab.h>
4162306a36Sopenharmony_ci#include <linux/uaccess.h>
4262306a36Sopenharmony_ci#include <linux/skbuff.h>
4362306a36Sopenharmony_ci#include <linux/netdevice.h>
4462306a36Sopenharmony_ci#include <linux/rtnetlink.h>
4562306a36Sopenharmony_ci#include <linux/proc_fs.h>
4662306a36Sopenharmony_ci#include <linux/seq_file.h>
4762306a36Sopenharmony_ci#include <linux/notifier.h>
4862306a36Sopenharmony_ci#include <linux/security.h>
4962306a36Sopenharmony_ci#include <linux/jhash.h>
5062306a36Sopenharmony_ci#include <linux/jiffies.h>
5162306a36Sopenharmony_ci#include <linux/random.h>
5262306a36Sopenharmony_ci#include <linux/bitops.h>
5362306a36Sopenharmony_ci#include <linux/mm.h>
5462306a36Sopenharmony_ci#include <linux/types.h>
5562306a36Sopenharmony_ci#include <linux/audit.h>
5662306a36Sopenharmony_ci#include <linux/mutex.h>
5762306a36Sopenharmony_ci#include <linux/vmalloc.h>
5862306a36Sopenharmony_ci#include <linux/if_arp.h>
5962306a36Sopenharmony_ci#include <linux/rhashtable.h>
6062306a36Sopenharmony_ci#include <asm/cacheflush.h>
6162306a36Sopenharmony_ci#include <linux/hash.h>
6262306a36Sopenharmony_ci#include <linux/genetlink.h>
6362306a36Sopenharmony_ci#include <linux/net_namespace.h>
6462306a36Sopenharmony_ci#include <linux/nospec.h>
6562306a36Sopenharmony_ci#include <linux/btf_ids.h>
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#include <net/net_namespace.h>
6862306a36Sopenharmony_ci#include <net/netns/generic.h>
6962306a36Sopenharmony_ci#include <net/sock.h>
7062306a36Sopenharmony_ci#include <net/scm.h>
7162306a36Sopenharmony_ci#include <net/netlink.h>
7262306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
7362306a36Sopenharmony_ci#include <trace/events/netlink.h>
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#include "af_netlink.h"
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct listeners {
7862306a36Sopenharmony_ci	struct rcu_head		rcu;
7962306a36Sopenharmony_ci	unsigned long		masks[];
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* state bits */
8362306a36Sopenharmony_ci#define NETLINK_S_CONGESTED		0x0
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic inline int netlink_is_kernel(struct sock *sk)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return nlk_test_bit(KERNEL_SOCKET, sk);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct netlink_table *nl_table __read_mostly;
9162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nl_table);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic struct lock_class_key nlk_cb_mutex_keys[MAX_LINKS];
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const char *const nlk_cb_mutex_key_strings[MAX_LINKS + 1] = {
9862306a36Sopenharmony_ci	"nlk_cb_mutex-ROUTE",
9962306a36Sopenharmony_ci	"nlk_cb_mutex-1",
10062306a36Sopenharmony_ci	"nlk_cb_mutex-USERSOCK",
10162306a36Sopenharmony_ci	"nlk_cb_mutex-FIREWALL",
10262306a36Sopenharmony_ci	"nlk_cb_mutex-SOCK_DIAG",
10362306a36Sopenharmony_ci	"nlk_cb_mutex-NFLOG",
10462306a36Sopenharmony_ci	"nlk_cb_mutex-XFRM",
10562306a36Sopenharmony_ci	"nlk_cb_mutex-SELINUX",
10662306a36Sopenharmony_ci	"nlk_cb_mutex-ISCSI",
10762306a36Sopenharmony_ci	"nlk_cb_mutex-AUDIT",
10862306a36Sopenharmony_ci	"nlk_cb_mutex-FIB_LOOKUP",
10962306a36Sopenharmony_ci	"nlk_cb_mutex-CONNECTOR",
11062306a36Sopenharmony_ci	"nlk_cb_mutex-NETFILTER",
11162306a36Sopenharmony_ci	"nlk_cb_mutex-IP6_FW",
11262306a36Sopenharmony_ci	"nlk_cb_mutex-DNRTMSG",
11362306a36Sopenharmony_ci	"nlk_cb_mutex-KOBJECT_UEVENT",
11462306a36Sopenharmony_ci	"nlk_cb_mutex-GENERIC",
11562306a36Sopenharmony_ci	"nlk_cb_mutex-17",
11662306a36Sopenharmony_ci	"nlk_cb_mutex-SCSITRANSPORT",
11762306a36Sopenharmony_ci	"nlk_cb_mutex-ECRYPTFS",
11862306a36Sopenharmony_ci	"nlk_cb_mutex-RDMA",
11962306a36Sopenharmony_ci	"nlk_cb_mutex-CRYPTO",
12062306a36Sopenharmony_ci	"nlk_cb_mutex-SMC",
12162306a36Sopenharmony_ci	"nlk_cb_mutex-23",
12262306a36Sopenharmony_ci	"nlk_cb_mutex-24",
12362306a36Sopenharmony_ci	"nlk_cb_mutex-25",
12462306a36Sopenharmony_ci	"nlk_cb_mutex-26",
12562306a36Sopenharmony_ci	"nlk_cb_mutex-27",
12662306a36Sopenharmony_ci	"nlk_cb_mutex-28",
12762306a36Sopenharmony_ci	"nlk_cb_mutex-29",
12862306a36Sopenharmony_ci	"nlk_cb_mutex-30",
12962306a36Sopenharmony_ci	"nlk_cb_mutex-31",
13062306a36Sopenharmony_ci	"nlk_cb_mutex-MAX_LINKS"
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int netlink_dump(struct sock *sk);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* nl_table locking explained:
13662306a36Sopenharmony_ci * Lookup and traversal are protected with an RCU read-side lock. Insertion
13762306a36Sopenharmony_ci * and removal are protected with per bucket lock while using RCU list
13862306a36Sopenharmony_ci * modification primitives and may run in parallel to RCU protected lookups.
13962306a36Sopenharmony_ci * Destruction of the Netlink socket may only occur *after* nl_table_lock has
14062306a36Sopenharmony_ci * been acquired * either during or after the socket has been removed from
14162306a36Sopenharmony_ci * the list and after an RCU grace period.
14262306a36Sopenharmony_ci */
14362306a36Sopenharmony_ciDEFINE_RWLOCK(nl_table_lock);
14462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nl_table_lock);
14562306a36Sopenharmony_cistatic atomic_t nl_table_users = ATOMIC_INIT(0);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(netlink_chain);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct rhashtable_params netlink_rhashtable_params;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_civoid do_trace_netlink_extack(const char *msg)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	trace_netlink_extack(msg);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ciEXPORT_SYMBOL(do_trace_netlink_extack);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline u32 netlink_group_mask(u32 group)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	if (group > 32)
16362306a36Sopenharmony_ci		return 0;
16462306a36Sopenharmony_ci	return group ? 1 << (group - 1) : 0;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
16862306a36Sopenharmony_ci					   gfp_t gfp_mask)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	unsigned int len = skb->len;
17162306a36Sopenharmony_ci	struct sk_buff *new;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	new = alloc_skb(len, gfp_mask);
17462306a36Sopenharmony_ci	if (new == NULL)
17562306a36Sopenharmony_ci		return NULL;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	NETLINK_CB(new).portid = NETLINK_CB(skb).portid;
17862306a36Sopenharmony_ci	NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group;
17962306a36Sopenharmony_ci	NETLINK_CB(new).creds = NETLINK_CB(skb).creds;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	skb_put_data(new, skb->data, len);
18262306a36Sopenharmony_ci	return new;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic unsigned int netlink_tap_net_id;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistruct netlink_tap_net {
18862306a36Sopenharmony_ci	struct list_head netlink_tap_all;
18962306a36Sopenharmony_ci	struct mutex netlink_tap_lock;
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciint netlink_add_tap(struct netlink_tap *nt)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct net *net = dev_net(nt->dev);
19562306a36Sopenharmony_ci	struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (unlikely(nt->dev->type != ARPHRD_NETLINK))
19862306a36Sopenharmony_ci		return -EINVAL;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	mutex_lock(&nn->netlink_tap_lock);
20162306a36Sopenharmony_ci	list_add_rcu(&nt->list, &nn->netlink_tap_all);
20262306a36Sopenharmony_ci	mutex_unlock(&nn->netlink_tap_lock);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	__module_get(nt->module);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return 0;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_add_tap);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int __netlink_remove_tap(struct netlink_tap *nt)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct net *net = dev_net(nt->dev);
21362306a36Sopenharmony_ci	struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
21462306a36Sopenharmony_ci	bool found = false;
21562306a36Sopenharmony_ci	struct netlink_tap *tmp;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	mutex_lock(&nn->netlink_tap_lock);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	list_for_each_entry(tmp, &nn->netlink_tap_all, list) {
22062306a36Sopenharmony_ci		if (nt == tmp) {
22162306a36Sopenharmony_ci			list_del_rcu(&nt->list);
22262306a36Sopenharmony_ci			found = true;
22362306a36Sopenharmony_ci			goto out;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	pr_warn("__netlink_remove_tap: %p not found\n", nt);
22862306a36Sopenharmony_ciout:
22962306a36Sopenharmony_ci	mutex_unlock(&nn->netlink_tap_lock);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (found)
23262306a36Sopenharmony_ci		module_put(nt->module);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return found ? 0 : -ENODEV;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciint netlink_remove_tap(struct netlink_tap *nt)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	int ret;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	ret = __netlink_remove_tap(nt);
24262306a36Sopenharmony_ci	synchronize_net();
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return ret;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_remove_tap);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic __net_init int netlink_tap_init_net(struct net *net)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	INIT_LIST_HEAD(&nn->netlink_tap_all);
25362306a36Sopenharmony_ci	mutex_init(&nn->netlink_tap_lock);
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic struct pernet_operations netlink_tap_net_ops = {
25862306a36Sopenharmony_ci	.init = netlink_tap_init_net,
25962306a36Sopenharmony_ci	.id   = &netlink_tap_net_id,
26062306a36Sopenharmony_ci	.size = sizeof(struct netlink_tap_net),
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic bool netlink_filter_tap(const struct sk_buff *skb)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct sock *sk = skb->sk;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* We take the more conservative approach and
26862306a36Sopenharmony_ci	 * whitelist socket protocols that may pass.
26962306a36Sopenharmony_ci	 */
27062306a36Sopenharmony_ci	switch (sk->sk_protocol) {
27162306a36Sopenharmony_ci	case NETLINK_ROUTE:
27262306a36Sopenharmony_ci	case NETLINK_USERSOCK:
27362306a36Sopenharmony_ci	case NETLINK_SOCK_DIAG:
27462306a36Sopenharmony_ci	case NETLINK_NFLOG:
27562306a36Sopenharmony_ci	case NETLINK_XFRM:
27662306a36Sopenharmony_ci	case NETLINK_FIB_LOOKUP:
27762306a36Sopenharmony_ci	case NETLINK_NETFILTER:
27862306a36Sopenharmony_ci	case NETLINK_GENERIC:
27962306a36Sopenharmony_ci		return true;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return false;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int __netlink_deliver_tap_skb(struct sk_buff *skb,
28662306a36Sopenharmony_ci				     struct net_device *dev)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct sk_buff *nskb;
28962306a36Sopenharmony_ci	struct sock *sk = skb->sk;
29062306a36Sopenharmony_ci	int ret = -ENOMEM;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), sock_net(sk)))
29362306a36Sopenharmony_ci		return 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	dev_hold(dev);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (is_vmalloc_addr(skb->head))
29862306a36Sopenharmony_ci		nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
29962306a36Sopenharmony_ci	else
30062306a36Sopenharmony_ci		nskb = skb_clone(skb, GFP_ATOMIC);
30162306a36Sopenharmony_ci	if (nskb) {
30262306a36Sopenharmony_ci		nskb->dev = dev;
30362306a36Sopenharmony_ci		nskb->protocol = htons((u16) sk->sk_protocol);
30462306a36Sopenharmony_ci		nskb->pkt_type = netlink_is_kernel(sk) ?
30562306a36Sopenharmony_ci				 PACKET_KERNEL : PACKET_USER;
30662306a36Sopenharmony_ci		skb_reset_network_header(nskb);
30762306a36Sopenharmony_ci		ret = dev_queue_xmit(nskb);
30862306a36Sopenharmony_ci		if (unlikely(ret > 0))
30962306a36Sopenharmony_ci			ret = net_xmit_errno(ret);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	dev_put(dev);
31362306a36Sopenharmony_ci	return ret;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void __netlink_deliver_tap(struct sk_buff *skb, struct netlink_tap_net *nn)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	int ret;
31962306a36Sopenharmony_ci	struct netlink_tap *tmp;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (!netlink_filter_tap(skb))
32262306a36Sopenharmony_ci		return;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	list_for_each_entry_rcu(tmp, &nn->netlink_tap_all, list) {
32562306a36Sopenharmony_ci		ret = __netlink_deliver_tap_skb(skb, tmp->dev);
32662306a36Sopenharmony_ci		if (unlikely(ret))
32762306a36Sopenharmony_ci			break;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void netlink_deliver_tap(struct net *net, struct sk_buff *skb)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	rcu_read_lock();
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if (unlikely(!list_empty(&nn->netlink_tap_all)))
33862306a36Sopenharmony_ci		__netlink_deliver_tap(skb, nn);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	rcu_read_unlock();
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src,
34462306a36Sopenharmony_ci				       struct sk_buff *skb)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	if (!(netlink_is_kernel(dst) && netlink_is_kernel(src)))
34762306a36Sopenharmony_ci		netlink_deliver_tap(sock_net(dst), skb);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void netlink_overrun(struct sock *sk)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	if (!nlk_test_bit(RECV_NO_ENOBUFS, sk)) {
35362306a36Sopenharmony_ci		if (!test_and_set_bit(NETLINK_S_CONGESTED,
35462306a36Sopenharmony_ci				      &nlk_sk(sk)->state)) {
35562306a36Sopenharmony_ci			WRITE_ONCE(sk->sk_err, ENOBUFS);
35662306a36Sopenharmony_ci			sk_error_report(sk);
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	atomic_inc(&sk->sk_drops);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void netlink_rcv_wake(struct sock *sk)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (skb_queue_empty_lockless(&sk->sk_receive_queue))
36762306a36Sopenharmony_ci		clear_bit(NETLINK_S_CONGESTED, &nlk->state);
36862306a36Sopenharmony_ci	if (!test_bit(NETLINK_S_CONGESTED, &nlk->state))
36962306a36Sopenharmony_ci		wake_up_interruptible(&nlk->wait);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void netlink_skb_destructor(struct sk_buff *skb)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	if (is_vmalloc_addr(skb->head)) {
37562306a36Sopenharmony_ci		if (!skb->cloned ||
37662306a36Sopenharmony_ci		    !atomic_dec_return(&(skb_shinfo(skb)->dataref)))
37762306a36Sopenharmony_ci			vfree_atomic(skb->head);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		skb->head = NULL;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci	if (skb->sk != NULL)
38262306a36Sopenharmony_ci		sock_rfree(skb);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	WARN_ON(skb->sk != NULL);
38862306a36Sopenharmony_ci	skb->sk = sk;
38962306a36Sopenharmony_ci	skb->destructor = netlink_skb_destructor;
39062306a36Sopenharmony_ci	atomic_add(skb->truesize, &sk->sk_rmem_alloc);
39162306a36Sopenharmony_ci	sk_mem_charge(sk, skb->truesize);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void netlink_sock_destruct(struct sock *sk)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (nlk->cb_running) {
39962306a36Sopenharmony_ci		if (nlk->cb.done)
40062306a36Sopenharmony_ci			nlk->cb.done(&nlk->cb);
40162306a36Sopenharmony_ci		module_put(nlk->cb.module);
40262306a36Sopenharmony_ci		kfree_skb(nlk->cb.skb);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	skb_queue_purge(&sk->sk_receive_queue);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD)) {
40862306a36Sopenharmony_ci		printk(KERN_ERR "Freeing alive netlink socket %p\n", sk);
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	WARN_ON(atomic_read(&sk->sk_rmem_alloc));
41362306a36Sopenharmony_ci	WARN_ON(refcount_read(&sk->sk_wmem_alloc));
41462306a36Sopenharmony_ci	WARN_ON(nlk_sk(sk)->groups);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic void netlink_sock_destruct_work(struct work_struct *work)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	struct netlink_sock *nlk = container_of(work, struct netlink_sock,
42062306a36Sopenharmony_ci						work);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	sk_free(&nlk->sk);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
42662306a36Sopenharmony_ci * SMP. Look, when several writers sleep and reader wakes them up, all but one
42762306a36Sopenharmony_ci * immediately hit write lock and grab all the cpus. Exclusive sleep solves
42862306a36Sopenharmony_ci * this, _but_ remember, it adds useless work on UP machines.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_civoid netlink_table_grab(void)
43262306a36Sopenharmony_ci	__acquires(nl_table_lock)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	might_sleep();
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	write_lock_irq(&nl_table_lock);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (atomic_read(&nl_table_users)) {
43962306a36Sopenharmony_ci		DECLARE_WAITQUEUE(wait, current);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		add_wait_queue_exclusive(&nl_table_wait, &wait);
44262306a36Sopenharmony_ci		for (;;) {
44362306a36Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
44462306a36Sopenharmony_ci			if (atomic_read(&nl_table_users) == 0)
44562306a36Sopenharmony_ci				break;
44662306a36Sopenharmony_ci			write_unlock_irq(&nl_table_lock);
44762306a36Sopenharmony_ci			schedule();
44862306a36Sopenharmony_ci			write_lock_irq(&nl_table_lock);
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		__set_current_state(TASK_RUNNING);
45262306a36Sopenharmony_ci		remove_wait_queue(&nl_table_wait, &wait);
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_civoid netlink_table_ungrab(void)
45762306a36Sopenharmony_ci	__releases(nl_table_lock)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	write_unlock_irq(&nl_table_lock);
46062306a36Sopenharmony_ci	wake_up(&nl_table_wait);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic inline void
46462306a36Sopenharmony_cinetlink_lock_table(void)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	unsigned long flags;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* read_lock() synchronizes us to netlink_table_grab */
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	read_lock_irqsave(&nl_table_lock, flags);
47162306a36Sopenharmony_ci	atomic_inc(&nl_table_users);
47262306a36Sopenharmony_ci	read_unlock_irqrestore(&nl_table_lock, flags);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic inline void
47662306a36Sopenharmony_cinetlink_unlock_table(void)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	if (atomic_dec_and_test(&nl_table_users))
47962306a36Sopenharmony_ci		wake_up(&nl_table_wait);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistruct netlink_compare_arg
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	possible_net_t pnet;
48562306a36Sopenharmony_ci	u32 portid;
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/* Doing sizeof directly may yield 4 extra bytes on 64-bit. */
48962306a36Sopenharmony_ci#define netlink_compare_arg_len \
49062306a36Sopenharmony_ci	(offsetof(struct netlink_compare_arg, portid) + sizeof(u32))
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic inline int netlink_compare(struct rhashtable_compare_arg *arg,
49362306a36Sopenharmony_ci				  const void *ptr)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	const struct netlink_compare_arg *x = arg->key;
49662306a36Sopenharmony_ci	const struct netlink_sock *nlk = ptr;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return nlk->portid != x->portid ||
49962306a36Sopenharmony_ci	       !net_eq(sock_net(&nlk->sk), read_pnet(&x->pnet));
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void netlink_compare_arg_init(struct netlink_compare_arg *arg,
50362306a36Sopenharmony_ci				     struct net *net, u32 portid)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	memset(arg, 0, sizeof(*arg));
50662306a36Sopenharmony_ci	write_pnet(&arg->pnet, net);
50762306a36Sopenharmony_ci	arg->portid = portid;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic struct sock *__netlink_lookup(struct netlink_table *table, u32 portid,
51162306a36Sopenharmony_ci				     struct net *net)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct netlink_compare_arg arg;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	netlink_compare_arg_init(&arg, net, portid);
51662306a36Sopenharmony_ci	return rhashtable_lookup_fast(&table->hash, &arg,
51762306a36Sopenharmony_ci				      netlink_rhashtable_params);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int __netlink_insert(struct netlink_table *table, struct sock *sk)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct netlink_compare_arg arg;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	netlink_compare_arg_init(&arg, sock_net(sk), nlk_sk(sk)->portid);
52562306a36Sopenharmony_ci	return rhashtable_lookup_insert_key(&table->hash, &arg,
52662306a36Sopenharmony_ci					    &nlk_sk(sk)->node,
52762306a36Sopenharmony_ci					    netlink_rhashtable_params);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic struct sock *netlink_lookup(struct net *net, int protocol, u32 portid)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct netlink_table *table = &nl_table[protocol];
53362306a36Sopenharmony_ci	struct sock *sk;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	rcu_read_lock();
53662306a36Sopenharmony_ci	sk = __netlink_lookup(table, portid, net);
53762306a36Sopenharmony_ci	if (sk)
53862306a36Sopenharmony_ci		sock_hold(sk);
53962306a36Sopenharmony_ci	rcu_read_unlock();
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	return sk;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic const struct proto_ops netlink_ops;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic void
54762306a36Sopenharmony_cinetlink_update_listeners(struct sock *sk)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct netlink_table *tbl = &nl_table[sk->sk_protocol];
55062306a36Sopenharmony_ci	unsigned long mask;
55162306a36Sopenharmony_ci	unsigned int i;
55262306a36Sopenharmony_ci	struct listeners *listeners;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	listeners = nl_deref_protected(tbl->listeners);
55562306a36Sopenharmony_ci	if (!listeners)
55662306a36Sopenharmony_ci		return;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
55962306a36Sopenharmony_ci		mask = 0;
56062306a36Sopenharmony_ci		sk_for_each_bound(sk, &tbl->mc_list) {
56162306a36Sopenharmony_ci			if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
56262306a36Sopenharmony_ci				mask |= nlk_sk(sk)->groups[i];
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci		listeners->masks[i] = mask;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci	/* this function is only called with the netlink table "grabbed", which
56762306a36Sopenharmony_ci	 * makes sure updates are visible before bind or setsockopt return. */
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int netlink_insert(struct sock *sk, u32 portid)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct netlink_table *table = &nl_table[sk->sk_protocol];
57362306a36Sopenharmony_ci	int err;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	lock_sock(sk);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY;
57862306a36Sopenharmony_ci	if (nlk_sk(sk)->bound)
57962306a36Sopenharmony_ci		goto err;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* portid can be read locklessly from netlink_getname(). */
58262306a36Sopenharmony_ci	WRITE_ONCE(nlk_sk(sk)->portid, portid);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	sock_hold(sk);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	err = __netlink_insert(table, sk);
58762306a36Sopenharmony_ci	if (err) {
58862306a36Sopenharmony_ci		/* In case the hashtable backend returns with -EBUSY
58962306a36Sopenharmony_ci		 * from here, it must not escape to the caller.
59062306a36Sopenharmony_ci		 */
59162306a36Sopenharmony_ci		if (unlikely(err == -EBUSY))
59262306a36Sopenharmony_ci			err = -EOVERFLOW;
59362306a36Sopenharmony_ci		if (err == -EEXIST)
59462306a36Sopenharmony_ci			err = -EADDRINUSE;
59562306a36Sopenharmony_ci		sock_put(sk);
59662306a36Sopenharmony_ci		goto err;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* We need to ensure that the socket is hashed and visible. */
60062306a36Sopenharmony_ci	smp_wmb();
60162306a36Sopenharmony_ci	/* Paired with lockless reads from netlink_bind(),
60262306a36Sopenharmony_ci	 * netlink_connect() and netlink_sendmsg().
60362306a36Sopenharmony_ci	 */
60462306a36Sopenharmony_ci	WRITE_ONCE(nlk_sk(sk)->bound, portid);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cierr:
60762306a36Sopenharmony_ci	release_sock(sk);
60862306a36Sopenharmony_ci	return err;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic void netlink_remove(struct sock *sk)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	struct netlink_table *table;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	table = &nl_table[sk->sk_protocol];
61662306a36Sopenharmony_ci	if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node,
61762306a36Sopenharmony_ci				    netlink_rhashtable_params)) {
61862306a36Sopenharmony_ci		WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
61962306a36Sopenharmony_ci		__sock_put(sk);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	netlink_table_grab();
62362306a36Sopenharmony_ci	if (nlk_sk(sk)->subscriptions) {
62462306a36Sopenharmony_ci		__sk_del_bind_node(sk);
62562306a36Sopenharmony_ci		netlink_update_listeners(sk);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci	if (sk->sk_protocol == NETLINK_GENERIC)
62862306a36Sopenharmony_ci		atomic_inc(&genl_sk_destructing_cnt);
62962306a36Sopenharmony_ci	netlink_table_ungrab();
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic struct proto netlink_proto = {
63362306a36Sopenharmony_ci	.name	  = "NETLINK",
63462306a36Sopenharmony_ci	.owner	  = THIS_MODULE,
63562306a36Sopenharmony_ci	.obj_size = sizeof(struct netlink_sock),
63662306a36Sopenharmony_ci};
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int __netlink_create(struct net *net, struct socket *sock,
63962306a36Sopenharmony_ci			    struct mutex *cb_mutex, int protocol,
64062306a36Sopenharmony_ci			    int kern)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct sock *sk;
64362306a36Sopenharmony_ci	struct netlink_sock *nlk;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	sock->ops = &netlink_ops;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern);
64862306a36Sopenharmony_ci	if (!sk)
64962306a36Sopenharmony_ci		return -ENOMEM;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	sock_init_data(sock, sk);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	nlk = nlk_sk(sk);
65462306a36Sopenharmony_ci	if (cb_mutex) {
65562306a36Sopenharmony_ci		nlk->cb_mutex = cb_mutex;
65662306a36Sopenharmony_ci	} else {
65762306a36Sopenharmony_ci		nlk->cb_mutex = &nlk->cb_def_mutex;
65862306a36Sopenharmony_ci		mutex_init(nlk->cb_mutex);
65962306a36Sopenharmony_ci		lockdep_set_class_and_name(nlk->cb_mutex,
66062306a36Sopenharmony_ci					   nlk_cb_mutex_keys + protocol,
66162306a36Sopenharmony_ci					   nlk_cb_mutex_key_strings[protocol]);
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci	init_waitqueue_head(&nlk->wait);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	sk->sk_destruct = netlink_sock_destruct;
66662306a36Sopenharmony_ci	sk->sk_protocol = protocol;
66762306a36Sopenharmony_ci	return 0;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int netlink_create(struct net *net, struct socket *sock, int protocol,
67162306a36Sopenharmony_ci			  int kern)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct module *module = NULL;
67462306a36Sopenharmony_ci	struct mutex *cb_mutex;
67562306a36Sopenharmony_ci	struct netlink_sock *nlk;
67662306a36Sopenharmony_ci	int (*bind)(struct net *net, int group);
67762306a36Sopenharmony_ci	void (*unbind)(struct net *net, int group);
67862306a36Sopenharmony_ci	void (*release)(struct sock *sock, unsigned long *groups);
67962306a36Sopenharmony_ci	int err = 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	sock->state = SS_UNCONNECTED;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
68462306a36Sopenharmony_ci		return -ESOCKTNOSUPPORT;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (protocol < 0 || protocol >= MAX_LINKS)
68762306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
68862306a36Sopenharmony_ci	protocol = array_index_nospec(protocol, MAX_LINKS);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	netlink_lock_table();
69162306a36Sopenharmony_ci#ifdef CONFIG_MODULES
69262306a36Sopenharmony_ci	if (!nl_table[protocol].registered) {
69362306a36Sopenharmony_ci		netlink_unlock_table();
69462306a36Sopenharmony_ci		request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
69562306a36Sopenharmony_ci		netlink_lock_table();
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci#endif
69862306a36Sopenharmony_ci	if (nl_table[protocol].registered &&
69962306a36Sopenharmony_ci	    try_module_get(nl_table[protocol].module))
70062306a36Sopenharmony_ci		module = nl_table[protocol].module;
70162306a36Sopenharmony_ci	else
70262306a36Sopenharmony_ci		err = -EPROTONOSUPPORT;
70362306a36Sopenharmony_ci	cb_mutex = nl_table[protocol].cb_mutex;
70462306a36Sopenharmony_ci	bind = nl_table[protocol].bind;
70562306a36Sopenharmony_ci	unbind = nl_table[protocol].unbind;
70662306a36Sopenharmony_ci	release = nl_table[protocol].release;
70762306a36Sopenharmony_ci	netlink_unlock_table();
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (err < 0)
71062306a36Sopenharmony_ci		goto out;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	err = __netlink_create(net, sock, cb_mutex, protocol, kern);
71362306a36Sopenharmony_ci	if (err < 0)
71462306a36Sopenharmony_ci		goto out_module;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	sock_prot_inuse_add(net, &netlink_proto, 1);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	nlk = nlk_sk(sock->sk);
71962306a36Sopenharmony_ci	nlk->module = module;
72062306a36Sopenharmony_ci	nlk->netlink_bind = bind;
72162306a36Sopenharmony_ci	nlk->netlink_unbind = unbind;
72262306a36Sopenharmony_ci	nlk->netlink_release = release;
72362306a36Sopenharmony_ciout:
72462306a36Sopenharmony_ci	return err;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ciout_module:
72762306a36Sopenharmony_ci	module_put(module);
72862306a36Sopenharmony_ci	goto out;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void deferred_put_nlk_sk(struct rcu_head *head)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
73462306a36Sopenharmony_ci	struct sock *sk = &nlk->sk;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	kfree(nlk->groups);
73762306a36Sopenharmony_ci	nlk->groups = NULL;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (!refcount_dec_and_test(&sk->sk_refcnt))
74062306a36Sopenharmony_ci		return;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (nlk->cb_running && nlk->cb.done) {
74362306a36Sopenharmony_ci		INIT_WORK(&nlk->work, netlink_sock_destruct_work);
74462306a36Sopenharmony_ci		schedule_work(&nlk->work);
74562306a36Sopenharmony_ci		return;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	sk_free(sk);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic int netlink_release(struct socket *sock)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct sock *sk = sock->sk;
75462306a36Sopenharmony_ci	struct netlink_sock *nlk;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (!sk)
75762306a36Sopenharmony_ci		return 0;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	netlink_remove(sk);
76062306a36Sopenharmony_ci	sock_orphan(sk);
76162306a36Sopenharmony_ci	nlk = nlk_sk(sk);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/*
76462306a36Sopenharmony_ci	 * OK. Socket is unlinked, any packets that arrive now
76562306a36Sopenharmony_ci	 * will be purged.
76662306a36Sopenharmony_ci	 */
76762306a36Sopenharmony_ci	if (nlk->netlink_release)
76862306a36Sopenharmony_ci		nlk->netlink_release(sk, nlk->groups);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* must not acquire netlink_table_lock in any way again before unbind
77162306a36Sopenharmony_ci	 * and notifying genetlink is done as otherwise it might deadlock
77262306a36Sopenharmony_ci	 */
77362306a36Sopenharmony_ci	if (nlk->netlink_unbind) {
77462306a36Sopenharmony_ci		int i;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		for (i = 0; i < nlk->ngroups; i++)
77762306a36Sopenharmony_ci			if (test_bit(i, nlk->groups))
77862306a36Sopenharmony_ci				nlk->netlink_unbind(sock_net(sk), i + 1);
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci	if (sk->sk_protocol == NETLINK_GENERIC &&
78162306a36Sopenharmony_ci	    atomic_dec_return(&genl_sk_destructing_cnt) == 0)
78262306a36Sopenharmony_ci		wake_up(&genl_sk_destructing_waitq);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	sock->sk = NULL;
78562306a36Sopenharmony_ci	wake_up_interruptible_all(&nlk->wait);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	skb_queue_purge(&sk->sk_write_queue);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (nlk->portid && nlk->bound) {
79062306a36Sopenharmony_ci		struct netlink_notify n = {
79162306a36Sopenharmony_ci						.net = sock_net(sk),
79262306a36Sopenharmony_ci						.protocol = sk->sk_protocol,
79362306a36Sopenharmony_ci						.portid = nlk->portid,
79462306a36Sopenharmony_ci					  };
79562306a36Sopenharmony_ci		blocking_notifier_call_chain(&netlink_chain,
79662306a36Sopenharmony_ci				NETLINK_URELEASE, &n);
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	module_put(nlk->module);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (netlink_is_kernel(sk)) {
80262306a36Sopenharmony_ci		netlink_table_grab();
80362306a36Sopenharmony_ci		BUG_ON(nl_table[sk->sk_protocol].registered == 0);
80462306a36Sopenharmony_ci		if (--nl_table[sk->sk_protocol].registered == 0) {
80562306a36Sopenharmony_ci			struct listeners *old;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci			old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
80862306a36Sopenharmony_ci			RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
80962306a36Sopenharmony_ci			kfree_rcu(old, rcu);
81062306a36Sopenharmony_ci			nl_table[sk->sk_protocol].module = NULL;
81162306a36Sopenharmony_ci			nl_table[sk->sk_protocol].bind = NULL;
81262306a36Sopenharmony_ci			nl_table[sk->sk_protocol].unbind = NULL;
81362306a36Sopenharmony_ci			nl_table[sk->sk_protocol].flags = 0;
81462306a36Sopenharmony_ci			nl_table[sk->sk_protocol].registered = 0;
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci		netlink_table_ungrab();
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/* Because struct net might disappear soon, do not keep a pointer. */
82262306a36Sopenharmony_ci	if (!sk->sk_net_refcnt && sock_net(sk) != &init_net) {
82362306a36Sopenharmony_ci		__netns_tracker_free(sock_net(sk), &sk->ns_tracker, false);
82462306a36Sopenharmony_ci		/* Because of deferred_put_nlk_sk and use of work queue,
82562306a36Sopenharmony_ci		 * it is possible  netns will be freed before this socket.
82662306a36Sopenharmony_ci		 */
82762306a36Sopenharmony_ci		sock_net_set(sk, &init_net);
82862306a36Sopenharmony_ci		__netns_tracker_alloc(&init_net, &sk->ns_tracker,
82962306a36Sopenharmony_ci				      false, GFP_KERNEL);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci	call_rcu(&nlk->rcu, deferred_put_nlk_sk);
83262306a36Sopenharmony_ci	return 0;
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic int netlink_autobind(struct socket *sock)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	struct sock *sk = sock->sk;
83862306a36Sopenharmony_ci	struct net *net = sock_net(sk);
83962306a36Sopenharmony_ci	struct netlink_table *table = &nl_table[sk->sk_protocol];
84062306a36Sopenharmony_ci	s32 portid = task_tgid_vnr(current);
84162306a36Sopenharmony_ci	int err;
84262306a36Sopenharmony_ci	s32 rover = -4096;
84362306a36Sopenharmony_ci	bool ok;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ciretry:
84662306a36Sopenharmony_ci	cond_resched();
84762306a36Sopenharmony_ci	rcu_read_lock();
84862306a36Sopenharmony_ci	ok = !__netlink_lookup(table, portid, net);
84962306a36Sopenharmony_ci	rcu_read_unlock();
85062306a36Sopenharmony_ci	if (!ok) {
85162306a36Sopenharmony_ci		/* Bind collision, search negative portid values. */
85262306a36Sopenharmony_ci		if (rover == -4096)
85362306a36Sopenharmony_ci			/* rover will be in range [S32_MIN, -4097] */
85462306a36Sopenharmony_ci			rover = S32_MIN + get_random_u32_below(-4096 - S32_MIN);
85562306a36Sopenharmony_ci		else if (rover >= -4096)
85662306a36Sopenharmony_ci			rover = -4097;
85762306a36Sopenharmony_ci		portid = rover--;
85862306a36Sopenharmony_ci		goto retry;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	err = netlink_insert(sk, portid);
86262306a36Sopenharmony_ci	if (err == -EADDRINUSE)
86362306a36Sopenharmony_ci		goto retry;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* If 2 threads race to autobind, that is fine.  */
86662306a36Sopenharmony_ci	if (err == -EBUSY)
86762306a36Sopenharmony_ci		err = 0;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	return err;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci/**
87362306a36Sopenharmony_ci * __netlink_ns_capable - General netlink message capability test
87462306a36Sopenharmony_ci * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace.
87562306a36Sopenharmony_ci * @user_ns: The user namespace of the capability to use
87662306a36Sopenharmony_ci * @cap: The capability to use
87762306a36Sopenharmony_ci *
87862306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message
87962306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the
88062306a36Sopenharmony_ci * message has the capability @cap in the user namespace @user_ns.
88162306a36Sopenharmony_ci */
88262306a36Sopenharmony_cibool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
88362306a36Sopenharmony_ci			struct user_namespace *user_ns, int cap)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	return ((nsp->flags & NETLINK_SKB_DST) ||
88662306a36Sopenharmony_ci		file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) &&
88762306a36Sopenharmony_ci		ns_capable(user_ns, cap);
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_ns_capable);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci/**
89262306a36Sopenharmony_ci * netlink_ns_capable - General netlink message capability test
89362306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace
89462306a36Sopenharmony_ci * @user_ns: The user namespace of the capability to use
89562306a36Sopenharmony_ci * @cap: The capability to use
89662306a36Sopenharmony_ci *
89762306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message
89862306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the
89962306a36Sopenharmony_ci * message has the capability @cap in the user namespace @user_ns.
90062306a36Sopenharmony_ci */
90162306a36Sopenharmony_cibool netlink_ns_capable(const struct sk_buff *skb,
90262306a36Sopenharmony_ci			struct user_namespace *user_ns, int cap)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_ns_capable);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci/**
90962306a36Sopenharmony_ci * netlink_capable - Netlink global message capability test
91062306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace
91162306a36Sopenharmony_ci * @cap: The capability to use
91262306a36Sopenharmony_ci *
91362306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message
91462306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the
91562306a36Sopenharmony_ci * message has the capability @cap in all user namespaces.
91662306a36Sopenharmony_ci */
91762306a36Sopenharmony_cibool netlink_capable(const struct sk_buff *skb, int cap)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	return netlink_ns_capable(skb, &init_user_ns, cap);
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_capable);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/**
92462306a36Sopenharmony_ci * netlink_net_capable - Netlink network namespace message capability test
92562306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace
92662306a36Sopenharmony_ci * @cap: The capability to use
92762306a36Sopenharmony_ci *
92862306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message
92962306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the
93062306a36Sopenharmony_ci * message has the capability @cap over the network namespace of
93162306a36Sopenharmony_ci * the socket we received the message from.
93262306a36Sopenharmony_ci */
93362306a36Sopenharmony_cibool netlink_net_capable(const struct sk_buff *skb, int cap)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_net_capable);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic inline int netlink_allowed(const struct socket *sock, unsigned int flag)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	return (nl_table[sock->sk->sk_protocol].flags & flag) ||
94262306a36Sopenharmony_ci		ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic void
94662306a36Sopenharmony_cinetlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (nlk->subscriptions && !subscriptions)
95162306a36Sopenharmony_ci		__sk_del_bind_node(sk);
95262306a36Sopenharmony_ci	else if (!nlk->subscriptions && subscriptions)
95362306a36Sopenharmony_ci		sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list);
95462306a36Sopenharmony_ci	nlk->subscriptions = subscriptions;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic int netlink_realloc_groups(struct sock *sk)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
96062306a36Sopenharmony_ci	unsigned int groups;
96162306a36Sopenharmony_ci	unsigned long *new_groups;
96262306a36Sopenharmony_ci	int err = 0;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	netlink_table_grab();
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	groups = nl_table[sk->sk_protocol].groups;
96762306a36Sopenharmony_ci	if (!nl_table[sk->sk_protocol].registered) {
96862306a36Sopenharmony_ci		err = -ENOENT;
96962306a36Sopenharmony_ci		goto out_unlock;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (nlk->ngroups >= groups)
97362306a36Sopenharmony_ci		goto out_unlock;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
97662306a36Sopenharmony_ci	if (new_groups == NULL) {
97762306a36Sopenharmony_ci		err = -ENOMEM;
97862306a36Sopenharmony_ci		goto out_unlock;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci	memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0,
98162306a36Sopenharmony_ci	       NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	nlk->groups = new_groups;
98462306a36Sopenharmony_ci	nlk->ngroups = groups;
98562306a36Sopenharmony_ci out_unlock:
98662306a36Sopenharmony_ci	netlink_table_ungrab();
98762306a36Sopenharmony_ci	return err;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic void netlink_undo_bind(int group, long unsigned int groups,
99162306a36Sopenharmony_ci			      struct sock *sk)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
99462306a36Sopenharmony_ci	int undo;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!nlk->netlink_unbind)
99762306a36Sopenharmony_ci		return;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	for (undo = 0; undo < group; undo++)
100062306a36Sopenharmony_ci		if (test_bit(undo, &groups))
100162306a36Sopenharmony_ci			nlk->netlink_unbind(sock_net(sk), undo + 1);
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int netlink_bind(struct socket *sock, struct sockaddr *addr,
100562306a36Sopenharmony_ci			int addr_len)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct sock *sk = sock->sk;
100862306a36Sopenharmony_ci	struct net *net = sock_net(sk);
100962306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
101062306a36Sopenharmony_ci	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
101162306a36Sopenharmony_ci	int err = 0;
101262306a36Sopenharmony_ci	unsigned long groups;
101362306a36Sopenharmony_ci	bool bound;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (addr_len < sizeof(struct sockaddr_nl))
101662306a36Sopenharmony_ci		return -EINVAL;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (nladdr->nl_family != AF_NETLINK)
101962306a36Sopenharmony_ci		return -EINVAL;
102062306a36Sopenharmony_ci	groups = nladdr->nl_groups;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* Only superuser is allowed to listen multicasts */
102362306a36Sopenharmony_ci	if (groups) {
102462306a36Sopenharmony_ci		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
102562306a36Sopenharmony_ci			return -EPERM;
102662306a36Sopenharmony_ci		err = netlink_realloc_groups(sk);
102762306a36Sopenharmony_ci		if (err)
102862306a36Sopenharmony_ci			return err;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (nlk->ngroups < BITS_PER_LONG)
103262306a36Sopenharmony_ci		groups &= (1UL << nlk->ngroups) - 1;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/* Paired with WRITE_ONCE() in netlink_insert() */
103562306a36Sopenharmony_ci	bound = READ_ONCE(nlk->bound);
103662306a36Sopenharmony_ci	if (bound) {
103762306a36Sopenharmony_ci		/* Ensure nlk->portid is up-to-date. */
103862306a36Sopenharmony_ci		smp_rmb();
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		if (nladdr->nl_pid != nlk->portid)
104162306a36Sopenharmony_ci			return -EINVAL;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	if (nlk->netlink_bind && groups) {
104562306a36Sopenharmony_ci		int group;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		/* nl_groups is a u32, so cap the maximum groups we can bind */
104862306a36Sopenharmony_ci		for (group = 0; group < BITS_PER_TYPE(u32); group++) {
104962306a36Sopenharmony_ci			if (!test_bit(group, &groups))
105062306a36Sopenharmony_ci				continue;
105162306a36Sopenharmony_ci			err = nlk->netlink_bind(net, group + 1);
105262306a36Sopenharmony_ci			if (!err)
105362306a36Sopenharmony_ci				continue;
105462306a36Sopenharmony_ci			netlink_undo_bind(group, groups, sk);
105562306a36Sopenharmony_ci			return err;
105662306a36Sopenharmony_ci		}
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* No need for barriers here as we return to user-space without
106062306a36Sopenharmony_ci	 * using any of the bound attributes.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	netlink_lock_table();
106362306a36Sopenharmony_ci	if (!bound) {
106462306a36Sopenharmony_ci		err = nladdr->nl_pid ?
106562306a36Sopenharmony_ci			netlink_insert(sk, nladdr->nl_pid) :
106662306a36Sopenharmony_ci			netlink_autobind(sock);
106762306a36Sopenharmony_ci		if (err) {
106862306a36Sopenharmony_ci			netlink_undo_bind(BITS_PER_TYPE(u32), groups, sk);
106962306a36Sopenharmony_ci			goto unlock;
107062306a36Sopenharmony_ci		}
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
107462306a36Sopenharmony_ci		goto unlock;
107562306a36Sopenharmony_ci	netlink_unlock_table();
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	netlink_table_grab();
107862306a36Sopenharmony_ci	netlink_update_subscriptions(sk, nlk->subscriptions +
107962306a36Sopenharmony_ci					 hweight32(groups) -
108062306a36Sopenharmony_ci					 hweight32(nlk->groups[0]));
108162306a36Sopenharmony_ci	nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups;
108262306a36Sopenharmony_ci	netlink_update_listeners(sk);
108362306a36Sopenharmony_ci	netlink_table_ungrab();
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ciunlock:
108862306a36Sopenharmony_ci	netlink_unlock_table();
108962306a36Sopenharmony_ci	return err;
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic int netlink_connect(struct socket *sock, struct sockaddr *addr,
109362306a36Sopenharmony_ci			   int alen, int flags)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	int err = 0;
109662306a36Sopenharmony_ci	struct sock *sk = sock->sk;
109762306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
109862306a36Sopenharmony_ci	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (alen < sizeof(addr->sa_family))
110162306a36Sopenharmony_ci		return -EINVAL;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (addr->sa_family == AF_UNSPEC) {
110462306a36Sopenharmony_ci		/* paired with READ_ONCE() in netlink_getsockbyportid() */
110562306a36Sopenharmony_ci		WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED);
110662306a36Sopenharmony_ci		/* dst_portid and dst_group can be read locklessly */
110762306a36Sopenharmony_ci		WRITE_ONCE(nlk->dst_portid, 0);
110862306a36Sopenharmony_ci		WRITE_ONCE(nlk->dst_group, 0);
110962306a36Sopenharmony_ci		return 0;
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci	if (addr->sa_family != AF_NETLINK)
111262306a36Sopenharmony_ci		return -EINVAL;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (alen < sizeof(struct sockaddr_nl))
111562306a36Sopenharmony_ci		return -EINVAL;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if ((nladdr->nl_groups || nladdr->nl_pid) &&
111862306a36Sopenharmony_ci	    !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
111962306a36Sopenharmony_ci		return -EPERM;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* No need for barriers here as we return to user-space without
112262306a36Sopenharmony_ci	 * using any of the bound attributes.
112362306a36Sopenharmony_ci	 * Paired with WRITE_ONCE() in netlink_insert().
112462306a36Sopenharmony_ci	 */
112562306a36Sopenharmony_ci	if (!READ_ONCE(nlk->bound))
112662306a36Sopenharmony_ci		err = netlink_autobind(sock);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (err == 0) {
112962306a36Sopenharmony_ci		/* paired with READ_ONCE() in netlink_getsockbyportid() */
113062306a36Sopenharmony_ci		WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED);
113162306a36Sopenharmony_ci		/* dst_portid and dst_group can be read locklessly */
113262306a36Sopenharmony_ci		WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid);
113362306a36Sopenharmony_ci		WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups));
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	return err;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic int netlink_getname(struct socket *sock, struct sockaddr *addr,
114062306a36Sopenharmony_ci			   int peer)
114162306a36Sopenharmony_ci{
114262306a36Sopenharmony_ci	struct sock *sk = sock->sk;
114362306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
114462306a36Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	nladdr->nl_family = AF_NETLINK;
114762306a36Sopenharmony_ci	nladdr->nl_pad = 0;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if (peer) {
115062306a36Sopenharmony_ci		/* Paired with WRITE_ONCE() in netlink_connect() */
115162306a36Sopenharmony_ci		nladdr->nl_pid = READ_ONCE(nlk->dst_portid);
115262306a36Sopenharmony_ci		nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group));
115362306a36Sopenharmony_ci	} else {
115462306a36Sopenharmony_ci		/* Paired with WRITE_ONCE() in netlink_insert() */
115562306a36Sopenharmony_ci		nladdr->nl_pid = READ_ONCE(nlk->portid);
115662306a36Sopenharmony_ci		netlink_lock_table();
115762306a36Sopenharmony_ci		nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
115862306a36Sopenharmony_ci		netlink_unlock_table();
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci	return sizeof(*nladdr);
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_cistatic int netlink_ioctl(struct socket *sock, unsigned int cmd,
116462306a36Sopenharmony_ci			 unsigned long arg)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	/* try to hand this ioctl down to the NIC drivers.
116762306a36Sopenharmony_ci	 */
116862306a36Sopenharmony_ci	return -ENOIOCTLCMD;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	struct sock *sock;
117462306a36Sopenharmony_ci	struct netlink_sock *nlk;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, portid);
117762306a36Sopenharmony_ci	if (!sock)
117862306a36Sopenharmony_ci		return ERR_PTR(-ECONNREFUSED);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Don't bother queuing skb if kernel socket has no input function */
118162306a36Sopenharmony_ci	nlk = nlk_sk(sock);
118262306a36Sopenharmony_ci	/* dst_portid and sk_state can be changed in netlink_connect() */
118362306a36Sopenharmony_ci	if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED &&
118462306a36Sopenharmony_ci	    READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) {
118562306a36Sopenharmony_ci		sock_put(sock);
118662306a36Sopenharmony_ci		return ERR_PTR(-ECONNREFUSED);
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci	return sock;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistruct sock *netlink_getsockbyfilp(struct file *filp)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
119462306a36Sopenharmony_ci	struct sock *sock;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	if (!S_ISSOCK(inode->i_mode))
119762306a36Sopenharmony_ci		return ERR_PTR(-ENOTSOCK);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	sock = SOCKET_I(inode)->sk;
120062306a36Sopenharmony_ci	if (sock->sk_family != AF_NETLINK)
120162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	sock_hold(sock);
120462306a36Sopenharmony_ci	return sock;
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cistatic struct sk_buff *netlink_alloc_large_skb(unsigned int size,
120862306a36Sopenharmony_ci					       int broadcast)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct sk_buff *skb;
121162306a36Sopenharmony_ci	void *data;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (size <= NLMSG_GOODSIZE || broadcast)
121462306a36Sopenharmony_ci		return alloc_skb(size, GFP_KERNEL);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	size = SKB_DATA_ALIGN(size) +
121762306a36Sopenharmony_ci	       SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	data = vmalloc(size);
122062306a36Sopenharmony_ci	if (data == NULL)
122162306a36Sopenharmony_ci		return NULL;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	skb = __build_skb(data, size);
122462306a36Sopenharmony_ci	if (skb == NULL)
122562306a36Sopenharmony_ci		vfree(data);
122662306a36Sopenharmony_ci	else
122762306a36Sopenharmony_ci		skb->destructor = netlink_skb_destructor;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	return skb;
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci/*
123362306a36Sopenharmony_ci * Attach a skb to a netlink socket.
123462306a36Sopenharmony_ci * The caller must hold a reference to the destination socket. On error, the
123562306a36Sopenharmony_ci * reference is dropped. The skb is not send to the destination, just all
123662306a36Sopenharmony_ci * all error checks are performed and memory in the queue is reserved.
123762306a36Sopenharmony_ci * Return values:
123862306a36Sopenharmony_ci * < 0: error. skb freed, reference to sock dropped.
123962306a36Sopenharmony_ci * 0: continue
124062306a36Sopenharmony_ci * 1: repeat lookup - reference dropped while waiting for socket memory.
124162306a36Sopenharmony_ci */
124262306a36Sopenharmony_ciint netlink_attachskb(struct sock *sk, struct sk_buff *skb,
124362306a36Sopenharmony_ci		      long *timeo, struct sock *ssk)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct netlink_sock *nlk;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	nlk = nlk_sk(sk);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
125062306a36Sopenharmony_ci	     test_bit(NETLINK_S_CONGESTED, &nlk->state))) {
125162306a36Sopenharmony_ci		DECLARE_WAITQUEUE(wait, current);
125262306a36Sopenharmony_ci		if (!*timeo) {
125362306a36Sopenharmony_ci			if (!ssk || netlink_is_kernel(ssk))
125462306a36Sopenharmony_ci				netlink_overrun(sk);
125562306a36Sopenharmony_ci			sock_put(sk);
125662306a36Sopenharmony_ci			kfree_skb(skb);
125762306a36Sopenharmony_ci			return -EAGAIN;
125862306a36Sopenharmony_ci		}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci		__set_current_state(TASK_INTERRUPTIBLE);
126162306a36Sopenharmony_ci		add_wait_queue(&nlk->wait, &wait);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci		if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
126462306a36Sopenharmony_ci		     test_bit(NETLINK_S_CONGESTED, &nlk->state)) &&
126562306a36Sopenharmony_ci		    !sock_flag(sk, SOCK_DEAD))
126662306a36Sopenharmony_ci			*timeo = schedule_timeout(*timeo);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		__set_current_state(TASK_RUNNING);
126962306a36Sopenharmony_ci		remove_wait_queue(&nlk->wait, &wait);
127062306a36Sopenharmony_ci		sock_put(sk);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		if (signal_pending(current)) {
127362306a36Sopenharmony_ci			kfree_skb(skb);
127462306a36Sopenharmony_ci			return sock_intr_errno(*timeo);
127562306a36Sopenharmony_ci		}
127662306a36Sopenharmony_ci		return 1;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci	netlink_skb_set_owner_r(skb, sk);
127962306a36Sopenharmony_ci	return 0;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	int len = skb->len;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	netlink_deliver_tap(sock_net(sk), skb);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	skb_queue_tail(&sk->sk_receive_queue, skb);
128962306a36Sopenharmony_ci	sk->sk_data_ready(sk);
129062306a36Sopenharmony_ci	return len;
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ciint netlink_sendskb(struct sock *sk, struct sk_buff *skb)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	int len = __netlink_sendskb(sk, skb);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	sock_put(sk);
129862306a36Sopenharmony_ci	return len;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_civoid netlink_detachskb(struct sock *sk, struct sk_buff *skb)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	kfree_skb(skb);
130462306a36Sopenharmony_ci	sock_put(sk);
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
130862306a36Sopenharmony_ci{
130962306a36Sopenharmony_ci	int delta;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	WARN_ON(skb->sk != NULL);
131262306a36Sopenharmony_ci	delta = skb->end - skb->tail;
131362306a36Sopenharmony_ci	if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
131462306a36Sopenharmony_ci		return skb;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (skb_shared(skb)) {
131762306a36Sopenharmony_ci		struct sk_buff *nskb = skb_clone(skb, allocation);
131862306a36Sopenharmony_ci		if (!nskb)
131962306a36Sopenharmony_ci			return skb;
132062306a36Sopenharmony_ci		consume_skb(skb);
132162306a36Sopenharmony_ci		skb = nskb;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	pskb_expand_head(skb, 0, -delta,
132562306a36Sopenharmony_ci			 (allocation & ~__GFP_DIRECT_RECLAIM) |
132662306a36Sopenharmony_ci			 __GFP_NOWARN | __GFP_NORETRY);
132762306a36Sopenharmony_ci	return skb;
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
133162306a36Sopenharmony_ci				  struct sock *ssk)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	int ret;
133462306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	ret = -ECONNREFUSED;
133762306a36Sopenharmony_ci	if (nlk->netlink_rcv != NULL) {
133862306a36Sopenharmony_ci		ret = skb->len;
133962306a36Sopenharmony_ci		netlink_skb_set_owner_r(skb, sk);
134062306a36Sopenharmony_ci		NETLINK_CB(skb).sk = ssk;
134162306a36Sopenharmony_ci		netlink_deliver_tap_kernel(sk, ssk, skb);
134262306a36Sopenharmony_ci		nlk->netlink_rcv(skb);
134362306a36Sopenharmony_ci		consume_skb(skb);
134462306a36Sopenharmony_ci	} else {
134562306a36Sopenharmony_ci		kfree_skb(skb);
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci	sock_put(sk);
134862306a36Sopenharmony_ci	return ret;
134962306a36Sopenharmony_ci}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ciint netlink_unicast(struct sock *ssk, struct sk_buff *skb,
135262306a36Sopenharmony_ci		    u32 portid, int nonblock)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct sock *sk;
135562306a36Sopenharmony_ci	int err;
135662306a36Sopenharmony_ci	long timeo;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	skb = netlink_trim(skb, gfp_any());
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	timeo = sock_sndtimeo(ssk, nonblock);
136162306a36Sopenharmony_ciretry:
136262306a36Sopenharmony_ci	sk = netlink_getsockbyportid(ssk, portid);
136362306a36Sopenharmony_ci	if (IS_ERR(sk)) {
136462306a36Sopenharmony_ci		kfree_skb(skb);
136562306a36Sopenharmony_ci		return PTR_ERR(sk);
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci	if (netlink_is_kernel(sk))
136862306a36Sopenharmony_ci		return netlink_unicast_kernel(sk, skb, ssk);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	if (sk_filter(sk, skb)) {
137162306a36Sopenharmony_ci		err = skb->len;
137262306a36Sopenharmony_ci		kfree_skb(skb);
137362306a36Sopenharmony_ci		sock_put(sk);
137462306a36Sopenharmony_ci		return err;
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	err = netlink_attachskb(sk, skb, &timeo, ssk);
137862306a36Sopenharmony_ci	if (err == 1)
137962306a36Sopenharmony_ci		goto retry;
138062306a36Sopenharmony_ci	if (err)
138162306a36Sopenharmony_ci		return err;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	return netlink_sendskb(sk, skb);
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_unicast);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ciint netlink_has_listeners(struct sock *sk, unsigned int group)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	int res = 0;
139062306a36Sopenharmony_ci	struct listeners *listeners;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	BUG_ON(!netlink_is_kernel(sk));
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	rcu_read_lock();
139562306a36Sopenharmony_ci	listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
139862306a36Sopenharmony_ci		res = test_bit(group - 1, listeners->masks);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	rcu_read_unlock();
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return res;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_has_listeners);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cibool netlink_strict_get_check(struct sk_buff *skb)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	return nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk);
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_strict_get_check);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
141762306a36Sopenharmony_ci	    !test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
141862306a36Sopenharmony_ci		netlink_skb_set_owner_r(skb, sk);
141962306a36Sopenharmony_ci		__netlink_sendskb(sk, skb);
142062306a36Sopenharmony_ci		return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci	return -1;
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistruct netlink_broadcast_data {
142662306a36Sopenharmony_ci	struct sock *exclude_sk;
142762306a36Sopenharmony_ci	struct net *net;
142862306a36Sopenharmony_ci	u32 portid;
142962306a36Sopenharmony_ci	u32 group;
143062306a36Sopenharmony_ci	int failure;
143162306a36Sopenharmony_ci	int delivery_failure;
143262306a36Sopenharmony_ci	int congested;
143362306a36Sopenharmony_ci	int delivered;
143462306a36Sopenharmony_ci	gfp_t allocation;
143562306a36Sopenharmony_ci	struct sk_buff *skb, *skb2;
143662306a36Sopenharmony_ci	int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data);
143762306a36Sopenharmony_ci	void *tx_data;
143862306a36Sopenharmony_ci};
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_cistatic void do_one_broadcast(struct sock *sk,
144162306a36Sopenharmony_ci				    struct netlink_broadcast_data *p)
144262306a36Sopenharmony_ci{
144362306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
144462306a36Sopenharmony_ci	int val;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (p->exclude_sk == sk)
144762306a36Sopenharmony_ci		return;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups ||
145062306a36Sopenharmony_ci	    !test_bit(p->group - 1, nlk->groups))
145162306a36Sopenharmony_ci		return;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (!net_eq(sock_net(sk), p->net)) {
145462306a36Sopenharmony_ci		if (!nlk_test_bit(LISTEN_ALL_NSID, sk))
145562306a36Sopenharmony_ci			return;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci		if (!peernet_has_id(sock_net(sk), p->net))
145862306a36Sopenharmony_ci			return;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci		if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns,
146162306a36Sopenharmony_ci				     CAP_NET_BROADCAST))
146262306a36Sopenharmony_ci			return;
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	if (p->failure) {
146662306a36Sopenharmony_ci		netlink_overrun(sk);
146762306a36Sopenharmony_ci		return;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	sock_hold(sk);
147162306a36Sopenharmony_ci	if (p->skb2 == NULL) {
147262306a36Sopenharmony_ci		if (skb_shared(p->skb)) {
147362306a36Sopenharmony_ci			p->skb2 = skb_clone(p->skb, p->allocation);
147462306a36Sopenharmony_ci		} else {
147562306a36Sopenharmony_ci			p->skb2 = skb_get(p->skb);
147662306a36Sopenharmony_ci			/*
147762306a36Sopenharmony_ci			 * skb ownership may have been set when
147862306a36Sopenharmony_ci			 * delivered to a previous socket.
147962306a36Sopenharmony_ci			 */
148062306a36Sopenharmony_ci			skb_orphan(p->skb2);
148162306a36Sopenharmony_ci		}
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci	if (p->skb2 == NULL) {
148462306a36Sopenharmony_ci		netlink_overrun(sk);
148562306a36Sopenharmony_ci		/* Clone failed. Notify ALL listeners. */
148662306a36Sopenharmony_ci		p->failure = 1;
148762306a36Sopenharmony_ci		if (nlk_test_bit(BROADCAST_SEND_ERROR, sk))
148862306a36Sopenharmony_ci			p->delivery_failure = 1;
148962306a36Sopenharmony_ci		goto out;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) {
149362306a36Sopenharmony_ci		kfree_skb(p->skb2);
149462306a36Sopenharmony_ci		p->skb2 = NULL;
149562306a36Sopenharmony_ci		goto out;
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	if (sk_filter(sk, p->skb2)) {
149962306a36Sopenharmony_ci		kfree_skb(p->skb2);
150062306a36Sopenharmony_ci		p->skb2 = NULL;
150162306a36Sopenharmony_ci		goto out;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci	NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net);
150462306a36Sopenharmony_ci	if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED)
150562306a36Sopenharmony_ci		NETLINK_CB(p->skb2).nsid_is_set = true;
150662306a36Sopenharmony_ci	val = netlink_broadcast_deliver(sk, p->skb2);
150762306a36Sopenharmony_ci	if (val < 0) {
150862306a36Sopenharmony_ci		netlink_overrun(sk);
150962306a36Sopenharmony_ci		if (nlk_test_bit(BROADCAST_SEND_ERROR, sk))
151062306a36Sopenharmony_ci			p->delivery_failure = 1;
151162306a36Sopenharmony_ci	} else {
151262306a36Sopenharmony_ci		p->congested |= val;
151362306a36Sopenharmony_ci		p->delivered = 1;
151462306a36Sopenharmony_ci		p->skb2 = NULL;
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ciout:
151762306a36Sopenharmony_ci	sock_put(sk);
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ciint netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb,
152162306a36Sopenharmony_ci			       u32 portid,
152262306a36Sopenharmony_ci			       u32 group, gfp_t allocation,
152362306a36Sopenharmony_ci			       int (*filter)(struct sock *dsk,
152462306a36Sopenharmony_ci					     struct sk_buff *skb, void *data),
152562306a36Sopenharmony_ci			       void *filter_data)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	struct net *net = sock_net(ssk);
152862306a36Sopenharmony_ci	struct netlink_broadcast_data info;
152962306a36Sopenharmony_ci	struct sock *sk;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	skb = netlink_trim(skb, allocation);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	info.exclude_sk = ssk;
153462306a36Sopenharmony_ci	info.net = net;
153562306a36Sopenharmony_ci	info.portid = portid;
153662306a36Sopenharmony_ci	info.group = group;
153762306a36Sopenharmony_ci	info.failure = 0;
153862306a36Sopenharmony_ci	info.delivery_failure = 0;
153962306a36Sopenharmony_ci	info.congested = 0;
154062306a36Sopenharmony_ci	info.delivered = 0;
154162306a36Sopenharmony_ci	info.allocation = allocation;
154262306a36Sopenharmony_ci	info.skb = skb;
154362306a36Sopenharmony_ci	info.skb2 = NULL;
154462306a36Sopenharmony_ci	info.tx_filter = filter;
154562306a36Sopenharmony_ci	info.tx_data = filter_data;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	/* While we sleep in clone, do not allow to change socket list */
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	netlink_lock_table();
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
155262306a36Sopenharmony_ci		do_one_broadcast(sk, &info);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	consume_skb(skb);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	netlink_unlock_table();
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (info.delivery_failure) {
155962306a36Sopenharmony_ci		kfree_skb(info.skb2);
156062306a36Sopenharmony_ci		return -ENOBUFS;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci	consume_skb(info.skb2);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (info.delivered) {
156562306a36Sopenharmony_ci		if (info.congested && gfpflags_allow_blocking(allocation))
156662306a36Sopenharmony_ci			yield();
156762306a36Sopenharmony_ci		return 0;
156862306a36Sopenharmony_ci	}
156962306a36Sopenharmony_ci	return -ESRCH;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_broadcast_filtered);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ciint netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 portid,
157462306a36Sopenharmony_ci		      u32 group, gfp_t allocation)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	return netlink_broadcast_filtered(ssk, skb, portid, group, allocation,
157762306a36Sopenharmony_ci					  NULL, NULL);
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_broadcast);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistruct netlink_set_err_data {
158262306a36Sopenharmony_ci	struct sock *exclude_sk;
158362306a36Sopenharmony_ci	u32 portid;
158462306a36Sopenharmony_ci	u32 group;
158562306a36Sopenharmony_ci	int code;
158662306a36Sopenharmony_ci};
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
159162306a36Sopenharmony_ci	int ret = 0;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (sk == p->exclude_sk)
159462306a36Sopenharmony_ci		goto out;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (!net_eq(sock_net(sk), sock_net(p->exclude_sk)))
159762306a36Sopenharmony_ci		goto out;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups ||
160062306a36Sopenharmony_ci	    !test_bit(p->group - 1, nlk->groups))
160162306a36Sopenharmony_ci		goto out;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	if (p->code == ENOBUFS && nlk_test_bit(RECV_NO_ENOBUFS, sk)) {
160462306a36Sopenharmony_ci		ret = 1;
160562306a36Sopenharmony_ci		goto out;
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	WRITE_ONCE(sk->sk_err, p->code);
160962306a36Sopenharmony_ci	sk_error_report(sk);
161062306a36Sopenharmony_ciout:
161162306a36Sopenharmony_ci	return ret;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci/**
161562306a36Sopenharmony_ci * netlink_set_err - report error to broadcast listeners
161662306a36Sopenharmony_ci * @ssk: the kernel netlink socket, as returned by netlink_kernel_create()
161762306a36Sopenharmony_ci * @portid: the PORTID of a process that we want to skip (if any)
161862306a36Sopenharmony_ci * @group: the broadcast group that will notice the error
161962306a36Sopenharmony_ci * @code: error code, must be negative (as usual in kernelspace)
162062306a36Sopenharmony_ci *
162162306a36Sopenharmony_ci * This function returns the number of broadcast listeners that have set the
162262306a36Sopenharmony_ci * NETLINK_NO_ENOBUFS socket option.
162362306a36Sopenharmony_ci */
162462306a36Sopenharmony_ciint netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code)
162562306a36Sopenharmony_ci{
162662306a36Sopenharmony_ci	struct netlink_set_err_data info;
162762306a36Sopenharmony_ci	unsigned long flags;
162862306a36Sopenharmony_ci	struct sock *sk;
162962306a36Sopenharmony_ci	int ret = 0;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	info.exclude_sk = ssk;
163262306a36Sopenharmony_ci	info.portid = portid;
163362306a36Sopenharmony_ci	info.group = group;
163462306a36Sopenharmony_ci	/* sk->sk_err wants a positive error value */
163562306a36Sopenharmony_ci	info.code = -code;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	read_lock_irqsave(&nl_table_lock, flags);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
164062306a36Sopenharmony_ci		ret += do_one_set_err(sk, &info);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	read_unlock_irqrestore(&nl_table_lock, flags);
164362306a36Sopenharmony_ci	return ret;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_set_err);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci/* must be called with netlink table grabbed */
164862306a36Sopenharmony_cistatic void netlink_update_socket_mc(struct netlink_sock *nlk,
164962306a36Sopenharmony_ci				     unsigned int group,
165062306a36Sopenharmony_ci				     int is_new)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	int old, new = !!is_new, subscriptions;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	old = test_bit(group - 1, nlk->groups);
165562306a36Sopenharmony_ci	subscriptions = nlk->subscriptions - old + new;
165662306a36Sopenharmony_ci	__assign_bit(group - 1, nlk->groups, new);
165762306a36Sopenharmony_ci	netlink_update_subscriptions(&nlk->sk, subscriptions);
165862306a36Sopenharmony_ci	netlink_update_listeners(&nlk->sk);
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic int netlink_setsockopt(struct socket *sock, int level, int optname,
166262306a36Sopenharmony_ci			      sockptr_t optval, unsigned int optlen)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	struct sock *sk = sock->sk;
166562306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
166662306a36Sopenharmony_ci	unsigned int val = 0;
166762306a36Sopenharmony_ci	int nr = -1;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (level != SOL_NETLINK)
167062306a36Sopenharmony_ci		return -ENOPROTOOPT;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (optlen >= sizeof(int) &&
167362306a36Sopenharmony_ci	    copy_from_sockptr(&val, optval, sizeof(val)))
167462306a36Sopenharmony_ci		return -EFAULT;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	switch (optname) {
167762306a36Sopenharmony_ci	case NETLINK_PKTINFO:
167862306a36Sopenharmony_ci		nr = NETLINK_F_RECV_PKTINFO;
167962306a36Sopenharmony_ci		break;
168062306a36Sopenharmony_ci	case NETLINK_ADD_MEMBERSHIP:
168162306a36Sopenharmony_ci	case NETLINK_DROP_MEMBERSHIP: {
168262306a36Sopenharmony_ci		int err;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
168562306a36Sopenharmony_ci			return -EPERM;
168662306a36Sopenharmony_ci		err = netlink_realloc_groups(sk);
168762306a36Sopenharmony_ci		if (err)
168862306a36Sopenharmony_ci			return err;
168962306a36Sopenharmony_ci		if (!val || val - 1 >= nlk->ngroups)
169062306a36Sopenharmony_ci			return -EINVAL;
169162306a36Sopenharmony_ci		if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) {
169262306a36Sopenharmony_ci			err = nlk->netlink_bind(sock_net(sk), val);
169362306a36Sopenharmony_ci			if (err)
169462306a36Sopenharmony_ci				return err;
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci		netlink_table_grab();
169762306a36Sopenharmony_ci		netlink_update_socket_mc(nlk, val,
169862306a36Sopenharmony_ci					 optname == NETLINK_ADD_MEMBERSHIP);
169962306a36Sopenharmony_ci		netlink_table_ungrab();
170062306a36Sopenharmony_ci		if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
170162306a36Sopenharmony_ci			nlk->netlink_unbind(sock_net(sk), val);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci		break;
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci	case NETLINK_BROADCAST_ERROR:
170662306a36Sopenharmony_ci		nr = NETLINK_F_BROADCAST_SEND_ERROR;
170762306a36Sopenharmony_ci		break;
170862306a36Sopenharmony_ci	case NETLINK_NO_ENOBUFS:
170962306a36Sopenharmony_ci		assign_bit(NETLINK_F_RECV_NO_ENOBUFS, &nlk->flags, val);
171062306a36Sopenharmony_ci		if (val) {
171162306a36Sopenharmony_ci			clear_bit(NETLINK_S_CONGESTED, &nlk->state);
171262306a36Sopenharmony_ci			wake_up_interruptible(&nlk->wait);
171362306a36Sopenharmony_ci		}
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci	case NETLINK_LISTEN_ALL_NSID:
171662306a36Sopenharmony_ci		if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST))
171762306a36Sopenharmony_ci			return -EPERM;
171862306a36Sopenharmony_ci		nr = NETLINK_F_LISTEN_ALL_NSID;
171962306a36Sopenharmony_ci		break;
172062306a36Sopenharmony_ci	case NETLINK_CAP_ACK:
172162306a36Sopenharmony_ci		nr = NETLINK_F_CAP_ACK;
172262306a36Sopenharmony_ci		break;
172362306a36Sopenharmony_ci	case NETLINK_EXT_ACK:
172462306a36Sopenharmony_ci		nr = NETLINK_F_EXT_ACK;
172562306a36Sopenharmony_ci		break;
172662306a36Sopenharmony_ci	case NETLINK_GET_STRICT_CHK:
172762306a36Sopenharmony_ci		nr = NETLINK_F_STRICT_CHK;
172862306a36Sopenharmony_ci		break;
172962306a36Sopenharmony_ci	default:
173062306a36Sopenharmony_ci		return -ENOPROTOOPT;
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci	if (nr >= 0)
173362306a36Sopenharmony_ci		assign_bit(nr, &nlk->flags, val);
173462306a36Sopenharmony_ci	return 0;
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic int netlink_getsockopt(struct socket *sock, int level, int optname,
173862306a36Sopenharmony_ci			      char __user *optval, int __user *optlen)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
174162306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
174262306a36Sopenharmony_ci	unsigned int flag;
174362306a36Sopenharmony_ci	int len, val;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if (level != SOL_NETLINK)
174662306a36Sopenharmony_ci		return -ENOPROTOOPT;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	if (get_user(len, optlen))
174962306a36Sopenharmony_ci		return -EFAULT;
175062306a36Sopenharmony_ci	if (len < 0)
175162306a36Sopenharmony_ci		return -EINVAL;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	switch (optname) {
175462306a36Sopenharmony_ci	case NETLINK_PKTINFO:
175562306a36Sopenharmony_ci		flag = NETLINK_F_RECV_PKTINFO;
175662306a36Sopenharmony_ci		break;
175762306a36Sopenharmony_ci	case NETLINK_BROADCAST_ERROR:
175862306a36Sopenharmony_ci		flag = NETLINK_F_BROADCAST_SEND_ERROR;
175962306a36Sopenharmony_ci		break;
176062306a36Sopenharmony_ci	case NETLINK_NO_ENOBUFS:
176162306a36Sopenharmony_ci		flag = NETLINK_F_RECV_NO_ENOBUFS;
176262306a36Sopenharmony_ci		break;
176362306a36Sopenharmony_ci	case NETLINK_LIST_MEMBERSHIPS: {
176462306a36Sopenharmony_ci		int pos, idx, shift, err = 0;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci		netlink_lock_table();
176762306a36Sopenharmony_ci		for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) {
176862306a36Sopenharmony_ci			if (len - pos < sizeof(u32))
176962306a36Sopenharmony_ci				break;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci			idx = pos / sizeof(unsigned long);
177262306a36Sopenharmony_ci			shift = (pos % sizeof(unsigned long)) * 8;
177362306a36Sopenharmony_ci			if (put_user((u32)(nlk->groups[idx] >> shift),
177462306a36Sopenharmony_ci				     (u32 __user *)(optval + pos))) {
177562306a36Sopenharmony_ci				err = -EFAULT;
177662306a36Sopenharmony_ci				break;
177762306a36Sopenharmony_ci			}
177862306a36Sopenharmony_ci		}
177962306a36Sopenharmony_ci		if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen))
178062306a36Sopenharmony_ci			err = -EFAULT;
178162306a36Sopenharmony_ci		netlink_unlock_table();
178262306a36Sopenharmony_ci		return err;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	case NETLINK_CAP_ACK:
178562306a36Sopenharmony_ci		flag = NETLINK_F_CAP_ACK;
178662306a36Sopenharmony_ci		break;
178762306a36Sopenharmony_ci	case NETLINK_EXT_ACK:
178862306a36Sopenharmony_ci		flag = NETLINK_F_EXT_ACK;
178962306a36Sopenharmony_ci		break;
179062306a36Sopenharmony_ci	case NETLINK_GET_STRICT_CHK:
179162306a36Sopenharmony_ci		flag = NETLINK_F_STRICT_CHK;
179262306a36Sopenharmony_ci		break;
179362306a36Sopenharmony_ci	default:
179462306a36Sopenharmony_ci		return -ENOPROTOOPT;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (len < sizeof(int))
179862306a36Sopenharmony_ci		return -EINVAL;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	len = sizeof(int);
180162306a36Sopenharmony_ci	val = test_bit(flag, &nlk->flags);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (put_user(len, optlen) ||
180462306a36Sopenharmony_ci	    copy_to_user(optval, &val, len))
180562306a36Sopenharmony_ci		return -EFAULT;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	return 0;
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	struct nl_pktinfo info;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	info.group = NETLINK_CB(skb).dst_group;
181562306a36Sopenharmony_ci	put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info);
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_cistatic void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg,
181962306a36Sopenharmony_ci					 struct sk_buff *skb)
182062306a36Sopenharmony_ci{
182162306a36Sopenharmony_ci	if (!NETLINK_CB(skb).nsid_is_set)
182262306a36Sopenharmony_ci		return;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int),
182562306a36Sopenharmony_ci		 &NETLINK_CB(skb).nsid);
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_cistatic int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
182962306a36Sopenharmony_ci{
183062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
183162306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
183262306a36Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
183362306a36Sopenharmony_ci	u32 dst_portid;
183462306a36Sopenharmony_ci	u32 dst_group;
183562306a36Sopenharmony_ci	struct sk_buff *skb;
183662306a36Sopenharmony_ci	int err;
183762306a36Sopenharmony_ci	struct scm_cookie scm;
183862306a36Sopenharmony_ci	u32 netlink_skb_flags = 0;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (msg->msg_flags & MSG_OOB)
184162306a36Sopenharmony_ci		return -EOPNOTSUPP;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	if (len == 0) {
184462306a36Sopenharmony_ci		pr_warn_once("Zero length message leads to an empty skb\n");
184562306a36Sopenharmony_ci		return -ENODATA;
184662306a36Sopenharmony_ci	}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	err = scm_send(sock, msg, &scm, true);
184962306a36Sopenharmony_ci	if (err < 0)
185062306a36Sopenharmony_ci		return err;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (msg->msg_namelen) {
185362306a36Sopenharmony_ci		err = -EINVAL;
185462306a36Sopenharmony_ci		if (msg->msg_namelen < sizeof(struct sockaddr_nl))
185562306a36Sopenharmony_ci			goto out;
185662306a36Sopenharmony_ci		if (addr->nl_family != AF_NETLINK)
185762306a36Sopenharmony_ci			goto out;
185862306a36Sopenharmony_ci		dst_portid = addr->nl_pid;
185962306a36Sopenharmony_ci		dst_group = ffs(addr->nl_groups);
186062306a36Sopenharmony_ci		err =  -EPERM;
186162306a36Sopenharmony_ci		if ((dst_group || dst_portid) &&
186262306a36Sopenharmony_ci		    !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
186362306a36Sopenharmony_ci			goto out;
186462306a36Sopenharmony_ci		netlink_skb_flags |= NETLINK_SKB_DST;
186562306a36Sopenharmony_ci	} else {
186662306a36Sopenharmony_ci		/* Paired with WRITE_ONCE() in netlink_connect() */
186762306a36Sopenharmony_ci		dst_portid = READ_ONCE(nlk->dst_portid);
186862306a36Sopenharmony_ci		dst_group = READ_ONCE(nlk->dst_group);
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	/* Paired with WRITE_ONCE() in netlink_insert() */
187262306a36Sopenharmony_ci	if (!READ_ONCE(nlk->bound)) {
187362306a36Sopenharmony_ci		err = netlink_autobind(sock);
187462306a36Sopenharmony_ci		if (err)
187562306a36Sopenharmony_ci			goto out;
187662306a36Sopenharmony_ci	} else {
187762306a36Sopenharmony_ci		/* Ensure nlk is hashed and visible. */
187862306a36Sopenharmony_ci		smp_rmb();
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	err = -EMSGSIZE;
188262306a36Sopenharmony_ci	if (len > sk->sk_sndbuf - 32)
188362306a36Sopenharmony_ci		goto out;
188462306a36Sopenharmony_ci	err = -ENOBUFS;
188562306a36Sopenharmony_ci	skb = netlink_alloc_large_skb(len, dst_group);
188662306a36Sopenharmony_ci	if (skb == NULL)
188762306a36Sopenharmony_ci		goto out;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	NETLINK_CB(skb).portid	= nlk->portid;
189062306a36Sopenharmony_ci	NETLINK_CB(skb).dst_group = dst_group;
189162306a36Sopenharmony_ci	NETLINK_CB(skb).creds	= scm.creds;
189262306a36Sopenharmony_ci	NETLINK_CB(skb).flags	= netlink_skb_flags;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	err = -EFAULT;
189562306a36Sopenharmony_ci	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
189662306a36Sopenharmony_ci		kfree_skb(skb);
189762306a36Sopenharmony_ci		goto out;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	err = security_netlink_send(sk, skb);
190162306a36Sopenharmony_ci	if (err) {
190262306a36Sopenharmony_ci		kfree_skb(skb);
190362306a36Sopenharmony_ci		goto out;
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (dst_group) {
190762306a36Sopenharmony_ci		refcount_inc(&skb->users);
190862306a36Sopenharmony_ci		netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL);
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci	err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags & MSG_DONTWAIT);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ciout:
191362306a36Sopenharmony_ci	scm_destroy(&scm);
191462306a36Sopenharmony_ci	return err;
191562306a36Sopenharmony_ci}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
191862306a36Sopenharmony_ci			   int flags)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct scm_cookie scm;
192162306a36Sopenharmony_ci	struct sock *sk = sock->sk;
192262306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
192362306a36Sopenharmony_ci	size_t copied, max_recvmsg_len;
192462306a36Sopenharmony_ci	struct sk_buff *skb, *data_skb;
192562306a36Sopenharmony_ci	int err, ret;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (flags & MSG_OOB)
192862306a36Sopenharmony_ci		return -EOPNOTSUPP;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	copied = 0;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, &err);
193362306a36Sopenharmony_ci	if (skb == NULL)
193462306a36Sopenharmony_ci		goto out;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	data_skb = skb;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
193962306a36Sopenharmony_ci	if (unlikely(skb_shinfo(skb)->frag_list)) {
194062306a36Sopenharmony_ci		/*
194162306a36Sopenharmony_ci		 * If this skb has a frag_list, then here that means that we
194262306a36Sopenharmony_ci		 * will have to use the frag_list skb's data for compat tasks
194362306a36Sopenharmony_ci		 * and the regular skb's data for normal (non-compat) tasks.
194462306a36Sopenharmony_ci		 *
194562306a36Sopenharmony_ci		 * If we need to send the compat skb, assign it to the
194662306a36Sopenharmony_ci		 * 'data_skb' variable so that it will be used below for data
194762306a36Sopenharmony_ci		 * copying. We keep 'skb' for everything else, including
194862306a36Sopenharmony_ci		 * freeing both later.
194962306a36Sopenharmony_ci		 */
195062306a36Sopenharmony_ci		if (flags & MSG_CMSG_COMPAT)
195162306a36Sopenharmony_ci			data_skb = skb_shinfo(skb)->frag_list;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci#endif
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* Record the max length of recvmsg() calls for future allocations */
195662306a36Sopenharmony_ci	max_recvmsg_len = max(READ_ONCE(nlk->max_recvmsg_len), len);
195762306a36Sopenharmony_ci	max_recvmsg_len = min_t(size_t, max_recvmsg_len,
195862306a36Sopenharmony_ci				SKB_WITH_OVERHEAD(32768));
195962306a36Sopenharmony_ci	WRITE_ONCE(nlk->max_recvmsg_len, max_recvmsg_len);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	copied = data_skb->len;
196262306a36Sopenharmony_ci	if (len < copied) {
196362306a36Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
196462306a36Sopenharmony_ci		copied = len;
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	err = skb_copy_datagram_msg(data_skb, 0, msg, copied);
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	if (msg->msg_name) {
197062306a36Sopenharmony_ci		DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
197162306a36Sopenharmony_ci		addr->nl_family = AF_NETLINK;
197262306a36Sopenharmony_ci		addr->nl_pad    = 0;
197362306a36Sopenharmony_ci		addr->nl_pid	= NETLINK_CB(skb).portid;
197462306a36Sopenharmony_ci		addr->nl_groups	= netlink_group_mask(NETLINK_CB(skb).dst_group);
197562306a36Sopenharmony_ci		msg->msg_namelen = sizeof(*addr);
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	if (nlk_test_bit(RECV_PKTINFO, sk))
197962306a36Sopenharmony_ci		netlink_cmsg_recv_pktinfo(msg, skb);
198062306a36Sopenharmony_ci	if (nlk_test_bit(LISTEN_ALL_NSID, sk))
198162306a36Sopenharmony_ci		netlink_cmsg_listen_all_nsid(sk, msg, skb);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	memset(&scm, 0, sizeof(scm));
198462306a36Sopenharmony_ci	scm.creds = *NETLINK_CREDS(skb);
198562306a36Sopenharmony_ci	if (flags & MSG_TRUNC)
198662306a36Sopenharmony_ci		copied = data_skb->len;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	skb_free_datagram(sk, skb);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	if (READ_ONCE(nlk->cb_running) &&
199162306a36Sopenharmony_ci	    atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
199262306a36Sopenharmony_ci		ret = netlink_dump(sk);
199362306a36Sopenharmony_ci		if (ret) {
199462306a36Sopenharmony_ci			WRITE_ONCE(sk->sk_err, -ret);
199562306a36Sopenharmony_ci			sk_error_report(sk);
199662306a36Sopenharmony_ci		}
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	scm_recv(sock, msg, &scm, flags);
200062306a36Sopenharmony_ciout:
200162306a36Sopenharmony_ci	netlink_rcv_wake(sk);
200262306a36Sopenharmony_ci	return err ? : copied;
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cistatic void netlink_data_ready(struct sock *sk)
200662306a36Sopenharmony_ci{
200762306a36Sopenharmony_ci	BUG();
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci/*
201162306a36Sopenharmony_ci *	We export these functions to other modules. They provide a
201262306a36Sopenharmony_ci *	complete set of kernel non-blocking support for message
201362306a36Sopenharmony_ci *	queueing.
201462306a36Sopenharmony_ci */
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistruct sock *
201762306a36Sopenharmony_ci__netlink_kernel_create(struct net *net, int unit, struct module *module,
201862306a36Sopenharmony_ci			struct netlink_kernel_cfg *cfg)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	struct socket *sock;
202162306a36Sopenharmony_ci	struct sock *sk;
202262306a36Sopenharmony_ci	struct netlink_sock *nlk;
202362306a36Sopenharmony_ci	struct listeners *listeners = NULL;
202462306a36Sopenharmony_ci	struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL;
202562306a36Sopenharmony_ci	unsigned int groups;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	BUG_ON(!nl_table);
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	if (unit < 0 || unit >= MAX_LINKS)
203062306a36Sopenharmony_ci		return NULL;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
203362306a36Sopenharmony_ci		return NULL;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	if (__netlink_create(net, sock, cb_mutex, unit, 1) < 0)
203662306a36Sopenharmony_ci		goto out_sock_release_nosk;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	sk = sock->sk;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if (!cfg || cfg->groups < 32)
204162306a36Sopenharmony_ci		groups = 32;
204262306a36Sopenharmony_ci	else
204362306a36Sopenharmony_ci		groups = cfg->groups;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
204662306a36Sopenharmony_ci	if (!listeners)
204762306a36Sopenharmony_ci		goto out_sock_release;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	sk->sk_data_ready = netlink_data_ready;
205062306a36Sopenharmony_ci	if (cfg && cfg->input)
205162306a36Sopenharmony_ci		nlk_sk(sk)->netlink_rcv = cfg->input;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	if (netlink_insert(sk, 0))
205462306a36Sopenharmony_ci		goto out_sock_release;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	nlk = nlk_sk(sk);
205762306a36Sopenharmony_ci	set_bit(NETLINK_F_KERNEL_SOCKET, &nlk->flags);
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	netlink_table_grab();
206062306a36Sopenharmony_ci	if (!nl_table[unit].registered) {
206162306a36Sopenharmony_ci		nl_table[unit].groups = groups;
206262306a36Sopenharmony_ci		rcu_assign_pointer(nl_table[unit].listeners, listeners);
206362306a36Sopenharmony_ci		nl_table[unit].cb_mutex = cb_mutex;
206462306a36Sopenharmony_ci		nl_table[unit].module = module;
206562306a36Sopenharmony_ci		if (cfg) {
206662306a36Sopenharmony_ci			nl_table[unit].bind = cfg->bind;
206762306a36Sopenharmony_ci			nl_table[unit].unbind = cfg->unbind;
206862306a36Sopenharmony_ci			nl_table[unit].release = cfg->release;
206962306a36Sopenharmony_ci			nl_table[unit].flags = cfg->flags;
207062306a36Sopenharmony_ci		}
207162306a36Sopenharmony_ci		nl_table[unit].registered = 1;
207262306a36Sopenharmony_ci	} else {
207362306a36Sopenharmony_ci		kfree(listeners);
207462306a36Sopenharmony_ci		nl_table[unit].registered++;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci	netlink_table_ungrab();
207762306a36Sopenharmony_ci	return sk;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ciout_sock_release:
208062306a36Sopenharmony_ci	kfree(listeners);
208162306a36Sopenharmony_ci	netlink_kernel_release(sk);
208262306a36Sopenharmony_ci	return NULL;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ciout_sock_release_nosk:
208562306a36Sopenharmony_ci	sock_release(sock);
208662306a36Sopenharmony_ci	return NULL;
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_kernel_create);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_civoid
209162306a36Sopenharmony_cinetlink_kernel_release(struct sock *sk)
209262306a36Sopenharmony_ci{
209362306a36Sopenharmony_ci	if (sk == NULL || sk->sk_socket == NULL)
209462306a36Sopenharmony_ci		return;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	sock_release(sk->sk_socket);
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_kernel_release);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ciint __netlink_change_ngroups(struct sock *sk, unsigned int groups)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	struct listeners *new, *old;
210362306a36Sopenharmony_ci	struct netlink_table *tbl = &nl_table[sk->sk_protocol];
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	if (groups < 32)
210662306a36Sopenharmony_ci		groups = 32;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
210962306a36Sopenharmony_ci		new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
211062306a36Sopenharmony_ci		if (!new)
211162306a36Sopenharmony_ci			return -ENOMEM;
211262306a36Sopenharmony_ci		old = nl_deref_protected(tbl->listeners);
211362306a36Sopenharmony_ci		memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
211462306a36Sopenharmony_ci		rcu_assign_pointer(tbl->listeners, new);
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci		kfree_rcu(old, rcu);
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci	tbl->groups = groups;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	return 0;
212162306a36Sopenharmony_ci}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci/**
212462306a36Sopenharmony_ci * netlink_change_ngroups - change number of multicast groups
212562306a36Sopenharmony_ci *
212662306a36Sopenharmony_ci * This changes the number of multicast groups that are available
212762306a36Sopenharmony_ci * on a certain netlink family. Note that it is not possible to
212862306a36Sopenharmony_ci * change the number of groups to below 32. Also note that it does
212962306a36Sopenharmony_ci * not implicitly call netlink_clear_multicast_users() when the
213062306a36Sopenharmony_ci * number of groups is reduced.
213162306a36Sopenharmony_ci *
213262306a36Sopenharmony_ci * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
213362306a36Sopenharmony_ci * @groups: The new number of groups.
213462306a36Sopenharmony_ci */
213562306a36Sopenharmony_ciint netlink_change_ngroups(struct sock *sk, unsigned int groups)
213662306a36Sopenharmony_ci{
213762306a36Sopenharmony_ci	int err;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	netlink_table_grab();
214062306a36Sopenharmony_ci	err = __netlink_change_ngroups(sk, groups);
214162306a36Sopenharmony_ci	netlink_table_ungrab();
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	return err;
214462306a36Sopenharmony_ci}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_civoid __netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
214762306a36Sopenharmony_ci{
214862306a36Sopenharmony_ci	struct sock *sk;
214962306a36Sopenharmony_ci	struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	sk_for_each_bound(sk, &tbl->mc_list)
215262306a36Sopenharmony_ci		netlink_update_socket_mc(nlk_sk(sk), group, 0);
215362306a36Sopenharmony_ci}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_cistruct nlmsghdr *
215662306a36Sopenharmony_ci__nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	struct nlmsghdr *nlh;
215962306a36Sopenharmony_ci	int size = nlmsg_msg_size(len);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	nlh = skb_put(skb, NLMSG_ALIGN(size));
216262306a36Sopenharmony_ci	nlh->nlmsg_type = type;
216362306a36Sopenharmony_ci	nlh->nlmsg_len = size;
216462306a36Sopenharmony_ci	nlh->nlmsg_flags = flags;
216562306a36Sopenharmony_ci	nlh->nlmsg_pid = portid;
216662306a36Sopenharmony_ci	nlh->nlmsg_seq = seq;
216762306a36Sopenharmony_ci	if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)
216862306a36Sopenharmony_ci		memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size);
216962306a36Sopenharmony_ci	return nlh;
217062306a36Sopenharmony_ci}
217162306a36Sopenharmony_ciEXPORT_SYMBOL(__nlmsg_put);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci/*
217462306a36Sopenharmony_ci * It looks a bit ugly.
217562306a36Sopenharmony_ci * It would be better to create kernel thread.
217662306a36Sopenharmony_ci */
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_cistatic int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb,
217962306a36Sopenharmony_ci			     struct netlink_callback *cb,
218062306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	struct nlmsghdr *nlh;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno),
218562306a36Sopenharmony_ci			       NLM_F_MULTI | cb->answer_flags);
218662306a36Sopenharmony_ci	if (WARN_ON(!nlh))
218762306a36Sopenharmony_ci		return -ENOBUFS;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	nl_dump_check_consistent(cb, nlh);
219062306a36Sopenharmony_ci	memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno));
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	if (extack->_msg && test_bit(NETLINK_F_EXT_ACK, &nlk->flags)) {
219362306a36Sopenharmony_ci		nlh->nlmsg_flags |= NLM_F_ACK_TLVS;
219462306a36Sopenharmony_ci		if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg))
219562306a36Sopenharmony_ci			nlmsg_end(skb, nlh);
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	return 0;
219962306a36Sopenharmony_ci}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_cistatic int netlink_dump(struct sock *sk)
220262306a36Sopenharmony_ci{
220362306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(sk);
220462306a36Sopenharmony_ci	struct netlink_ext_ack extack = {};
220562306a36Sopenharmony_ci	struct netlink_callback *cb;
220662306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
220762306a36Sopenharmony_ci	size_t max_recvmsg_len;
220862306a36Sopenharmony_ci	struct module *module;
220962306a36Sopenharmony_ci	int err = -ENOBUFS;
221062306a36Sopenharmony_ci	int alloc_min_size;
221162306a36Sopenharmony_ci	int alloc_size;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	mutex_lock(nlk->cb_mutex);
221462306a36Sopenharmony_ci	if (!nlk->cb_running) {
221562306a36Sopenharmony_ci		err = -EINVAL;
221662306a36Sopenharmony_ci		goto errout_skb;
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
222062306a36Sopenharmony_ci		goto errout_skb;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	/* NLMSG_GOODSIZE is small to avoid high order allocations being
222362306a36Sopenharmony_ci	 * required, but it makes sense to _attempt_ a 16K bytes allocation
222462306a36Sopenharmony_ci	 * to reduce number of system calls on dump operations, if user
222562306a36Sopenharmony_ci	 * ever provided a big enough buffer.
222662306a36Sopenharmony_ci	 */
222762306a36Sopenharmony_ci	cb = &nlk->cb;
222862306a36Sopenharmony_ci	alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	max_recvmsg_len = READ_ONCE(nlk->max_recvmsg_len);
223162306a36Sopenharmony_ci	if (alloc_min_size < max_recvmsg_len) {
223262306a36Sopenharmony_ci		alloc_size = max_recvmsg_len;
223362306a36Sopenharmony_ci		skb = alloc_skb(alloc_size,
223462306a36Sopenharmony_ci				(GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) |
223562306a36Sopenharmony_ci				__GFP_NOWARN | __GFP_NORETRY);
223662306a36Sopenharmony_ci	}
223762306a36Sopenharmony_ci	if (!skb) {
223862306a36Sopenharmony_ci		alloc_size = alloc_min_size;
223962306a36Sopenharmony_ci		skb = alloc_skb(alloc_size, GFP_KERNEL);
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci	if (!skb)
224262306a36Sopenharmony_ci		goto errout_skb;
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	/* Trim skb to allocated size. User is expected to provide buffer as
224562306a36Sopenharmony_ci	 * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at
224662306a36Sopenharmony_ci	 * netlink_recvmsg())). dump will pack as many smaller messages as
224762306a36Sopenharmony_ci	 * could fit within the allocated skb. skb is typically allocated
224862306a36Sopenharmony_ci	 * with larger space than required (could be as much as near 2x the
224962306a36Sopenharmony_ci	 * requested size with align to next power of 2 approach). Allowing
225062306a36Sopenharmony_ci	 * dump to use the excess space makes it difficult for a user to have a
225162306a36Sopenharmony_ci	 * reasonable static buffer based on the expected largest dump of a
225262306a36Sopenharmony_ci	 * single netdev. The outcome is MSG_TRUNC error.
225362306a36Sopenharmony_ci	 */
225462306a36Sopenharmony_ci	skb_reserve(skb, skb_tailroom(skb) - alloc_size);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	/* Make sure malicious BPF programs can not read unitialized memory
225762306a36Sopenharmony_ci	 * from skb->head -> skb->data
225862306a36Sopenharmony_ci	 */
225962306a36Sopenharmony_ci	skb_reset_network_header(skb);
226062306a36Sopenharmony_ci	skb_reset_mac_header(skb);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	netlink_skb_set_owner_r(skb, sk);
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	if (nlk->dump_done_errno > 0) {
226562306a36Sopenharmony_ci		cb->extack = &extack;
226662306a36Sopenharmony_ci		nlk->dump_done_errno = cb->dump(skb, cb);
226762306a36Sopenharmony_ci		cb->extack = NULL;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	if (nlk->dump_done_errno > 0 ||
227162306a36Sopenharmony_ci	    skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) {
227262306a36Sopenharmony_ci		mutex_unlock(nlk->cb_mutex);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci		if (sk_filter(sk, skb))
227562306a36Sopenharmony_ci			kfree_skb(skb);
227662306a36Sopenharmony_ci		else
227762306a36Sopenharmony_ci			__netlink_sendskb(sk, skb);
227862306a36Sopenharmony_ci		return 0;
227962306a36Sopenharmony_ci	}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	if (netlink_dump_done(nlk, skb, cb, &extack))
228262306a36Sopenharmony_ci		goto errout_skb;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_NETLINK_MESSAGES
228562306a36Sopenharmony_ci	/* frag_list skb's data is used for compat tasks
228662306a36Sopenharmony_ci	 * and the regular skb's data for normal (non-compat) tasks.
228762306a36Sopenharmony_ci	 * See netlink_recvmsg().
228862306a36Sopenharmony_ci	 */
228962306a36Sopenharmony_ci	if (unlikely(skb_shinfo(skb)->frag_list)) {
229062306a36Sopenharmony_ci		if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack))
229162306a36Sopenharmony_ci			goto errout_skb;
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci#endif
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	if (sk_filter(sk, skb))
229662306a36Sopenharmony_ci		kfree_skb(skb);
229762306a36Sopenharmony_ci	else
229862306a36Sopenharmony_ci		__netlink_sendskb(sk, skb);
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	if (cb->done)
230162306a36Sopenharmony_ci		cb->done(cb);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	WRITE_ONCE(nlk->cb_running, false);
230462306a36Sopenharmony_ci	module = cb->module;
230562306a36Sopenharmony_ci	skb = cb->skb;
230662306a36Sopenharmony_ci	mutex_unlock(nlk->cb_mutex);
230762306a36Sopenharmony_ci	module_put(module);
230862306a36Sopenharmony_ci	consume_skb(skb);
230962306a36Sopenharmony_ci	return 0;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_cierrout_skb:
231262306a36Sopenharmony_ci	mutex_unlock(nlk->cb_mutex);
231362306a36Sopenharmony_ci	kfree_skb(skb);
231462306a36Sopenharmony_ci	return err;
231562306a36Sopenharmony_ci}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ciint __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
231862306a36Sopenharmony_ci			 const struct nlmsghdr *nlh,
231962306a36Sopenharmony_ci			 struct netlink_dump_control *control)
232062306a36Sopenharmony_ci{
232162306a36Sopenharmony_ci	struct netlink_callback *cb;
232262306a36Sopenharmony_ci	struct netlink_sock *nlk;
232362306a36Sopenharmony_ci	struct sock *sk;
232462306a36Sopenharmony_ci	int ret;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	refcount_inc(&skb->users);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid);
232962306a36Sopenharmony_ci	if (sk == NULL) {
233062306a36Sopenharmony_ci		ret = -ECONNREFUSED;
233162306a36Sopenharmony_ci		goto error_free;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	nlk = nlk_sk(sk);
233562306a36Sopenharmony_ci	mutex_lock(nlk->cb_mutex);
233662306a36Sopenharmony_ci	/* A dump is in progress... */
233762306a36Sopenharmony_ci	if (nlk->cb_running) {
233862306a36Sopenharmony_ci		ret = -EBUSY;
233962306a36Sopenharmony_ci		goto error_unlock;
234062306a36Sopenharmony_ci	}
234162306a36Sopenharmony_ci	/* add reference of module which cb->dump belongs to */
234262306a36Sopenharmony_ci	if (!try_module_get(control->module)) {
234362306a36Sopenharmony_ci		ret = -EPROTONOSUPPORT;
234462306a36Sopenharmony_ci		goto error_unlock;
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	cb = &nlk->cb;
234862306a36Sopenharmony_ci	memset(cb, 0, sizeof(*cb));
234962306a36Sopenharmony_ci	cb->dump = control->dump;
235062306a36Sopenharmony_ci	cb->done = control->done;
235162306a36Sopenharmony_ci	cb->nlh = nlh;
235262306a36Sopenharmony_ci	cb->data = control->data;
235362306a36Sopenharmony_ci	cb->module = control->module;
235462306a36Sopenharmony_ci	cb->min_dump_alloc = control->min_dump_alloc;
235562306a36Sopenharmony_ci	cb->skb = skb;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	cb->strict_check = nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk);
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	if (control->start) {
236062306a36Sopenharmony_ci		cb->extack = control->extack;
236162306a36Sopenharmony_ci		ret = control->start(cb);
236262306a36Sopenharmony_ci		cb->extack = NULL;
236362306a36Sopenharmony_ci		if (ret)
236462306a36Sopenharmony_ci			goto error_put;
236562306a36Sopenharmony_ci	}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	WRITE_ONCE(nlk->cb_running, true);
236862306a36Sopenharmony_ci	nlk->dump_done_errno = INT_MAX;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	mutex_unlock(nlk->cb_mutex);
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	ret = netlink_dump(sk);
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	sock_put(sk);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	if (ret)
237762306a36Sopenharmony_ci		return ret;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	/* We successfully started a dump, by returning -EINTR we
238062306a36Sopenharmony_ci	 * signal not to send ACK even if it was requested.
238162306a36Sopenharmony_ci	 */
238262306a36Sopenharmony_ci	return -EINTR;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_cierror_put:
238562306a36Sopenharmony_ci	module_put(control->module);
238662306a36Sopenharmony_cierror_unlock:
238762306a36Sopenharmony_ci	sock_put(sk);
238862306a36Sopenharmony_ci	mutex_unlock(nlk->cb_mutex);
238962306a36Sopenharmony_cierror_free:
239062306a36Sopenharmony_ci	kfree_skb(skb);
239162306a36Sopenharmony_ci	return ret;
239262306a36Sopenharmony_ci}
239362306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_dump_start);
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_cistatic size_t
239662306a36Sopenharmony_cinetlink_ack_tlv_len(struct netlink_sock *nlk, int err,
239762306a36Sopenharmony_ci		    const struct netlink_ext_ack *extack)
239862306a36Sopenharmony_ci{
239962306a36Sopenharmony_ci	size_t tlvlen;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	if (!extack || !test_bit(NETLINK_F_EXT_ACK, &nlk->flags))
240262306a36Sopenharmony_ci		return 0;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	tlvlen = 0;
240562306a36Sopenharmony_ci	if (extack->_msg)
240662306a36Sopenharmony_ci		tlvlen += nla_total_size(strlen(extack->_msg) + 1);
240762306a36Sopenharmony_ci	if (extack->cookie_len)
240862306a36Sopenharmony_ci		tlvlen += nla_total_size(extack->cookie_len);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	/* Following attributes are only reported as error (not warning) */
241162306a36Sopenharmony_ci	if (!err)
241262306a36Sopenharmony_ci		return tlvlen;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	if (extack->bad_attr)
241562306a36Sopenharmony_ci		tlvlen += nla_total_size(sizeof(u32));
241662306a36Sopenharmony_ci	if (extack->policy)
241762306a36Sopenharmony_ci		tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy);
241862306a36Sopenharmony_ci	if (extack->miss_type)
241962306a36Sopenharmony_ci		tlvlen += nla_total_size(sizeof(u32));
242062306a36Sopenharmony_ci	if (extack->miss_nest)
242162306a36Sopenharmony_ci		tlvlen += nla_total_size(sizeof(u32));
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	return tlvlen;
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_cistatic void
242762306a36Sopenharmony_cinetlink_ack_tlv_fill(struct sk_buff *in_skb, struct sk_buff *skb,
242862306a36Sopenharmony_ci		     struct nlmsghdr *nlh, int err,
242962306a36Sopenharmony_ci		     const struct netlink_ext_ack *extack)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	if (extack->_msg)
243262306a36Sopenharmony_ci		WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg));
243362306a36Sopenharmony_ci	if (extack->cookie_len)
243462306a36Sopenharmony_ci		WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
243562306a36Sopenharmony_ci				extack->cookie_len, extack->cookie));
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	if (!err)
243862306a36Sopenharmony_ci		return;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	if (extack->bad_attr &&
244162306a36Sopenharmony_ci	    !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
244262306a36Sopenharmony_ci		     (u8 *)extack->bad_attr >= in_skb->data + in_skb->len))
244362306a36Sopenharmony_ci		WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
244462306a36Sopenharmony_ci				    (u8 *)extack->bad_attr - (u8 *)nlh));
244562306a36Sopenharmony_ci	if (extack->policy)
244662306a36Sopenharmony_ci		netlink_policy_dump_write_attr(skb, extack->policy,
244762306a36Sopenharmony_ci					       NLMSGERR_ATTR_POLICY);
244862306a36Sopenharmony_ci	if (extack->miss_type)
244962306a36Sopenharmony_ci		WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_TYPE,
245062306a36Sopenharmony_ci				    extack->miss_type));
245162306a36Sopenharmony_ci	if (extack->miss_nest &&
245262306a36Sopenharmony_ci	    !WARN_ON((u8 *)extack->miss_nest < in_skb->data ||
245362306a36Sopenharmony_ci		     (u8 *)extack->miss_nest > in_skb->data + in_skb->len))
245462306a36Sopenharmony_ci		WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_NEST,
245562306a36Sopenharmony_ci				    (u8 *)extack->miss_nest - (u8 *)nlh));
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_civoid netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
245962306a36Sopenharmony_ci		 const struct netlink_ext_ack *extack)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	struct sk_buff *skb;
246262306a36Sopenharmony_ci	struct nlmsghdr *rep;
246362306a36Sopenharmony_ci	struct nlmsgerr *errmsg;
246462306a36Sopenharmony_ci	size_t payload = sizeof(*errmsg);
246562306a36Sopenharmony_ci	struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
246662306a36Sopenharmony_ci	unsigned int flags = 0;
246762306a36Sopenharmony_ci	size_t tlvlen;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	/* Error messages get the original request appened, unless the user
247062306a36Sopenharmony_ci	 * requests to cap the error message, and get extra error data if
247162306a36Sopenharmony_ci	 * requested.
247262306a36Sopenharmony_ci	 */
247362306a36Sopenharmony_ci	if (err && !test_bit(NETLINK_F_CAP_ACK, &nlk->flags))
247462306a36Sopenharmony_ci		payload += nlmsg_len(nlh);
247562306a36Sopenharmony_ci	else
247662306a36Sopenharmony_ci		flags |= NLM_F_CAPPED;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	tlvlen = netlink_ack_tlv_len(nlk, err, extack);
247962306a36Sopenharmony_ci	if (tlvlen)
248062306a36Sopenharmony_ci		flags |= NLM_F_ACK_TLVS;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
248362306a36Sopenharmony_ci	if (!skb)
248462306a36Sopenharmony_ci		goto err_skb;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
248762306a36Sopenharmony_ci			NLMSG_ERROR, sizeof(*errmsg), flags);
248862306a36Sopenharmony_ci	if (!rep)
248962306a36Sopenharmony_ci		goto err_bad_put;
249062306a36Sopenharmony_ci	errmsg = nlmsg_data(rep);
249162306a36Sopenharmony_ci	errmsg->error = err;
249262306a36Sopenharmony_ci	errmsg->msg = *nlh;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	if (!(flags & NLM_F_CAPPED)) {
249562306a36Sopenharmony_ci		if (!nlmsg_append(skb, nlmsg_len(nlh)))
249662306a36Sopenharmony_ci			goto err_bad_put;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci		memcpy(nlmsg_data(&errmsg->msg), nlmsg_data(nlh),
249962306a36Sopenharmony_ci		       nlmsg_len(nlh));
250062306a36Sopenharmony_ci	}
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	if (tlvlen)
250362306a36Sopenharmony_ci		netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	nlmsg_end(skb, rep);
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid);
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	return;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_cierr_bad_put:
251262306a36Sopenharmony_ci	nlmsg_free(skb);
251362306a36Sopenharmony_cierr_skb:
251462306a36Sopenharmony_ci	WRITE_ONCE(NETLINK_CB(in_skb).sk->sk_err, ENOBUFS);
251562306a36Sopenharmony_ci	sk_error_report(NETLINK_CB(in_skb).sk);
251662306a36Sopenharmony_ci}
251762306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_ack);
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ciint netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
252062306a36Sopenharmony_ci						   struct nlmsghdr *,
252162306a36Sopenharmony_ci						   struct netlink_ext_ack *))
252262306a36Sopenharmony_ci{
252362306a36Sopenharmony_ci	struct netlink_ext_ack extack;
252462306a36Sopenharmony_ci	struct nlmsghdr *nlh;
252562306a36Sopenharmony_ci	int err;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	while (skb->len >= nlmsg_total_size(0)) {
252862306a36Sopenharmony_ci		int msglen;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci		memset(&extack, 0, sizeof(extack));
253162306a36Sopenharmony_ci		nlh = nlmsg_hdr(skb);
253262306a36Sopenharmony_ci		err = 0;
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
253562306a36Sopenharmony_ci			return 0;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci		/* Only requests are handled by the kernel */
253862306a36Sopenharmony_ci		if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
253962306a36Sopenharmony_ci			goto ack;
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci		/* Skip control messages */
254262306a36Sopenharmony_ci		if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
254362306a36Sopenharmony_ci			goto ack;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci		err = cb(skb, nlh, &extack);
254662306a36Sopenharmony_ci		if (err == -EINTR)
254762306a36Sopenharmony_ci			goto skip;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ciack:
255062306a36Sopenharmony_ci		if (nlh->nlmsg_flags & NLM_F_ACK || err)
255162306a36Sopenharmony_ci			netlink_ack(skb, nlh, err, &extack);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ciskip:
255462306a36Sopenharmony_ci		msglen = NLMSG_ALIGN(nlh->nlmsg_len);
255562306a36Sopenharmony_ci		if (msglen > skb->len)
255662306a36Sopenharmony_ci			msglen = skb->len;
255762306a36Sopenharmony_ci		skb_pull(skb, msglen);
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	return 0;
256162306a36Sopenharmony_ci}
256262306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_rcv_skb);
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci/**
256562306a36Sopenharmony_ci * nlmsg_notify - send a notification netlink message
256662306a36Sopenharmony_ci * @sk: netlink socket to use
256762306a36Sopenharmony_ci * @skb: notification message
256862306a36Sopenharmony_ci * @portid: destination netlink portid for reports or 0
256962306a36Sopenharmony_ci * @group: destination multicast group or 0
257062306a36Sopenharmony_ci * @report: 1 to report back, 0 to disable
257162306a36Sopenharmony_ci * @flags: allocation flags
257262306a36Sopenharmony_ci */
257362306a36Sopenharmony_ciint nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
257462306a36Sopenharmony_ci		 unsigned int group, int report, gfp_t flags)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	int err = 0;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	if (group) {
257962306a36Sopenharmony_ci		int exclude_portid = 0;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci		if (report) {
258262306a36Sopenharmony_ci			refcount_inc(&skb->users);
258362306a36Sopenharmony_ci			exclude_portid = portid;
258462306a36Sopenharmony_ci		}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci		/* errors reported via destination sk->sk_err, but propagate
258762306a36Sopenharmony_ci		 * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
258862306a36Sopenharmony_ci		err = nlmsg_multicast(sk, skb, exclude_portid, group, flags);
258962306a36Sopenharmony_ci		if (err == -ESRCH)
259062306a36Sopenharmony_ci			err = 0;
259162306a36Sopenharmony_ci	}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	if (report) {
259462306a36Sopenharmony_ci		int err2;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci		err2 = nlmsg_unicast(sk, skb, portid);
259762306a36Sopenharmony_ci		if (!err)
259862306a36Sopenharmony_ci			err = err2;
259962306a36Sopenharmony_ci	}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	return err;
260262306a36Sopenharmony_ci}
260362306a36Sopenharmony_ciEXPORT_SYMBOL(nlmsg_notify);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
260662306a36Sopenharmony_cistruct nl_seq_iter {
260762306a36Sopenharmony_ci	struct seq_net_private p;
260862306a36Sopenharmony_ci	struct rhashtable_iter hti;
260962306a36Sopenharmony_ci	int link;
261062306a36Sopenharmony_ci};
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_cistatic void netlink_walk_start(struct nl_seq_iter *iter)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti);
261562306a36Sopenharmony_ci	rhashtable_walk_start(&iter->hti);
261662306a36Sopenharmony_ci}
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_cistatic void netlink_walk_stop(struct nl_seq_iter *iter)
261962306a36Sopenharmony_ci{
262062306a36Sopenharmony_ci	rhashtable_walk_stop(&iter->hti);
262162306a36Sopenharmony_ci	rhashtable_walk_exit(&iter->hti);
262262306a36Sopenharmony_ci}
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_cistatic void *__netlink_seq_next(struct seq_file *seq)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	struct nl_seq_iter *iter = seq->private;
262762306a36Sopenharmony_ci	struct netlink_sock *nlk;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	do {
263062306a36Sopenharmony_ci		for (;;) {
263162306a36Sopenharmony_ci			nlk = rhashtable_walk_next(&iter->hti);
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci			if (IS_ERR(nlk)) {
263462306a36Sopenharmony_ci				if (PTR_ERR(nlk) == -EAGAIN)
263562306a36Sopenharmony_ci					continue;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci				return nlk;
263862306a36Sopenharmony_ci			}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci			if (nlk)
264162306a36Sopenharmony_ci				break;
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci			netlink_walk_stop(iter);
264462306a36Sopenharmony_ci			if (++iter->link >= MAX_LINKS)
264562306a36Sopenharmony_ci				return NULL;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci			netlink_walk_start(iter);
264862306a36Sopenharmony_ci		}
264962306a36Sopenharmony_ci	} while (sock_net(&nlk->sk) != seq_file_net(seq));
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	return nlk;
265262306a36Sopenharmony_ci}
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_cistatic void *netlink_seq_start(struct seq_file *seq, loff_t *posp)
265562306a36Sopenharmony_ci	__acquires(RCU)
265662306a36Sopenharmony_ci{
265762306a36Sopenharmony_ci	struct nl_seq_iter *iter = seq->private;
265862306a36Sopenharmony_ci	void *obj = SEQ_START_TOKEN;
265962306a36Sopenharmony_ci	loff_t pos;
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	iter->link = 0;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	netlink_walk_start(iter);
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	for (pos = *posp; pos && obj && !IS_ERR(obj); pos--)
266662306a36Sopenharmony_ci		obj = __netlink_seq_next(seq);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	return obj;
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci	++*pos;
267462306a36Sopenharmony_ci	return __netlink_seq_next(seq);
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_cistatic void netlink_native_seq_stop(struct seq_file *seq, void *v)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	struct nl_seq_iter *iter = seq->private;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	if (iter->link >= MAX_LINKS)
268262306a36Sopenharmony_ci		return;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	netlink_walk_stop(iter);
268562306a36Sopenharmony_ci}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_cistatic int netlink_native_seq_show(struct seq_file *seq, void *v)
268962306a36Sopenharmony_ci{
269062306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
269162306a36Sopenharmony_ci		seq_puts(seq,
269262306a36Sopenharmony_ci			 "sk               Eth Pid        Groups   "
269362306a36Sopenharmony_ci			 "Rmem     Wmem     Dump  Locks    Drops    Inode\n");
269462306a36Sopenharmony_ci	} else {
269562306a36Sopenharmony_ci		struct sock *s = v;
269662306a36Sopenharmony_ci		struct netlink_sock *nlk = nlk_sk(s);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci		seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n",
269962306a36Sopenharmony_ci			   s,
270062306a36Sopenharmony_ci			   s->sk_protocol,
270162306a36Sopenharmony_ci			   nlk->portid,
270262306a36Sopenharmony_ci			   nlk->groups ? (u32)nlk->groups[0] : 0,
270362306a36Sopenharmony_ci			   sk_rmem_alloc_get(s),
270462306a36Sopenharmony_ci			   sk_wmem_alloc_get(s),
270562306a36Sopenharmony_ci			   READ_ONCE(nlk->cb_running),
270662306a36Sopenharmony_ci			   refcount_read(&s->sk_refcnt),
270762306a36Sopenharmony_ci			   atomic_read(&s->sk_drops),
270862306a36Sopenharmony_ci			   sock_i_ino(s)
270962306a36Sopenharmony_ci			);
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	}
271262306a36Sopenharmony_ci	return 0;
271362306a36Sopenharmony_ci}
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
271662306a36Sopenharmony_cistruct bpf_iter__netlink {
271762306a36Sopenharmony_ci	__bpf_md_ptr(struct bpf_iter_meta *, meta);
271862306a36Sopenharmony_ci	__bpf_md_ptr(struct netlink_sock *, sk);
271962306a36Sopenharmony_ci};
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ciDEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk)
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_cistatic int netlink_prog_seq_show(struct bpf_prog *prog,
272462306a36Sopenharmony_ci				  struct bpf_iter_meta *meta,
272562306a36Sopenharmony_ci				  void *v)
272662306a36Sopenharmony_ci{
272762306a36Sopenharmony_ci	struct bpf_iter__netlink ctx;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	meta->seq_num--;  /* skip SEQ_START_TOKEN */
273062306a36Sopenharmony_ci	ctx.meta = meta;
273162306a36Sopenharmony_ci	ctx.sk = nlk_sk((struct sock *)v);
273262306a36Sopenharmony_ci	return bpf_iter_run_prog(prog, &ctx);
273362306a36Sopenharmony_ci}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_cistatic int netlink_seq_show(struct seq_file *seq, void *v)
273662306a36Sopenharmony_ci{
273762306a36Sopenharmony_ci	struct bpf_iter_meta meta;
273862306a36Sopenharmony_ci	struct bpf_prog *prog;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	meta.seq = seq;
274162306a36Sopenharmony_ci	prog = bpf_iter_get_info(&meta, false);
274262306a36Sopenharmony_ci	if (!prog)
274362306a36Sopenharmony_ci		return netlink_native_seq_show(seq, v);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	if (v != SEQ_START_TOKEN)
274662306a36Sopenharmony_ci		return netlink_prog_seq_show(prog, &meta, v);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	return 0;
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_cistatic void netlink_seq_stop(struct seq_file *seq, void *v)
275262306a36Sopenharmony_ci{
275362306a36Sopenharmony_ci	struct bpf_iter_meta meta;
275462306a36Sopenharmony_ci	struct bpf_prog *prog;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	if (!v) {
275762306a36Sopenharmony_ci		meta.seq = seq;
275862306a36Sopenharmony_ci		prog = bpf_iter_get_info(&meta, true);
275962306a36Sopenharmony_ci		if (prog)
276062306a36Sopenharmony_ci			(void)netlink_prog_seq_show(prog, &meta, v);
276162306a36Sopenharmony_ci	}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	netlink_native_seq_stop(seq, v);
276462306a36Sopenharmony_ci}
276562306a36Sopenharmony_ci#else
276662306a36Sopenharmony_cistatic int netlink_seq_show(struct seq_file *seq, void *v)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	return netlink_native_seq_show(seq, v);
276962306a36Sopenharmony_ci}
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_cistatic void netlink_seq_stop(struct seq_file *seq, void *v)
277262306a36Sopenharmony_ci{
277362306a36Sopenharmony_ci	netlink_native_seq_stop(seq, v);
277462306a36Sopenharmony_ci}
277562306a36Sopenharmony_ci#endif
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_cistatic const struct seq_operations netlink_seq_ops = {
277862306a36Sopenharmony_ci	.start  = netlink_seq_start,
277962306a36Sopenharmony_ci	.next   = netlink_seq_next,
278062306a36Sopenharmony_ci	.stop   = netlink_seq_stop,
278162306a36Sopenharmony_ci	.show   = netlink_seq_show,
278262306a36Sopenharmony_ci};
278362306a36Sopenharmony_ci#endif
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_ciint netlink_register_notifier(struct notifier_block *nb)
278662306a36Sopenharmony_ci{
278762306a36Sopenharmony_ci	return blocking_notifier_chain_register(&netlink_chain, nb);
278862306a36Sopenharmony_ci}
278962306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_register_notifier);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ciint netlink_unregister_notifier(struct notifier_block *nb)
279262306a36Sopenharmony_ci{
279362306a36Sopenharmony_ci	return blocking_notifier_chain_unregister(&netlink_chain, nb);
279462306a36Sopenharmony_ci}
279562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_unregister_notifier);
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_cistatic const struct proto_ops netlink_ops = {
279862306a36Sopenharmony_ci	.family =	PF_NETLINK,
279962306a36Sopenharmony_ci	.owner =	THIS_MODULE,
280062306a36Sopenharmony_ci	.release =	netlink_release,
280162306a36Sopenharmony_ci	.bind =		netlink_bind,
280262306a36Sopenharmony_ci	.connect =	netlink_connect,
280362306a36Sopenharmony_ci	.socketpair =	sock_no_socketpair,
280462306a36Sopenharmony_ci	.accept =	sock_no_accept,
280562306a36Sopenharmony_ci	.getname =	netlink_getname,
280662306a36Sopenharmony_ci	.poll =		datagram_poll,
280762306a36Sopenharmony_ci	.ioctl =	netlink_ioctl,
280862306a36Sopenharmony_ci	.listen =	sock_no_listen,
280962306a36Sopenharmony_ci	.shutdown =	sock_no_shutdown,
281062306a36Sopenharmony_ci	.setsockopt =	netlink_setsockopt,
281162306a36Sopenharmony_ci	.getsockopt =	netlink_getsockopt,
281262306a36Sopenharmony_ci	.sendmsg =	netlink_sendmsg,
281362306a36Sopenharmony_ci	.recvmsg =	netlink_recvmsg,
281462306a36Sopenharmony_ci	.mmap =		sock_no_mmap,
281562306a36Sopenharmony_ci};
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_cistatic const struct net_proto_family netlink_family_ops = {
281862306a36Sopenharmony_ci	.family = PF_NETLINK,
281962306a36Sopenharmony_ci	.create = netlink_create,
282062306a36Sopenharmony_ci	.owner	= THIS_MODULE,	/* for consistency 8) */
282162306a36Sopenharmony_ci};
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_cistatic int __net_init netlink_net_init(struct net *net)
282462306a36Sopenharmony_ci{
282562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
282662306a36Sopenharmony_ci	if (!proc_create_net("netlink", 0, net->proc_net, &netlink_seq_ops,
282762306a36Sopenharmony_ci			sizeof(struct nl_seq_iter)))
282862306a36Sopenharmony_ci		return -ENOMEM;
282962306a36Sopenharmony_ci#endif
283062306a36Sopenharmony_ci	return 0;
283162306a36Sopenharmony_ci}
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_cistatic void __net_exit netlink_net_exit(struct net *net)
283462306a36Sopenharmony_ci{
283562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
283662306a36Sopenharmony_ci	remove_proc_entry("netlink", net->proc_net);
283762306a36Sopenharmony_ci#endif
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_cistatic void __init netlink_add_usersock_entry(void)
284162306a36Sopenharmony_ci{
284262306a36Sopenharmony_ci	struct listeners *listeners;
284362306a36Sopenharmony_ci	int groups = 32;
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
284662306a36Sopenharmony_ci	if (!listeners)
284762306a36Sopenharmony_ci		panic("netlink_add_usersock_entry: Cannot allocate listeners\n");
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	netlink_table_grab();
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	nl_table[NETLINK_USERSOCK].groups = groups;
285262306a36Sopenharmony_ci	rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
285362306a36Sopenharmony_ci	nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
285462306a36Sopenharmony_ci	nl_table[NETLINK_USERSOCK].registered = 1;
285562306a36Sopenharmony_ci	nl_table[NETLINK_USERSOCK].flags = NL_CFG_F_NONROOT_SEND;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	netlink_table_ungrab();
285862306a36Sopenharmony_ci}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_cistatic struct pernet_operations __net_initdata netlink_net_ops = {
286162306a36Sopenharmony_ci	.init = netlink_net_init,
286262306a36Sopenharmony_ci	.exit = netlink_net_exit,
286362306a36Sopenharmony_ci};
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_cistatic inline u32 netlink_hash(const void *data, u32 len, u32 seed)
286662306a36Sopenharmony_ci{
286762306a36Sopenharmony_ci	const struct netlink_sock *nlk = data;
286862306a36Sopenharmony_ci	struct netlink_compare_arg arg;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	netlink_compare_arg_init(&arg, sock_net(&nlk->sk), nlk->portid);
287162306a36Sopenharmony_ci	return jhash2((u32 *)&arg, netlink_compare_arg_len / sizeof(u32), seed);
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cistatic const struct rhashtable_params netlink_rhashtable_params = {
287562306a36Sopenharmony_ci	.head_offset = offsetof(struct netlink_sock, node),
287662306a36Sopenharmony_ci	.key_len = netlink_compare_arg_len,
287762306a36Sopenharmony_ci	.obj_hashfn = netlink_hash,
287862306a36Sopenharmony_ci	.obj_cmpfn = netlink_compare,
287962306a36Sopenharmony_ci	.automatic_shrinking = true,
288062306a36Sopenharmony_ci};
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
288362306a36Sopenharmony_ciBTF_ID_LIST(btf_netlink_sock_id)
288462306a36Sopenharmony_ciBTF_ID(struct, netlink_sock)
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_cistatic const struct bpf_iter_seq_info netlink_seq_info = {
288762306a36Sopenharmony_ci	.seq_ops		= &netlink_seq_ops,
288862306a36Sopenharmony_ci	.init_seq_private	= bpf_iter_init_seq_net,
288962306a36Sopenharmony_ci	.fini_seq_private	= bpf_iter_fini_seq_net,
289062306a36Sopenharmony_ci	.seq_priv_size		= sizeof(struct nl_seq_iter),
289162306a36Sopenharmony_ci};
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_cistatic struct bpf_iter_reg netlink_reg_info = {
289462306a36Sopenharmony_ci	.target			= "netlink",
289562306a36Sopenharmony_ci	.ctx_arg_info_size	= 1,
289662306a36Sopenharmony_ci	.ctx_arg_info		= {
289762306a36Sopenharmony_ci		{ offsetof(struct bpf_iter__netlink, sk),
289862306a36Sopenharmony_ci		  PTR_TO_BTF_ID_OR_NULL },
289962306a36Sopenharmony_ci	},
290062306a36Sopenharmony_ci	.seq_info		= &netlink_seq_info,
290162306a36Sopenharmony_ci};
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_cistatic int __init bpf_iter_register(void)
290462306a36Sopenharmony_ci{
290562306a36Sopenharmony_ci	netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id;
290662306a36Sopenharmony_ci	return bpf_iter_reg_target(&netlink_reg_info);
290762306a36Sopenharmony_ci}
290862306a36Sopenharmony_ci#endif
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_cistatic int __init netlink_proto_init(void)
291162306a36Sopenharmony_ci{
291262306a36Sopenharmony_ci	int i;
291362306a36Sopenharmony_ci	int err = proto_register(&netlink_proto, 0);
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	if (err != 0)
291662306a36Sopenharmony_ci		goto out;
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
291962306a36Sopenharmony_ci	err = bpf_iter_register();
292062306a36Sopenharmony_ci	if (err)
292162306a36Sopenharmony_ci		goto out;
292262306a36Sopenharmony_ci#endif
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb));
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
292762306a36Sopenharmony_ci	if (!nl_table)
292862306a36Sopenharmony_ci		goto panic;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	for (i = 0; i < MAX_LINKS; i++) {
293162306a36Sopenharmony_ci		if (rhashtable_init(&nl_table[i].hash,
293262306a36Sopenharmony_ci				    &netlink_rhashtable_params) < 0) {
293362306a36Sopenharmony_ci			while (--i > 0)
293462306a36Sopenharmony_ci				rhashtable_destroy(&nl_table[i].hash);
293562306a36Sopenharmony_ci			kfree(nl_table);
293662306a36Sopenharmony_ci			goto panic;
293762306a36Sopenharmony_ci		}
293862306a36Sopenharmony_ci	}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	netlink_add_usersock_entry();
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	sock_register(&netlink_family_ops);
294362306a36Sopenharmony_ci	register_pernet_subsys(&netlink_net_ops);
294462306a36Sopenharmony_ci	register_pernet_subsys(&netlink_tap_net_ops);
294562306a36Sopenharmony_ci	/* The netlink device handler may be needed early. */
294662306a36Sopenharmony_ci	rtnetlink_init();
294762306a36Sopenharmony_ciout:
294862306a36Sopenharmony_ci	return err;
294962306a36Sopenharmony_cipanic:
295062306a36Sopenharmony_ci	panic("netlink_init: Cannot allocate nl_table\n");
295162306a36Sopenharmony_ci}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_cicore_initcall(netlink_proto_init);
2954