linux/net/batman-adv/netlink.c
<<
>>
Prefs
   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
  57struct genl_family batadv_netlink_family;
  58
  59/* multicast groups */
  60enum batadv_netlink_multicast_groups {
  61        BATADV_NL_MCGRP_TPMETER,
  62};
  63
  64static const struct genl_multicast_group batadv_netlink_mcgrps[] = {
  65        [BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER },
  66};
  67
  68static 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 */
 116int
 117batadv_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 */
 132static int
 133batadv_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 */
 190static int
 191batadv_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 */
 250static int
 251batadv_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 */
 270int 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
 313nla_put_failure:
 314        genlmsg_cancel(msg, hdr);
 315        ret = -EMSGSIZE;
 316
 317err_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 */
 329static int
 330batadv_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 */
 406static int
 407batadv_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
 437out:
 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 */
 453static int
 454batadv_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 */
 493static int
 494batadv_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
 544static 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
 632struct 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 */
 648void __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 */
 660void batadv_netlink_unregister(void)
 661{
 662        genl_unregister_family(&batadv_netlink_family);
 663}
 664