xref: /openbmc/linux/net/batman-adv/netlink.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
309748a22SMatthias Schiffer  *
409748a22SMatthias Schiffer  * Matthias Schiffer
509748a22SMatthias Schiffer  */
609748a22SMatthias Schiffer 
709748a22SMatthias Schiffer #include "netlink.h"
809748a22SMatthias Schiffer #include "main.h"
909748a22SMatthias Schiffer 
10f32ed4b5SSven Eckelmann #include <linux/atomic.h>
11c4a7a8d9SSven Eckelmann #include <linux/bitops.h>
125c55a40fSSven Eckelmann #include <linux/bug.h>
138dad6f0dSSven Eckelmann #include <linux/byteorder/generic.h>
149bcb94c8SSven Eckelmann #include <linux/cache.h>
15c4a7a8d9SSven Eckelmann #include <linux/err.h>
165da0aef5SMatthias Schiffer #include <linux/errno.h>
179bcb94c8SSven Eckelmann #include <linux/export.h>
1809748a22SMatthias Schiffer #include <linux/genetlink.h>
19b92b94acSSven Eckelmann #include <linux/gfp.h>
205da0aef5SMatthias Schiffer #include <linux/if_ether.h>
2149e7e37cSSven Eckelmann #include <linux/if_vlan.h>
2209748a22SMatthias Schiffer #include <linux/init.h>
239bcb94c8SSven Eckelmann #include <linux/kernel.h>
24e1928752SSven Eckelmann #include <linux/limits.h>
25fb69be69SSven Eckelmann #include <linux/list.h>
26fcd193e1SSven Eckelmann #include <linux/minmax.h>
275da0aef5SMatthias Schiffer #include <linux/netdevice.h>
285da0aef5SMatthias Schiffer #include <linux/netlink.h>
2909748a22SMatthias Schiffer #include <linux/printk.h>
30fb69be69SSven Eckelmann #include <linux/rtnetlink.h>
31b60620cfSMatthias Schiffer #include <linux/skbuff.h>
325da0aef5SMatthias Schiffer #include <linux/stddef.h>
3333a3bb4aSAntonio Quartulli #include <linux/types.h>
3409748a22SMatthias Schiffer #include <net/genetlink.h>
3568a600deSSven Eckelmann #include <net/net_namespace.h>
365da0aef5SMatthias Schiffer #include <net/netlink.h>
37b60620cfSMatthias Schiffer #include <net/sock.h>
38fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
3909748a22SMatthias Schiffer #include <uapi/linux/batman_adv.h>
4009748a22SMatthias Schiffer 
4107a3061eSMatthias Schiffer #include "bat_algo.h"
4204f3f5bfSAndrew Lunn #include "bridge_loop_avoidance.h"
4341aeefccSLinus Lüssing #include "distributed-arp-table.h"
44d7129dafSSven Eckelmann #include "gateway_client.h"
45e2d0d35bSSven Eckelmann #include "gateway_common.h"
465da0aef5SMatthias Schiffer #include "hard-interface.h"
47b85bd091SSven Eckelmann #include "log.h"
4853dd9a68SLinus Lüssing #include "multicast.h"
496c57cde6SSven Eckelmann #include "network-coding.h"
5085cf8c85SMatthias Schiffer #include "originator.h"
515da0aef5SMatthias Schiffer #include "soft-interface.h"
5233a3bb4aSAntonio Quartulli #include "tp_meter.h"
53d34f0550SMatthias Schiffer #include "translation-table.h"
545da0aef5SMatthias Schiffer 
55489111e5SJohannes Berg struct genl_family batadv_netlink_family;
5609748a22SMatthias Schiffer 
5733a3bb4aSAntonio Quartulli /* multicast groups */
5833a3bb4aSAntonio Quartulli enum batadv_netlink_multicast_groups {
5960040513SSven Eckelmann 	BATADV_NL_MCGRP_CONFIG,
6033a3bb4aSAntonio Quartulli 	BATADV_NL_MCGRP_TPMETER,
6133a3bb4aSAntonio Quartulli };
6233a3bb4aSAntonio Quartulli 
63c4a7a8d9SSven Eckelmann /**
64c4a7a8d9SSven Eckelmann  * enum batadv_genl_ops_flags - flags for genl_ops's internal_flags
65c4a7a8d9SSven Eckelmann  */
66c4a7a8d9SSven Eckelmann enum batadv_genl_ops_flags {
67c4a7a8d9SSven Eckelmann 	/**
68c4a7a8d9SSven Eckelmann 	 * @BATADV_FLAG_NEED_MESH: request requires valid soft interface in
69c4a7a8d9SSven Eckelmann 	 *  attribute BATADV_ATTR_MESH_IFINDEX and expects a pointer to it to be
70c4a7a8d9SSven Eckelmann 	 *  saved in info->user_ptr[0]
71c4a7a8d9SSven Eckelmann 	 */
72c4a7a8d9SSven Eckelmann 	BATADV_FLAG_NEED_MESH = BIT(0),
735c55a40fSSven Eckelmann 
745c55a40fSSven Eckelmann 	/**
755c55a40fSSven Eckelmann 	 * @BATADV_FLAG_NEED_HARDIF: request requires valid hard interface in
765c55a40fSSven Eckelmann 	 *  attribute BATADV_ATTR_HARD_IFINDEX and expects a pointer to it to be
775c55a40fSSven Eckelmann 	 *  saved in info->user_ptr[1]
785c55a40fSSven Eckelmann 	 */
795c55a40fSSven Eckelmann 	BATADV_FLAG_NEED_HARDIF = BIT(1),
8049e7e37cSSven Eckelmann 
8149e7e37cSSven Eckelmann 	/**
8249e7e37cSSven Eckelmann 	 * @BATADV_FLAG_NEED_VLAN: request requires valid vlan in
8349e7e37cSSven Eckelmann 	 *  attribute BATADV_ATTR_VLANID and expects a pointer to it to be
8449e7e37cSSven Eckelmann 	 *  saved in info->user_ptr[1]
8549e7e37cSSven Eckelmann 	 */
8649e7e37cSSven Eckelmann 	BATADV_FLAG_NEED_VLAN = BIT(2),
87c4a7a8d9SSven Eckelmann };
88c4a7a8d9SSven Eckelmann 
89deeb91f5Sstephen hemminger static const struct genl_multicast_group batadv_netlink_mcgrps[] = {
9060040513SSven Eckelmann 	[BATADV_NL_MCGRP_CONFIG] = { .name = BATADV_NL_MCAST_GROUP_CONFIG },
9133a3bb4aSAntonio Quartulli 	[BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER },
9233a3bb4aSAntonio Quartulli };
9333a3bb4aSAntonio Quartulli 
94deeb91f5Sstephen hemminger static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
955da0aef5SMatthias Schiffer 	[BATADV_ATTR_VERSION]			= { .type = NLA_STRING },
965da0aef5SMatthias Schiffer 	[BATADV_ATTR_ALGO_NAME]			= { .type = NLA_STRING },
975da0aef5SMatthias Schiffer 	[BATADV_ATTR_MESH_IFINDEX]		= { .type = NLA_U32 },
985da0aef5SMatthias Schiffer 	[BATADV_ATTR_MESH_IFNAME]		= { .type = NLA_STRING },
995da0aef5SMatthias Schiffer 	[BATADV_ATTR_MESH_ADDRESS]		= { .len = ETH_ALEN },
1005da0aef5SMatthias Schiffer 	[BATADV_ATTR_HARD_IFINDEX]		= { .type = NLA_U32 },
1015da0aef5SMatthias Schiffer 	[BATADV_ATTR_HARD_IFNAME]		= { .type = NLA_STRING },
1025da0aef5SMatthias Schiffer 	[BATADV_ATTR_HARD_ADDRESS]		= { .len = ETH_ALEN },
10333a3bb4aSAntonio Quartulli 	[BATADV_ATTR_ORIG_ADDRESS]		= { .len = ETH_ALEN },
10433a3bb4aSAntonio Quartulli 	[BATADV_ATTR_TPMETER_RESULT]		= { .type = NLA_U8 },
10533a3bb4aSAntonio Quartulli 	[BATADV_ATTR_TPMETER_TEST_TIME]		= { .type = NLA_U32 },
10633a3bb4aSAntonio Quartulli 	[BATADV_ATTR_TPMETER_BYTES]		= { .type = NLA_U64 },
10733a3bb4aSAntonio Quartulli 	[BATADV_ATTR_TPMETER_COOKIE]		= { .type = NLA_U32 },
108b60620cfSMatthias Schiffer 	[BATADV_ATTR_ACTIVE]			= { .type = NLA_FLAG },
109d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_ADDRESS]		= { .len = ETH_ALEN },
110d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_TTVN]			= { .type = NLA_U8 },
111d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_LAST_TTVN]		= { .type = NLA_U8 },
112d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_CRC32]			= { .type = NLA_U32 },
113d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_VID]			= { .type = NLA_U16 },
114d34f0550SMatthias Schiffer 	[BATADV_ATTR_TT_FLAGS]			= { .type = NLA_U32 },
115d34f0550SMatthias Schiffer 	[BATADV_ATTR_FLAG_BEST]			= { .type = NLA_FLAG },
116d34f0550SMatthias Schiffer 	[BATADV_ATTR_LAST_SEEN_MSECS]		= { .type = NLA_U32 },
117024f99cbSMatthias Schiffer 	[BATADV_ATTR_NEIGH_ADDRESS]		= { .len = ETH_ALEN },
118024f99cbSMatthias Schiffer 	[BATADV_ATTR_TQ]			= { .type = NLA_U8 },
119f02a478fSMatthias Schiffer 	[BATADV_ATTR_THROUGHPUT]		= { .type = NLA_U32 },
120d7129dafSSven Eckelmann 	[BATADV_ATTR_BANDWIDTH_UP]		= { .type = NLA_U32 },
121d7129dafSSven Eckelmann 	[BATADV_ATTR_BANDWIDTH_DOWN]		= { .type = NLA_U32 },
122d7129dafSSven Eckelmann 	[BATADV_ATTR_ROUTER]			= { .len = ETH_ALEN },
12304f3f5bfSAndrew Lunn 	[BATADV_ATTR_BLA_OWN]			= { .type = NLA_FLAG },
12404f3f5bfSAndrew Lunn 	[BATADV_ATTR_BLA_ADDRESS]		= { .len = ETH_ALEN },
12504f3f5bfSAndrew Lunn 	[BATADV_ATTR_BLA_VID]			= { .type = NLA_U16 },
12604f3f5bfSAndrew Lunn 	[BATADV_ATTR_BLA_BACKBONE]		= { .len = ETH_ALEN },
12704f3f5bfSAndrew Lunn 	[BATADV_ATTR_BLA_CRC]			= { .type = NLA_U16 },
12841aeefccSLinus Lüssing 	[BATADV_ATTR_DAT_CACHE_IP4ADDRESS]	= { .type = NLA_U32 },
12941aeefccSLinus Lüssing 	[BATADV_ATTR_DAT_CACHE_HWADDRESS]	= { .len = ETH_ALEN },
13041aeefccSLinus Lüssing 	[BATADV_ATTR_DAT_CACHE_VID]		= { .type = NLA_U16 },
13153dd9a68SLinus Lüssing 	[BATADV_ATTR_MCAST_FLAGS]		= { .type = NLA_U32 },
13253dd9a68SLinus Lüssing 	[BATADV_ATTR_MCAST_FLAGS_PRIV]		= { .type = NLA_U32 },
13349e7e37cSSven Eckelmann 	[BATADV_ATTR_VLANID]			= { .type = NLA_U16 },
1349ab4cee5SSven Eckelmann 	[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]	= { .type = NLA_U8 },
135e43d16b8SSven Eckelmann 	[BATADV_ATTR_AP_ISOLATION_ENABLED]	= { .type = NLA_U8 },
136e43d16b8SSven Eckelmann 	[BATADV_ATTR_ISOLATION_MARK]		= { .type = NLA_U32 },
137e43d16b8SSven Eckelmann 	[BATADV_ATTR_ISOLATION_MASK]		= { .type = NLA_U32 },
138d7e52506SSven Eckelmann 	[BATADV_ATTR_BONDING_ENABLED]		= { .type = NLA_U8 },
13943ff6105SSven Eckelmann 	[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]	= { .type = NLA_U8 },
140a1c8de80SSven Eckelmann 	[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]	= { .type = NLA_U8 },
1413e15b06eSSven Eckelmann 	[BATADV_ATTR_FRAGMENTATION_ENABLED]	= { .type = NLA_U8 },
142e2d0d35bSSven Eckelmann 	[BATADV_ATTR_GW_BANDWIDTH_DOWN]		= { .type = NLA_U32 },
143e2d0d35bSSven Eckelmann 	[BATADV_ATTR_GW_BANDWIDTH_UP]		= { .type = NLA_U32 },
144e2d0d35bSSven Eckelmann 	[BATADV_ATTR_GW_MODE]			= { .type = NLA_U8 },
145e2d0d35bSSven Eckelmann 	[BATADV_ATTR_GW_SEL_CLASS]		= { .type = NLA_U32 },
146bfc7f1beSSven Eckelmann 	[BATADV_ATTR_HOP_PENALTY]		= { .type = NLA_U8 },
147b85bd091SSven Eckelmann 	[BATADV_ATTR_LOG_LEVEL]			= { .type = NLA_U32 },
148f75b56bcSSven Eckelmann 	[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]	= { .type = NLA_U8 },
14932e72744SLinus Lüssing 	[BATADV_ATTR_MULTICAST_FANOUT]		= { .type = NLA_U32 },
1506c57cde6SSven Eckelmann 	[BATADV_ATTR_NETWORK_CODING_ENABLED]	= { .type = NLA_U8 },
1517b751b39SSven Eckelmann 	[BATADV_ATTR_ORIG_INTERVAL]		= { .type = NLA_U32 },
152a1080082SSven Eckelmann 	[BATADV_ATTR_ELP_INTERVAL]		= { .type = NLA_U32 },
1539a182242SSven Eckelmann 	[BATADV_ATTR_THROUGHPUT_OVERRIDE]	= { .type = NLA_U32 },
1545da0aef5SMatthias Schiffer };
1555da0aef5SMatthias Schiffer 
1565da0aef5SMatthias Schiffer /**
1577e9a8c2cSSven Eckelmann  * batadv_netlink_get_ifindex() - Extract an interface index from a message
158b60620cfSMatthias Schiffer  * @nlh: Message header
159b60620cfSMatthias Schiffer  * @attrtype: Attribute which holds an interface index
160b60620cfSMatthias Schiffer  *
161b60620cfSMatthias Schiffer  * Return: interface index, or 0.
162b60620cfSMatthias Schiffer  */
163d34f0550SMatthias Schiffer int
batadv_netlink_get_ifindex(const struct nlmsghdr * nlh,int attrtype)164b60620cfSMatthias Schiffer batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype)
165b60620cfSMatthias Schiffer {
166b60620cfSMatthias Schiffer 	struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
167b60620cfSMatthias Schiffer 
1683ee1bb7aSEric Dumazet 	return (attr && nla_len(attr) == sizeof(u32)) ? nla_get_u32(attr) : 0;
169b60620cfSMatthias Schiffer }
170b60620cfSMatthias Schiffer 
171b60620cfSMatthias Schiffer /**
172e43d16b8SSven Eckelmann  * batadv_netlink_mesh_fill_ap_isolation() - Add ap_isolation softif attribute
173e43d16b8SSven Eckelmann  * @msg: Netlink message to dump into
174e43d16b8SSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
175e43d16b8SSven Eckelmann  *
176e43d16b8SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
177e43d16b8SSven Eckelmann  */
batadv_netlink_mesh_fill_ap_isolation(struct sk_buff * msg,struct batadv_priv * bat_priv)178e43d16b8SSven Eckelmann static int batadv_netlink_mesh_fill_ap_isolation(struct sk_buff *msg,
179e43d16b8SSven Eckelmann 						 struct batadv_priv *bat_priv)
180e43d16b8SSven Eckelmann {
181e43d16b8SSven Eckelmann 	struct batadv_softif_vlan *vlan;
182e43d16b8SSven Eckelmann 	u8 ap_isolation;
183e43d16b8SSven Eckelmann 
184e43d16b8SSven Eckelmann 	vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
185e43d16b8SSven Eckelmann 	if (!vlan)
186e43d16b8SSven Eckelmann 		return 0;
187e43d16b8SSven Eckelmann 
188e43d16b8SSven Eckelmann 	ap_isolation = atomic_read(&vlan->ap_isolation);
189e43d16b8SSven Eckelmann 	batadv_softif_vlan_put(vlan);
190e43d16b8SSven Eckelmann 
191e43d16b8SSven Eckelmann 	return nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED,
192e43d16b8SSven Eckelmann 			  !!ap_isolation);
193e43d16b8SSven Eckelmann }
194e43d16b8SSven Eckelmann 
195e43d16b8SSven Eckelmann /**
19625d81f93SSven Eckelmann  * batadv_netlink_set_mesh_ap_isolation() - Set ap_isolation from genl msg
197e43d16b8SSven Eckelmann  * @attr: parsed BATADV_ATTR_AP_ISOLATION_ENABLED attribute
198e43d16b8SSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
199e43d16b8SSven Eckelmann  *
200e43d16b8SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
201e43d16b8SSven Eckelmann  */
batadv_netlink_set_mesh_ap_isolation(struct nlattr * attr,struct batadv_priv * bat_priv)202e43d16b8SSven Eckelmann static int batadv_netlink_set_mesh_ap_isolation(struct nlattr *attr,
203e43d16b8SSven Eckelmann 						struct batadv_priv *bat_priv)
204e43d16b8SSven Eckelmann {
205e43d16b8SSven Eckelmann 	struct batadv_softif_vlan *vlan;
206e43d16b8SSven Eckelmann 
207e43d16b8SSven Eckelmann 	vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
208e43d16b8SSven Eckelmann 	if (!vlan)
209e43d16b8SSven Eckelmann 		return -ENOENT;
210e43d16b8SSven Eckelmann 
211e43d16b8SSven Eckelmann 	atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr));
212e43d16b8SSven Eckelmann 	batadv_softif_vlan_put(vlan);
213e43d16b8SSven Eckelmann 
214e43d16b8SSven Eckelmann 	return 0;
215e43d16b8SSven Eckelmann }
216e43d16b8SSven Eckelmann 
217e43d16b8SSven Eckelmann /**
21860040513SSven Eckelmann  * batadv_netlink_mesh_fill() - Fill message with mesh attributes
21960040513SSven Eckelmann  * @msg: Netlink message to dump into
22060040513SSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
22160040513SSven Eckelmann  * @cmd: type of message to generate
22260040513SSven Eckelmann  * @portid: Port making netlink request
22360040513SSven Eckelmann  * @seq: sequence number for message
22460040513SSven Eckelmann  * @flags: Additional flags for message
2255da0aef5SMatthias Schiffer  *
22660040513SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
2275da0aef5SMatthias Schiffer  */
batadv_netlink_mesh_fill(struct sk_buff * msg,struct batadv_priv * bat_priv,enum batadv_nl_commands cmd,u32 portid,u32 seq,int flags)22860040513SSven Eckelmann static int batadv_netlink_mesh_fill(struct sk_buff *msg,
22960040513SSven Eckelmann 				    struct batadv_priv *bat_priv,
23060040513SSven Eckelmann 				    enum batadv_nl_commands cmd,
23160040513SSven Eckelmann 				    u32 portid, u32 seq, int flags)
2325da0aef5SMatthias Schiffer {
23360040513SSven Eckelmann 	struct net_device *soft_iface = bat_priv->soft_iface;
2345da0aef5SMatthias Schiffer 	struct batadv_hard_iface *primary_if = NULL;
2355da0aef5SMatthias Schiffer 	struct net_device *hard_iface;
23660040513SSven Eckelmann 	void *hdr;
23760040513SSven Eckelmann 
23860040513SSven Eckelmann 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd);
23960040513SSven Eckelmann 	if (!hdr)
24060040513SSven Eckelmann 		return -ENOBUFS;
2415da0aef5SMatthias Schiffer 
2425da0aef5SMatthias Schiffer 	if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) ||
2435da0aef5SMatthias Schiffer 	    nla_put_string(msg, BATADV_ATTR_ALGO_NAME,
24429824a55SAntonio Quartulli 			   bat_priv->algo_ops->name) ||
2455da0aef5SMatthias Schiffer 	    nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) ||
2465da0aef5SMatthias Schiffer 	    nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) ||
2475da0aef5SMatthias Schiffer 	    nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN,
248f32ed4b5SSven Eckelmann 		    soft_iface->dev_addr) ||
249f32ed4b5SSven Eckelmann 	    nla_put_u8(msg, BATADV_ATTR_TT_TTVN,
250f32ed4b5SSven Eckelmann 		       (u8)atomic_read(&bat_priv->tt.vn)))
25160040513SSven Eckelmann 		goto nla_put_failure;
2525da0aef5SMatthias Schiffer 
2538dad6f0dSSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BLA
2548dad6f0dSSven Eckelmann 	if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
2558dad6f0dSSven Eckelmann 			ntohs(bat_priv->bla.claim_dest.group)))
25660040513SSven Eckelmann 		goto nla_put_failure;
2578dad6f0dSSven Eckelmann #endif
2588dad6f0dSSven Eckelmann 
25953dd9a68SLinus Lüssing 	if (batadv_mcast_mesh_info_put(msg, bat_priv))
26060040513SSven Eckelmann 		goto nla_put_failure;
26153dd9a68SLinus Lüssing 
2625da0aef5SMatthias Schiffer 	primary_if = batadv_primary_if_get_selected(bat_priv);
2635da0aef5SMatthias Schiffer 	if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) {
2645da0aef5SMatthias Schiffer 		hard_iface = primary_if->net_dev;
2655da0aef5SMatthias Schiffer 
2665da0aef5SMatthias Schiffer 		if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
2675da0aef5SMatthias Schiffer 				hard_iface->ifindex) ||
2685da0aef5SMatthias Schiffer 		    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
2695da0aef5SMatthias Schiffer 				   hard_iface->name) ||
2705da0aef5SMatthias Schiffer 		    nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
2715da0aef5SMatthias Schiffer 			    hard_iface->dev_addr))
27260040513SSven Eckelmann 			goto nla_put_failure;
2735da0aef5SMatthias Schiffer 	}
2745da0aef5SMatthias Schiffer 
2759ab4cee5SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS_ENABLED,
2769ab4cee5SSven Eckelmann 		       !!atomic_read(&bat_priv->aggregated_ogms)))
2779ab4cee5SSven Eckelmann 		goto nla_put_failure;
2789ab4cee5SSven Eckelmann 
279e43d16b8SSven Eckelmann 	if (batadv_netlink_mesh_fill_ap_isolation(msg, bat_priv))
280e43d16b8SSven Eckelmann 		goto nla_put_failure;
281e43d16b8SSven Eckelmann 
282e43d16b8SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MARK,
283e43d16b8SSven Eckelmann 			bat_priv->isolation_mark))
284e43d16b8SSven Eckelmann 		goto nla_put_failure;
285e43d16b8SSven Eckelmann 
286e43d16b8SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_ISOLATION_MASK,
287e43d16b8SSven Eckelmann 			bat_priv->isolation_mark_mask))
288e43d16b8SSven Eckelmann 		goto nla_put_failure;
289e43d16b8SSven Eckelmann 
290d7e52506SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED,
291d7e52506SSven Eckelmann 		       !!atomic_read(&bat_priv->bonding)))
292d7e52506SSven Eckelmann 		goto nla_put_failure;
293d7e52506SSven Eckelmann 
29443ff6105SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BLA
29543ff6105SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED,
29643ff6105SSven Eckelmann 		       !!atomic_read(&bat_priv->bridge_loop_avoidance)))
29743ff6105SSven Eckelmann 		goto nla_put_failure;
29843ff6105SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_BLA */
29943ff6105SSven Eckelmann 
300a1c8de80SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DAT
301a1c8de80SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED,
302a1c8de80SSven Eckelmann 		       !!atomic_read(&bat_priv->distributed_arp_table)))
303a1c8de80SSven Eckelmann 		goto nla_put_failure;
304a1c8de80SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_DAT */
305a1c8de80SSven Eckelmann 
3063e15b06eSSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION_ENABLED,
3073e15b06eSSven Eckelmann 		       !!atomic_read(&bat_priv->fragmentation)))
3083e15b06eSSven Eckelmann 		goto nla_put_failure;
3093e15b06eSSven Eckelmann 
310e2d0d35bSSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN,
311e2d0d35bSSven Eckelmann 			atomic_read(&bat_priv->gw.bandwidth_down)))
312e2d0d35bSSven Eckelmann 		goto nla_put_failure;
313e2d0d35bSSven Eckelmann 
314e2d0d35bSSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP,
315e2d0d35bSSven Eckelmann 			atomic_read(&bat_priv->gw.bandwidth_up)))
316e2d0d35bSSven Eckelmann 		goto nla_put_failure;
317e2d0d35bSSven Eckelmann 
318e2d0d35bSSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_GW_MODE,
319e2d0d35bSSven Eckelmann 		       atomic_read(&bat_priv->gw.mode)))
320e2d0d35bSSven Eckelmann 		goto nla_put_failure;
321e2d0d35bSSven Eckelmann 
322e2d0d35bSSven Eckelmann 	if (bat_priv->algo_ops->gw.get_best_gw_node &&
323e2d0d35bSSven Eckelmann 	    bat_priv->algo_ops->gw.is_eligible) {
324e2d0d35bSSven Eckelmann 		/* GW selection class is not available if the routing algorithm
325e2d0d35bSSven Eckelmann 		 * in use does not implement the GW API
326e2d0d35bSSven Eckelmann 		 */
327e2d0d35bSSven Eckelmann 		if (nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS,
328e2d0d35bSSven Eckelmann 				atomic_read(&bat_priv->gw.sel_class)))
329e2d0d35bSSven Eckelmann 			goto nla_put_failure;
330e2d0d35bSSven Eckelmann 	}
331e2d0d35bSSven Eckelmann 
332bfc7f1beSSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY,
333bfc7f1beSSven Eckelmann 		       atomic_read(&bat_priv->hop_penalty)))
334bfc7f1beSSven Eckelmann 		goto nla_put_failure;
335bfc7f1beSSven Eckelmann 
336b85bd091SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUG
337b85bd091SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL,
338b85bd091SSven Eckelmann 			atomic_read(&bat_priv->log_level)))
339b85bd091SSven Eckelmann 		goto nla_put_failure;
340b85bd091SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_DEBUG */
341b85bd091SSven Eckelmann 
342f75b56bcSSven Eckelmann #ifdef CONFIG_BATMAN_ADV_MCAST
343f75b56bcSSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED,
344f75b56bcSSven Eckelmann 		       !atomic_read(&bat_priv->multicast_mode)))
345f75b56bcSSven Eckelmann 		goto nla_put_failure;
34632e72744SLinus Lüssing 
34732e72744SLinus Lüssing 	if (nla_put_u32(msg, BATADV_ATTR_MULTICAST_FANOUT,
34832e72744SLinus Lüssing 			atomic_read(&bat_priv->multicast_fanout)))
34932e72744SLinus Lüssing 		goto nla_put_failure;
350f75b56bcSSven Eckelmann #endif /* CONFIG_BATMAN_ADV_MCAST */
351f75b56bcSSven Eckelmann 
3526c57cde6SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_NC
3536c57cde6SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_NETWORK_CODING_ENABLED,
3546c57cde6SSven Eckelmann 		       !!atomic_read(&bat_priv->network_coding)))
3556c57cde6SSven Eckelmann 		goto nla_put_failure;
3566c57cde6SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_NC */
3576c57cde6SSven Eckelmann 
3587b751b39SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL,
3597b751b39SSven Eckelmann 			atomic_read(&bat_priv->orig_interval)))
3607b751b39SSven Eckelmann 		goto nla_put_failure;
3617b751b39SSven Eckelmann 
3625da0aef5SMatthias Schiffer 	batadv_hardif_put(primary_if);
3635da0aef5SMatthias Schiffer 
36460040513SSven Eckelmann 	genlmsg_end(msg, hdr);
36560040513SSven Eckelmann 	return 0;
36660040513SSven Eckelmann 
36760040513SSven Eckelmann nla_put_failure:
36860040513SSven Eckelmann 	batadv_hardif_put(primary_if);
36960040513SSven Eckelmann 
37060040513SSven Eckelmann 	genlmsg_cancel(msg, hdr);
37160040513SSven Eckelmann 	return -EMSGSIZE;
37260040513SSven Eckelmann }
37360040513SSven Eckelmann 
37460040513SSven Eckelmann /**
37560040513SSven Eckelmann  * batadv_netlink_notify_mesh() - send softif attributes to listener
37660040513SSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
37760040513SSven Eckelmann  *
37860040513SSven Eckelmann  * Return: 0 on success, < 0 on error
37960040513SSven Eckelmann  */
batadv_netlink_notify_mesh(struct batadv_priv * bat_priv)38002e61f06SSven Eckelmann static int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv)
38160040513SSven Eckelmann {
38260040513SSven Eckelmann 	struct sk_buff *msg;
38360040513SSven Eckelmann 	int ret;
38460040513SSven Eckelmann 
38560040513SSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
38660040513SSven Eckelmann 	if (!msg)
38760040513SSven Eckelmann 		return -ENOMEM;
38860040513SSven Eckelmann 
38960040513SSven Eckelmann 	ret = batadv_netlink_mesh_fill(msg, bat_priv, BATADV_CMD_SET_MESH,
39060040513SSven Eckelmann 				       0, 0, 0);
39160040513SSven Eckelmann 	if (ret < 0) {
39260040513SSven Eckelmann 		nlmsg_free(msg);
39360040513SSven Eckelmann 		return ret;
39460040513SSven Eckelmann 	}
39560040513SSven Eckelmann 
39660040513SSven Eckelmann 	genlmsg_multicast_netns(&batadv_netlink_family,
39760040513SSven Eckelmann 				dev_net(bat_priv->soft_iface), msg, 0,
39860040513SSven Eckelmann 				BATADV_NL_MCGRP_CONFIG, GFP_KERNEL);
39960040513SSven Eckelmann 
40060040513SSven Eckelmann 	return 0;
40160040513SSven Eckelmann }
40260040513SSven Eckelmann 
40360040513SSven Eckelmann /**
40460040513SSven Eckelmann  * batadv_netlink_get_mesh() - Get softif attributes
40560040513SSven Eckelmann  * @skb: Netlink message with request data
40660040513SSven Eckelmann  * @info: receiver information
40760040513SSven Eckelmann  *
40860040513SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
40960040513SSven Eckelmann  */
batadv_netlink_get_mesh(struct sk_buff * skb,struct genl_info * info)41060040513SSven Eckelmann static int batadv_netlink_get_mesh(struct sk_buff *skb, struct genl_info *info)
41160040513SSven Eckelmann {
41260040513SSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
41360040513SSven Eckelmann 	struct sk_buff *msg;
41460040513SSven Eckelmann 	int ret;
41560040513SSven Eckelmann 
41660040513SSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
41760040513SSven Eckelmann 	if (!msg)
41860040513SSven Eckelmann 		return -ENOMEM;
41960040513SSven Eckelmann 
42060040513SSven Eckelmann 	ret = batadv_netlink_mesh_fill(msg, bat_priv, BATADV_CMD_GET_MESH,
42160040513SSven Eckelmann 				       info->snd_portid, info->snd_seq, 0);
42260040513SSven Eckelmann 	if (ret < 0) {
42360040513SSven Eckelmann 		nlmsg_free(msg);
42460040513SSven Eckelmann 		return ret;
42560040513SSven Eckelmann 	}
42660040513SSven Eckelmann 
42760040513SSven Eckelmann 	ret = genlmsg_reply(msg, info);
42860040513SSven Eckelmann 
4295da0aef5SMatthias Schiffer 	return ret;
4305da0aef5SMatthias Schiffer }
4315da0aef5SMatthias Schiffer 
4325da0aef5SMatthias Schiffer /**
43360040513SSven Eckelmann  * batadv_netlink_set_mesh() - Set softif attributes
43460040513SSven Eckelmann  * @skb: Netlink message with request data
4355da0aef5SMatthias Schiffer  * @info: receiver information
4365da0aef5SMatthias Schiffer  *
43760040513SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
4385da0aef5SMatthias Schiffer  */
batadv_netlink_set_mesh(struct sk_buff * skb,struct genl_info * info)43960040513SSven Eckelmann static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
4405da0aef5SMatthias Schiffer {
44160040513SSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
4429ab4cee5SSven Eckelmann 	struct nlattr *attr;
4439ab4cee5SSven Eckelmann 
4449ab4cee5SSven Eckelmann 	if (info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]) {
4459ab4cee5SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED];
4469ab4cee5SSven Eckelmann 
4479ab4cee5SSven Eckelmann 		atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr));
4489ab4cee5SSven Eckelmann 	}
4495da0aef5SMatthias Schiffer 
450e43d16b8SSven Eckelmann 	if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) {
451e43d16b8SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED];
452e43d16b8SSven Eckelmann 
453e43d16b8SSven Eckelmann 		batadv_netlink_set_mesh_ap_isolation(attr, bat_priv);
454e43d16b8SSven Eckelmann 	}
455e43d16b8SSven Eckelmann 
456e43d16b8SSven Eckelmann 	if (info->attrs[BATADV_ATTR_ISOLATION_MARK]) {
457e43d16b8SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_ISOLATION_MARK];
458e43d16b8SSven Eckelmann 
459e43d16b8SSven Eckelmann 		bat_priv->isolation_mark = nla_get_u32(attr);
460e43d16b8SSven Eckelmann 	}
461e43d16b8SSven Eckelmann 
462e43d16b8SSven Eckelmann 	if (info->attrs[BATADV_ATTR_ISOLATION_MASK]) {
463e43d16b8SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_ISOLATION_MASK];
464e43d16b8SSven Eckelmann 
465e43d16b8SSven Eckelmann 		bat_priv->isolation_mark_mask = nla_get_u32(attr);
466e43d16b8SSven Eckelmann 	}
467e43d16b8SSven Eckelmann 
468d7e52506SSven Eckelmann 	if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) {
469d7e52506SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_BONDING_ENABLED];
470d7e52506SSven Eckelmann 
471d7e52506SSven Eckelmann 		atomic_set(&bat_priv->bonding, !!nla_get_u8(attr));
472d7e52506SSven Eckelmann 	}
473d7e52506SSven Eckelmann 
47443ff6105SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BLA
47543ff6105SSven Eckelmann 	if (info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]) {
47643ff6105SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED];
47743ff6105SSven Eckelmann 
47843ff6105SSven Eckelmann 		atomic_set(&bat_priv->bridge_loop_avoidance,
47943ff6105SSven Eckelmann 			   !!nla_get_u8(attr));
48043ff6105SSven Eckelmann 		batadv_bla_status_update(bat_priv->soft_iface);
48143ff6105SSven Eckelmann 	}
48243ff6105SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_BLA */
48343ff6105SSven Eckelmann 
484a1c8de80SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DAT
485a1c8de80SSven Eckelmann 	if (info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]) {
486a1c8de80SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED];
487a1c8de80SSven Eckelmann 
488a1c8de80SSven Eckelmann 		atomic_set(&bat_priv->distributed_arp_table,
489a1c8de80SSven Eckelmann 			   !!nla_get_u8(attr));
490a1c8de80SSven Eckelmann 		batadv_dat_status_update(bat_priv->soft_iface);
491a1c8de80SSven Eckelmann 	}
492a1c8de80SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_DAT */
493a1c8de80SSven Eckelmann 
4943e15b06eSSven Eckelmann 	if (info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]) {
4953e15b06eSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED];
4963e15b06eSSven Eckelmann 
4973e15b06eSSven Eckelmann 		atomic_set(&bat_priv->fragmentation, !!nla_get_u8(attr));
498*987aae75SSven Eckelmann 
499*987aae75SSven Eckelmann 		rtnl_lock();
5003e15b06eSSven Eckelmann 		batadv_update_min_mtu(bat_priv->soft_iface);
501*987aae75SSven Eckelmann 		rtnl_unlock();
5023e15b06eSSven Eckelmann 	}
5033e15b06eSSven Eckelmann 
504e2d0d35bSSven Eckelmann 	if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) {
505e2d0d35bSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN];
506e2d0d35bSSven Eckelmann 
507e2d0d35bSSven Eckelmann 		atomic_set(&bat_priv->gw.bandwidth_down, nla_get_u32(attr));
508e2d0d35bSSven Eckelmann 		batadv_gw_tvlv_container_update(bat_priv);
509e2d0d35bSSven Eckelmann 	}
510e2d0d35bSSven Eckelmann 
511e2d0d35bSSven Eckelmann 	if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) {
512e2d0d35bSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP];
513e2d0d35bSSven Eckelmann 
514e2d0d35bSSven Eckelmann 		atomic_set(&bat_priv->gw.bandwidth_up, nla_get_u32(attr));
515e2d0d35bSSven Eckelmann 		batadv_gw_tvlv_container_update(bat_priv);
516e2d0d35bSSven Eckelmann 	}
517e2d0d35bSSven Eckelmann 
518e2d0d35bSSven Eckelmann 	if (info->attrs[BATADV_ATTR_GW_MODE]) {
519e2d0d35bSSven Eckelmann 		u8 gw_mode;
520e2d0d35bSSven Eckelmann 
521e2d0d35bSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_GW_MODE];
522e2d0d35bSSven Eckelmann 		gw_mode = nla_get_u8(attr);
523e2d0d35bSSven Eckelmann 
524e2d0d35bSSven Eckelmann 		if (gw_mode <= BATADV_GW_MODE_SERVER) {
525e2d0d35bSSven Eckelmann 			/* Invoking batadv_gw_reselect() is not enough to really
526e2d0d35bSSven Eckelmann 			 * de-select the current GW. It will only instruct the
527e2d0d35bSSven Eckelmann 			 * gateway client code to perform a re-election the next
528e2d0d35bSSven Eckelmann 			 * time that this is needed.
529e2d0d35bSSven Eckelmann 			 *
530e2d0d35bSSven Eckelmann 			 * When gw client mode is being switched off the current
531e2d0d35bSSven Eckelmann 			 * GW must be de-selected explicitly otherwise no GW_ADD
532e2d0d35bSSven Eckelmann 			 * uevent is thrown on client mode re-activation. This
533e2d0d35bSSven Eckelmann 			 * is operation is performed in
534e2d0d35bSSven Eckelmann 			 * batadv_gw_check_client_stop().
535e2d0d35bSSven Eckelmann 			 */
536e2d0d35bSSven Eckelmann 			batadv_gw_reselect(bat_priv);
537e2d0d35bSSven Eckelmann 
538e2d0d35bSSven Eckelmann 			/* always call batadv_gw_check_client_stop() before
539e2d0d35bSSven Eckelmann 			 * changing the gateway state
540e2d0d35bSSven Eckelmann 			 */
541e2d0d35bSSven Eckelmann 			batadv_gw_check_client_stop(bat_priv);
542e2d0d35bSSven Eckelmann 			atomic_set(&bat_priv->gw.mode, gw_mode);
543e2d0d35bSSven Eckelmann 			batadv_gw_tvlv_container_update(bat_priv);
544e2d0d35bSSven Eckelmann 		}
545e2d0d35bSSven Eckelmann 	}
546e2d0d35bSSven Eckelmann 
547e2d0d35bSSven Eckelmann 	if (info->attrs[BATADV_ATTR_GW_SEL_CLASS] &&
548e2d0d35bSSven Eckelmann 	    bat_priv->algo_ops->gw.get_best_gw_node &&
549e2d0d35bSSven Eckelmann 	    bat_priv->algo_ops->gw.is_eligible) {
550e2d0d35bSSven Eckelmann 		/* setting the GW selection class is allowed only if the routing
551e2d0d35bSSven Eckelmann 		 * algorithm in use implements the GW API
552e2d0d35bSSven Eckelmann 		 */
553e2d0d35bSSven Eckelmann 
5546f96d46fSSven Eckelmann 		u32 sel_class_max = bat_priv->algo_ops->gw.sel_class_max;
555e2d0d35bSSven Eckelmann 		u32 sel_class;
556e2d0d35bSSven Eckelmann 
557e2d0d35bSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_GW_SEL_CLASS];
558e2d0d35bSSven Eckelmann 		sel_class = nla_get_u32(attr);
559e2d0d35bSSven Eckelmann 
560e2d0d35bSSven Eckelmann 		if (sel_class >= 1 && sel_class <= sel_class_max) {
561e2d0d35bSSven Eckelmann 			atomic_set(&bat_priv->gw.sel_class, sel_class);
562e2d0d35bSSven Eckelmann 			batadv_gw_reselect(bat_priv);
563e2d0d35bSSven Eckelmann 		}
564e2d0d35bSSven Eckelmann 	}
565e2d0d35bSSven Eckelmann 
566bfc7f1beSSven Eckelmann 	if (info->attrs[BATADV_ATTR_HOP_PENALTY]) {
567bfc7f1beSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_HOP_PENALTY];
568bfc7f1beSSven Eckelmann 
569bfc7f1beSSven Eckelmann 		atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr));
570bfc7f1beSSven Eckelmann 	}
571bfc7f1beSSven Eckelmann 
572b85bd091SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_DEBUG
573b85bd091SSven Eckelmann 	if (info->attrs[BATADV_ATTR_LOG_LEVEL]) {
574b85bd091SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_LOG_LEVEL];
575b85bd091SSven Eckelmann 
576b85bd091SSven Eckelmann 		atomic_set(&bat_priv->log_level,
577b85bd091SSven Eckelmann 			   nla_get_u32(attr) & BATADV_DBG_ALL);
578b85bd091SSven Eckelmann 	}
579b85bd091SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_DEBUG */
580b85bd091SSven Eckelmann 
581f75b56bcSSven Eckelmann #ifdef CONFIG_BATMAN_ADV_MCAST
582f75b56bcSSven Eckelmann 	if (info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]) {
583f75b56bcSSven Eckelmann 		attr = info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED];
584f75b56bcSSven Eckelmann 
585f75b56bcSSven Eckelmann 		atomic_set(&bat_priv->multicast_mode, !nla_get_u8(attr));
586f75b56bcSSven Eckelmann 	}
58732e72744SLinus Lüssing 
58832e72744SLinus Lüssing 	if (info->attrs[BATADV_ATTR_MULTICAST_FANOUT]) {
58932e72744SLinus Lüssing 		attr = info->attrs[BATADV_ATTR_MULTICAST_FANOUT];
59032e72744SLinus Lüssing 
59132e72744SLinus Lüssing 		atomic_set(&bat_priv->multicast_fanout, nla_get_u32(attr));
59232e72744SLinus Lüssing 	}
593f75b56bcSSven Eckelmann #endif /* CONFIG_BATMAN_ADV_MCAST */
594f75b56bcSSven Eckelmann 
5956c57cde6SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_NC
5966c57cde6SSven Eckelmann 	if (info->attrs[BATADV_ATTR_NETWORK_CODING_ENABLED]) {
5976c57cde6SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_NETWORK_CODING_ENABLED];
5986c57cde6SSven Eckelmann 
5996c57cde6SSven Eckelmann 		atomic_set(&bat_priv->network_coding, !!nla_get_u8(attr));
6006c57cde6SSven Eckelmann 		batadv_nc_status_update(bat_priv->soft_iface);
6016c57cde6SSven Eckelmann 	}
6026c57cde6SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_NC */
6036c57cde6SSven Eckelmann 
6047b751b39SSven Eckelmann 	if (info->attrs[BATADV_ATTR_ORIG_INTERVAL]) {
6057b751b39SSven Eckelmann 		u32 orig_interval;
6067b751b39SSven Eckelmann 
6077b751b39SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_ORIG_INTERVAL];
6087b751b39SSven Eckelmann 		orig_interval = nla_get_u32(attr);
6097b751b39SSven Eckelmann 
6107b751b39SSven Eckelmann 		orig_interval = min_t(u32, orig_interval, INT_MAX);
6117b751b39SSven Eckelmann 		orig_interval = max_t(u32, orig_interval, 2 * BATADV_JITTER);
6127b751b39SSven Eckelmann 
6137b751b39SSven Eckelmann 		atomic_set(&bat_priv->orig_interval, orig_interval);
6147b751b39SSven Eckelmann 	}
6157b751b39SSven Eckelmann 
61660040513SSven Eckelmann 	batadv_netlink_notify_mesh(bat_priv);
6175da0aef5SMatthias Schiffer 
61860040513SSven Eckelmann 	return 0;
6195da0aef5SMatthias Schiffer }
6205da0aef5SMatthias Schiffer 
62133a3bb4aSAntonio Quartulli /**
6227e9a8c2cSSven Eckelmann  * batadv_netlink_tp_meter_put() - Fill information of started tp_meter session
62333a3bb4aSAntonio Quartulli  * @msg: netlink message to be sent back
62433a3bb4aSAntonio Quartulli  * @cookie: tp meter session cookie
62533a3bb4aSAntonio Quartulli  *
62633a3bb4aSAntonio Quartulli  *  Return: 0 on success, < 0 on error
62733a3bb4aSAntonio Quartulli  */
62833a3bb4aSAntonio Quartulli static int
batadv_netlink_tp_meter_put(struct sk_buff * msg,u32 cookie)62933a3bb4aSAntonio Quartulli batadv_netlink_tp_meter_put(struct sk_buff *msg, u32 cookie)
63033a3bb4aSAntonio Quartulli {
63133a3bb4aSAntonio Quartulli 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie))
63233a3bb4aSAntonio Quartulli 		return -ENOBUFS;
63333a3bb4aSAntonio Quartulli 
63433a3bb4aSAntonio Quartulli 	return 0;
63533a3bb4aSAntonio Quartulli }
63633a3bb4aSAntonio Quartulli 
63733a3bb4aSAntonio Quartulli /**
6387e9a8c2cSSven Eckelmann  * batadv_netlink_tpmeter_notify() - send tp_meter result via netlink to client
63933a3bb4aSAntonio Quartulli  * @bat_priv: the bat priv with all the soft interface information
64033a3bb4aSAntonio Quartulli  * @dst: destination of tp_meter session
64133a3bb4aSAntonio Quartulli  * @result: reason for tp meter session stop
642bccb48c8SSven Eckelmann  * @test_time: total time of the tp_meter session
64333a3bb4aSAntonio Quartulli  * @total_bytes: bytes acked to the receiver
64433a3bb4aSAntonio Quartulli  * @cookie: cookie of tp_meter session
64533a3bb4aSAntonio Quartulli  *
64633a3bb4aSAntonio Quartulli  * Return: 0 on success, < 0 on error
64733a3bb4aSAntonio Quartulli  */
batadv_netlink_tpmeter_notify(struct batadv_priv * bat_priv,const u8 * dst,u8 result,u32 test_time,u64 total_bytes,u32 cookie)64833a3bb4aSAntonio Quartulli int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst,
64933a3bb4aSAntonio Quartulli 				  u8 result, u32 test_time, u64 total_bytes,
65033a3bb4aSAntonio Quartulli 				  u32 cookie)
65133a3bb4aSAntonio Quartulli {
65233a3bb4aSAntonio Quartulli 	struct sk_buff *msg;
65333a3bb4aSAntonio Quartulli 	void *hdr;
65433a3bb4aSAntonio Quartulli 	int ret;
65533a3bb4aSAntonio Quartulli 
65633a3bb4aSAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
65733a3bb4aSAntonio Quartulli 	if (!msg)
65833a3bb4aSAntonio Quartulli 		return -ENOMEM;
65933a3bb4aSAntonio Quartulli 
66033a3bb4aSAntonio Quartulli 	hdr = genlmsg_put(msg, 0, 0, &batadv_netlink_family, 0,
66133a3bb4aSAntonio Quartulli 			  BATADV_CMD_TP_METER);
66233a3bb4aSAntonio Quartulli 	if (!hdr) {
66333a3bb4aSAntonio Quartulli 		ret = -ENOBUFS;
66433a3bb4aSAntonio Quartulli 		goto err_genlmsg;
66533a3bb4aSAntonio Quartulli 	}
66633a3bb4aSAntonio Quartulli 
66733a3bb4aSAntonio Quartulli 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie))
66833a3bb4aSAntonio Quartulli 		goto nla_put_failure;
66933a3bb4aSAntonio Quartulli 
67033a3bb4aSAntonio Quartulli 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_TEST_TIME, test_time))
67133a3bb4aSAntonio Quartulli 		goto nla_put_failure;
67233a3bb4aSAntonio Quartulli 
67333a3bb4aSAntonio Quartulli 	if (nla_put_u64_64bit(msg, BATADV_ATTR_TPMETER_BYTES, total_bytes,
67433a3bb4aSAntonio Quartulli 			      BATADV_ATTR_PAD))
67533a3bb4aSAntonio Quartulli 		goto nla_put_failure;
67633a3bb4aSAntonio Quartulli 
67733a3bb4aSAntonio Quartulli 	if (nla_put_u8(msg, BATADV_ATTR_TPMETER_RESULT, result))
67833a3bb4aSAntonio Quartulli 		goto nla_put_failure;
67933a3bb4aSAntonio Quartulli 
68033a3bb4aSAntonio Quartulli 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst))
68133a3bb4aSAntonio Quartulli 		goto nla_put_failure;
68233a3bb4aSAntonio Quartulli 
68333a3bb4aSAntonio Quartulli 	genlmsg_end(msg, hdr);
68433a3bb4aSAntonio Quartulli 
68533a3bb4aSAntonio Quartulli 	genlmsg_multicast_netns(&batadv_netlink_family,
68633a3bb4aSAntonio Quartulli 				dev_net(bat_priv->soft_iface), msg, 0,
68733a3bb4aSAntonio Quartulli 				BATADV_NL_MCGRP_TPMETER, GFP_KERNEL);
68833a3bb4aSAntonio Quartulli 
68933a3bb4aSAntonio Quartulli 	return 0;
69033a3bb4aSAntonio Quartulli 
69133a3bb4aSAntonio Quartulli nla_put_failure:
69233a3bb4aSAntonio Quartulli 	genlmsg_cancel(msg, hdr);
69333a3bb4aSAntonio Quartulli 	ret = -EMSGSIZE;
69433a3bb4aSAntonio Quartulli 
69533a3bb4aSAntonio Quartulli err_genlmsg:
69633a3bb4aSAntonio Quartulli 	nlmsg_free(msg);
69733a3bb4aSAntonio Quartulli 	return ret;
69833a3bb4aSAntonio Quartulli }
69933a3bb4aSAntonio Quartulli 
70033a3bb4aSAntonio Quartulli /**
7017e9a8c2cSSven Eckelmann  * batadv_netlink_tp_meter_start() - Start a new tp_meter session
70233a3bb4aSAntonio Quartulli  * @skb: received netlink message
70333a3bb4aSAntonio Quartulli  * @info: receiver information
70433a3bb4aSAntonio Quartulli  *
70533a3bb4aSAntonio Quartulli  * Return: 0 on success, < 0 on error
70633a3bb4aSAntonio Quartulli  */
70733a3bb4aSAntonio Quartulli static int
batadv_netlink_tp_meter_start(struct sk_buff * skb,struct genl_info * info)70833a3bb4aSAntonio Quartulli batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
70933a3bb4aSAntonio Quartulli {
710c4a7a8d9SSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
71133a3bb4aSAntonio Quartulli 	struct sk_buff *msg = NULL;
71233a3bb4aSAntonio Quartulli 	u32 test_length;
71333a3bb4aSAntonio Quartulli 	void *msg_head;
71433a3bb4aSAntonio Quartulli 	u32 cookie;
71533a3bb4aSAntonio Quartulli 	u8 *dst;
71633a3bb4aSAntonio Quartulli 	int ret;
71733a3bb4aSAntonio Quartulli 
71833a3bb4aSAntonio Quartulli 	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
71933a3bb4aSAntonio Quartulli 		return -EINVAL;
72033a3bb4aSAntonio Quartulli 
72133a3bb4aSAntonio Quartulli 	if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME])
72233a3bb4aSAntonio Quartulli 		return -EINVAL;
72333a3bb4aSAntonio Quartulli 
72433a3bb4aSAntonio Quartulli 	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
72533a3bb4aSAntonio Quartulli 
72633a3bb4aSAntonio Quartulli 	test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]);
72733a3bb4aSAntonio Quartulli 
72833a3bb4aSAntonio Quartulli 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
72933a3bb4aSAntonio Quartulli 	if (!msg) {
73033a3bb4aSAntonio Quartulli 		ret = -ENOMEM;
73133a3bb4aSAntonio Quartulli 		goto out;
73233a3bb4aSAntonio Quartulli 	}
73333a3bb4aSAntonio Quartulli 
73433a3bb4aSAntonio Quartulli 	msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq,
73533a3bb4aSAntonio Quartulli 			       &batadv_netlink_family, 0,
73633a3bb4aSAntonio Quartulli 			       BATADV_CMD_TP_METER);
73733a3bb4aSAntonio Quartulli 	if (!msg_head) {
73833a3bb4aSAntonio Quartulli 		ret = -ENOBUFS;
73933a3bb4aSAntonio Quartulli 		goto out;
74033a3bb4aSAntonio Quartulli 	}
74133a3bb4aSAntonio Quartulli 
74233a3bb4aSAntonio Quartulli 	batadv_tp_start(bat_priv, dst, test_length, &cookie);
74333a3bb4aSAntonio Quartulli 
74433a3bb4aSAntonio Quartulli 	ret = batadv_netlink_tp_meter_put(msg, cookie);
74533a3bb4aSAntonio Quartulli 
74633a3bb4aSAntonio Quartulli  out:
74733a3bb4aSAntonio Quartulli 	if (ret) {
74833a3bb4aSAntonio Quartulli 		if (msg)
74933a3bb4aSAntonio Quartulli 			nlmsg_free(msg);
75033a3bb4aSAntonio Quartulli 		return ret;
75133a3bb4aSAntonio Quartulli 	}
75233a3bb4aSAntonio Quartulli 
75333a3bb4aSAntonio Quartulli 	genlmsg_end(msg, msg_head);
75433a3bb4aSAntonio Quartulli 	return genlmsg_reply(msg, info);
75533a3bb4aSAntonio Quartulli }
75633a3bb4aSAntonio Quartulli 
75733a3bb4aSAntonio Quartulli /**
75825d81f93SSven Eckelmann  * batadv_netlink_tp_meter_cancel() - Cancel a running tp_meter session
75933a3bb4aSAntonio Quartulli  * @skb: received netlink message
76033a3bb4aSAntonio Quartulli  * @info: receiver information
76133a3bb4aSAntonio Quartulli  *
76233a3bb4aSAntonio Quartulli  * Return: 0 on success, < 0 on error
76333a3bb4aSAntonio Quartulli  */
76433a3bb4aSAntonio Quartulli static int
batadv_netlink_tp_meter_cancel(struct sk_buff * skb,struct genl_info * info)76533a3bb4aSAntonio Quartulli batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info)
76633a3bb4aSAntonio Quartulli {
767c4a7a8d9SSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
76833a3bb4aSAntonio Quartulli 	u8 *dst;
76933a3bb4aSAntonio Quartulli 	int ret = 0;
77033a3bb4aSAntonio Quartulli 
77133a3bb4aSAntonio Quartulli 	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
77233a3bb4aSAntonio Quartulli 		return -EINVAL;
77333a3bb4aSAntonio Quartulli 
77433a3bb4aSAntonio Quartulli 	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
77533a3bb4aSAntonio Quartulli 
77633a3bb4aSAntonio Quartulli 	batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL);
77733a3bb4aSAntonio Quartulli 
77833a3bb4aSAntonio Quartulli 	return ret;
77933a3bb4aSAntonio Quartulli }
78033a3bb4aSAntonio Quartulli 
781b60620cfSMatthias Schiffer /**
7825c55a40fSSven Eckelmann  * batadv_netlink_hardif_fill() - Fill message with hardif attributes
783b60620cfSMatthias Schiffer  * @msg: Netlink message to dump into
7845c55a40fSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
7855c55a40fSSven Eckelmann  * @hard_iface: hard interface which was modified
7865c55a40fSSven Eckelmann  * @cmd: type of message to generate
787b60620cfSMatthias Schiffer  * @portid: Port making netlink request
7885c55a40fSSven Eckelmann  * @seq: sequence number for message
7895c55a40fSSven Eckelmann  * @flags: Additional flags for message
790fb69be69SSven Eckelmann  * @cb: Control block containing additional options
791b60620cfSMatthias Schiffer  *
7925c55a40fSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
793b60620cfSMatthias Schiffer  */
batadv_netlink_hardif_fill(struct sk_buff * msg,struct batadv_priv * bat_priv,struct batadv_hard_iface * hard_iface,enum batadv_nl_commands cmd,u32 portid,u32 seq,int flags,struct netlink_callback * cb)7945c55a40fSSven Eckelmann static int batadv_netlink_hardif_fill(struct sk_buff *msg,
7955c55a40fSSven Eckelmann 				      struct batadv_priv *bat_priv,
7965c55a40fSSven Eckelmann 				      struct batadv_hard_iface *hard_iface,
7975c55a40fSSven Eckelmann 				      enum batadv_nl_commands cmd,
7985c55a40fSSven Eckelmann 				      u32 portid, u32 seq, int flags,
7995c55a40fSSven Eckelmann 				      struct netlink_callback *cb)
800b60620cfSMatthias Schiffer {
801b60620cfSMatthias Schiffer 	struct net_device *net_dev = hard_iface->net_dev;
802b60620cfSMatthias Schiffer 	void *hdr;
803b60620cfSMatthias Schiffer 
8045c55a40fSSven Eckelmann 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd);
805b60620cfSMatthias Schiffer 	if (!hdr)
8065c55a40fSSven Eckelmann 		return -ENOBUFS;
807b60620cfSMatthias Schiffer 
8085c55a40fSSven Eckelmann 	if (cb)
809fb69be69SSven Eckelmann 		genl_dump_check_consistent(cb, hdr);
810fb69be69SSven Eckelmann 
8115c55a40fSSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX,
8125c55a40fSSven Eckelmann 			bat_priv->soft_iface->ifindex))
8135c55a40fSSven Eckelmann 		goto nla_put_failure;
8145c55a40fSSven Eckelmann 
815d295345aSSven Eckelmann 	if (nla_put_string(msg, BATADV_ATTR_MESH_IFNAME,
816d295345aSSven Eckelmann 			   bat_priv->soft_iface->name))
817d295345aSSven Eckelmann 		goto nla_put_failure;
818d295345aSSven Eckelmann 
819b60620cfSMatthias Schiffer 	if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
820b60620cfSMatthias Schiffer 			net_dev->ifindex) ||
821b60620cfSMatthias Schiffer 	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
822b60620cfSMatthias Schiffer 			   net_dev->name) ||
823b60620cfSMatthias Schiffer 	    nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
824b60620cfSMatthias Schiffer 		    net_dev->dev_addr))
825b60620cfSMatthias Schiffer 		goto nla_put_failure;
826b60620cfSMatthias Schiffer 
827b60620cfSMatthias Schiffer 	if (hard_iface->if_status == BATADV_IF_ACTIVE) {
828b60620cfSMatthias Schiffer 		if (nla_put_flag(msg, BATADV_ATTR_ACTIVE))
829b60620cfSMatthias Schiffer 			goto nla_put_failure;
830b60620cfSMatthias Schiffer 	}
831b60620cfSMatthias Schiffer 
8323bda14d0SLinus Lüssing 	if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY,
8333bda14d0SLinus Lüssing 		       atomic_read(&hard_iface->hop_penalty)))
8343bda14d0SLinus Lüssing 		goto nla_put_failure;
8353bda14d0SLinus Lüssing 
836a1080082SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BATMAN_V
837a1080082SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL,
838a1080082SSven Eckelmann 			atomic_read(&hard_iface->bat_v.elp_interval)))
839a1080082SSven Eckelmann 		goto nla_put_failure;
8409a182242SSven Eckelmann 
8419a182242SSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT_OVERRIDE,
8429a182242SSven Eckelmann 			atomic_read(&hard_iface->bat_v.throughput_override)))
8439a182242SSven Eckelmann 		goto nla_put_failure;
844a1080082SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_BATMAN_V */
845a1080082SSven Eckelmann 
846b60620cfSMatthias Schiffer 	genlmsg_end(msg, hdr);
847b60620cfSMatthias Schiffer 	return 0;
848b60620cfSMatthias Schiffer 
849b60620cfSMatthias Schiffer nla_put_failure:
850b60620cfSMatthias Schiffer 	genlmsg_cancel(msg, hdr);
851b60620cfSMatthias Schiffer 	return -EMSGSIZE;
852b60620cfSMatthias Schiffer }
853b60620cfSMatthias Schiffer 
854b60620cfSMatthias Schiffer /**
8555c55a40fSSven Eckelmann  * batadv_netlink_notify_hardif() - send hardif attributes to listener
8565c55a40fSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
8575c55a40fSSven Eckelmann  * @hard_iface: hard interface which was modified
8585c55a40fSSven Eckelmann  *
8595c55a40fSSven Eckelmann  * Return: 0 on success, < 0 on error
8605c55a40fSSven Eckelmann  */
batadv_netlink_notify_hardif(struct batadv_priv * bat_priv,struct batadv_hard_iface * hard_iface)86102e61f06SSven Eckelmann static int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv,
8625c55a40fSSven Eckelmann 					struct batadv_hard_iface *hard_iface)
8635c55a40fSSven Eckelmann {
8645c55a40fSSven Eckelmann 	struct sk_buff *msg;
8655c55a40fSSven Eckelmann 	int ret;
8665c55a40fSSven Eckelmann 
8675c55a40fSSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8685c55a40fSSven Eckelmann 	if (!msg)
8695c55a40fSSven Eckelmann 		return -ENOMEM;
8705c55a40fSSven Eckelmann 
8715c55a40fSSven Eckelmann 	ret = batadv_netlink_hardif_fill(msg, bat_priv, hard_iface,
8725c55a40fSSven Eckelmann 					 BATADV_CMD_SET_HARDIF, 0, 0, 0, NULL);
8735c55a40fSSven Eckelmann 	if (ret < 0) {
8745c55a40fSSven Eckelmann 		nlmsg_free(msg);
8755c55a40fSSven Eckelmann 		return ret;
8765c55a40fSSven Eckelmann 	}
8775c55a40fSSven Eckelmann 
8785c55a40fSSven Eckelmann 	genlmsg_multicast_netns(&batadv_netlink_family,
8795c55a40fSSven Eckelmann 				dev_net(bat_priv->soft_iface), msg, 0,
8805c55a40fSSven Eckelmann 				BATADV_NL_MCGRP_CONFIG, GFP_KERNEL);
8815c55a40fSSven Eckelmann 
8825c55a40fSSven Eckelmann 	return 0;
8835c55a40fSSven Eckelmann }
8845c55a40fSSven Eckelmann 
8855c55a40fSSven Eckelmann /**
8865c55a40fSSven Eckelmann  * batadv_netlink_get_hardif() - Get hardif attributes
8875c55a40fSSven Eckelmann  * @skb: Netlink message with request data
8885c55a40fSSven Eckelmann  * @info: receiver information
8895c55a40fSSven Eckelmann  *
8905c55a40fSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
8915c55a40fSSven Eckelmann  */
batadv_netlink_get_hardif(struct sk_buff * skb,struct genl_info * info)8925c55a40fSSven Eckelmann static int batadv_netlink_get_hardif(struct sk_buff *skb,
8935c55a40fSSven Eckelmann 				     struct genl_info *info)
8945c55a40fSSven Eckelmann {
8955c55a40fSSven Eckelmann 	struct batadv_hard_iface *hard_iface = info->user_ptr[1];
8965c55a40fSSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
8975c55a40fSSven Eckelmann 	struct sk_buff *msg;
8985c55a40fSSven Eckelmann 	int ret;
8995c55a40fSSven Eckelmann 
9005c55a40fSSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9015c55a40fSSven Eckelmann 	if (!msg)
9025c55a40fSSven Eckelmann 		return -ENOMEM;
9035c55a40fSSven Eckelmann 
9045c55a40fSSven Eckelmann 	ret = batadv_netlink_hardif_fill(msg, bat_priv, hard_iface,
9055c55a40fSSven Eckelmann 					 BATADV_CMD_GET_HARDIF,
9065c55a40fSSven Eckelmann 					 info->snd_portid, info->snd_seq, 0,
9075c55a40fSSven Eckelmann 					 NULL);
9085c55a40fSSven Eckelmann 	if (ret < 0) {
9095c55a40fSSven Eckelmann 		nlmsg_free(msg);
9105c55a40fSSven Eckelmann 		return ret;
9115c55a40fSSven Eckelmann 	}
9125c55a40fSSven Eckelmann 
9135c55a40fSSven Eckelmann 	ret = genlmsg_reply(msg, info);
9145c55a40fSSven Eckelmann 
9155c55a40fSSven Eckelmann 	return ret;
9165c55a40fSSven Eckelmann }
9175c55a40fSSven Eckelmann 
9185c55a40fSSven Eckelmann /**
9195c55a40fSSven Eckelmann  * batadv_netlink_set_hardif() - Set hardif attributes
9205c55a40fSSven Eckelmann  * @skb: Netlink message with request data
9215c55a40fSSven Eckelmann  * @info: receiver information
9225c55a40fSSven Eckelmann  *
9235c55a40fSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
9245c55a40fSSven Eckelmann  */
batadv_netlink_set_hardif(struct sk_buff * skb,struct genl_info * info)9255c55a40fSSven Eckelmann static int batadv_netlink_set_hardif(struct sk_buff *skb,
9265c55a40fSSven Eckelmann 				     struct genl_info *info)
9275c55a40fSSven Eckelmann {
9285c55a40fSSven Eckelmann 	struct batadv_hard_iface *hard_iface = info->user_ptr[1];
9295c55a40fSSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
9303bda14d0SLinus Lüssing 	struct nlattr *attr;
9313bda14d0SLinus Lüssing 
9323bda14d0SLinus Lüssing 	if (info->attrs[BATADV_ATTR_HOP_PENALTY]) {
9333bda14d0SLinus Lüssing 		attr = info->attrs[BATADV_ATTR_HOP_PENALTY];
9343bda14d0SLinus Lüssing 
9353bda14d0SLinus Lüssing 		atomic_set(&hard_iface->hop_penalty, nla_get_u8(attr));
9363bda14d0SLinus Lüssing 	}
9375c55a40fSSven Eckelmann 
938a1080082SSven Eckelmann #ifdef CONFIG_BATMAN_ADV_BATMAN_V
939a1080082SSven Eckelmann 
940a1080082SSven Eckelmann 	if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) {
941a1080082SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_ELP_INTERVAL];
942a1080082SSven Eckelmann 
943a1080082SSven Eckelmann 		atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr));
944a1080082SSven Eckelmann 	}
9459a182242SSven Eckelmann 
9469a182242SSven Eckelmann 	if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) {
9479a182242SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE];
9489a182242SSven Eckelmann 
9499a182242SSven Eckelmann 		atomic_set(&hard_iface->bat_v.throughput_override,
9509a182242SSven Eckelmann 			   nla_get_u32(attr));
9519a182242SSven Eckelmann 	}
952a1080082SSven Eckelmann #endif /* CONFIG_BATMAN_ADV_BATMAN_V */
953a1080082SSven Eckelmann 
9545c55a40fSSven Eckelmann 	batadv_netlink_notify_hardif(bat_priv, hard_iface);
9555c55a40fSSven Eckelmann 
9565c55a40fSSven Eckelmann 	return 0;
9575c55a40fSSven Eckelmann }
9585c55a40fSSven Eckelmann 
9595c55a40fSSven Eckelmann /**
9605c55a40fSSven Eckelmann  * batadv_netlink_dump_hardif() - Dump all hard interface into a messages
961b60620cfSMatthias Schiffer  * @msg: Netlink message to dump into
962b60620cfSMatthias Schiffer  * @cb: Parameters from query
963b60620cfSMatthias Schiffer  *
964b60620cfSMatthias Schiffer  * Return: error code, or length of reply message on success
965b60620cfSMatthias Schiffer  */
966b60620cfSMatthias Schiffer static int
batadv_netlink_dump_hardif(struct sk_buff * msg,struct netlink_callback * cb)9675c55a40fSSven Eckelmann batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb)
968b60620cfSMatthias Schiffer {
969b60620cfSMatthias Schiffer 	struct net *net = sock_net(cb->skb->sk);
970b60620cfSMatthias Schiffer 	struct net_device *soft_iface;
971b60620cfSMatthias Schiffer 	struct batadv_hard_iface *hard_iface;
9725c55a40fSSven Eckelmann 	struct batadv_priv *bat_priv;
973b60620cfSMatthias Schiffer 	int ifindex;
974b60620cfSMatthias Schiffer 	int portid = NETLINK_CB(cb->skb).portid;
975b60620cfSMatthias Schiffer 	int skip = cb->args[0];
976b60620cfSMatthias Schiffer 	int i = 0;
977b60620cfSMatthias Schiffer 
978b60620cfSMatthias Schiffer 	ifindex = batadv_netlink_get_ifindex(cb->nlh,
979b60620cfSMatthias Schiffer 					     BATADV_ATTR_MESH_IFINDEX);
980b60620cfSMatthias Schiffer 	if (!ifindex)
981b60620cfSMatthias Schiffer 		return -EINVAL;
982b60620cfSMatthias Schiffer 
983b60620cfSMatthias Schiffer 	soft_iface = dev_get_by_index(net, ifindex);
984b60620cfSMatthias Schiffer 	if (!soft_iface)
985b60620cfSMatthias Schiffer 		return -ENODEV;
986b60620cfSMatthias Schiffer 
987b60620cfSMatthias Schiffer 	if (!batadv_softif_is_valid(soft_iface)) {
988b60620cfSMatthias Schiffer 		dev_put(soft_iface);
989b60620cfSMatthias Schiffer 		return -ENODEV;
990b60620cfSMatthias Schiffer 	}
991b60620cfSMatthias Schiffer 
9925c55a40fSSven Eckelmann 	bat_priv = netdev_priv(soft_iface);
9935c55a40fSSven Eckelmann 
994fb69be69SSven Eckelmann 	rtnl_lock();
995fb69be69SSven Eckelmann 	cb->seq = batadv_hardif_generation << 1 | 1;
996b60620cfSMatthias Schiffer 
997fb69be69SSven Eckelmann 	list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
998b60620cfSMatthias Schiffer 		if (hard_iface->soft_iface != soft_iface)
999b60620cfSMatthias Schiffer 			continue;
1000b60620cfSMatthias Schiffer 
1001b60620cfSMatthias Schiffer 		if (i++ < skip)
1002b60620cfSMatthias Schiffer 			continue;
1003b60620cfSMatthias Schiffer 
10045c55a40fSSven Eckelmann 		if (batadv_netlink_hardif_fill(msg, bat_priv, hard_iface,
10055c55a40fSSven Eckelmann 					       BATADV_CMD_GET_HARDIF,
10065c55a40fSSven Eckelmann 					       portid, cb->nlh->nlmsg_seq,
10075c55a40fSSven Eckelmann 					       NLM_F_MULTI, cb)) {
1008b60620cfSMatthias Schiffer 			i--;
1009b60620cfSMatthias Schiffer 			break;
1010b60620cfSMatthias Schiffer 		}
1011b60620cfSMatthias Schiffer 	}
1012b60620cfSMatthias Schiffer 
1013fb69be69SSven Eckelmann 	rtnl_unlock();
1014b60620cfSMatthias Schiffer 
1015b60620cfSMatthias Schiffer 	dev_put(soft_iface);
1016b60620cfSMatthias Schiffer 
1017b60620cfSMatthias Schiffer 	cb->args[0] = i;
1018b60620cfSMatthias Schiffer 
1019b60620cfSMatthias Schiffer 	return msg->len;
1020b60620cfSMatthias Schiffer }
1021b60620cfSMatthias Schiffer 
1022c4a7a8d9SSven Eckelmann /**
102349e7e37cSSven Eckelmann  * batadv_netlink_vlan_fill() - Fill message with vlan attributes
102449e7e37cSSven Eckelmann  * @msg: Netlink message to dump into
102549e7e37cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
102649e7e37cSSven Eckelmann  * @vlan: vlan which was modified
102749e7e37cSSven Eckelmann  * @cmd: type of message to generate
102849e7e37cSSven Eckelmann  * @portid: Port making netlink request
102949e7e37cSSven Eckelmann  * @seq: sequence number for message
103049e7e37cSSven Eckelmann  * @flags: Additional flags for message
103149e7e37cSSven Eckelmann  *
103249e7e37cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
103349e7e37cSSven Eckelmann  */
batadv_netlink_vlan_fill(struct sk_buff * msg,struct batadv_priv * bat_priv,struct batadv_softif_vlan * vlan,enum batadv_nl_commands cmd,u32 portid,u32 seq,int flags)103449e7e37cSSven Eckelmann static int batadv_netlink_vlan_fill(struct sk_buff *msg,
103549e7e37cSSven Eckelmann 				    struct batadv_priv *bat_priv,
103649e7e37cSSven Eckelmann 				    struct batadv_softif_vlan *vlan,
103749e7e37cSSven Eckelmann 				    enum batadv_nl_commands cmd,
103849e7e37cSSven Eckelmann 				    u32 portid, u32 seq, int flags)
103949e7e37cSSven Eckelmann {
104049e7e37cSSven Eckelmann 	void *hdr;
104149e7e37cSSven Eckelmann 
104249e7e37cSSven Eckelmann 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, flags, cmd);
104349e7e37cSSven Eckelmann 	if (!hdr)
104449e7e37cSSven Eckelmann 		return -ENOBUFS;
104549e7e37cSSven Eckelmann 
104649e7e37cSSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX,
104749e7e37cSSven Eckelmann 			bat_priv->soft_iface->ifindex))
104849e7e37cSSven Eckelmann 		goto nla_put_failure;
104949e7e37cSSven Eckelmann 
1050d295345aSSven Eckelmann 	if (nla_put_string(msg, BATADV_ATTR_MESH_IFNAME,
1051d295345aSSven Eckelmann 			   bat_priv->soft_iface->name))
1052d295345aSSven Eckelmann 		goto nla_put_failure;
1053d295345aSSven Eckelmann 
105449e7e37cSSven Eckelmann 	if (nla_put_u32(msg, BATADV_ATTR_VLANID, vlan->vid & VLAN_VID_MASK))
105549e7e37cSSven Eckelmann 		goto nla_put_failure;
105649e7e37cSSven Eckelmann 
1057e43d16b8SSven Eckelmann 	if (nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED,
1058e43d16b8SSven Eckelmann 		       !!atomic_read(&vlan->ap_isolation)))
1059e43d16b8SSven Eckelmann 		goto nla_put_failure;
1060e43d16b8SSven Eckelmann 
106149e7e37cSSven Eckelmann 	genlmsg_end(msg, hdr);
106249e7e37cSSven Eckelmann 	return 0;
106349e7e37cSSven Eckelmann 
106449e7e37cSSven Eckelmann nla_put_failure:
106549e7e37cSSven Eckelmann 	genlmsg_cancel(msg, hdr);
106649e7e37cSSven Eckelmann 	return -EMSGSIZE;
106749e7e37cSSven Eckelmann }
106849e7e37cSSven Eckelmann 
106949e7e37cSSven Eckelmann /**
107049e7e37cSSven Eckelmann  * batadv_netlink_notify_vlan() - send vlan attributes to listener
107149e7e37cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
107249e7e37cSSven Eckelmann  * @vlan: vlan which was modified
107349e7e37cSSven Eckelmann  *
107449e7e37cSSven Eckelmann  * Return: 0 on success, < 0 on error
107549e7e37cSSven Eckelmann  */
batadv_netlink_notify_vlan(struct batadv_priv * bat_priv,struct batadv_softif_vlan * vlan)107602e61f06SSven Eckelmann static int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv,
107749e7e37cSSven Eckelmann 				      struct batadv_softif_vlan *vlan)
107849e7e37cSSven Eckelmann {
107949e7e37cSSven Eckelmann 	struct sk_buff *msg;
108049e7e37cSSven Eckelmann 	int ret;
108149e7e37cSSven Eckelmann 
108249e7e37cSSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
108349e7e37cSSven Eckelmann 	if (!msg)
108449e7e37cSSven Eckelmann 		return -ENOMEM;
108549e7e37cSSven Eckelmann 
108649e7e37cSSven Eckelmann 	ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan,
108749e7e37cSSven Eckelmann 				       BATADV_CMD_SET_VLAN, 0, 0, 0);
108849e7e37cSSven Eckelmann 	if (ret < 0) {
108949e7e37cSSven Eckelmann 		nlmsg_free(msg);
109049e7e37cSSven Eckelmann 		return ret;
109149e7e37cSSven Eckelmann 	}
109249e7e37cSSven Eckelmann 
109349e7e37cSSven Eckelmann 	genlmsg_multicast_netns(&batadv_netlink_family,
109449e7e37cSSven Eckelmann 				dev_net(bat_priv->soft_iface), msg, 0,
109549e7e37cSSven Eckelmann 				BATADV_NL_MCGRP_CONFIG, GFP_KERNEL);
109649e7e37cSSven Eckelmann 
109749e7e37cSSven Eckelmann 	return 0;
109849e7e37cSSven Eckelmann }
109949e7e37cSSven Eckelmann 
110049e7e37cSSven Eckelmann /**
110149e7e37cSSven Eckelmann  * batadv_netlink_get_vlan() - Get vlan attributes
110249e7e37cSSven Eckelmann  * @skb: Netlink message with request data
110349e7e37cSSven Eckelmann  * @info: receiver information
110449e7e37cSSven Eckelmann  *
110549e7e37cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
110649e7e37cSSven Eckelmann  */
batadv_netlink_get_vlan(struct sk_buff * skb,struct genl_info * info)110749e7e37cSSven Eckelmann static int batadv_netlink_get_vlan(struct sk_buff *skb, struct genl_info *info)
110849e7e37cSSven Eckelmann {
110949e7e37cSSven Eckelmann 	struct batadv_softif_vlan *vlan = info->user_ptr[1];
111049e7e37cSSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
111149e7e37cSSven Eckelmann 	struct sk_buff *msg;
111249e7e37cSSven Eckelmann 	int ret;
111349e7e37cSSven Eckelmann 
111449e7e37cSSven Eckelmann 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
111549e7e37cSSven Eckelmann 	if (!msg)
111649e7e37cSSven Eckelmann 		return -ENOMEM;
111749e7e37cSSven Eckelmann 
111849e7e37cSSven Eckelmann 	ret = batadv_netlink_vlan_fill(msg, bat_priv, vlan, BATADV_CMD_GET_VLAN,
111949e7e37cSSven Eckelmann 				       info->snd_portid, info->snd_seq, 0);
112049e7e37cSSven Eckelmann 	if (ret < 0) {
112149e7e37cSSven Eckelmann 		nlmsg_free(msg);
112249e7e37cSSven Eckelmann 		return ret;
112349e7e37cSSven Eckelmann 	}
112449e7e37cSSven Eckelmann 
112549e7e37cSSven Eckelmann 	ret = genlmsg_reply(msg, info);
112649e7e37cSSven Eckelmann 
112749e7e37cSSven Eckelmann 	return ret;
112849e7e37cSSven Eckelmann }
112949e7e37cSSven Eckelmann 
113049e7e37cSSven Eckelmann /**
113149e7e37cSSven Eckelmann  * batadv_netlink_set_vlan() - Get vlan attributes
113249e7e37cSSven Eckelmann  * @skb: Netlink message with request data
113349e7e37cSSven Eckelmann  * @info: receiver information
113449e7e37cSSven Eckelmann  *
113549e7e37cSSven Eckelmann  * Return: 0 on success or negative error number in case of failure
113649e7e37cSSven Eckelmann  */
batadv_netlink_set_vlan(struct sk_buff * skb,struct genl_info * info)113749e7e37cSSven Eckelmann static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info)
113849e7e37cSSven Eckelmann {
113949e7e37cSSven Eckelmann 	struct batadv_softif_vlan *vlan = info->user_ptr[1];
114049e7e37cSSven Eckelmann 	struct batadv_priv *bat_priv = info->user_ptr[0];
1141e43d16b8SSven Eckelmann 	struct nlattr *attr;
1142e43d16b8SSven Eckelmann 
1143e43d16b8SSven Eckelmann 	if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) {
1144e43d16b8SSven Eckelmann 		attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED];
1145e43d16b8SSven Eckelmann 
1146e43d16b8SSven Eckelmann 		atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr));
1147e43d16b8SSven Eckelmann 	}
114849e7e37cSSven Eckelmann 
114949e7e37cSSven Eckelmann 	batadv_netlink_notify_vlan(bat_priv, vlan);
115049e7e37cSSven Eckelmann 
115149e7e37cSSven Eckelmann 	return 0;
115249e7e37cSSven Eckelmann }
115349e7e37cSSven Eckelmann 
115449e7e37cSSven Eckelmann /**
1155c4a7a8d9SSven Eckelmann  * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes
1156c4a7a8d9SSven Eckelmann  * @net: the applicable net namespace
1157c4a7a8d9SSven Eckelmann  * @info: receiver information
1158c4a7a8d9SSven Eckelmann  *
1159c4a7a8d9SSven Eckelmann  * Return: Pointer to soft interface (with increased refcnt) on success, error
1160c4a7a8d9SSven Eckelmann  *  pointer on error
1161c4a7a8d9SSven Eckelmann  */
1162c4a7a8d9SSven Eckelmann static struct net_device *
batadv_get_softif_from_info(struct net * net,struct genl_info * info)1163c4a7a8d9SSven Eckelmann batadv_get_softif_from_info(struct net *net, struct genl_info *info)
1164c4a7a8d9SSven Eckelmann {
1165c4a7a8d9SSven Eckelmann 	struct net_device *soft_iface;
1166c4a7a8d9SSven Eckelmann 	int ifindex;
1167c4a7a8d9SSven Eckelmann 
1168c4a7a8d9SSven Eckelmann 	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
1169c4a7a8d9SSven Eckelmann 		return ERR_PTR(-EINVAL);
1170c4a7a8d9SSven Eckelmann 
1171c4a7a8d9SSven Eckelmann 	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
1172c4a7a8d9SSven Eckelmann 
1173c4a7a8d9SSven Eckelmann 	soft_iface = dev_get_by_index(net, ifindex);
1174c4a7a8d9SSven Eckelmann 	if (!soft_iface)
1175c4a7a8d9SSven Eckelmann 		return ERR_PTR(-ENODEV);
1176c4a7a8d9SSven Eckelmann 
1177c4a7a8d9SSven Eckelmann 	if (!batadv_softif_is_valid(soft_iface))
1178c4a7a8d9SSven Eckelmann 		goto err_put_softif;
1179c4a7a8d9SSven Eckelmann 
1180c4a7a8d9SSven Eckelmann 	return soft_iface;
1181c4a7a8d9SSven Eckelmann 
1182c4a7a8d9SSven Eckelmann err_put_softif:
1183c4a7a8d9SSven Eckelmann 	dev_put(soft_iface);
1184c4a7a8d9SSven Eckelmann 
1185c4a7a8d9SSven Eckelmann 	return ERR_PTR(-EINVAL);
1186c4a7a8d9SSven Eckelmann }
1187c4a7a8d9SSven Eckelmann 
1188c4a7a8d9SSven Eckelmann /**
11895c55a40fSSven Eckelmann  * batadv_get_hardif_from_info() - Retrieve hardif from genl attributes
11905c55a40fSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
11915c55a40fSSven Eckelmann  * @net: the applicable net namespace
11925c55a40fSSven Eckelmann  * @info: receiver information
11935c55a40fSSven Eckelmann  *
11945c55a40fSSven Eckelmann  * Return: Pointer to hard interface (with increased refcnt) on success, error
11955c55a40fSSven Eckelmann  *  pointer on error
11965c55a40fSSven Eckelmann  */
11975c55a40fSSven Eckelmann static struct batadv_hard_iface *
batadv_get_hardif_from_info(struct batadv_priv * bat_priv,struct net * net,struct genl_info * info)11985c55a40fSSven Eckelmann batadv_get_hardif_from_info(struct batadv_priv *bat_priv, struct net *net,
11995c55a40fSSven Eckelmann 			    struct genl_info *info)
12005c55a40fSSven Eckelmann {
12015c55a40fSSven Eckelmann 	struct batadv_hard_iface *hard_iface;
12025c55a40fSSven Eckelmann 	struct net_device *hard_dev;
12035c55a40fSSven Eckelmann 	unsigned int hardif_index;
12045c55a40fSSven Eckelmann 
12055c55a40fSSven Eckelmann 	if (!info->attrs[BATADV_ATTR_HARD_IFINDEX])
12065c55a40fSSven Eckelmann 		return ERR_PTR(-EINVAL);
12075c55a40fSSven Eckelmann 
12085c55a40fSSven Eckelmann 	hardif_index = nla_get_u32(info->attrs[BATADV_ATTR_HARD_IFINDEX]);
12095c55a40fSSven Eckelmann 
12105c55a40fSSven Eckelmann 	hard_dev = dev_get_by_index(net, hardif_index);
12115c55a40fSSven Eckelmann 	if (!hard_dev)
12125c55a40fSSven Eckelmann 		return ERR_PTR(-ENODEV);
12135c55a40fSSven Eckelmann 
12145c55a40fSSven Eckelmann 	hard_iface = batadv_hardif_get_by_netdev(hard_dev);
12155c55a40fSSven Eckelmann 	if (!hard_iface)
12165c55a40fSSven Eckelmann 		goto err_put_harddev;
12175c55a40fSSven Eckelmann 
12185c55a40fSSven Eckelmann 	if (hard_iface->soft_iface != bat_priv->soft_iface)
12195c55a40fSSven Eckelmann 		goto err_put_hardif;
12205c55a40fSSven Eckelmann 
12215c55a40fSSven Eckelmann 	/* hard_dev is referenced by hard_iface and not needed here */
12225c55a40fSSven Eckelmann 	dev_put(hard_dev);
12235c55a40fSSven Eckelmann 
12245c55a40fSSven Eckelmann 	return hard_iface;
12255c55a40fSSven Eckelmann 
12265c55a40fSSven Eckelmann err_put_hardif:
12275c55a40fSSven Eckelmann 	batadv_hardif_put(hard_iface);
12285c55a40fSSven Eckelmann err_put_harddev:
12295c55a40fSSven Eckelmann 	dev_put(hard_dev);
12305c55a40fSSven Eckelmann 
12315c55a40fSSven Eckelmann 	return ERR_PTR(-EINVAL);
12325c55a40fSSven Eckelmann }
12335c55a40fSSven Eckelmann 
12345c55a40fSSven Eckelmann /**
123549e7e37cSSven Eckelmann  * batadv_get_vlan_from_info() - Retrieve vlan from genl attributes
123649e7e37cSSven Eckelmann  * @bat_priv: the bat priv with all the soft interface information
123749e7e37cSSven Eckelmann  * @net: the applicable net namespace
123849e7e37cSSven Eckelmann  * @info: receiver information
123949e7e37cSSven Eckelmann  *
124049e7e37cSSven Eckelmann  * Return: Pointer to vlan on success (with increased refcnt), error pointer
124149e7e37cSSven Eckelmann  *  on error
124249e7e37cSSven Eckelmann  */
124349e7e37cSSven Eckelmann static struct batadv_softif_vlan *
batadv_get_vlan_from_info(struct batadv_priv * bat_priv,struct net * net,struct genl_info * info)124449e7e37cSSven Eckelmann batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net,
124549e7e37cSSven Eckelmann 			  struct genl_info *info)
124649e7e37cSSven Eckelmann {
124749e7e37cSSven Eckelmann 	struct batadv_softif_vlan *vlan;
124849e7e37cSSven Eckelmann 	u16 vid;
124949e7e37cSSven Eckelmann 
125049e7e37cSSven Eckelmann 	if (!info->attrs[BATADV_ATTR_VLANID])
125149e7e37cSSven Eckelmann 		return ERR_PTR(-EINVAL);
125249e7e37cSSven Eckelmann 
125349e7e37cSSven Eckelmann 	vid = nla_get_u16(info->attrs[BATADV_ATTR_VLANID]);
125449e7e37cSSven Eckelmann 
125549e7e37cSSven Eckelmann 	vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG);
125649e7e37cSSven Eckelmann 	if (!vlan)
125749e7e37cSSven Eckelmann 		return ERR_PTR(-ENOENT);
125849e7e37cSSven Eckelmann 
125949e7e37cSSven Eckelmann 	return vlan;
126049e7e37cSSven Eckelmann }
126149e7e37cSSven Eckelmann 
126249e7e37cSSven Eckelmann /**
1263c4a7a8d9SSven Eckelmann  * batadv_pre_doit() - Prepare batman-adv genl doit request
1264c4a7a8d9SSven Eckelmann  * @ops: requested netlink operation
1265c4a7a8d9SSven Eckelmann  * @skb: Netlink message with request data
1266c4a7a8d9SSven Eckelmann  * @info: receiver information
1267c4a7a8d9SSven Eckelmann  *
1268c4a7a8d9SSven Eckelmann  * Return: 0 on success or negative error number in case of failure
1269c4a7a8d9SSven Eckelmann  */
batadv_pre_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)127020b0b53aSJakub Kicinski static int batadv_pre_doit(const struct genl_split_ops *ops,
127120b0b53aSJakub Kicinski 			   struct sk_buff *skb,
1272c4a7a8d9SSven Eckelmann 			   struct genl_info *info)
1273c4a7a8d9SSven Eckelmann {
1274c4a7a8d9SSven Eckelmann 	struct net *net = genl_info_net(info);
12755c55a40fSSven Eckelmann 	struct batadv_hard_iface *hard_iface;
12765c55a40fSSven Eckelmann 	struct batadv_priv *bat_priv = NULL;
127749e7e37cSSven Eckelmann 	struct batadv_softif_vlan *vlan;
1278c4a7a8d9SSven Eckelmann 	struct net_device *soft_iface;
12795c55a40fSSven Eckelmann 	u8 user_ptr1_flags;
12805c55a40fSSven Eckelmann 	u8 mesh_dep_flags;
12815c55a40fSSven Eckelmann 	int ret;
12825c55a40fSSven Eckelmann 
128349e7e37cSSven Eckelmann 	user_ptr1_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN;
12845c55a40fSSven Eckelmann 	if (WARN_ON(hweight8(ops->internal_flags & user_ptr1_flags) > 1))
12855c55a40fSSven Eckelmann 		return -EINVAL;
12865c55a40fSSven Eckelmann 
128749e7e37cSSven Eckelmann 	mesh_dep_flags = BATADV_FLAG_NEED_HARDIF | BATADV_FLAG_NEED_VLAN;
12885c55a40fSSven Eckelmann 	if (WARN_ON((ops->internal_flags & mesh_dep_flags) &&
12895c55a40fSSven Eckelmann 		    (~ops->internal_flags & BATADV_FLAG_NEED_MESH)))
12905c55a40fSSven Eckelmann 		return -EINVAL;
1291c4a7a8d9SSven Eckelmann 
1292c4a7a8d9SSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_MESH) {
1293c4a7a8d9SSven Eckelmann 		soft_iface = batadv_get_softif_from_info(net, info);
1294c4a7a8d9SSven Eckelmann 		if (IS_ERR(soft_iface))
1295c4a7a8d9SSven Eckelmann 			return PTR_ERR(soft_iface);
1296c4a7a8d9SSven Eckelmann 
1297c4a7a8d9SSven Eckelmann 		bat_priv = netdev_priv(soft_iface);
1298c4a7a8d9SSven Eckelmann 		info->user_ptr[0] = bat_priv;
1299c4a7a8d9SSven Eckelmann 	}
1300c4a7a8d9SSven Eckelmann 
13015c55a40fSSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF) {
13025c55a40fSSven Eckelmann 		hard_iface = batadv_get_hardif_from_info(bat_priv, net, info);
13035c55a40fSSven Eckelmann 		if (IS_ERR(hard_iface)) {
13045c55a40fSSven Eckelmann 			ret = PTR_ERR(hard_iface);
13055c55a40fSSven Eckelmann 			goto err_put_softif;
13065c55a40fSSven Eckelmann 		}
13075c55a40fSSven Eckelmann 
13085c55a40fSSven Eckelmann 		info->user_ptr[1] = hard_iface;
13095c55a40fSSven Eckelmann 	}
13105c55a40fSSven Eckelmann 
131149e7e37cSSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_VLAN) {
131249e7e37cSSven Eckelmann 		vlan = batadv_get_vlan_from_info(bat_priv, net, info);
131349e7e37cSSven Eckelmann 		if (IS_ERR(vlan)) {
131449e7e37cSSven Eckelmann 			ret = PTR_ERR(vlan);
131549e7e37cSSven Eckelmann 			goto err_put_softif;
131649e7e37cSSven Eckelmann 		}
131749e7e37cSSven Eckelmann 
131849e7e37cSSven Eckelmann 		info->user_ptr[1] = vlan;
131949e7e37cSSven Eckelmann 	}
132049e7e37cSSven Eckelmann 
1321c4a7a8d9SSven Eckelmann 	return 0;
13225c55a40fSSven Eckelmann 
13235c55a40fSSven Eckelmann err_put_softif:
13245c55a40fSSven Eckelmann 	if (bat_priv)
13255c55a40fSSven Eckelmann 		dev_put(bat_priv->soft_iface);
13265c55a40fSSven Eckelmann 
13275c55a40fSSven Eckelmann 	return ret;
1328c4a7a8d9SSven Eckelmann }
1329c4a7a8d9SSven Eckelmann 
1330c4a7a8d9SSven Eckelmann /**
1331c4a7a8d9SSven Eckelmann  * batadv_post_doit() - End batman-adv genl doit request
1332c4a7a8d9SSven Eckelmann  * @ops: requested netlink operation
1333c4a7a8d9SSven Eckelmann  * @skb: Netlink message with request data
1334c4a7a8d9SSven Eckelmann  * @info: receiver information
1335c4a7a8d9SSven Eckelmann  */
batadv_post_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)133620b0b53aSJakub Kicinski static void batadv_post_doit(const struct genl_split_ops *ops,
133720b0b53aSJakub Kicinski 			     struct sk_buff *skb,
1338c4a7a8d9SSven Eckelmann 			     struct genl_info *info)
1339c4a7a8d9SSven Eckelmann {
13405c55a40fSSven Eckelmann 	struct batadv_hard_iface *hard_iface;
134149e7e37cSSven Eckelmann 	struct batadv_softif_vlan *vlan;
1342c4a7a8d9SSven Eckelmann 	struct batadv_priv *bat_priv;
1343c4a7a8d9SSven Eckelmann 
13445c55a40fSSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_HARDIF &&
13455c55a40fSSven Eckelmann 	    info->user_ptr[1]) {
13465c55a40fSSven Eckelmann 		hard_iface = info->user_ptr[1];
13475c55a40fSSven Eckelmann 
13485c55a40fSSven Eckelmann 		batadv_hardif_put(hard_iface);
13495c55a40fSSven Eckelmann 	}
13505c55a40fSSven Eckelmann 
135149e7e37cSSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_VLAN && info->user_ptr[1]) {
135249e7e37cSSven Eckelmann 		vlan = info->user_ptr[1];
135349e7e37cSSven Eckelmann 		batadv_softif_vlan_put(vlan);
135449e7e37cSSven Eckelmann 	}
135549e7e37cSSven Eckelmann 
1356c4a7a8d9SSven Eckelmann 	if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) {
1357c4a7a8d9SSven Eckelmann 		bat_priv = info->user_ptr[0];
1358c4a7a8d9SSven Eckelmann 		dev_put(bat_priv->soft_iface);
1359c4a7a8d9SSven Eckelmann 	}
1360c4a7a8d9SSven Eckelmann }
1361c4a7a8d9SSven Eckelmann 
136266a9b928SJakub Kicinski static const struct genl_small_ops batadv_netlink_ops[] = {
13635da0aef5SMatthias Schiffer 	{
136460040513SSven Eckelmann 		.cmd = BATADV_CMD_GET_MESH,
1365ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
136660040513SSven Eckelmann 		/* can be retrieved by unprivileged users */
136760040513SSven Eckelmann 		.doit = batadv_netlink_get_mesh,
136860040513SSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH,
13695da0aef5SMatthias Schiffer 	},
137033a3bb4aSAntonio Quartulli 	{
137133a3bb4aSAntonio Quartulli 		.cmd = BATADV_CMD_TP_METER,
1372ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13739057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
137433a3bb4aSAntonio Quartulli 		.doit = batadv_netlink_tp_meter_start,
1375c4a7a8d9SSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH,
137633a3bb4aSAntonio Quartulli 	},
137733a3bb4aSAntonio Quartulli 	{
137833a3bb4aSAntonio Quartulli 		.cmd = BATADV_CMD_TP_METER_CANCEL,
1379ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13809057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
138133a3bb4aSAntonio Quartulli 		.doit = batadv_netlink_tp_meter_cancel,
1382c4a7a8d9SSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH,
138333a3bb4aSAntonio Quartulli 	},
138407a3061eSMatthias Schiffer 	{
138507a3061eSMatthias Schiffer 		.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
1386ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13879057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
138807a3061eSMatthias Schiffer 		.dumpit = batadv_algo_dump,
138907a3061eSMatthias Schiffer 	},
1390b60620cfSMatthias Schiffer 	{
13915c55a40fSSven Eckelmann 		.cmd = BATADV_CMD_GET_HARDIF,
1392ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
13935c55a40fSSven Eckelmann 		/* can be retrieved by unprivileged users */
13945c55a40fSSven Eckelmann 		.dumpit = batadv_netlink_dump_hardif,
13955c55a40fSSven Eckelmann 		.doit = batadv_netlink_get_hardif,
13965c55a40fSSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH |
13975c55a40fSSven Eckelmann 				  BATADV_FLAG_NEED_HARDIF,
1398b60620cfSMatthias Schiffer 	},
1399d34f0550SMatthias Schiffer 	{
1400d34f0550SMatthias Schiffer 		.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
1401ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14029057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
1403d34f0550SMatthias Schiffer 		.dumpit = batadv_tt_local_dump,
1404d34f0550SMatthias Schiffer 	},
1405d34f0550SMatthias Schiffer 	{
1406d34f0550SMatthias Schiffer 		.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
1407ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14089057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
1409d34f0550SMatthias Schiffer 		.dumpit = batadv_tt_global_dump,
1410d34f0550SMatthias Schiffer 	},
141185cf8c85SMatthias Schiffer 	{
141285cf8c85SMatthias Schiffer 		.cmd = BATADV_CMD_GET_ORIGINATORS,
1413ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14149057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
141585cf8c85SMatthias Schiffer 		.dumpit = batadv_orig_dump,
141685cf8c85SMatthias Schiffer 	},
141785cf8c85SMatthias Schiffer 	{
141885cf8c85SMatthias Schiffer 		.cmd = BATADV_CMD_GET_NEIGHBORS,
1419ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14209057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
142185cf8c85SMatthias Schiffer 		.dumpit = batadv_hardif_neigh_dump,
142285cf8c85SMatthias Schiffer 	},
1423d7129dafSSven Eckelmann 	{
1424d7129dafSSven Eckelmann 		.cmd = BATADV_CMD_GET_GATEWAYS,
1425ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14269057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
1427d7129dafSSven Eckelmann 		.dumpit = batadv_gw_dump,
1428d7129dafSSven Eckelmann 	},
142904f3f5bfSAndrew Lunn 	{
143004f3f5bfSAndrew Lunn 		.cmd = BATADV_CMD_GET_BLA_CLAIM,
1431ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14329057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
143304f3f5bfSAndrew Lunn 		.dumpit = batadv_bla_claim_dump,
143404f3f5bfSAndrew Lunn 	},
1435ea4152e1SSimon Wunderlich 	{
1436ea4152e1SSimon Wunderlich 		.cmd = BATADV_CMD_GET_BLA_BACKBONE,
1437ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14389057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
1439ea4152e1SSimon Wunderlich 		.dumpit = batadv_bla_backbone_dump,
1440ea4152e1SSimon Wunderlich 	},
144141aeefccSLinus Lüssing 	{
144241aeefccSLinus Lüssing 		.cmd = BATADV_CMD_GET_DAT_CACHE,
1443ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14449057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
144541aeefccSLinus Lüssing 		.dumpit = batadv_dat_cache_dump,
144641aeefccSLinus Lüssing 	},
144753dd9a68SLinus Lüssing 	{
144853dd9a68SLinus Lüssing 		.cmd = BATADV_CMD_GET_MCAST_FLAGS,
1449ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14509057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
145153dd9a68SLinus Lüssing 		.dumpit = batadv_mcast_flags_dump,
145253dd9a68SLinus Lüssing 	},
145360040513SSven Eckelmann 	{
145460040513SSven Eckelmann 		.cmd = BATADV_CMD_SET_MESH,
1455ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14569057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
145760040513SSven Eckelmann 		.doit = batadv_netlink_set_mesh,
145860040513SSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH,
145960040513SSven Eckelmann 	},
14605c55a40fSSven Eckelmann 	{
14615c55a40fSSven Eckelmann 		.cmd = BATADV_CMD_SET_HARDIF,
1462ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14639057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
14645c55a40fSSven Eckelmann 		.doit = batadv_netlink_set_hardif,
14655c55a40fSSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH |
14665c55a40fSSven Eckelmann 				  BATADV_FLAG_NEED_HARDIF,
14675c55a40fSSven Eckelmann 	},
146849e7e37cSSven Eckelmann 	{
146949e7e37cSSven Eckelmann 		.cmd = BATADV_CMD_GET_VLAN,
1470ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
147149e7e37cSSven Eckelmann 		/* can be retrieved by unprivileged users */
147249e7e37cSSven Eckelmann 		.doit = batadv_netlink_get_vlan,
147349e7e37cSSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH |
147449e7e37cSSven Eckelmann 				  BATADV_FLAG_NEED_VLAN,
147549e7e37cSSven Eckelmann 	},
147649e7e37cSSven Eckelmann 	{
147749e7e37cSSven Eckelmann 		.cmd = BATADV_CMD_SET_VLAN,
1478ef6243acSJohannes Berg 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
14799057d6c2SLinus Lüssing 		.flags = GENL_UNS_ADMIN_PERM,
148049e7e37cSSven Eckelmann 		.doit = batadv_netlink_set_vlan,
148149e7e37cSSven Eckelmann 		.internal_flags = BATADV_FLAG_NEED_MESH |
148249e7e37cSSven Eckelmann 				  BATADV_FLAG_NEED_VLAN,
148349e7e37cSSven Eckelmann 	},
148409748a22SMatthias Schiffer };
148509748a22SMatthias Schiffer 
148656989f6dSJohannes Berg struct genl_family batadv_netlink_family __ro_after_init = {
1487489111e5SJohannes Berg 	.hdrsize = 0,
1488489111e5SJohannes Berg 	.name = BATADV_NL_NAME,
1489489111e5SJohannes Berg 	.version = 1,
1490489111e5SJohannes Berg 	.maxattr = BATADV_ATTR_MAX,
14913b0f31f2SJohannes Berg 	.policy = batadv_netlink_policy,
1492489111e5SJohannes Berg 	.netnsok = true,
1493c4a7a8d9SSven Eckelmann 	.pre_doit = batadv_pre_doit,
1494c4a7a8d9SSven Eckelmann 	.post_doit = batadv_post_doit,
1495489111e5SJohannes Berg 	.module = THIS_MODULE,
149666a9b928SJakub Kicinski 	.small_ops = batadv_netlink_ops,
149766a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(batadv_netlink_ops),
14989c5d03d3SJakub Kicinski 	.resv_start_op = BATADV_CMD_SET_VLAN + 1,
1499489111e5SJohannes Berg 	.mcgrps = batadv_netlink_mcgrps,
1500489111e5SJohannes Berg 	.n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps),
1501489111e5SJohannes Berg };
1502489111e5SJohannes Berg 
150309748a22SMatthias Schiffer /**
15047e9a8c2cSSven Eckelmann  * batadv_netlink_register() - register batadv genl netlink family
150509748a22SMatthias Schiffer  */
batadv_netlink_register(void)150609748a22SMatthias Schiffer void __init batadv_netlink_register(void)
150709748a22SMatthias Schiffer {
150809748a22SMatthias Schiffer 	int ret;
150909748a22SMatthias Schiffer 
1510489111e5SJohannes Berg 	ret = genl_register_family(&batadv_netlink_family);
151109748a22SMatthias Schiffer 	if (ret)
151209748a22SMatthias Schiffer 		pr_warn("unable to register netlink family");
151309748a22SMatthias Schiffer }
151409748a22SMatthias Schiffer 
151509748a22SMatthias Schiffer /**
15167e9a8c2cSSven Eckelmann  * batadv_netlink_unregister() - unregister batadv genl netlink family
151709748a22SMatthias Schiffer  */
batadv_netlink_unregister(void)151809748a22SMatthias Schiffer void batadv_netlink_unregister(void)
151909748a22SMatthias Schiffer {
152009748a22SMatthias Schiffer 	genl_unregister_family(&batadv_netlink_family);
152109748a22SMatthias Schiffer }
1522