xref: /openbmc/linux/net/batman-adv/netlink.c (revision a34a3ed7)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2016-2017  B.A.T.M.A.N. contributors:
3  *
4  * Matthias Schiffer
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "netlink.h"
20 #include "main.h"
21 
22 #include <linux/atomic.h>
23 #include <linux/byteorder/generic.h>
24 #include <linux/cache.h>
25 #include <linux/errno.h>
26 #include <linux/export.h>
27 #include <linux/genetlink.h>
28 #include <linux/gfp.h>
29 #include <linux/if_ether.h>
30 #include <linux/init.h>
31 #include <linux/kernel.h>
32 #include <linux/netdevice.h>
33 #include <linux/netlink.h>
34 #include <linux/printk.h>
35 #include <linux/rculist.h>
36 #include <linux/rcupdate.h>
37 #include <linux/skbuff.h>
38 #include <linux/stddef.h>
39 #include <linux/types.h>
40 #include <net/genetlink.h>
41 #include <net/netlink.h>
42 #include <net/sock.h>
43 #include <uapi/linux/batadv_packet.h>
44 #include <uapi/linux/batman_adv.h>
45 
46 #include "bat_algo.h"
47 #include "bridge_loop_avoidance.h"
48 #include "gateway_client.h"
49 #include "hard-interface.h"
50 #include "originator.h"
51 #include "soft-interface.h"
52 #include "tp_meter.h"
53 #include "translation-table.h"
54 
55 struct genl_family batadv_netlink_family;
56 
57 /* multicast groups */
58 enum batadv_netlink_multicast_groups {
59 	BATADV_NL_MCGRP_TPMETER,
60 };
61 
62 static const struct genl_multicast_group batadv_netlink_mcgrps[] = {
63 	[BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER },
64 };
65 
66 static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
67 	[BATADV_ATTR_VERSION]		= { .type = NLA_STRING },
68 	[BATADV_ATTR_ALGO_NAME]		= { .type = NLA_STRING },
69 	[BATADV_ATTR_MESH_IFINDEX]	= { .type = NLA_U32 },
70 	[BATADV_ATTR_MESH_IFNAME]	= { .type = NLA_STRING },
71 	[BATADV_ATTR_MESH_ADDRESS]	= { .len = ETH_ALEN },
72 	[BATADV_ATTR_HARD_IFINDEX]	= { .type = NLA_U32 },
73 	[BATADV_ATTR_HARD_IFNAME]	= { .type = NLA_STRING },
74 	[BATADV_ATTR_HARD_ADDRESS]	= { .len = ETH_ALEN },
75 	[BATADV_ATTR_ORIG_ADDRESS]	= { .len = ETH_ALEN },
76 	[BATADV_ATTR_TPMETER_RESULT]	= { .type = NLA_U8 },
77 	[BATADV_ATTR_TPMETER_TEST_TIME]	= { .type = NLA_U32 },
78 	[BATADV_ATTR_TPMETER_BYTES]	= { .type = NLA_U64 },
79 	[BATADV_ATTR_TPMETER_COOKIE]	= { .type = NLA_U32 },
80 	[BATADV_ATTR_ACTIVE]		= { .type = NLA_FLAG },
81 	[BATADV_ATTR_TT_ADDRESS]	= { .len = ETH_ALEN },
82 	[BATADV_ATTR_TT_TTVN]		= { .type = NLA_U8 },
83 	[BATADV_ATTR_TT_LAST_TTVN]	= { .type = NLA_U8 },
84 	[BATADV_ATTR_TT_CRC32]		= { .type = NLA_U32 },
85 	[BATADV_ATTR_TT_VID]		= { .type = NLA_U16 },
86 	[BATADV_ATTR_TT_FLAGS]		= { .type = NLA_U32 },
87 	[BATADV_ATTR_FLAG_BEST]		= { .type = NLA_FLAG },
88 	[BATADV_ATTR_LAST_SEEN_MSECS]	= { .type = NLA_U32 },
89 	[BATADV_ATTR_NEIGH_ADDRESS]	= { .len = ETH_ALEN },
90 	[BATADV_ATTR_TQ]		= { .type = NLA_U8 },
91 	[BATADV_ATTR_THROUGHPUT]	= { .type = NLA_U32 },
92 	[BATADV_ATTR_BANDWIDTH_UP]	= { .type = NLA_U32 },
93 	[BATADV_ATTR_BANDWIDTH_DOWN]	= { .type = NLA_U32 },
94 	[BATADV_ATTR_ROUTER]		= { .len = ETH_ALEN },
95 	[BATADV_ATTR_BLA_OWN]		= { .type = NLA_FLAG },
96 	[BATADV_ATTR_BLA_ADDRESS]	= { .len = ETH_ALEN },
97 	[BATADV_ATTR_BLA_VID]		= { .type = NLA_U16 },
98 	[BATADV_ATTR_BLA_BACKBONE]	= { .len = ETH_ALEN },
99 	[BATADV_ATTR_BLA_CRC]		= { .type = NLA_U16 },
100 };
101 
102 /**
103  * batadv_netlink_get_ifindex() - Extract an interface index from a message
104  * @nlh: Message header
105  * @attrtype: Attribute which holds an interface index
106  *
107  * Return: interface index, or 0.
108  */
109 int
110 batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype)
111 {
112 	struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
113 
114 	return attr ? nla_get_u32(attr) : 0;
115 }
116 
117 /**
118  * batadv_netlink_mesh_info_put() - fill in generic information about mesh
119  *  interface
120  * @msg: netlink message to be sent back
121  * @soft_iface: interface for which the data should be taken
122  *
123  * Return: 0 on success, < 0 on error
124  */
125 static int
126 batadv_netlink_mesh_info_put(struct sk_buff *msg, struct net_device *soft_iface)
127 {
128 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
129 	struct batadv_hard_iface *primary_if = NULL;
130 	struct net_device *hard_iface;
131 	int ret = -ENOBUFS;
132 
133 	if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) ||
134 	    nla_put_string(msg, BATADV_ATTR_ALGO_NAME,
135 			   bat_priv->algo_ops->name) ||
136 	    nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, soft_iface->ifindex) ||
137 	    nla_put_string(msg, BATADV_ATTR_MESH_IFNAME, soft_iface->name) ||
138 	    nla_put(msg, BATADV_ATTR_MESH_ADDRESS, ETH_ALEN,
139 		    soft_iface->dev_addr) ||
140 	    nla_put_u8(msg, BATADV_ATTR_TT_TTVN,
141 		       (u8)atomic_read(&bat_priv->tt.vn)))
142 		goto out;
143 
144 #ifdef CONFIG_BATMAN_ADV_BLA
145 	if (nla_put_u16(msg, BATADV_ATTR_BLA_CRC,
146 			ntohs(bat_priv->bla.claim_dest.group)))
147 		goto out;
148 #endif
149 
150 	primary_if = batadv_primary_if_get_selected(bat_priv);
151 	if (primary_if && primary_if->if_status == BATADV_IF_ACTIVE) {
152 		hard_iface = primary_if->net_dev;
153 
154 		if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
155 				hard_iface->ifindex) ||
156 		    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
157 				   hard_iface->name) ||
158 		    nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
159 			    hard_iface->dev_addr))
160 			goto out;
161 	}
162 
163 	ret = 0;
164 
165  out:
166 	if (primary_if)
167 		batadv_hardif_put(primary_if);
168 
169 	return ret;
170 }
171 
172 /**
173  * batadv_netlink_get_mesh_info() - handle incoming BATADV_CMD_GET_MESH_INFO
174  *  netlink request
175  * @skb: received netlink message
176  * @info: receiver information
177  *
178  * Return: 0 on success, < 0 on error
179  */
180 static int
181 batadv_netlink_get_mesh_info(struct sk_buff *skb, struct genl_info *info)
182 {
183 	struct net *net = genl_info_net(info);
184 	struct net_device *soft_iface;
185 	struct sk_buff *msg = NULL;
186 	void *msg_head;
187 	int ifindex;
188 	int ret;
189 
190 	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
191 		return -EINVAL;
192 
193 	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
194 	if (!ifindex)
195 		return -EINVAL;
196 
197 	soft_iface = dev_get_by_index(net, ifindex);
198 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
199 		ret = -ENODEV;
200 		goto out;
201 	}
202 
203 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
204 	if (!msg) {
205 		ret = -ENOMEM;
206 		goto out;
207 	}
208 
209 	msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq,
210 			       &batadv_netlink_family, 0,
211 			       BATADV_CMD_GET_MESH_INFO);
212 	if (!msg_head) {
213 		ret = -ENOBUFS;
214 		goto out;
215 	}
216 
217 	ret = batadv_netlink_mesh_info_put(msg, soft_iface);
218 
219  out:
220 	if (soft_iface)
221 		dev_put(soft_iface);
222 
223 	if (ret) {
224 		if (msg)
225 			nlmsg_free(msg);
226 		return ret;
227 	}
228 
229 	genlmsg_end(msg, msg_head);
230 	return genlmsg_reply(msg, info);
231 }
232 
233 /**
234  * batadv_netlink_tp_meter_put() - Fill information of started tp_meter session
235  * @msg: netlink message to be sent back
236  * @cookie: tp meter session cookie
237  *
238  *  Return: 0 on success, < 0 on error
239  */
240 static int
241 batadv_netlink_tp_meter_put(struct sk_buff *msg, u32 cookie)
242 {
243 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie))
244 		return -ENOBUFS;
245 
246 	return 0;
247 }
248 
249 /**
250  * batadv_netlink_tpmeter_notify() - send tp_meter result via netlink to client
251  * @bat_priv: the bat priv with all the soft interface information
252  * @dst: destination of tp_meter session
253  * @result: reason for tp meter session stop
254  * @test_time: total time ot the tp_meter session
255  * @total_bytes: bytes acked to the receiver
256  * @cookie: cookie of tp_meter session
257  *
258  * Return: 0 on success, < 0 on error
259  */
260 int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst,
261 				  u8 result, u32 test_time, u64 total_bytes,
262 				  u32 cookie)
263 {
264 	struct sk_buff *msg;
265 	void *hdr;
266 	int ret;
267 
268 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
269 	if (!msg)
270 		return -ENOMEM;
271 
272 	hdr = genlmsg_put(msg, 0, 0, &batadv_netlink_family, 0,
273 			  BATADV_CMD_TP_METER);
274 	if (!hdr) {
275 		ret = -ENOBUFS;
276 		goto err_genlmsg;
277 	}
278 
279 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_COOKIE, cookie))
280 		goto nla_put_failure;
281 
282 	if (nla_put_u32(msg, BATADV_ATTR_TPMETER_TEST_TIME, test_time))
283 		goto nla_put_failure;
284 
285 	if (nla_put_u64_64bit(msg, BATADV_ATTR_TPMETER_BYTES, total_bytes,
286 			      BATADV_ATTR_PAD))
287 		goto nla_put_failure;
288 
289 	if (nla_put_u8(msg, BATADV_ATTR_TPMETER_RESULT, result))
290 		goto nla_put_failure;
291 
292 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst))
293 		goto nla_put_failure;
294 
295 	genlmsg_end(msg, hdr);
296 
297 	genlmsg_multicast_netns(&batadv_netlink_family,
298 				dev_net(bat_priv->soft_iface), msg, 0,
299 				BATADV_NL_MCGRP_TPMETER, GFP_KERNEL);
300 
301 	return 0;
302 
303 nla_put_failure:
304 	genlmsg_cancel(msg, hdr);
305 	ret = -EMSGSIZE;
306 
307 err_genlmsg:
308 	nlmsg_free(msg);
309 	return ret;
310 }
311 
312 /**
313  * batadv_netlink_tp_meter_start() - Start a new tp_meter session
314  * @skb: received netlink message
315  * @info: receiver information
316  *
317  * Return: 0 on success, < 0 on error
318  */
319 static int
320 batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
321 {
322 	struct net *net = genl_info_net(info);
323 	struct net_device *soft_iface;
324 	struct batadv_priv *bat_priv;
325 	struct sk_buff *msg = NULL;
326 	u32 test_length;
327 	void *msg_head;
328 	int ifindex;
329 	u32 cookie;
330 	u8 *dst;
331 	int ret;
332 
333 	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
334 		return -EINVAL;
335 
336 	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
337 		return -EINVAL;
338 
339 	if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME])
340 		return -EINVAL;
341 
342 	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
343 	if (!ifindex)
344 		return -EINVAL;
345 
346 	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
347 
348 	test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]);
349 
350 	soft_iface = dev_get_by_index(net, ifindex);
351 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
352 		ret = -ENODEV;
353 		goto out;
354 	}
355 
356 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
357 	if (!msg) {
358 		ret = -ENOMEM;
359 		goto out;
360 	}
361 
362 	msg_head = genlmsg_put(msg, info->snd_portid, info->snd_seq,
363 			       &batadv_netlink_family, 0,
364 			       BATADV_CMD_TP_METER);
365 	if (!msg_head) {
366 		ret = -ENOBUFS;
367 		goto out;
368 	}
369 
370 	bat_priv = netdev_priv(soft_iface);
371 	batadv_tp_start(bat_priv, dst, test_length, &cookie);
372 
373 	ret = batadv_netlink_tp_meter_put(msg, cookie);
374 
375  out:
376 	if (soft_iface)
377 		dev_put(soft_iface);
378 
379 	if (ret) {
380 		if (msg)
381 			nlmsg_free(msg);
382 		return ret;
383 	}
384 
385 	genlmsg_end(msg, msg_head);
386 	return genlmsg_reply(msg, info);
387 }
388 
389 /**
390  * batadv_netlink_tp_meter_start() - Cancel a running tp_meter session
391  * @skb: received netlink message
392  * @info: receiver information
393  *
394  * Return: 0 on success, < 0 on error
395  */
396 static int
397 batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info)
398 {
399 	struct net *net = genl_info_net(info);
400 	struct net_device *soft_iface;
401 	struct batadv_priv *bat_priv;
402 	int ifindex;
403 	u8 *dst;
404 	int ret = 0;
405 
406 	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
407 		return -EINVAL;
408 
409 	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
410 		return -EINVAL;
411 
412 	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
413 	if (!ifindex)
414 		return -EINVAL;
415 
416 	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);
417 
418 	soft_iface = dev_get_by_index(net, ifindex);
419 	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
420 		ret = -ENODEV;
421 		goto out;
422 	}
423 
424 	bat_priv = netdev_priv(soft_iface);
425 	batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL);
426 
427 out:
428 	if (soft_iface)
429 		dev_put(soft_iface);
430 
431 	return ret;
432 }
433 
434 /**
435  * batadv_netlink_dump_hardif_entry() - Dump one hard interface into a message
436  * @msg: Netlink message to dump into
437  * @portid: Port making netlink request
438  * @seq: Sequence number of netlink message
439  * @hard_iface: Hard interface to dump
440  *
441  * Return: error code, or 0 on success
442  */
443 static int
444 batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, u32 seq,
445 				 struct batadv_hard_iface *hard_iface)
446 {
447 	struct net_device *net_dev = hard_iface->net_dev;
448 	void *hdr;
449 
450 	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
451 			  BATADV_CMD_GET_HARDIFS);
452 	if (!hdr)
453 		return -EMSGSIZE;
454 
455 	if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
456 			net_dev->ifindex) ||
457 	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
458 			   net_dev->name) ||
459 	    nla_put(msg, BATADV_ATTR_HARD_ADDRESS, ETH_ALEN,
460 		    net_dev->dev_addr))
461 		goto nla_put_failure;
462 
463 	if (hard_iface->if_status == BATADV_IF_ACTIVE) {
464 		if (nla_put_flag(msg, BATADV_ATTR_ACTIVE))
465 			goto nla_put_failure;
466 	}
467 
468 	genlmsg_end(msg, hdr);
469 	return 0;
470 
471  nla_put_failure:
472 	genlmsg_cancel(msg, hdr);
473 	return -EMSGSIZE;
474 }
475 
476 /**
477  * batadv_netlink_dump_hardifs() - Dump all hard interface into a messages
478  * @msg: Netlink message to dump into
479  * @cb: Parameters from query
480  *
481  * Return: error code, or length of reply message on success
482  */
483 static int
484 batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
485 {
486 	struct net *net = sock_net(cb->skb->sk);
487 	struct net_device *soft_iface;
488 	struct batadv_hard_iface *hard_iface;
489 	int ifindex;
490 	int portid = NETLINK_CB(cb->skb).portid;
491 	int seq = cb->nlh->nlmsg_seq;
492 	int skip = cb->args[0];
493 	int i = 0;
494 
495 	ifindex = batadv_netlink_get_ifindex(cb->nlh,
496 					     BATADV_ATTR_MESH_IFINDEX);
497 	if (!ifindex)
498 		return -EINVAL;
499 
500 	soft_iface = dev_get_by_index(net, ifindex);
501 	if (!soft_iface)
502 		return -ENODEV;
503 
504 	if (!batadv_softif_is_valid(soft_iface)) {
505 		dev_put(soft_iface);
506 		return -ENODEV;
507 	}
508 
509 	rcu_read_lock();
510 
511 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
512 		if (hard_iface->soft_iface != soft_iface)
513 			continue;
514 
515 		if (i++ < skip)
516 			continue;
517 
518 		if (batadv_netlink_dump_hardif_entry(msg, portid, seq,
519 						     hard_iface)) {
520 			i--;
521 			break;
522 		}
523 	}
524 
525 	rcu_read_unlock();
526 
527 	dev_put(soft_iface);
528 
529 	cb->args[0] = i;
530 
531 	return msg->len;
532 }
533 
534 static const struct genl_ops batadv_netlink_ops[] = {
535 	{
536 		.cmd = BATADV_CMD_GET_MESH_INFO,
537 		.flags = GENL_ADMIN_PERM,
538 		.policy = batadv_netlink_policy,
539 		.doit = batadv_netlink_get_mesh_info,
540 	},
541 	{
542 		.cmd = BATADV_CMD_TP_METER,
543 		.flags = GENL_ADMIN_PERM,
544 		.policy = batadv_netlink_policy,
545 		.doit = batadv_netlink_tp_meter_start,
546 	},
547 	{
548 		.cmd = BATADV_CMD_TP_METER_CANCEL,
549 		.flags = GENL_ADMIN_PERM,
550 		.policy = batadv_netlink_policy,
551 		.doit = batadv_netlink_tp_meter_cancel,
552 	},
553 	{
554 		.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
555 		.flags = GENL_ADMIN_PERM,
556 		.policy = batadv_netlink_policy,
557 		.dumpit = batadv_algo_dump,
558 	},
559 	{
560 		.cmd = BATADV_CMD_GET_HARDIFS,
561 		.flags = GENL_ADMIN_PERM,
562 		.policy = batadv_netlink_policy,
563 		.dumpit = batadv_netlink_dump_hardifs,
564 	},
565 	{
566 		.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
567 		.flags = GENL_ADMIN_PERM,
568 		.policy = batadv_netlink_policy,
569 		.dumpit = batadv_tt_local_dump,
570 	},
571 	{
572 		.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
573 		.flags = GENL_ADMIN_PERM,
574 		.policy = batadv_netlink_policy,
575 		.dumpit = batadv_tt_global_dump,
576 	},
577 	{
578 		.cmd = BATADV_CMD_GET_ORIGINATORS,
579 		.flags = GENL_ADMIN_PERM,
580 		.policy = batadv_netlink_policy,
581 		.dumpit = batadv_orig_dump,
582 	},
583 	{
584 		.cmd = BATADV_CMD_GET_NEIGHBORS,
585 		.flags = GENL_ADMIN_PERM,
586 		.policy = batadv_netlink_policy,
587 		.dumpit = batadv_hardif_neigh_dump,
588 	},
589 	{
590 		.cmd = BATADV_CMD_GET_GATEWAYS,
591 		.flags = GENL_ADMIN_PERM,
592 		.policy = batadv_netlink_policy,
593 		.dumpit = batadv_gw_dump,
594 	},
595 	{
596 		.cmd = BATADV_CMD_GET_BLA_CLAIM,
597 		.flags = GENL_ADMIN_PERM,
598 		.policy = batadv_netlink_policy,
599 		.dumpit = batadv_bla_claim_dump,
600 	},
601 	{
602 		.cmd = BATADV_CMD_GET_BLA_BACKBONE,
603 		.flags = GENL_ADMIN_PERM,
604 		.policy = batadv_netlink_policy,
605 		.dumpit = batadv_bla_backbone_dump,
606 	},
607 
608 };
609 
610 struct genl_family batadv_netlink_family __ro_after_init = {
611 	.hdrsize = 0,
612 	.name = BATADV_NL_NAME,
613 	.version = 1,
614 	.maxattr = BATADV_ATTR_MAX,
615 	.netnsok = true,
616 	.module = THIS_MODULE,
617 	.ops = batadv_netlink_ops,
618 	.n_ops = ARRAY_SIZE(batadv_netlink_ops),
619 	.mcgrps = batadv_netlink_mcgrps,
620 	.n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps),
621 };
622 
623 /**
624  * batadv_netlink_register() - register batadv genl netlink family
625  */
626 void __init batadv_netlink_register(void)
627 {
628 	int ret;
629 
630 	ret = genl_register_family(&batadv_netlink_family);
631 	if (ret)
632 		pr_warn("unable to register netlink family");
633 }
634 
635 /**
636  * batadv_netlink_unregister() - unregister batadv genl netlink family
637  */
638 void batadv_netlink_unregister(void)
639 {
640 	genl_unregister_family(&batadv_netlink_family);
641 }
642