xref: /linux/drivers/net/ovpn/netlink.c (revision 2c7e4a2663a1ab5a740c59c31991579b6b865a26)
1b7a63391SAntonio Quartulli // SPDX-License-Identifier: GPL-2.0
2b7a63391SAntonio Quartulli /*  OpenVPN data channel offload
3b7a63391SAntonio Quartulli  *
4b7a63391SAntonio Quartulli  *  Copyright (C) 2020-2025 OpenVPN, Inc.
5b7a63391SAntonio Quartulli  *
6b7a63391SAntonio Quartulli  *  Author:	Antonio Quartulli <antonio@openvpn.net>
7b7a63391SAntonio Quartulli  */
8b7a63391SAntonio Quartulli 
9b7a63391SAntonio Quartulli #include <linux/netdevice.h>
101d36a36fSAntonio Quartulli #include <linux/types.h>
11b7a63391SAntonio Quartulli #include <net/genetlink.h>
12b7a63391SAntonio Quartulli 
13b7a63391SAntonio Quartulli #include <uapi/linux/ovpn.h>
14b7a63391SAntonio Quartulli 
15b7a63391SAntonio Quartulli #include "ovpnpriv.h"
16b7a63391SAntonio Quartulli #include "main.h"
17b7a63391SAntonio Quartulli #include "netlink.h"
18b7a63391SAntonio Quartulli #include "netlink-gen.h"
191d36a36fSAntonio Quartulli #include "bind.h"
20203e2bf5SAntonio Quartulli #include "crypto.h"
211d36a36fSAntonio Quartulli #include "peer.h"
221d36a36fSAntonio Quartulli #include "socket.h"
23b7a63391SAntonio Quartulli 
24b7a63391SAntonio Quartulli MODULE_ALIAS_GENL_FAMILY(OVPN_FAMILY_NAME);
25b7a63391SAntonio Quartulli 
26b7a63391SAntonio Quartulli /**
27b7a63391SAntonio Quartulli  * ovpn_get_dev_from_attrs - retrieve the ovpn private data from the netdevice
28b7a63391SAntonio Quartulli  *			     a netlink message is targeting
29b7a63391SAntonio Quartulli  * @net: network namespace where to look for the interface
30b7a63391SAntonio Quartulli  * @info: generic netlink info from the user request
31b7a63391SAntonio Quartulli  * @tracker: tracker object to be used for the netdev reference acquisition
32b7a63391SAntonio Quartulli  *
33b7a63391SAntonio Quartulli  * Return: the ovpn private data, if found, or an error otherwise
34b7a63391SAntonio Quartulli  */
35b7a63391SAntonio Quartulli static struct ovpn_priv *
ovpn_get_dev_from_attrs(struct net * net,const struct genl_info * info,netdevice_tracker * tracker)36b7a63391SAntonio Quartulli ovpn_get_dev_from_attrs(struct net *net, const struct genl_info *info,
37b7a63391SAntonio Quartulli 			netdevice_tracker *tracker)
38b7a63391SAntonio Quartulli {
39b7a63391SAntonio Quartulli 	struct ovpn_priv *ovpn;
40b7a63391SAntonio Quartulli 	struct net_device *dev;
41b7a63391SAntonio Quartulli 	int ifindex;
42b7a63391SAntonio Quartulli 
43b7a63391SAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_IFINDEX))
44b7a63391SAntonio Quartulli 		return ERR_PTR(-EINVAL);
45b7a63391SAntonio Quartulli 
46b7a63391SAntonio Quartulli 	ifindex = nla_get_u32(info->attrs[OVPN_A_IFINDEX]);
47b7a63391SAntonio Quartulli 
48b7a63391SAntonio Quartulli 	rcu_read_lock();
49b7a63391SAntonio Quartulli 	dev = dev_get_by_index_rcu(net, ifindex);
50b7a63391SAntonio Quartulli 	if (!dev) {
51b7a63391SAntonio Quartulli 		rcu_read_unlock();
52b7a63391SAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
53b7a63391SAntonio Quartulli 				   "ifindex does not match any interface");
54b7a63391SAntonio Quartulli 		return ERR_PTR(-ENODEV);
55b7a63391SAntonio Quartulli 	}
56b7a63391SAntonio Quartulli 
57b7a63391SAntonio Quartulli 	if (!ovpn_dev_is_valid(dev)) {
58b7a63391SAntonio Quartulli 		rcu_read_unlock();
59b7a63391SAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
60b7a63391SAntonio Quartulli 				   "specified interface is not ovpn");
61b7a63391SAntonio Quartulli 		NL_SET_BAD_ATTR(info->extack, info->attrs[OVPN_A_IFINDEX]);
62b7a63391SAntonio Quartulli 		return ERR_PTR(-EINVAL);
63b7a63391SAntonio Quartulli 	}
64b7a63391SAntonio Quartulli 
65b7a63391SAntonio Quartulli 	ovpn = netdev_priv(dev);
66b7a63391SAntonio Quartulli 	netdev_hold(dev, tracker, GFP_ATOMIC);
67b7a63391SAntonio Quartulli 	rcu_read_unlock();
68b7a63391SAntonio Quartulli 
69b7a63391SAntonio Quartulli 	return ovpn;
70b7a63391SAntonio Quartulli }
71b7a63391SAntonio Quartulli 
ovpn_nl_pre_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)72b7a63391SAntonio Quartulli int ovpn_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
73b7a63391SAntonio Quartulli 		     struct genl_info *info)
74b7a63391SAntonio Quartulli {
75b7a63391SAntonio Quartulli 	netdevice_tracker *tracker = (netdevice_tracker *)&info->user_ptr[1];
76b7a63391SAntonio Quartulli 	struct ovpn_priv *ovpn = ovpn_get_dev_from_attrs(genl_info_net(info),
77b7a63391SAntonio Quartulli 							 info, tracker);
78b7a63391SAntonio Quartulli 
79b7a63391SAntonio Quartulli 	if (IS_ERR(ovpn))
80b7a63391SAntonio Quartulli 		return PTR_ERR(ovpn);
81b7a63391SAntonio Quartulli 
82b7a63391SAntonio Quartulli 	info->user_ptr[0] = ovpn;
83b7a63391SAntonio Quartulli 
84b7a63391SAntonio Quartulli 	return 0;
85b7a63391SAntonio Quartulli }
86b7a63391SAntonio Quartulli 
ovpn_nl_post_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)87b7a63391SAntonio Quartulli void ovpn_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
88b7a63391SAntonio Quartulli 		       struct genl_info *info)
89b7a63391SAntonio Quartulli {
90b7a63391SAntonio Quartulli 	netdevice_tracker *tracker = (netdevice_tracker *)&info->user_ptr[1];
91b7a63391SAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
92b7a63391SAntonio Quartulli 
93b7a63391SAntonio Quartulli 	if (ovpn)
94b7a63391SAntonio Quartulli 		netdev_put(ovpn->dev, tracker);
95b7a63391SAntonio Quartulli }
96b7a63391SAntonio Quartulli 
ovpn_nl_attr_sockaddr_remote(struct nlattr ** attrs,struct sockaddr_storage * ss)971d36a36fSAntonio Quartulli static bool ovpn_nl_attr_sockaddr_remote(struct nlattr **attrs,
981d36a36fSAntonio Quartulli 					 struct sockaddr_storage *ss)
991d36a36fSAntonio Quartulli {
1001d36a36fSAntonio Quartulli 	struct sockaddr_in6 *sin6;
1011d36a36fSAntonio Quartulli 	struct sockaddr_in *sin;
1021d36a36fSAntonio Quartulli 	struct in6_addr *in6;
1031d36a36fSAntonio Quartulli 	__be16 port = 0;
1041d36a36fSAntonio Quartulli 	__be32 *in;
1051d36a36fSAntonio Quartulli 
1061d36a36fSAntonio Quartulli 	ss->ss_family = AF_UNSPEC;
1071d36a36fSAntonio Quartulli 
1081d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_REMOTE_PORT])
1091d36a36fSAntonio Quartulli 		port = nla_get_be16(attrs[OVPN_A_PEER_REMOTE_PORT]);
1101d36a36fSAntonio Quartulli 
1111d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_REMOTE_IPV4]) {
1121d36a36fSAntonio Quartulli 		ss->ss_family = AF_INET;
1131d36a36fSAntonio Quartulli 		in = nla_data(attrs[OVPN_A_PEER_REMOTE_IPV4]);
1141d36a36fSAntonio Quartulli 	} else if (attrs[OVPN_A_PEER_REMOTE_IPV6]) {
1151d36a36fSAntonio Quartulli 		ss->ss_family = AF_INET6;
1161d36a36fSAntonio Quartulli 		in6 = nla_data(attrs[OVPN_A_PEER_REMOTE_IPV6]);
1171d36a36fSAntonio Quartulli 	} else {
1181d36a36fSAntonio Quartulli 		return false;
1191d36a36fSAntonio Quartulli 	}
1201d36a36fSAntonio Quartulli 
1211d36a36fSAntonio Quartulli 	switch (ss->ss_family) {
1221d36a36fSAntonio Quartulli 	case AF_INET6:
1231d36a36fSAntonio Quartulli 		/* If this is a regular IPv6 just break and move on,
1241d36a36fSAntonio Quartulli 		 * otherwise switch to AF_INET and extract the IPv4 accordingly
1251d36a36fSAntonio Quartulli 		 */
1261d36a36fSAntonio Quartulli 		if (!ipv6_addr_v4mapped(in6)) {
1271d36a36fSAntonio Quartulli 			sin6 = (struct sockaddr_in6 *)ss;
1281d36a36fSAntonio Quartulli 			sin6->sin6_port = port;
1291d36a36fSAntonio Quartulli 			memcpy(&sin6->sin6_addr, in6, sizeof(*in6));
1301d36a36fSAntonio Quartulli 			break;
1311d36a36fSAntonio Quartulli 		}
1321d36a36fSAntonio Quartulli 
1331d36a36fSAntonio Quartulli 		/* v4-mapped-v6 address */
1341d36a36fSAntonio Quartulli 		ss->ss_family = AF_INET;
1351d36a36fSAntonio Quartulli 		in = &in6->s6_addr32[3];
1361d36a36fSAntonio Quartulli 		fallthrough;
1371d36a36fSAntonio Quartulli 	case AF_INET:
1381d36a36fSAntonio Quartulli 		sin = (struct sockaddr_in *)ss;
1391d36a36fSAntonio Quartulli 		sin->sin_port = port;
1401d36a36fSAntonio Quartulli 		sin->sin_addr.s_addr = *in;
1411d36a36fSAntonio Quartulli 		break;
1421d36a36fSAntonio Quartulli 	}
1431d36a36fSAntonio Quartulli 
1441d36a36fSAntonio Quartulli 	return true;
1451d36a36fSAntonio Quartulli }
1461d36a36fSAntonio Quartulli 
ovpn_nl_attr_local_ip(struct nlattr ** attrs)1471d36a36fSAntonio Quartulli static u8 *ovpn_nl_attr_local_ip(struct nlattr **attrs)
1481d36a36fSAntonio Quartulli {
1491d36a36fSAntonio Quartulli 	u8 *addr6;
1501d36a36fSAntonio Quartulli 
1511d36a36fSAntonio Quartulli 	if (!attrs[OVPN_A_PEER_LOCAL_IPV4] && !attrs[OVPN_A_PEER_LOCAL_IPV6])
1521d36a36fSAntonio Quartulli 		return NULL;
1531d36a36fSAntonio Quartulli 
1541d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_LOCAL_IPV4])
1551d36a36fSAntonio Quartulli 		return nla_data(attrs[OVPN_A_PEER_LOCAL_IPV4]);
1561d36a36fSAntonio Quartulli 
1571d36a36fSAntonio Quartulli 	addr6 = nla_data(attrs[OVPN_A_PEER_LOCAL_IPV6]);
1581d36a36fSAntonio Quartulli 	/* this is an IPv4-mapped IPv6 address, therefore extract the actual
1591d36a36fSAntonio Quartulli 	 * v4 address from the last 4 bytes
1601d36a36fSAntonio Quartulli 	 */
1611d36a36fSAntonio Quartulli 	if (ipv6_addr_v4mapped((struct in6_addr *)addr6))
1621d36a36fSAntonio Quartulli 		return addr6 + 12;
1631d36a36fSAntonio Quartulli 
1641d36a36fSAntonio Quartulli 	return addr6;
1651d36a36fSAntonio Quartulli }
1661d36a36fSAntonio Quartulli 
ovpn_nl_family_get(struct nlattr * addr4,struct nlattr * addr6)1671d36a36fSAntonio Quartulli static sa_family_t ovpn_nl_family_get(struct nlattr *addr4,
1681d36a36fSAntonio Quartulli 				      struct nlattr *addr6)
1691d36a36fSAntonio Quartulli {
1701d36a36fSAntonio Quartulli 	if (addr4)
1711d36a36fSAntonio Quartulli 		return AF_INET;
1721d36a36fSAntonio Quartulli 
1731d36a36fSAntonio Quartulli 	if (addr6) {
1741d36a36fSAntonio Quartulli 		if (ipv6_addr_v4mapped((struct in6_addr *)nla_data(addr6)))
1751d36a36fSAntonio Quartulli 			return AF_INET;
1761d36a36fSAntonio Quartulli 		return AF_INET6;
1771d36a36fSAntonio Quartulli 	}
1781d36a36fSAntonio Quartulli 
1791d36a36fSAntonio Quartulli 	return AF_UNSPEC;
1801d36a36fSAntonio Quartulli }
1811d36a36fSAntonio Quartulli 
ovpn_nl_peer_precheck(struct ovpn_priv * ovpn,struct genl_info * info,struct nlattr ** attrs)1821d36a36fSAntonio Quartulli static int ovpn_nl_peer_precheck(struct ovpn_priv *ovpn,
1831d36a36fSAntonio Quartulli 				 struct genl_info *info,
1841d36a36fSAntonio Quartulli 				 struct nlattr **attrs)
1851d36a36fSAntonio Quartulli {
1861d36a36fSAntonio Quartulli 	sa_family_t local_fam, remote_fam;
1871d36a36fSAntonio Quartulli 
1881d36a36fSAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_PEER], attrs,
1891d36a36fSAntonio Quartulli 			      OVPN_A_PEER_ID))
1901d36a36fSAntonio Quartulli 		return -EINVAL;
1911d36a36fSAntonio Quartulli 
1921d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_REMOTE_IPV4] && attrs[OVPN_A_PEER_REMOTE_IPV6]) {
1931d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
1941d36a36fSAntonio Quartulli 				   "cannot specify both remote IPv4 or IPv6 address");
1951d36a36fSAntonio Quartulli 		return -EINVAL;
1961d36a36fSAntonio Quartulli 	}
1971d36a36fSAntonio Quartulli 
1981d36a36fSAntonio Quartulli 	if (!attrs[OVPN_A_PEER_REMOTE_IPV4] &&
1991d36a36fSAntonio Quartulli 	    !attrs[OVPN_A_PEER_REMOTE_IPV6] && attrs[OVPN_A_PEER_REMOTE_PORT]) {
2001d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2011d36a36fSAntonio Quartulli 				   "cannot specify remote port without IP address");
2021d36a36fSAntonio Quartulli 		return -EINVAL;
2031d36a36fSAntonio Quartulli 	}
2041d36a36fSAntonio Quartulli 
2051d36a36fSAntonio Quartulli 	if ((attrs[OVPN_A_PEER_REMOTE_IPV4] ||
2061d36a36fSAntonio Quartulli 	     attrs[OVPN_A_PEER_REMOTE_IPV6]) &&
2071d36a36fSAntonio Quartulli 	    !attrs[OVPN_A_PEER_REMOTE_PORT]) {
2081d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2091d36a36fSAntonio Quartulli 				   "cannot specify remote IP address without port");
2101d36a36fSAntonio Quartulli 		return -EINVAL;
2111d36a36fSAntonio Quartulli 	}
2121d36a36fSAntonio Quartulli 
2131d36a36fSAntonio Quartulli 	if (!attrs[OVPN_A_PEER_REMOTE_IPV4] &&
2141d36a36fSAntonio Quartulli 	    attrs[OVPN_A_PEER_LOCAL_IPV4]) {
2151d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2161d36a36fSAntonio Quartulli 				   "cannot specify local IPv4 address without remote");
2171d36a36fSAntonio Quartulli 		return -EINVAL;
2181d36a36fSAntonio Quartulli 	}
2191d36a36fSAntonio Quartulli 
2201d36a36fSAntonio Quartulli 	if (!attrs[OVPN_A_PEER_REMOTE_IPV6] &&
2211d36a36fSAntonio Quartulli 	    attrs[OVPN_A_PEER_LOCAL_IPV6]) {
2221d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2231d36a36fSAntonio Quartulli 				   "cannot specify local IPV6 address without remote");
2241d36a36fSAntonio Quartulli 		return -EINVAL;
2251d36a36fSAntonio Quartulli 	}
2261d36a36fSAntonio Quartulli 
2271d36a36fSAntonio Quartulli 	/* check that local and remote address families are the same even
2281d36a36fSAntonio Quartulli 	 * after parsing v4mapped IPv6 addresses.
2291d36a36fSAntonio Quartulli 	 * (if addresses are not provided, family will be AF_UNSPEC and
2301d36a36fSAntonio Quartulli 	 * the check is skipped)
2311d36a36fSAntonio Quartulli 	 */
2321d36a36fSAntonio Quartulli 	local_fam = ovpn_nl_family_get(attrs[OVPN_A_PEER_LOCAL_IPV4],
2331d36a36fSAntonio Quartulli 				       attrs[OVPN_A_PEER_LOCAL_IPV6]);
2341d36a36fSAntonio Quartulli 	remote_fam = ovpn_nl_family_get(attrs[OVPN_A_PEER_REMOTE_IPV4],
2351d36a36fSAntonio Quartulli 					attrs[OVPN_A_PEER_REMOTE_IPV6]);
2361d36a36fSAntonio Quartulli 	if (local_fam != AF_UNSPEC && remote_fam != AF_UNSPEC &&
2371d36a36fSAntonio Quartulli 	    local_fam != remote_fam) {
2381d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2391d36a36fSAntonio Quartulli 				   "mismatching local and remote address families");
2401d36a36fSAntonio Quartulli 		return -EINVAL;
2411d36a36fSAntonio Quartulli 	}
2421d36a36fSAntonio Quartulli 
2431d36a36fSAntonio Quartulli 	if (remote_fam != AF_INET6 && attrs[OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID]) {
2441d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack,
2451d36a36fSAntonio Quartulli 				   "cannot specify scope id without remote IPv6 address");
2461d36a36fSAntonio Quartulli 		return -EINVAL;
2471d36a36fSAntonio Quartulli 	}
2481d36a36fSAntonio Quartulli 
2491d36a36fSAntonio Quartulli 	/* VPN IPs are needed only in MP mode for selecting the right peer */
2501d36a36fSAntonio Quartulli 	if (ovpn->mode == OVPN_MODE_P2P && (attrs[OVPN_A_PEER_VPN_IPV4] ||
2511d36a36fSAntonio Quartulli 					    attrs[OVPN_A_PEER_VPN_IPV6])) {
2521d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
2531d36a36fSAntonio Quartulli 				       "unexpected VPN IP in P2P mode");
2541d36a36fSAntonio Quartulli 		return -EINVAL;
2551d36a36fSAntonio Quartulli 	}
2561d36a36fSAntonio Quartulli 
2571d36a36fSAntonio Quartulli 	if ((attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
2581d36a36fSAntonio Quartulli 	     !attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]) ||
2591d36a36fSAntonio Quartulli 	    (!attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
2601d36a36fSAntonio Quartulli 	     attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT])) {
2611d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
2621d36a36fSAntonio Quartulli 				       "keepalive interval and timeout are required together");
2631d36a36fSAntonio Quartulli 		return -EINVAL;
2641d36a36fSAntonio Quartulli 	}
2651d36a36fSAntonio Quartulli 
2661d36a36fSAntonio Quartulli 	return 0;
2671d36a36fSAntonio Quartulli }
2681d36a36fSAntonio Quartulli 
2691d36a36fSAntonio Quartulli /**
2701d36a36fSAntonio Quartulli  * ovpn_nl_peer_modify - modify the peer attributes according to the incoming msg
2711d36a36fSAntonio Quartulli  * @peer: the peer to modify
2721d36a36fSAntonio Quartulli  * @info: generic netlink info from the user request
2731d36a36fSAntonio Quartulli  * @attrs: the attributes from the user request
2741d36a36fSAntonio Quartulli  *
2751d36a36fSAntonio Quartulli  * Return: a negative error code in case of failure, 0 on success or 1 on
2761d36a36fSAntonio Quartulli  *	   success and the VPN IPs have been modified (requires rehashing in MP
2771d36a36fSAntonio Quartulli  *	   mode)
2781d36a36fSAntonio Quartulli  */
ovpn_nl_peer_modify(struct ovpn_peer * peer,struct genl_info * info,struct nlattr ** attrs)2791d36a36fSAntonio Quartulli static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
2801d36a36fSAntonio Quartulli 			       struct nlattr **attrs)
2811d36a36fSAntonio Quartulli {
2821d36a36fSAntonio Quartulli 	struct sockaddr_storage ss = {};
2831d36a36fSAntonio Quartulli 	void *local_ip = NULL;
2841d36a36fSAntonio Quartulli 	u32 interv, timeout;
2851d36a36fSAntonio Quartulli 	bool rehash = false;
2861d36a36fSAntonio Quartulli 	int ret;
2871d36a36fSAntonio Quartulli 
2881d36a36fSAntonio Quartulli 	spin_lock_bh(&peer->lock);
2891d36a36fSAntonio Quartulli 
2901d36a36fSAntonio Quartulli 	if (ovpn_nl_attr_sockaddr_remote(attrs, &ss)) {
2911d36a36fSAntonio Quartulli 		/* we carry the local IP in a generic container.
2921d36a36fSAntonio Quartulli 		 * ovpn_peer_reset_sockaddr() will properly interpret it
2931d36a36fSAntonio Quartulli 		 * based on ss.ss_family
2941d36a36fSAntonio Quartulli 		 */
2951d36a36fSAntonio Quartulli 		local_ip = ovpn_nl_attr_local_ip(attrs);
2961d36a36fSAntonio Quartulli 
2971d36a36fSAntonio Quartulli 		/* set peer sockaddr */
2981d36a36fSAntonio Quartulli 		ret = ovpn_peer_reset_sockaddr(peer, &ss, local_ip);
2991d36a36fSAntonio Quartulli 		if (ret < 0) {
3001d36a36fSAntonio Quartulli 			NL_SET_ERR_MSG_FMT_MOD(info->extack,
3011d36a36fSAntonio Quartulli 					       "cannot set peer sockaddr: %d",
3021d36a36fSAntonio Quartulli 					       ret);
3031d36a36fSAntonio Quartulli 			goto err_unlock;
3041d36a36fSAntonio Quartulli 		}
3051d36a36fSAntonio Quartulli 		dst_cache_reset(&peer->dst_cache);
3061d36a36fSAntonio Quartulli 	}
3071d36a36fSAntonio Quartulli 
3081d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_VPN_IPV4]) {
3091d36a36fSAntonio Quartulli 		rehash = true;
3101d36a36fSAntonio Quartulli 		peer->vpn_addrs.ipv4.s_addr =
3111d36a36fSAntonio Quartulli 			nla_get_in_addr(attrs[OVPN_A_PEER_VPN_IPV4]);
3121d36a36fSAntonio Quartulli 	}
3131d36a36fSAntonio Quartulli 
3141d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_VPN_IPV6]) {
3151d36a36fSAntonio Quartulli 		rehash = true;
3161d36a36fSAntonio Quartulli 		peer->vpn_addrs.ipv6 =
3171d36a36fSAntonio Quartulli 			nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
3181d36a36fSAntonio Quartulli 	}
3191d36a36fSAntonio Quartulli 
3201d36a36fSAntonio Quartulli 	/* when setting the keepalive, both parameters have to be configured */
3211d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
3221d36a36fSAntonio Quartulli 	    attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]) {
3231d36a36fSAntonio Quartulli 		interv = nla_get_u32(attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL]);
3241d36a36fSAntonio Quartulli 		timeout = nla_get_u32(attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]);
3251d36a36fSAntonio Quartulli 		ovpn_peer_keepalive_set(peer, interv, timeout);
3261d36a36fSAntonio Quartulli 	}
3271d36a36fSAntonio Quartulli 
3281d36a36fSAntonio Quartulli 	netdev_dbg(peer->ovpn->dev,
3291d36a36fSAntonio Quartulli 		   "modify peer id=%u endpoint=%pIScp VPN-IPv4=%pI4 VPN-IPv6=%pI6c\n",
3301d36a36fSAntonio Quartulli 		   peer->id, &ss,
3311d36a36fSAntonio Quartulli 		   &peer->vpn_addrs.ipv4.s_addr, &peer->vpn_addrs.ipv6);
3321d36a36fSAntonio Quartulli 
3331d36a36fSAntonio Quartulli 	spin_unlock_bh(&peer->lock);
3341d36a36fSAntonio Quartulli 
3351d36a36fSAntonio Quartulli 	return rehash ? 1 : 0;
3361d36a36fSAntonio Quartulli err_unlock:
3371d36a36fSAntonio Quartulli 	spin_unlock_bh(&peer->lock);
3381d36a36fSAntonio Quartulli 	return ret;
3391d36a36fSAntonio Quartulli }
3401d36a36fSAntonio Quartulli 
ovpn_nl_peer_new_doit(struct sk_buff * skb,struct genl_info * info)341b7a63391SAntonio Quartulli int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info)
342b7a63391SAntonio Quartulli {
3431d36a36fSAntonio Quartulli 	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
3441d36a36fSAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
3451d36a36fSAntonio Quartulli 	struct ovpn_socket *ovpn_sock;
3461d36a36fSAntonio Quartulli 	struct socket *sock = NULL;
3471d36a36fSAntonio Quartulli 	struct ovpn_peer *peer;
3481d36a36fSAntonio Quartulli 	u32 sockfd, peer_id;
3491d36a36fSAntonio Quartulli 	int ret;
3501d36a36fSAntonio Quartulli 
3511d36a36fSAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_PEER))
3521d36a36fSAntonio Quartulli 		return -EINVAL;
3531d36a36fSAntonio Quartulli 
3541d36a36fSAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER],
3551d36a36fSAntonio Quartulli 			       ovpn_peer_nl_policy, info->extack);
3561d36a36fSAntonio Quartulli 	if (ret)
3571d36a36fSAntonio Quartulli 		return ret;
3581d36a36fSAntonio Quartulli 
3591d36a36fSAntonio Quartulli 	ret = ovpn_nl_peer_precheck(ovpn, info, attrs);
3601d36a36fSAntonio Quartulli 	if (ret < 0)
3611d36a36fSAntonio Quartulli 		return ret;
3621d36a36fSAntonio Quartulli 
3631d36a36fSAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_PEER], attrs,
3641d36a36fSAntonio Quartulli 			      OVPN_A_PEER_SOCKET))
3651d36a36fSAntonio Quartulli 		return -EINVAL;
3661d36a36fSAntonio Quartulli 
3671d36a36fSAntonio Quartulli 	/* in MP mode VPN IPs are required for selecting the right peer */
3681d36a36fSAntonio Quartulli 	if (ovpn->mode == OVPN_MODE_MP && !attrs[OVPN_A_PEER_VPN_IPV4] &&
3691d36a36fSAntonio Quartulli 	    !attrs[OVPN_A_PEER_VPN_IPV6]) {
3701d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
3711d36a36fSAntonio Quartulli 				       "VPN IP must be provided in MP mode");
3721d36a36fSAntonio Quartulli 		return -EINVAL;
3731d36a36fSAntonio Quartulli 	}
3741d36a36fSAntonio Quartulli 
3751d36a36fSAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
3761d36a36fSAntonio Quartulli 	peer = ovpn_peer_new(ovpn, peer_id);
3771d36a36fSAntonio Quartulli 	if (IS_ERR(peer)) {
3781d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
3791d36a36fSAntonio Quartulli 				       "cannot create new peer object for peer %u: %ld",
3801d36a36fSAntonio Quartulli 				       peer_id, PTR_ERR(peer));
3811d36a36fSAntonio Quartulli 		return PTR_ERR(peer);
3821d36a36fSAntonio Quartulli 	}
3831d36a36fSAntonio Quartulli 
3841d36a36fSAntonio Quartulli 	/* lookup the fd in the kernel table and extract the socket object */
3851d36a36fSAntonio Quartulli 	sockfd = nla_get_u32(attrs[OVPN_A_PEER_SOCKET]);
3861d36a36fSAntonio Quartulli 	/* sockfd_lookup() increases sock's refcounter */
3871d36a36fSAntonio Quartulli 	sock = sockfd_lookup(sockfd, &ret);
3881d36a36fSAntonio Quartulli 	if (!sock) {
3891d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
3901d36a36fSAntonio Quartulli 				       "cannot lookup peer socket (fd=%u): %d",
3911d36a36fSAntonio Quartulli 				       sockfd, ret);
3921d36a36fSAntonio Quartulli 		ret = -ENOTSOCK;
3931d36a36fSAntonio Quartulli 		goto peer_release;
3941d36a36fSAntonio Quartulli 	}
3951d36a36fSAntonio Quartulli 
3961d36a36fSAntonio Quartulli 	/* Only when using UDP as transport protocol the remote endpoint
3971d36a36fSAntonio Quartulli 	 * can be configured so that ovpn knows where to send packets to.
3981d36a36fSAntonio Quartulli 	 */
3991d36a36fSAntonio Quartulli 	if (sock->sk->sk_protocol == IPPROTO_UDP &&
4001d36a36fSAntonio Quartulli 	    !attrs[OVPN_A_PEER_REMOTE_IPV4] &&
4011d36a36fSAntonio Quartulli 	    !attrs[OVPN_A_PEER_REMOTE_IPV6]) {
4021d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4031d36a36fSAntonio Quartulli 				       "missing remote IP address for UDP socket");
4041d36a36fSAntonio Quartulli 		sockfd_put(sock);
4051d36a36fSAntonio Quartulli 		ret = -EINVAL;
4061d36a36fSAntonio Quartulli 		goto peer_release;
4071d36a36fSAntonio Quartulli 	}
4081d36a36fSAntonio Quartulli 
4091d36a36fSAntonio Quartulli 	/* In case of TCP, the socket is connected to the peer and ovpn
4101d36a36fSAntonio Quartulli 	 * will just send bytes over it, without the need to specify a
4111d36a36fSAntonio Quartulli 	 * destination.
4121d36a36fSAntonio Quartulli 	 */
4131d36a36fSAntonio Quartulli 	if (sock->sk->sk_protocol == IPPROTO_TCP &&
4141d36a36fSAntonio Quartulli 	    (attrs[OVPN_A_PEER_REMOTE_IPV4] ||
4151d36a36fSAntonio Quartulli 	     attrs[OVPN_A_PEER_REMOTE_IPV6])) {
4161d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4171d36a36fSAntonio Quartulli 				       "unexpected remote IP address with TCP socket");
4181d36a36fSAntonio Quartulli 		sockfd_put(sock);
4191d36a36fSAntonio Quartulli 		ret = -EINVAL;
4201d36a36fSAntonio Quartulli 		goto peer_release;
4211d36a36fSAntonio Quartulli 	}
4221d36a36fSAntonio Quartulli 
4231d36a36fSAntonio Quartulli 	ovpn_sock = ovpn_socket_new(sock, peer);
4241d36a36fSAntonio Quartulli 	/* at this point we unconditionally drop the reference to the socket:
4251d36a36fSAntonio Quartulli 	 * - in case of error, the socket has to be dropped
4261d36a36fSAntonio Quartulli 	 * - if case of success, the socket is configured and let
4271d36a36fSAntonio Quartulli 	 *   userspace own the reference, so that the latter can
4281d36a36fSAntonio Quartulli 	 *   trigger the final close()
4291d36a36fSAntonio Quartulli 	 */
4301d36a36fSAntonio Quartulli 	sockfd_put(sock);
4311d36a36fSAntonio Quartulli 	if (IS_ERR(ovpn_sock)) {
4321d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4331d36a36fSAntonio Quartulli 				       "cannot encapsulate socket: %ld",
4341d36a36fSAntonio Quartulli 				       PTR_ERR(ovpn_sock));
4351d36a36fSAntonio Quartulli 		ret = -ENOTSOCK;
4361d36a36fSAntonio Quartulli 		goto peer_release;
4371d36a36fSAntonio Quartulli 	}
4381d36a36fSAntonio Quartulli 
4391d36a36fSAntonio Quartulli 	rcu_assign_pointer(peer->sock, ovpn_sock);
4401d36a36fSAntonio Quartulli 
4411d36a36fSAntonio Quartulli 	ret = ovpn_nl_peer_modify(peer, info, attrs);
4421d36a36fSAntonio Quartulli 	if (ret < 0)
4431d36a36fSAntonio Quartulli 		goto sock_release;
4441d36a36fSAntonio Quartulli 
4451d36a36fSAntonio Quartulli 	ret = ovpn_peer_add(ovpn, peer);
4461d36a36fSAntonio Quartulli 	if (ret < 0) {
4471d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4481d36a36fSAntonio Quartulli 				       "cannot add new peer (id=%u) to hashtable: %d",
4491d36a36fSAntonio Quartulli 				       peer->id, ret);
4501d36a36fSAntonio Quartulli 		goto sock_release;
4511d36a36fSAntonio Quartulli 	}
4521d36a36fSAntonio Quartulli 
4531d36a36fSAntonio Quartulli 	return 0;
4541d36a36fSAntonio Quartulli 
4551d36a36fSAntonio Quartulli sock_release:
4561d36a36fSAntonio Quartulli 	ovpn_socket_release(peer);
4571d36a36fSAntonio Quartulli peer_release:
4581d36a36fSAntonio Quartulli 	/* release right away because peer was not yet hashed, thus it is not
4591d36a36fSAntonio Quartulli 	 * used in any context
4601d36a36fSAntonio Quartulli 	 */
4611d36a36fSAntonio Quartulli 	ovpn_peer_release(peer);
4621d36a36fSAntonio Quartulli 
4631d36a36fSAntonio Quartulli 	return ret;
464b7a63391SAntonio Quartulli }
465b7a63391SAntonio Quartulli 
ovpn_nl_peer_set_doit(struct sk_buff * skb,struct genl_info * info)466b7a63391SAntonio Quartulli int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
467b7a63391SAntonio Quartulli {
4681d36a36fSAntonio Quartulli 	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
4691d36a36fSAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
4701d36a36fSAntonio Quartulli 	struct ovpn_socket *sock;
4711d36a36fSAntonio Quartulli 	struct ovpn_peer *peer;
4721d36a36fSAntonio Quartulli 	u32 peer_id;
4731d36a36fSAntonio Quartulli 	int ret;
4741d36a36fSAntonio Quartulli 
4751d36a36fSAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_PEER))
4761d36a36fSAntonio Quartulli 		return -EINVAL;
4771d36a36fSAntonio Quartulli 
4781d36a36fSAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER],
4791d36a36fSAntonio Quartulli 			       ovpn_peer_nl_policy, info->extack);
4801d36a36fSAntonio Quartulli 	if (ret)
4811d36a36fSAntonio Quartulli 		return ret;
4821d36a36fSAntonio Quartulli 
4831d36a36fSAntonio Quartulli 	ret = ovpn_nl_peer_precheck(ovpn, info, attrs);
4841d36a36fSAntonio Quartulli 	if (ret < 0)
4851d36a36fSAntonio Quartulli 		return ret;
4861d36a36fSAntonio Quartulli 
4871d36a36fSAntonio Quartulli 	if (attrs[OVPN_A_PEER_SOCKET]) {
4881d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4891d36a36fSAntonio Quartulli 				       "socket cannot be modified");
4901d36a36fSAntonio Quartulli 		return -EINVAL;
4911d36a36fSAntonio Quartulli 	}
4921d36a36fSAntonio Quartulli 
4931d36a36fSAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
4941d36a36fSAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
4951d36a36fSAntonio Quartulli 	if (!peer) {
4961d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
4971d36a36fSAntonio Quartulli 				       "cannot find peer with id %u", peer_id);
4981d36a36fSAntonio Quartulli 		return -ENOENT;
4991d36a36fSAntonio Quartulli 	}
5001d36a36fSAntonio Quartulli 
5011d36a36fSAntonio Quartulli 	/* when using a TCP socket the remote IP is not expected */
5021d36a36fSAntonio Quartulli 	rcu_read_lock();
5031d36a36fSAntonio Quartulli 	sock = rcu_dereference(peer->sock);
504*ba499a07SAntonio Quartulli 	if (sock && sock->sk->sk_protocol == IPPROTO_TCP &&
5051d36a36fSAntonio Quartulli 	    (attrs[OVPN_A_PEER_REMOTE_IPV4] ||
5061d36a36fSAntonio Quartulli 	     attrs[OVPN_A_PEER_REMOTE_IPV6])) {
5071d36a36fSAntonio Quartulli 		rcu_read_unlock();
5081d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
5091d36a36fSAntonio Quartulli 				       "unexpected remote IP address with TCP socket");
5101d36a36fSAntonio Quartulli 		ovpn_peer_put(peer);
5111d36a36fSAntonio Quartulli 		return -EINVAL;
5121d36a36fSAntonio Quartulli 	}
5131d36a36fSAntonio Quartulli 	rcu_read_unlock();
5141d36a36fSAntonio Quartulli 
5151d36a36fSAntonio Quartulli 	spin_lock_bh(&ovpn->lock);
5161d36a36fSAntonio Quartulli 	ret = ovpn_nl_peer_modify(peer, info, attrs);
5171d36a36fSAntonio Quartulli 	if (ret < 0) {
5181d36a36fSAntonio Quartulli 		spin_unlock_bh(&ovpn->lock);
5191d36a36fSAntonio Quartulli 		ovpn_peer_put(peer);
5201d36a36fSAntonio Quartulli 		return ret;
5211d36a36fSAntonio Quartulli 	}
5221d36a36fSAntonio Quartulli 
5231d36a36fSAntonio Quartulli 	/* ret == 1 means that VPN IPv4/6 has been modified and rehashing
5241d36a36fSAntonio Quartulli 	 * is required
5251d36a36fSAntonio Quartulli 	 */
5261d36a36fSAntonio Quartulli 	if (ret > 0)
5271d36a36fSAntonio Quartulli 		ovpn_peer_hash_vpn_ip(peer);
5281d36a36fSAntonio Quartulli 	spin_unlock_bh(&ovpn->lock);
5291d36a36fSAntonio Quartulli 	ovpn_peer_put(peer);
5301d36a36fSAntonio Quartulli 
5311d36a36fSAntonio Quartulli 	return 0;
5321d36a36fSAntonio Quartulli }
5331d36a36fSAntonio Quartulli 
ovpn_nl_send_peer(struct sk_buff * skb,const struct genl_info * info,const struct ovpn_peer * peer,u32 portid,u32 seq,int flags)5341d36a36fSAntonio Quartulli static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info,
5351d36a36fSAntonio Quartulli 			     const struct ovpn_peer *peer, u32 portid, u32 seq,
5361d36a36fSAntonio Quartulli 			     int flags)
5371d36a36fSAntonio Quartulli {
5381d36a36fSAntonio Quartulli 	const struct ovpn_bind *bind;
5391d36a36fSAntonio Quartulli 	struct ovpn_socket *sock;
5401d36a36fSAntonio Quartulli 	int ret = -EMSGSIZE;
5411d36a36fSAntonio Quartulli 	struct nlattr *attr;
5421d36a36fSAntonio Quartulli 	__be16 local_port;
5431d36a36fSAntonio Quartulli 	void *hdr;
5441d36a36fSAntonio Quartulli 	int id;
5451d36a36fSAntonio Quartulli 
5461d36a36fSAntonio Quartulli 	hdr = genlmsg_put(skb, portid, seq, &ovpn_nl_family, flags,
5471d36a36fSAntonio Quartulli 			  OVPN_CMD_PEER_GET);
5481d36a36fSAntonio Quartulli 	if (!hdr)
5491d36a36fSAntonio Quartulli 		return -ENOBUFS;
5501d36a36fSAntonio Quartulli 
5511d36a36fSAntonio Quartulli 	attr = nla_nest_start(skb, OVPN_A_PEER);
5521d36a36fSAntonio Quartulli 	if (!attr)
5531d36a36fSAntonio Quartulli 		goto err;
5541d36a36fSAntonio Quartulli 
5551d36a36fSAntonio Quartulli 	rcu_read_lock();
5561d36a36fSAntonio Quartulli 	sock = rcu_dereference(peer->sock);
5571d36a36fSAntonio Quartulli 	if (!sock) {
5581d36a36fSAntonio Quartulli 		ret = -EINVAL;
5591d36a36fSAntonio Quartulli 		goto err_unlock;
5601d36a36fSAntonio Quartulli 	}
5611d36a36fSAntonio Quartulli 
562*ba499a07SAntonio Quartulli 	if (!net_eq(genl_info_net(info), sock_net(sock->sk))) {
5631d36a36fSAntonio Quartulli 		id = peernet2id_alloc(genl_info_net(info),
564*ba499a07SAntonio Quartulli 				      sock_net(sock->sk),
5651d36a36fSAntonio Quartulli 				      GFP_ATOMIC);
5661d36a36fSAntonio Quartulli 		if (nla_put_s32(skb, OVPN_A_PEER_SOCKET_NETNSID, id))
5671d36a36fSAntonio Quartulli 			goto err_unlock;
5681d36a36fSAntonio Quartulli 	}
569*ba499a07SAntonio Quartulli 	local_port = inet_sk(sock->sk)->inet_sport;
5701d36a36fSAntonio Quartulli 	rcu_read_unlock();
5711d36a36fSAntonio Quartulli 
5721d36a36fSAntonio Quartulli 	if (nla_put_u32(skb, OVPN_A_PEER_ID, peer->id))
5731d36a36fSAntonio Quartulli 		goto err;
5741d36a36fSAntonio Quartulli 
5751d36a36fSAntonio Quartulli 	if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY))
5761d36a36fSAntonio Quartulli 		if (nla_put_in_addr(skb, OVPN_A_PEER_VPN_IPV4,
5771d36a36fSAntonio Quartulli 				    peer->vpn_addrs.ipv4.s_addr))
5781d36a36fSAntonio Quartulli 			goto err;
5791d36a36fSAntonio Quartulli 
5801d36a36fSAntonio Quartulli 	if (!ipv6_addr_equal(&peer->vpn_addrs.ipv6, &in6addr_any))
5811d36a36fSAntonio Quartulli 		if (nla_put_in6_addr(skb, OVPN_A_PEER_VPN_IPV6,
5821d36a36fSAntonio Quartulli 				     &peer->vpn_addrs.ipv6))
5831d36a36fSAntonio Quartulli 			goto err;
5841d36a36fSAntonio Quartulli 
5851d36a36fSAntonio Quartulli 	if (nla_put_u32(skb, OVPN_A_PEER_KEEPALIVE_INTERVAL,
5861d36a36fSAntonio Quartulli 			peer->keepalive_interval) ||
5871d36a36fSAntonio Quartulli 	    nla_put_u32(skb, OVPN_A_PEER_KEEPALIVE_TIMEOUT,
5881d36a36fSAntonio Quartulli 			peer->keepalive_timeout))
5891d36a36fSAntonio Quartulli 		goto err;
5901d36a36fSAntonio Quartulli 
5911d36a36fSAntonio Quartulli 	rcu_read_lock();
5921d36a36fSAntonio Quartulli 	bind = rcu_dereference(peer->bind);
5931d36a36fSAntonio Quartulli 	if (bind) {
5941d36a36fSAntonio Quartulli 		if (bind->remote.in4.sin_family == AF_INET) {
5951d36a36fSAntonio Quartulli 			if (nla_put_in_addr(skb, OVPN_A_PEER_REMOTE_IPV4,
5961d36a36fSAntonio Quartulli 					    bind->remote.in4.sin_addr.s_addr) ||
5971d36a36fSAntonio Quartulli 			    nla_put_net16(skb, OVPN_A_PEER_REMOTE_PORT,
5981d36a36fSAntonio Quartulli 					  bind->remote.in4.sin_port) ||
5991d36a36fSAntonio Quartulli 			    nla_put_in_addr(skb, OVPN_A_PEER_LOCAL_IPV4,
6001d36a36fSAntonio Quartulli 					    bind->local.ipv4.s_addr))
6011d36a36fSAntonio Quartulli 				goto err_unlock;
6021d36a36fSAntonio Quartulli 		} else if (bind->remote.in4.sin_family == AF_INET6) {
6031d36a36fSAntonio Quartulli 			if (nla_put_in6_addr(skb, OVPN_A_PEER_REMOTE_IPV6,
6041d36a36fSAntonio Quartulli 					     &bind->remote.in6.sin6_addr) ||
6051d36a36fSAntonio Quartulli 			    nla_put_u32(skb, OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID,
6061d36a36fSAntonio Quartulli 					bind->remote.in6.sin6_scope_id) ||
6071d36a36fSAntonio Quartulli 			    nla_put_net16(skb, OVPN_A_PEER_REMOTE_PORT,
6081d36a36fSAntonio Quartulli 					  bind->remote.in6.sin6_port) ||
6091d36a36fSAntonio Quartulli 			    nla_put_in6_addr(skb, OVPN_A_PEER_LOCAL_IPV6,
6101d36a36fSAntonio Quartulli 					     &bind->local.ipv6))
6111d36a36fSAntonio Quartulli 				goto err_unlock;
6121d36a36fSAntonio Quartulli 		}
6131d36a36fSAntonio Quartulli 	}
6141d36a36fSAntonio Quartulli 	rcu_read_unlock();
6151d36a36fSAntonio Quartulli 
6161d36a36fSAntonio Quartulli 	if (nla_put_net16(skb, OVPN_A_PEER_LOCAL_PORT, local_port) ||
6171d36a36fSAntonio Quartulli 	    /* VPN RX stats */
6181d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_VPN_RX_BYTES,
6191d36a36fSAntonio Quartulli 			 atomic64_read(&peer->vpn_stats.rx.bytes)) ||
6201d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_VPN_RX_PACKETS,
6211d36a36fSAntonio Quartulli 			 atomic64_read(&peer->vpn_stats.rx.packets)) ||
6221d36a36fSAntonio Quartulli 	    /* VPN TX stats */
6231d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_VPN_TX_BYTES,
6241d36a36fSAntonio Quartulli 			 atomic64_read(&peer->vpn_stats.tx.bytes)) ||
6251d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_VPN_TX_PACKETS,
6261d36a36fSAntonio Quartulli 			 atomic64_read(&peer->vpn_stats.tx.packets)) ||
6271d36a36fSAntonio Quartulli 	    /* link RX stats */
6281d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_LINK_RX_BYTES,
6291d36a36fSAntonio Quartulli 			 atomic64_read(&peer->link_stats.rx.bytes)) ||
6301d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_LINK_RX_PACKETS,
6311d36a36fSAntonio Quartulli 			 atomic64_read(&peer->link_stats.rx.packets)) ||
6321d36a36fSAntonio Quartulli 	    /* link TX stats */
6331d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_LINK_TX_BYTES,
6341d36a36fSAntonio Quartulli 			 atomic64_read(&peer->link_stats.tx.bytes)) ||
6351d36a36fSAntonio Quartulli 	    nla_put_uint(skb, OVPN_A_PEER_LINK_TX_PACKETS,
6361d36a36fSAntonio Quartulli 			 atomic64_read(&peer->link_stats.tx.packets)))
6371d36a36fSAntonio Quartulli 		goto err;
6381d36a36fSAntonio Quartulli 
6391d36a36fSAntonio Quartulli 	nla_nest_end(skb, attr);
6401d36a36fSAntonio Quartulli 	genlmsg_end(skb, hdr);
6411d36a36fSAntonio Quartulli 
6421d36a36fSAntonio Quartulli 	return 0;
6431d36a36fSAntonio Quartulli err_unlock:
6441d36a36fSAntonio Quartulli 	rcu_read_unlock();
6451d36a36fSAntonio Quartulli err:
6461d36a36fSAntonio Quartulli 	genlmsg_cancel(skb, hdr);
6471d36a36fSAntonio Quartulli 	return ret;
648b7a63391SAntonio Quartulli }
649b7a63391SAntonio Quartulli 
ovpn_nl_peer_get_doit(struct sk_buff * skb,struct genl_info * info)650b7a63391SAntonio Quartulli int ovpn_nl_peer_get_doit(struct sk_buff *skb, struct genl_info *info)
651b7a63391SAntonio Quartulli {
6521d36a36fSAntonio Quartulli 	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
6531d36a36fSAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
6541d36a36fSAntonio Quartulli 	struct ovpn_peer *peer;
6551d36a36fSAntonio Quartulli 	struct sk_buff *msg;
6561d36a36fSAntonio Quartulli 	u32 peer_id;
6571d36a36fSAntonio Quartulli 	int ret;
6581d36a36fSAntonio Quartulli 
6591d36a36fSAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_PEER))
6601d36a36fSAntonio Quartulli 		return -EINVAL;
6611d36a36fSAntonio Quartulli 
6621d36a36fSAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER],
6631d36a36fSAntonio Quartulli 			       ovpn_peer_nl_policy, info->extack);
6641d36a36fSAntonio Quartulli 	if (ret)
6651d36a36fSAntonio Quartulli 		return ret;
6661d36a36fSAntonio Quartulli 
6671d36a36fSAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_PEER], attrs,
6681d36a36fSAntonio Quartulli 			      OVPN_A_PEER_ID))
6691d36a36fSAntonio Quartulli 		return -EINVAL;
6701d36a36fSAntonio Quartulli 
6711d36a36fSAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
6721d36a36fSAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
6731d36a36fSAntonio Quartulli 	if (!peer) {
6741d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
6751d36a36fSAntonio Quartulli 				       "cannot find peer with id %u", peer_id);
6761d36a36fSAntonio Quartulli 		return -ENOENT;
6771d36a36fSAntonio Quartulli 	}
6781d36a36fSAntonio Quartulli 
6791d36a36fSAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6801d36a36fSAntonio Quartulli 	if (!msg) {
6811d36a36fSAntonio Quartulli 		ret = -ENOMEM;
6821d36a36fSAntonio Quartulli 		goto err;
6831d36a36fSAntonio Quartulli 	}
6841d36a36fSAntonio Quartulli 
6851d36a36fSAntonio Quartulli 	ret = ovpn_nl_send_peer(msg, info, peer, info->snd_portid,
6861d36a36fSAntonio Quartulli 				info->snd_seq, 0);
6871d36a36fSAntonio Quartulli 	if (ret < 0) {
6881d36a36fSAntonio Quartulli 		nlmsg_free(msg);
6891d36a36fSAntonio Quartulli 		goto err;
6901d36a36fSAntonio Quartulli 	}
6911d36a36fSAntonio Quartulli 
6921d36a36fSAntonio Quartulli 	ret = genlmsg_reply(msg, info);
6931d36a36fSAntonio Quartulli err:
6941d36a36fSAntonio Quartulli 	ovpn_peer_put(peer);
6951d36a36fSAntonio Quartulli 	return ret;
696b7a63391SAntonio Quartulli }
697b7a63391SAntonio Quartulli 
ovpn_nl_peer_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)698b7a63391SAntonio Quartulli int ovpn_nl_peer_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
699b7a63391SAntonio Quartulli {
7001d36a36fSAntonio Quartulli 	const struct genl_info *info = genl_info_dump(cb);
7011d36a36fSAntonio Quartulli 	int bkt, last_idx = cb->args[1], dumped = 0;
7021d36a36fSAntonio Quartulli 	netdevice_tracker tracker;
7031d36a36fSAntonio Quartulli 	struct ovpn_priv *ovpn;
7041d36a36fSAntonio Quartulli 	struct ovpn_peer *peer;
7051d36a36fSAntonio Quartulli 
7061d36a36fSAntonio Quartulli 	ovpn = ovpn_get_dev_from_attrs(sock_net(cb->skb->sk), info, &tracker);
7071d36a36fSAntonio Quartulli 	if (IS_ERR(ovpn))
7081d36a36fSAntonio Quartulli 		return PTR_ERR(ovpn);
7091d36a36fSAntonio Quartulli 
7101d36a36fSAntonio Quartulli 	if (ovpn->mode == OVPN_MODE_P2P) {
7111d36a36fSAntonio Quartulli 		/* if we already dumped a peer it means we are done */
7121d36a36fSAntonio Quartulli 		if (last_idx)
7131d36a36fSAntonio Quartulli 			goto out;
7141d36a36fSAntonio Quartulli 
7151d36a36fSAntonio Quartulli 		rcu_read_lock();
7161d36a36fSAntonio Quartulli 		peer = rcu_dereference(ovpn->peer);
7171d36a36fSAntonio Quartulli 		if (peer) {
7181d36a36fSAntonio Quartulli 			if (ovpn_nl_send_peer(skb, info, peer,
7191d36a36fSAntonio Quartulli 					      NETLINK_CB(cb->skb).portid,
7201d36a36fSAntonio Quartulli 					      cb->nlh->nlmsg_seq,
7211d36a36fSAntonio Quartulli 					      NLM_F_MULTI) == 0)
7221d36a36fSAntonio Quartulli 				dumped++;
7231d36a36fSAntonio Quartulli 		}
7241d36a36fSAntonio Quartulli 		rcu_read_unlock();
7251d36a36fSAntonio Quartulli 	} else {
7261d36a36fSAntonio Quartulli 		rcu_read_lock();
7271d36a36fSAntonio Quartulli 		hash_for_each_rcu(ovpn->peers->by_id, bkt, peer,
7281d36a36fSAntonio Quartulli 				  hash_entry_id) {
7291d36a36fSAntonio Quartulli 			/* skip already dumped peers that were dumped by
7301d36a36fSAntonio Quartulli 			 * previous invocations
7311d36a36fSAntonio Quartulli 			 */
7321d36a36fSAntonio Quartulli 			if (last_idx > 0) {
7331d36a36fSAntonio Quartulli 				last_idx--;
7341d36a36fSAntonio Quartulli 				continue;
7351d36a36fSAntonio Quartulli 			}
7361d36a36fSAntonio Quartulli 
7371d36a36fSAntonio Quartulli 			if (ovpn_nl_send_peer(skb, info, peer,
7381d36a36fSAntonio Quartulli 					      NETLINK_CB(cb->skb).portid,
7391d36a36fSAntonio Quartulli 					      cb->nlh->nlmsg_seq,
7401d36a36fSAntonio Quartulli 					      NLM_F_MULTI) < 0)
7411d36a36fSAntonio Quartulli 				break;
7421d36a36fSAntonio Quartulli 
7431d36a36fSAntonio Quartulli 			/* count peers being dumped during this invocation */
7441d36a36fSAntonio Quartulli 			dumped++;
7451d36a36fSAntonio Quartulli 		}
7461d36a36fSAntonio Quartulli 		rcu_read_unlock();
7471d36a36fSAntonio Quartulli 	}
7481d36a36fSAntonio Quartulli 
7491d36a36fSAntonio Quartulli out:
7501d36a36fSAntonio Quartulli 	netdev_put(ovpn->dev, &tracker);
7511d36a36fSAntonio Quartulli 
7521d36a36fSAntonio Quartulli 	/* sum up peers dumped in this message, so that at the next invocation
7531d36a36fSAntonio Quartulli 	 * we can continue from where we left
7541d36a36fSAntonio Quartulli 	 */
7551d36a36fSAntonio Quartulli 	cb->args[1] += dumped;
7561d36a36fSAntonio Quartulli 	return skb->len;
757b7a63391SAntonio Quartulli }
758b7a63391SAntonio Quartulli 
ovpn_nl_peer_del_doit(struct sk_buff * skb,struct genl_info * info)759b7a63391SAntonio Quartulli int ovpn_nl_peer_del_doit(struct sk_buff *skb, struct genl_info *info)
760b7a63391SAntonio Quartulli {
7611d36a36fSAntonio Quartulli 	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
7621d36a36fSAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
7631d36a36fSAntonio Quartulli 	struct ovpn_peer *peer;
7641d36a36fSAntonio Quartulli 	u32 peer_id;
7651d36a36fSAntonio Quartulli 	int ret;
7661d36a36fSAntonio Quartulli 
7671d36a36fSAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_PEER))
7681d36a36fSAntonio Quartulli 		return -EINVAL;
7691d36a36fSAntonio Quartulli 
7701d36a36fSAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_PEER_MAX, info->attrs[OVPN_A_PEER],
7711d36a36fSAntonio Quartulli 			       ovpn_peer_nl_policy, info->extack);
7721d36a36fSAntonio Quartulli 	if (ret)
7731d36a36fSAntonio Quartulli 		return ret;
7741d36a36fSAntonio Quartulli 
7751d36a36fSAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_PEER], attrs,
7761d36a36fSAntonio Quartulli 			      OVPN_A_PEER_ID))
7771d36a36fSAntonio Quartulli 		return -EINVAL;
7781d36a36fSAntonio Quartulli 
7791d36a36fSAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_PEER_ID]);
7801d36a36fSAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
7811d36a36fSAntonio Quartulli 	if (!peer) {
7821d36a36fSAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
7831d36a36fSAntonio Quartulli 				       "cannot find peer with id %u", peer_id);
7841d36a36fSAntonio Quartulli 		return -ENOENT;
7851d36a36fSAntonio Quartulli 	}
7861d36a36fSAntonio Quartulli 
7871d36a36fSAntonio Quartulli 	netdev_dbg(ovpn->dev, "del peer %u\n", peer->id);
7881d36a36fSAntonio Quartulli 	ret = ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_USERSPACE);
7891d36a36fSAntonio Quartulli 	ovpn_peer_put(peer);
7901d36a36fSAntonio Quartulli 
7911d36a36fSAntonio Quartulli 	return ret;
792b7a63391SAntonio Quartulli }
793b7a63391SAntonio Quartulli 
ovpn_nl_get_key_dir(struct genl_info * info,struct nlattr * key,enum ovpn_cipher_alg cipher,struct ovpn_key_direction * dir)794203e2bf5SAntonio Quartulli static int ovpn_nl_get_key_dir(struct genl_info *info, struct nlattr *key,
795203e2bf5SAntonio Quartulli 			       enum ovpn_cipher_alg cipher,
796203e2bf5SAntonio Quartulli 			       struct ovpn_key_direction *dir)
797203e2bf5SAntonio Quartulli {
798203e2bf5SAntonio Quartulli 	struct nlattr *attrs[OVPN_A_KEYDIR_MAX + 1];
799203e2bf5SAntonio Quartulli 	int ret;
800203e2bf5SAntonio Quartulli 
801203e2bf5SAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_KEYDIR_MAX, key,
802203e2bf5SAntonio Quartulli 			       ovpn_keydir_nl_policy, info->extack);
803203e2bf5SAntonio Quartulli 	if (ret)
804203e2bf5SAntonio Quartulli 		return ret;
805203e2bf5SAntonio Quartulli 
806203e2bf5SAntonio Quartulli 	switch (cipher) {
807203e2bf5SAntonio Quartulli 	case OVPN_CIPHER_ALG_AES_GCM:
808203e2bf5SAntonio Quartulli 	case OVPN_CIPHER_ALG_CHACHA20_POLY1305:
809203e2bf5SAntonio Quartulli 		if (NL_REQ_ATTR_CHECK(info->extack, key, attrs,
810203e2bf5SAntonio Quartulli 				      OVPN_A_KEYDIR_CIPHER_KEY) ||
811203e2bf5SAntonio Quartulli 		    NL_REQ_ATTR_CHECK(info->extack, key, attrs,
812203e2bf5SAntonio Quartulli 				      OVPN_A_KEYDIR_NONCE_TAIL))
813203e2bf5SAntonio Quartulli 			return -EINVAL;
814203e2bf5SAntonio Quartulli 
815203e2bf5SAntonio Quartulli 		dir->cipher_key = nla_data(attrs[OVPN_A_KEYDIR_CIPHER_KEY]);
816203e2bf5SAntonio Quartulli 		dir->cipher_key_size = nla_len(attrs[OVPN_A_KEYDIR_CIPHER_KEY]);
817203e2bf5SAntonio Quartulli 
818203e2bf5SAntonio Quartulli 		/* These algorithms require a 96bit nonce,
819203e2bf5SAntonio Quartulli 		 * Construct it by combining 4-bytes packet id and
820203e2bf5SAntonio Quartulli 		 * 8-bytes nonce-tail from userspace
821203e2bf5SAntonio Quartulli 		 */
822203e2bf5SAntonio Quartulli 		dir->nonce_tail = nla_data(attrs[OVPN_A_KEYDIR_NONCE_TAIL]);
823203e2bf5SAntonio Quartulli 		dir->nonce_tail_size = nla_len(attrs[OVPN_A_KEYDIR_NONCE_TAIL]);
824203e2bf5SAntonio Quartulli 		break;
825203e2bf5SAntonio Quartulli 	default:
826203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_MOD(info->extack, "unsupported cipher");
827203e2bf5SAntonio Quartulli 		return -EINVAL;
828203e2bf5SAntonio Quartulli 	}
829203e2bf5SAntonio Quartulli 
830203e2bf5SAntonio Quartulli 	return 0;
831203e2bf5SAntonio Quartulli }
832203e2bf5SAntonio Quartulli 
833203e2bf5SAntonio Quartulli /**
834203e2bf5SAntonio Quartulli  * ovpn_nl_key_new_doit - configure a new key for the specified peer
835203e2bf5SAntonio Quartulli  * @skb: incoming netlink message
836203e2bf5SAntonio Quartulli  * @info: genetlink metadata
837203e2bf5SAntonio Quartulli  *
838203e2bf5SAntonio Quartulli  * This function allows the user to install a new key in the peer crypto
839203e2bf5SAntonio Quartulli  * state.
840203e2bf5SAntonio Quartulli  * Each peer has two 'slots', namely 'primary' and 'secondary', where
841203e2bf5SAntonio Quartulli  * keys can be installed. The key in the 'primary' slot is used for
842203e2bf5SAntonio Quartulli  * encryption, while both keys can be used for decryption by matching the
843203e2bf5SAntonio Quartulli  * key ID carried in the incoming packet.
844203e2bf5SAntonio Quartulli  *
845203e2bf5SAntonio Quartulli  * The user is responsible for rotating keys when necessary. The user
846203e2bf5SAntonio Quartulli  * may fetch peer traffic statistics via netlink in order to better
847203e2bf5SAntonio Quartulli  * identify the right time to rotate keys.
848203e2bf5SAntonio Quartulli  * The renegotiation follows these steps:
849203e2bf5SAntonio Quartulli  * 1. a new key is computed by the user and is installed in the 'secondary'
850203e2bf5SAntonio Quartulli  *    slot
851203e2bf5SAntonio Quartulli  * 2. at user discretion (usually after a predetermined time) 'primary' and
852203e2bf5SAntonio Quartulli  *    'secondary' contents are swapped and the new key starts being used for
853203e2bf5SAntonio Quartulli  *    encryption, while the old key is kept around for decryption of late
854203e2bf5SAntonio Quartulli  *    packets.
855203e2bf5SAntonio Quartulli  *
856203e2bf5SAntonio Quartulli  * Return: 0 on success or a negative error code otherwise.
857203e2bf5SAntonio Quartulli  */
ovpn_nl_key_new_doit(struct sk_buff * skb,struct genl_info * info)858b7a63391SAntonio Quartulli int ovpn_nl_key_new_doit(struct sk_buff *skb, struct genl_info *info)
859b7a63391SAntonio Quartulli {
860203e2bf5SAntonio Quartulli 	struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1];
861203e2bf5SAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
862203e2bf5SAntonio Quartulli 	struct ovpn_peer_key_reset pkr;
863203e2bf5SAntonio Quartulli 	struct ovpn_peer *peer;
864203e2bf5SAntonio Quartulli 	u32 peer_id;
865203e2bf5SAntonio Quartulli 	int ret;
866203e2bf5SAntonio Quartulli 
867203e2bf5SAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF))
868203e2bf5SAntonio Quartulli 		return -EINVAL;
869203e2bf5SAntonio Quartulli 
870203e2bf5SAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX,
871203e2bf5SAntonio Quartulli 			       info->attrs[OVPN_A_KEYCONF],
872203e2bf5SAntonio Quartulli 			       ovpn_keyconf_nl_policy, info->extack);
873203e2bf5SAntonio Quartulli 	if (ret)
874203e2bf5SAntonio Quartulli 		return ret;
875203e2bf5SAntonio Quartulli 
876203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
877203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_PEER_ID))
878203e2bf5SAntonio Quartulli 		return -EINVAL;
879203e2bf5SAntonio Quartulli 
880203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
881203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_SLOT) ||
882203e2bf5SAntonio Quartulli 	    NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
883203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_KEY_ID) ||
884203e2bf5SAntonio Quartulli 	    NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
885203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_CIPHER_ALG) ||
886203e2bf5SAntonio Quartulli 	    NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
887203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_ENCRYPT_DIR) ||
888203e2bf5SAntonio Quartulli 	    NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
889203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_DECRYPT_DIR))
890203e2bf5SAntonio Quartulli 		return -EINVAL;
891203e2bf5SAntonio Quartulli 
892203e2bf5SAntonio Quartulli 	pkr.slot = nla_get_u32(attrs[OVPN_A_KEYCONF_SLOT]);
893203e2bf5SAntonio Quartulli 	pkr.key.key_id = nla_get_u32(attrs[OVPN_A_KEYCONF_KEY_ID]);
894203e2bf5SAntonio Quartulli 	pkr.key.cipher_alg = nla_get_u32(attrs[OVPN_A_KEYCONF_CIPHER_ALG]);
895203e2bf5SAntonio Quartulli 
896203e2bf5SAntonio Quartulli 	ret = ovpn_nl_get_key_dir(info, attrs[OVPN_A_KEYCONF_ENCRYPT_DIR],
897203e2bf5SAntonio Quartulli 				  pkr.key.cipher_alg, &pkr.key.encrypt);
898203e2bf5SAntonio Quartulli 	if (ret < 0)
899203e2bf5SAntonio Quartulli 		return ret;
900203e2bf5SAntonio Quartulli 
901203e2bf5SAntonio Quartulli 	ret = ovpn_nl_get_key_dir(info, attrs[OVPN_A_KEYCONF_DECRYPT_DIR],
902203e2bf5SAntonio Quartulli 				  pkr.key.cipher_alg, &pkr.key.decrypt);
903203e2bf5SAntonio Quartulli 	if (ret < 0)
904203e2bf5SAntonio Quartulli 		return ret;
905203e2bf5SAntonio Quartulli 
906203e2bf5SAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]);
907203e2bf5SAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
908203e2bf5SAntonio Quartulli 	if (!peer) {
909203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
910203e2bf5SAntonio Quartulli 				       "no peer with id %u to set key for",
911203e2bf5SAntonio Quartulli 				       peer_id);
912203e2bf5SAntonio Quartulli 		return -ENOENT;
913203e2bf5SAntonio Quartulli 	}
914203e2bf5SAntonio Quartulli 
915203e2bf5SAntonio Quartulli 	ret = ovpn_crypto_state_reset(&peer->crypto, &pkr);
916203e2bf5SAntonio Quartulli 	if (ret < 0) {
917203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
918203e2bf5SAntonio Quartulli 				       "cannot install new key for peer %u",
919203e2bf5SAntonio Quartulli 				       peer_id);
920203e2bf5SAntonio Quartulli 		goto out;
921203e2bf5SAntonio Quartulli 	}
922203e2bf5SAntonio Quartulli 
923203e2bf5SAntonio Quartulli 	netdev_dbg(ovpn->dev, "new key installed (id=%u) for peer %u\n",
924203e2bf5SAntonio Quartulli 		   pkr.key.key_id, peer_id);
925203e2bf5SAntonio Quartulli out:
926203e2bf5SAntonio Quartulli 	ovpn_peer_put(peer);
927203e2bf5SAntonio Quartulli 	return ret;
928203e2bf5SAntonio Quartulli }
929203e2bf5SAntonio Quartulli 
ovpn_nl_send_key(struct sk_buff * skb,const struct genl_info * info,u32 peer_id,enum ovpn_key_slot slot,const struct ovpn_key_config * keyconf)930203e2bf5SAntonio Quartulli static int ovpn_nl_send_key(struct sk_buff *skb, const struct genl_info *info,
931203e2bf5SAntonio Quartulli 			    u32 peer_id, enum ovpn_key_slot slot,
932203e2bf5SAntonio Quartulli 			    const struct ovpn_key_config *keyconf)
933203e2bf5SAntonio Quartulli {
934203e2bf5SAntonio Quartulli 	struct nlattr *attr;
935203e2bf5SAntonio Quartulli 	void *hdr;
936203e2bf5SAntonio Quartulli 
937203e2bf5SAntonio Quartulli 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, &ovpn_nl_family,
938203e2bf5SAntonio Quartulli 			  0, OVPN_CMD_KEY_GET);
939203e2bf5SAntonio Quartulli 	if (!hdr)
940203e2bf5SAntonio Quartulli 		return -ENOBUFS;
941203e2bf5SAntonio Quartulli 
942203e2bf5SAntonio Quartulli 	attr = nla_nest_start(skb, OVPN_A_KEYCONF);
943203e2bf5SAntonio Quartulli 	if (!attr)
944203e2bf5SAntonio Quartulli 		goto err;
945203e2bf5SAntonio Quartulli 
946203e2bf5SAntonio Quartulli 	if (nla_put_u32(skb, OVPN_A_KEYCONF_PEER_ID, peer_id))
947203e2bf5SAntonio Quartulli 		goto err;
948203e2bf5SAntonio Quartulli 
949203e2bf5SAntonio Quartulli 	if (nla_put_u32(skb, OVPN_A_KEYCONF_SLOT, slot) ||
950203e2bf5SAntonio Quartulli 	    nla_put_u32(skb, OVPN_A_KEYCONF_KEY_ID, keyconf->key_id) ||
951203e2bf5SAntonio Quartulli 	    nla_put_u32(skb, OVPN_A_KEYCONF_CIPHER_ALG, keyconf->cipher_alg))
952203e2bf5SAntonio Quartulli 		goto err;
953203e2bf5SAntonio Quartulli 
954203e2bf5SAntonio Quartulli 	nla_nest_end(skb, attr);
955203e2bf5SAntonio Quartulli 	genlmsg_end(skb, hdr);
956203e2bf5SAntonio Quartulli 
957203e2bf5SAntonio Quartulli 	return 0;
958203e2bf5SAntonio Quartulli err:
959203e2bf5SAntonio Quartulli 	genlmsg_cancel(skb, hdr);
960203e2bf5SAntonio Quartulli 	return -EMSGSIZE;
961b7a63391SAntonio Quartulli }
962b7a63391SAntonio Quartulli 
ovpn_nl_key_get_doit(struct sk_buff * skb,struct genl_info * info)963b7a63391SAntonio Quartulli int ovpn_nl_key_get_doit(struct sk_buff *skb, struct genl_info *info)
964b7a63391SAntonio Quartulli {
965203e2bf5SAntonio Quartulli 	struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1];
966203e2bf5SAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
967203e2bf5SAntonio Quartulli 	struct ovpn_key_config keyconf = { 0 };
968203e2bf5SAntonio Quartulli 	enum ovpn_key_slot slot;
969203e2bf5SAntonio Quartulli 	struct ovpn_peer *peer;
970203e2bf5SAntonio Quartulli 	struct sk_buff *msg;
971203e2bf5SAntonio Quartulli 	u32 peer_id;
972203e2bf5SAntonio Quartulli 	int ret;
973203e2bf5SAntonio Quartulli 
974203e2bf5SAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF))
975203e2bf5SAntonio Quartulli 		return -EINVAL;
976203e2bf5SAntonio Quartulli 
977203e2bf5SAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX,
978203e2bf5SAntonio Quartulli 			       info->attrs[OVPN_A_KEYCONF],
979203e2bf5SAntonio Quartulli 			       ovpn_keyconf_nl_policy, info->extack);
980203e2bf5SAntonio Quartulli 	if (ret)
981203e2bf5SAntonio Quartulli 		return ret;
982203e2bf5SAntonio Quartulli 
983203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
984203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_PEER_ID))
985203e2bf5SAntonio Quartulli 		return -EINVAL;
986203e2bf5SAntonio Quartulli 
987203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
988203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_SLOT))
989203e2bf5SAntonio Quartulli 		return -EINVAL;
990203e2bf5SAntonio Quartulli 
991203e2bf5SAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]);
992203e2bf5SAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
993203e2bf5SAntonio Quartulli 	if (!peer) {
994203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
995203e2bf5SAntonio Quartulli 				       "cannot find peer with id %u", peer_id);
996203e2bf5SAntonio Quartulli 		return -ENOENT;
997203e2bf5SAntonio Quartulli 	}
998203e2bf5SAntonio Quartulli 
999203e2bf5SAntonio Quartulli 	slot = nla_get_u32(attrs[OVPN_A_KEYCONF_SLOT]);
1000203e2bf5SAntonio Quartulli 
1001203e2bf5SAntonio Quartulli 	ret = ovpn_crypto_config_get(&peer->crypto, slot, &keyconf);
1002203e2bf5SAntonio Quartulli 	if (ret < 0) {
1003203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
1004203e2bf5SAntonio Quartulli 				       "cannot extract key from slot %u for peer %u",
1005203e2bf5SAntonio Quartulli 				       slot, peer_id);
1006203e2bf5SAntonio Quartulli 		goto err;
1007203e2bf5SAntonio Quartulli 	}
1008203e2bf5SAntonio Quartulli 
1009203e2bf5SAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1010203e2bf5SAntonio Quartulli 	if (!msg) {
1011203e2bf5SAntonio Quartulli 		ret = -ENOMEM;
1012203e2bf5SAntonio Quartulli 		goto err;
1013203e2bf5SAntonio Quartulli 	}
1014203e2bf5SAntonio Quartulli 
1015203e2bf5SAntonio Quartulli 	ret = ovpn_nl_send_key(msg, info, peer->id, slot, &keyconf);
1016203e2bf5SAntonio Quartulli 	if (ret < 0) {
1017203e2bf5SAntonio Quartulli 		nlmsg_free(msg);
1018203e2bf5SAntonio Quartulli 		goto err;
1019203e2bf5SAntonio Quartulli 	}
1020203e2bf5SAntonio Quartulli 
1021203e2bf5SAntonio Quartulli 	ret = genlmsg_reply(msg, info);
1022203e2bf5SAntonio Quartulli err:
1023203e2bf5SAntonio Quartulli 	ovpn_peer_put(peer);
1024203e2bf5SAntonio Quartulli 	return ret;
1025b7a63391SAntonio Quartulli }
1026b7a63391SAntonio Quartulli 
ovpn_nl_key_swap_doit(struct sk_buff * skb,struct genl_info * info)1027b7a63391SAntonio Quartulli int ovpn_nl_key_swap_doit(struct sk_buff *skb, struct genl_info *info)
1028b7a63391SAntonio Quartulli {
1029203e2bf5SAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
1030203e2bf5SAntonio Quartulli 	struct nlattr *attrs[OVPN_A_PEER_MAX + 1];
1031203e2bf5SAntonio Quartulli 	struct ovpn_peer *peer;
1032203e2bf5SAntonio Quartulli 	u32 peer_id;
1033203e2bf5SAntonio Quartulli 	int ret;
1034203e2bf5SAntonio Quartulli 
1035203e2bf5SAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF))
1036203e2bf5SAntonio Quartulli 		return -EINVAL;
1037203e2bf5SAntonio Quartulli 
1038203e2bf5SAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX,
1039203e2bf5SAntonio Quartulli 			       info->attrs[OVPN_A_KEYCONF],
1040203e2bf5SAntonio Quartulli 			       ovpn_keyconf_nl_policy, info->extack);
1041203e2bf5SAntonio Quartulli 	if (ret)
1042203e2bf5SAntonio Quartulli 		return ret;
1043203e2bf5SAntonio Quartulli 
1044203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
1045203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_PEER_ID))
1046203e2bf5SAntonio Quartulli 		return -EINVAL;
1047203e2bf5SAntonio Quartulli 
1048203e2bf5SAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]);
1049203e2bf5SAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
1050203e2bf5SAntonio Quartulli 	if (!peer) {
1051203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
1052203e2bf5SAntonio Quartulli 				       "no peer with id %u to swap keys for",
1053203e2bf5SAntonio Quartulli 				       peer_id);
1054203e2bf5SAntonio Quartulli 		return -ENOENT;
1055203e2bf5SAntonio Quartulli 	}
1056203e2bf5SAntonio Quartulli 
1057203e2bf5SAntonio Quartulli 	ovpn_crypto_key_slots_swap(&peer->crypto);
1058203e2bf5SAntonio Quartulli 	ovpn_peer_put(peer);
1059203e2bf5SAntonio Quartulli 
1060203e2bf5SAntonio Quartulli 	return 0;
1061b7a63391SAntonio Quartulli }
1062b7a63391SAntonio Quartulli 
ovpn_nl_key_del_doit(struct sk_buff * skb,struct genl_info * info)1063b7a63391SAntonio Quartulli int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info)
1064b7a63391SAntonio Quartulli {
1065203e2bf5SAntonio Quartulli 	struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1];
1066203e2bf5SAntonio Quartulli 	struct ovpn_priv *ovpn = info->user_ptr[0];
1067203e2bf5SAntonio Quartulli 	enum ovpn_key_slot slot;
1068203e2bf5SAntonio Quartulli 	struct ovpn_peer *peer;
1069203e2bf5SAntonio Quartulli 	u32 peer_id;
1070203e2bf5SAntonio Quartulli 	int ret;
1071203e2bf5SAntonio Quartulli 
1072203e2bf5SAntonio Quartulli 	if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF))
1073203e2bf5SAntonio Quartulli 		return -EINVAL;
1074203e2bf5SAntonio Quartulli 
1075203e2bf5SAntonio Quartulli 	ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX,
1076203e2bf5SAntonio Quartulli 			       info->attrs[OVPN_A_KEYCONF],
1077203e2bf5SAntonio Quartulli 			       ovpn_keyconf_nl_policy, info->extack);
1078203e2bf5SAntonio Quartulli 	if (ret)
1079203e2bf5SAntonio Quartulli 		return ret;
1080203e2bf5SAntonio Quartulli 
1081203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
1082203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_PEER_ID))
1083203e2bf5SAntonio Quartulli 		return -EINVAL;
1084203e2bf5SAntonio Quartulli 
1085203e2bf5SAntonio Quartulli 	if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs,
1086203e2bf5SAntonio Quartulli 			      OVPN_A_KEYCONF_SLOT))
1087203e2bf5SAntonio Quartulli 		return -EINVAL;
1088203e2bf5SAntonio Quartulli 
1089203e2bf5SAntonio Quartulli 	peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]);
1090203e2bf5SAntonio Quartulli 	slot = nla_get_u32(attrs[OVPN_A_KEYCONF_SLOT]);
1091203e2bf5SAntonio Quartulli 
1092203e2bf5SAntonio Quartulli 	peer = ovpn_peer_get_by_id(ovpn, peer_id);
1093203e2bf5SAntonio Quartulli 	if (!peer) {
1094203e2bf5SAntonio Quartulli 		NL_SET_ERR_MSG_FMT_MOD(info->extack,
1095203e2bf5SAntonio Quartulli 				       "no peer with id %u to delete key for",
1096203e2bf5SAntonio Quartulli 				       peer_id);
1097203e2bf5SAntonio Quartulli 		return -ENOENT;
1098203e2bf5SAntonio Quartulli 	}
1099203e2bf5SAntonio Quartulli 
1100203e2bf5SAntonio Quartulli 	ovpn_crypto_key_slot_delete(&peer->crypto, slot);
1101203e2bf5SAntonio Quartulli 	ovpn_peer_put(peer);
1102203e2bf5SAntonio Quartulli 
1103203e2bf5SAntonio Quartulli 	return 0;
1104b7a63391SAntonio Quartulli }
1105b7a63391SAntonio Quartulli 
1106b7a63391SAntonio Quartulli /**
1107a215d253SAntonio Quartulli  * ovpn_nl_peer_del_notify - notify userspace about peer being deleted
1108a215d253SAntonio Quartulli  * @peer: the peer being deleted
1109a215d253SAntonio Quartulli  *
1110a215d253SAntonio Quartulli  * Return: 0 on success or a negative error code otherwise
1111a215d253SAntonio Quartulli  */
ovpn_nl_peer_del_notify(struct ovpn_peer * peer)1112a215d253SAntonio Quartulli int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
1113a215d253SAntonio Quartulli {
1114a215d253SAntonio Quartulli 	struct ovpn_socket *sock;
1115a215d253SAntonio Quartulli 	struct sk_buff *msg;
1116a215d253SAntonio Quartulli 	struct nlattr *attr;
1117a215d253SAntonio Quartulli 	int ret = -EMSGSIZE;
1118a215d253SAntonio Quartulli 	void *hdr;
1119a215d253SAntonio Quartulli 
1120a215d253SAntonio Quartulli 	netdev_info(peer->ovpn->dev, "deleting peer with id %u, reason %d\n",
1121a215d253SAntonio Quartulli 		    peer->id, peer->delete_reason);
1122a215d253SAntonio Quartulli 
1123a215d253SAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1124a215d253SAntonio Quartulli 	if (!msg)
1125a215d253SAntonio Quartulli 		return -ENOMEM;
1126a215d253SAntonio Quartulli 
1127a215d253SAntonio Quartulli 	hdr = genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, OVPN_CMD_PEER_DEL_NTF);
1128a215d253SAntonio Quartulli 	if (!hdr) {
1129a215d253SAntonio Quartulli 		ret = -ENOBUFS;
1130a215d253SAntonio Quartulli 		goto err_free_msg;
1131a215d253SAntonio Quartulli 	}
1132a215d253SAntonio Quartulli 
1133a215d253SAntonio Quartulli 	if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex))
1134a215d253SAntonio Quartulli 		goto err_cancel_msg;
1135a215d253SAntonio Quartulli 
1136a215d253SAntonio Quartulli 	attr = nla_nest_start(msg, OVPN_A_PEER);
1137a215d253SAntonio Quartulli 	if (!attr)
1138a215d253SAntonio Quartulli 		goto err_cancel_msg;
1139a215d253SAntonio Quartulli 
1140a215d253SAntonio Quartulli 	if (nla_put_u32(msg, OVPN_A_PEER_DEL_REASON, peer->delete_reason))
1141a215d253SAntonio Quartulli 		goto err_cancel_msg;
1142a215d253SAntonio Quartulli 
1143a215d253SAntonio Quartulli 	if (nla_put_u32(msg, OVPN_A_PEER_ID, peer->id))
1144a215d253SAntonio Quartulli 		goto err_cancel_msg;
1145a215d253SAntonio Quartulli 
1146a215d253SAntonio Quartulli 	nla_nest_end(msg, attr);
1147a215d253SAntonio Quartulli 
1148a215d253SAntonio Quartulli 	genlmsg_end(msg, hdr);
1149a215d253SAntonio Quartulli 
1150a215d253SAntonio Quartulli 	rcu_read_lock();
1151a215d253SAntonio Quartulli 	sock = rcu_dereference(peer->sock);
1152a215d253SAntonio Quartulli 	if (!sock) {
1153a215d253SAntonio Quartulli 		ret = -EINVAL;
1154a215d253SAntonio Quartulli 		goto err_unlock;
1155a215d253SAntonio Quartulli 	}
1156*ba499a07SAntonio Quartulli 	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
1157*ba499a07SAntonio Quartulli 				OVPN_NLGRP_PEERS, GFP_ATOMIC);
1158a215d253SAntonio Quartulli 	rcu_read_unlock();
1159a215d253SAntonio Quartulli 
1160a215d253SAntonio Quartulli 	return 0;
1161a215d253SAntonio Quartulli 
1162a215d253SAntonio Quartulli err_unlock:
1163a215d253SAntonio Quartulli 	rcu_read_unlock();
1164a215d253SAntonio Quartulli err_cancel_msg:
1165a215d253SAntonio Quartulli 	genlmsg_cancel(msg, hdr);
1166a215d253SAntonio Quartulli err_free_msg:
1167a215d253SAntonio Quartulli 	nlmsg_free(msg);
1168a215d253SAntonio Quartulli 	return ret;
1169a215d253SAntonio Quartulli }
1170a215d253SAntonio Quartulli 
1171a215d253SAntonio Quartulli /**
117289d3c0e4SAntonio Quartulli  * ovpn_nl_key_swap_notify - notify userspace peer's key must be renewed
117389d3c0e4SAntonio Quartulli  * @peer: the peer whose key needs to be renewed
117489d3c0e4SAntonio Quartulli  * @key_id: the ID of the key that needs to be renewed
117589d3c0e4SAntonio Quartulli  *
117689d3c0e4SAntonio Quartulli  * Return: 0 on success or a negative error code otherwise
117789d3c0e4SAntonio Quartulli  */
ovpn_nl_key_swap_notify(struct ovpn_peer * peer,u8 key_id)117889d3c0e4SAntonio Quartulli int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
117989d3c0e4SAntonio Quartulli {
118089d3c0e4SAntonio Quartulli 	struct ovpn_socket *sock;
118189d3c0e4SAntonio Quartulli 	struct nlattr *k_attr;
118289d3c0e4SAntonio Quartulli 	struct sk_buff *msg;
118389d3c0e4SAntonio Quartulli 	int ret = -EMSGSIZE;
118489d3c0e4SAntonio Quartulli 	void *hdr;
118589d3c0e4SAntonio Quartulli 
118689d3c0e4SAntonio Quartulli 	netdev_info(peer->ovpn->dev, "peer with id %u must rekey - primary key unusable.\n",
118789d3c0e4SAntonio Quartulli 		    peer->id);
118889d3c0e4SAntonio Quartulli 
118989d3c0e4SAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
119089d3c0e4SAntonio Quartulli 	if (!msg)
119189d3c0e4SAntonio Quartulli 		return -ENOMEM;
119289d3c0e4SAntonio Quartulli 
119389d3c0e4SAntonio Quartulli 	hdr = genlmsg_put(msg, 0, 0, &ovpn_nl_family, 0, OVPN_CMD_KEY_SWAP_NTF);
119489d3c0e4SAntonio Quartulli 	if (!hdr) {
119589d3c0e4SAntonio Quartulli 		ret = -ENOBUFS;
119689d3c0e4SAntonio Quartulli 		goto err_free_msg;
119789d3c0e4SAntonio Quartulli 	}
119889d3c0e4SAntonio Quartulli 
119989d3c0e4SAntonio Quartulli 	if (nla_put_u32(msg, OVPN_A_IFINDEX, peer->ovpn->dev->ifindex))
120089d3c0e4SAntonio Quartulli 		goto err_cancel_msg;
120189d3c0e4SAntonio Quartulli 
120289d3c0e4SAntonio Quartulli 	k_attr = nla_nest_start(msg, OVPN_A_KEYCONF);
120389d3c0e4SAntonio Quartulli 	if (!k_attr)
120489d3c0e4SAntonio Quartulli 		goto err_cancel_msg;
120589d3c0e4SAntonio Quartulli 
120689d3c0e4SAntonio Quartulli 	if (nla_put_u32(msg, OVPN_A_KEYCONF_PEER_ID, peer->id))
120789d3c0e4SAntonio Quartulli 		goto err_cancel_msg;
120889d3c0e4SAntonio Quartulli 
120989d3c0e4SAntonio Quartulli 	if (nla_put_u16(msg, OVPN_A_KEYCONF_KEY_ID, key_id))
121089d3c0e4SAntonio Quartulli 		goto err_cancel_msg;
121189d3c0e4SAntonio Quartulli 
121289d3c0e4SAntonio Quartulli 	nla_nest_end(msg, k_attr);
121389d3c0e4SAntonio Quartulli 	genlmsg_end(msg, hdr);
121489d3c0e4SAntonio Quartulli 
121589d3c0e4SAntonio Quartulli 	rcu_read_lock();
121689d3c0e4SAntonio Quartulli 	sock = rcu_dereference(peer->sock);
121789d3c0e4SAntonio Quartulli 	if (!sock) {
121889d3c0e4SAntonio Quartulli 		ret = -EINVAL;
121989d3c0e4SAntonio Quartulli 		goto err_unlock;
122089d3c0e4SAntonio Quartulli 	}
1221*ba499a07SAntonio Quartulli 	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
1222*ba499a07SAntonio Quartulli 				OVPN_NLGRP_PEERS, GFP_ATOMIC);
122389d3c0e4SAntonio Quartulli 	rcu_read_unlock();
122489d3c0e4SAntonio Quartulli 
122589d3c0e4SAntonio Quartulli 	return 0;
122689d3c0e4SAntonio Quartulli err_unlock:
122789d3c0e4SAntonio Quartulli 	rcu_read_unlock();
122889d3c0e4SAntonio Quartulli err_cancel_msg:
122989d3c0e4SAntonio Quartulli 	genlmsg_cancel(msg, hdr);
123089d3c0e4SAntonio Quartulli err_free_msg:
123189d3c0e4SAntonio Quartulli 	nlmsg_free(msg);
123289d3c0e4SAntonio Quartulli 	return ret;
123389d3c0e4SAntonio Quartulli }
123489d3c0e4SAntonio Quartulli 
123589d3c0e4SAntonio Quartulli /**
1236b7a63391SAntonio Quartulli  * ovpn_nl_register - perform any needed registration in the NL subsustem
1237b7a63391SAntonio Quartulli  *
1238b7a63391SAntonio Quartulli  * Return: 0 on success, a negative error code otherwise
1239b7a63391SAntonio Quartulli  */
ovpn_nl_register(void)1240b7a63391SAntonio Quartulli int __init ovpn_nl_register(void)
1241b7a63391SAntonio Quartulli {
1242b7a63391SAntonio Quartulli 	int ret = genl_register_family(&ovpn_nl_family);
1243b7a63391SAntonio Quartulli 
1244b7a63391SAntonio Quartulli 	if (ret) {
1245b7a63391SAntonio Quartulli 		pr_err("ovpn: genl_register_family failed: %d\n", ret);
1246b7a63391SAntonio Quartulli 		return ret;
1247b7a63391SAntonio Quartulli 	}
1248b7a63391SAntonio Quartulli 
1249b7a63391SAntonio Quartulli 	return 0;
1250b7a63391SAntonio Quartulli }
1251b7a63391SAntonio Quartulli 
1252b7a63391SAntonio Quartulli /**
1253b7a63391SAntonio Quartulli  * ovpn_nl_unregister - undo any module wide netlink registration
1254b7a63391SAntonio Quartulli  */
ovpn_nl_unregister(void)1255b7a63391SAntonio Quartulli void ovpn_nl_unregister(void)
1256b7a63391SAntonio Quartulli {
1257b7a63391SAntonio Quartulli 	genl_unregister_family(&ovpn_nl_family);
1258b7a63391SAntonio Quartulli }
1259