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