linux/net/netfilter/nfnetlink.c
<<
>>
Prefs
   1/* Netfilter messages via netlink socket. Allows for user space
   2 * protocol helpers and general trouble making from userspace.
   3 *
   4 * (C) 2001 by Jay Schulist <jschlst@samba.org>,
   5 * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
   6 * (C) 2005-2017 by Pablo Neira Ayuso <pablo@netfilter.org>
   7 *
   8 * Initial netfilter messages via netlink development funded and
   9 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
  10 *
  11 * Further development of this code funded by Astaro AG (http://www.astaro.com)
  12 *
  13 * This software may be used and distributed according to the terms
  14 * of the GNU General Public License, incorporated herein by reference.
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/types.h>
  19#include <linux/socket.h>
  20#include <linux/kernel.h>
  21#include <linux/string.h>
  22#include <linux/sockios.h>
  23#include <linux/net.h>
  24#include <linux/skbuff.h>
  25#include <linux/uaccess.h>
  26#include <net/sock.h>
  27#include <linux/init.h>
  28#include <linux/sched/signal.h>
  29
  30#include <net/netlink.h>
  31#include <linux/netfilter/nfnetlink.h>
  32
  33MODULE_LICENSE("GPL");
  34MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  35MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
  36
  37#define nfnl_dereference_protected(id) \
  38        rcu_dereference_protected(table[(id)].subsys, \
  39                                  lockdep_nfnl_is_held((id)))
  40
  41#define NFNL_MAX_ATTR_COUNT     32
  42
  43static struct {
  44        struct mutex                            mutex;
  45        const struct nfnetlink_subsystem __rcu  *subsys;
  46} table[NFNL_SUBSYS_COUNT];
  47
  48static const int nfnl_group2type[NFNLGRP_MAX+1] = {
  49        [NFNLGRP_CONNTRACK_NEW]         = NFNL_SUBSYS_CTNETLINK,
  50        [NFNLGRP_CONNTRACK_UPDATE]      = NFNL_SUBSYS_CTNETLINK,
  51        [NFNLGRP_CONNTRACK_DESTROY]     = NFNL_SUBSYS_CTNETLINK,
  52        [NFNLGRP_CONNTRACK_EXP_NEW]     = NFNL_SUBSYS_CTNETLINK_EXP,
  53        [NFNLGRP_CONNTRACK_EXP_UPDATE]  = NFNL_SUBSYS_CTNETLINK_EXP,
  54        [NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
  55        [NFNLGRP_NFTABLES]              = NFNL_SUBSYS_NFTABLES,
  56        [NFNLGRP_ACCT_QUOTA]            = NFNL_SUBSYS_ACCT,
  57        [NFNLGRP_NFTRACE]               = NFNL_SUBSYS_NFTABLES,
  58};
  59
  60void nfnl_lock(__u8 subsys_id)
  61{
  62        mutex_lock(&table[subsys_id].mutex);
  63}
  64EXPORT_SYMBOL_GPL(nfnl_lock);
  65
  66void nfnl_unlock(__u8 subsys_id)
  67{
  68        mutex_unlock(&table[subsys_id].mutex);
  69}
  70EXPORT_SYMBOL_GPL(nfnl_unlock);
  71
  72#ifdef CONFIG_PROVE_LOCKING
  73bool lockdep_nfnl_is_held(u8 subsys_id)
  74{
  75        return lockdep_is_held(&table[subsys_id].mutex);
  76}
  77EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held);
  78#endif
  79
  80int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
  81{
  82        u8 cb_id;
  83
  84        /* Sanity-check attr_count size to avoid stack buffer overflow. */
  85        for (cb_id = 0; cb_id < n->cb_count; cb_id++)
  86                if (WARN_ON(n->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT))
  87                        return -EINVAL;
  88
  89        nfnl_lock(n->subsys_id);
  90        if (table[n->subsys_id].subsys) {
  91                nfnl_unlock(n->subsys_id);
  92                return -EBUSY;
  93        }
  94        rcu_assign_pointer(table[n->subsys_id].subsys, n);
  95        nfnl_unlock(n->subsys_id);
  96
  97        return 0;
  98}
  99EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
 100
 101int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
 102{
 103        nfnl_lock(n->subsys_id);
 104        table[n->subsys_id].subsys = NULL;
 105        nfnl_unlock(n->subsys_id);
 106        synchronize_rcu();
 107        return 0;
 108}
 109EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
 110
 111static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u16 type)
 112{
 113        u8 subsys_id = NFNL_SUBSYS_ID(type);
 114
 115        if (subsys_id >= NFNL_SUBSYS_COUNT)
 116                return NULL;
 117
 118        return rcu_dereference(table[subsys_id].subsys);
 119}
 120
 121static inline const struct nfnl_callback *
 122nfnetlink_find_client(u16 type, const struct nfnetlink_subsystem *ss)
 123{
 124        u8 cb_id = NFNL_MSG_TYPE(type);
 125
 126        if (cb_id >= ss->cb_count)
 127                return NULL;
 128
 129        return &ss->cb[cb_id];
 130}
 131
 132int nfnetlink_has_listeners(struct net *net, unsigned int group)
 133{
 134        return netlink_has_listeners(net->nfnl, group);
 135}
 136EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
 137
 138int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
 139                   unsigned int group, int echo, gfp_t flags)
 140{
 141        return nlmsg_notify(net->nfnl, skb, portid, group, echo, flags);
 142}
 143EXPORT_SYMBOL_GPL(nfnetlink_send);
 144
 145int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
 146{
 147        return netlink_set_err(net->nfnl, portid, group, error);
 148}
 149EXPORT_SYMBOL_GPL(nfnetlink_set_err);
 150
 151int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid)
 152{
 153        int err;
 154
 155        err = nlmsg_unicast(net->nfnl, skb, portid);
 156        if (err == -EAGAIN)
 157                err = -ENOBUFS;
 158
 159        return err;
 160}
 161EXPORT_SYMBOL_GPL(nfnetlink_unicast);
 162
 163/* Process one complete nfnetlink message. */
 164static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
 165                             struct netlink_ext_ack *extack)
 166{
 167        struct net *net = sock_net(skb->sk);
 168        const struct nfnl_callback *nc;
 169        const struct nfnetlink_subsystem *ss;
 170        int type, err;
 171
 172        /* All the messages must at least contain nfgenmsg */
 173        if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
 174                return 0;
 175
 176        type = nlh->nlmsg_type;
 177replay:
 178        rcu_read_lock();
 179        ss = nfnetlink_get_subsys(type);
 180        if (!ss) {
 181#ifdef CONFIG_MODULES
 182                rcu_read_unlock();
 183                request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
 184                rcu_read_lock();
 185                ss = nfnetlink_get_subsys(type);
 186                if (!ss)
 187#endif
 188                {
 189                        rcu_read_unlock();
 190                        return -EINVAL;
 191                }
 192        }
 193
 194        nc = nfnetlink_find_client(type, ss);
 195        if (!nc) {
 196                rcu_read_unlock();
 197                return -EINVAL;
 198        }
 199
 200        {
 201                int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 202                u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
 203                struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
 204                struct nlattr *attr = (void *)nlh + min_len;
 205                int attrlen = nlh->nlmsg_len - min_len;
 206                __u8 subsys_id = NFNL_SUBSYS_ID(type);
 207
 208                /* Sanity-check NFNL_MAX_ATTR_COUNT */
 209                if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
 210                        rcu_read_unlock();
 211                        return -ENOMEM;
 212                }
 213
 214                err = nla_parse_deprecated(cda, ss->cb[cb_id].attr_count,
 215                                           attr, attrlen,
 216                                           ss->cb[cb_id].policy, extack);
 217                if (err < 0) {
 218                        rcu_read_unlock();
 219                        return err;
 220                }
 221
 222                if (nc->call_rcu) {
 223                        err = nc->call_rcu(net, net->nfnl, skb, nlh,
 224                                           (const struct nlattr **)cda,
 225                                           extack);
 226                        rcu_read_unlock();
 227                } else {
 228                        rcu_read_unlock();
 229                        nfnl_lock(subsys_id);
 230                        if (nfnl_dereference_protected(subsys_id) != ss ||
 231                            nfnetlink_find_client(type, ss) != nc)
 232                                err = -EAGAIN;
 233                        else if (nc->call)
 234                                err = nc->call(net, net->nfnl, skb, nlh,
 235                                               (const struct nlattr **)cda,
 236                                               extack);
 237                        else
 238                                err = -EINVAL;
 239                        nfnl_unlock(subsys_id);
 240                }
 241                if (err == -EAGAIN)
 242                        goto replay;
 243                return err;
 244        }
 245}
 246
 247struct nfnl_err {
 248        struct list_head        head;
 249        struct nlmsghdr         *nlh;
 250        int                     err;
 251        struct netlink_ext_ack  extack;
 252};
 253
 254static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err,
 255                        const struct netlink_ext_ack *extack)
 256{
 257        struct nfnl_err *nfnl_err;
 258
 259        nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL);
 260        if (nfnl_err == NULL)
 261                return -ENOMEM;
 262
 263        nfnl_err->nlh = nlh;
 264        nfnl_err->err = err;
 265        nfnl_err->extack = *extack;
 266        list_add_tail(&nfnl_err->head, list);
 267
 268        return 0;
 269}
 270
 271static void nfnl_err_del(struct nfnl_err *nfnl_err)
 272{
 273        list_del(&nfnl_err->head);
 274        kfree(nfnl_err);
 275}
 276
 277static void nfnl_err_reset(struct list_head *err_list)
 278{
 279        struct nfnl_err *nfnl_err, *next;
 280
 281        list_for_each_entry_safe(nfnl_err, next, err_list, head)
 282                nfnl_err_del(nfnl_err);
 283}
 284
 285static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
 286{
 287        struct nfnl_err *nfnl_err, *next;
 288
 289        list_for_each_entry_safe(nfnl_err, next, err_list, head) {
 290                netlink_ack(skb, nfnl_err->nlh, nfnl_err->err,
 291                            &nfnl_err->extack);
 292                nfnl_err_del(nfnl_err);
 293        }
 294}
 295
 296enum {
 297        NFNL_BATCH_FAILURE      = (1 << 0),
 298        NFNL_BATCH_DONE         = (1 << 1),
 299        NFNL_BATCH_REPLAY       = (1 << 2),
 300};
 301
 302static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
 303                                u16 subsys_id, u32 genid)
 304{
 305        struct sk_buff *oskb = skb;
 306        struct net *net = sock_net(skb->sk);
 307        const struct nfnetlink_subsystem *ss;
 308        const struct nfnl_callback *nc;
 309        struct netlink_ext_ack extack;
 310        LIST_HEAD(err_list);
 311        u32 status;
 312        int err;
 313
 314        if (subsys_id >= NFNL_SUBSYS_COUNT)
 315                return netlink_ack(skb, nlh, -EINVAL, NULL);
 316replay:
 317        status = 0;
 318replay_abort:
 319        skb = netlink_skb_clone(oskb, GFP_KERNEL);
 320        if (!skb)
 321                return netlink_ack(oskb, nlh, -ENOMEM, NULL);
 322
 323        nfnl_lock(subsys_id);
 324        ss = nfnl_dereference_protected(subsys_id);
 325        if (!ss) {
 326#ifdef CONFIG_MODULES
 327                nfnl_unlock(subsys_id);
 328                request_module("nfnetlink-subsys-%d", subsys_id);
 329                nfnl_lock(subsys_id);
 330                ss = nfnl_dereference_protected(subsys_id);
 331                if (!ss)
 332#endif
 333                {
 334                        nfnl_unlock(subsys_id);
 335                        netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
 336                        return kfree_skb(skb);
 337                }
 338        }
 339
 340        if (!ss->valid_genid || !ss->commit || !ss->abort) {
 341                nfnl_unlock(subsys_id);
 342                netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
 343                return kfree_skb(skb);
 344        }
 345
 346        if (!try_module_get(ss->owner)) {
 347                nfnl_unlock(subsys_id);
 348                netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
 349                return kfree_skb(skb);
 350        }
 351
 352        if (!ss->valid_genid(net, genid)) {
 353                module_put(ss->owner);
 354                nfnl_unlock(subsys_id);
 355                netlink_ack(oskb, nlh, -ERESTART, NULL);
 356                return kfree_skb(skb);
 357        }
 358
 359        nfnl_unlock(subsys_id);
 360
 361        while (skb->len >= nlmsg_total_size(0)) {
 362                int msglen, type;
 363
 364                if (fatal_signal_pending(current)) {
 365                        nfnl_err_reset(&err_list);
 366                        err = -EINTR;
 367                        status = NFNL_BATCH_FAILURE;
 368                        goto done;
 369                }
 370
 371                memset(&extack, 0, sizeof(extack));
 372                nlh = nlmsg_hdr(skb);
 373                err = 0;
 374
 375                if (nlh->nlmsg_len < NLMSG_HDRLEN ||
 376                    skb->len < nlh->nlmsg_len ||
 377                    nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
 378                        nfnl_err_reset(&err_list);
 379                        status |= NFNL_BATCH_FAILURE;
 380                        goto done;
 381                }
 382
 383                /* Only requests are handled by the kernel */
 384                if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
 385                        err = -EINVAL;
 386                        goto ack;
 387                }
 388
 389                type = nlh->nlmsg_type;
 390                if (type == NFNL_MSG_BATCH_BEGIN) {
 391                        /* Malformed: Batch begin twice */
 392                        nfnl_err_reset(&err_list);
 393                        status |= NFNL_BATCH_FAILURE;
 394                        goto done;
 395                } else if (type == NFNL_MSG_BATCH_END) {
 396                        status |= NFNL_BATCH_DONE;
 397                        goto done;
 398                } else if (type < NLMSG_MIN_TYPE) {
 399                        err = -EINVAL;
 400                        goto ack;
 401                }
 402
 403                /* We only accept a batch with messages for the same
 404                 * subsystem.
 405                 */
 406                if (NFNL_SUBSYS_ID(type) != subsys_id) {
 407                        err = -EINVAL;
 408                        goto ack;
 409                }
 410
 411                nc = nfnetlink_find_client(type, ss);
 412                if (!nc) {
 413                        err = -EINVAL;
 414                        goto ack;
 415                }
 416
 417                {
 418                        int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 419                        u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
 420                        struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
 421                        struct nlattr *attr = (void *)nlh + min_len;
 422                        int attrlen = nlh->nlmsg_len - min_len;
 423
 424                        /* Sanity-check NFTA_MAX_ATTR */
 425                        if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
 426                                err = -ENOMEM;
 427                                goto ack;
 428                        }
 429
 430                        err = nla_parse_deprecated(cda,
 431                                                   ss->cb[cb_id].attr_count,
 432                                                   attr, attrlen,
 433                                                   ss->cb[cb_id].policy, NULL);
 434                        if (err < 0)
 435                                goto ack;
 436
 437                        if (nc->call_batch) {
 438                                err = nc->call_batch(net, net->nfnl, skb, nlh,
 439                                                     (const struct nlattr **)cda,
 440                                                     &extack);
 441                        }
 442
 443                        /* The lock was released to autoload some module, we
 444                         * have to abort and start from scratch using the
 445                         * original skb.
 446                         */
 447                        if (err == -EAGAIN) {
 448                                status |= NFNL_BATCH_REPLAY;
 449                                goto done;
 450                        }
 451                }
 452ack:
 453                if (nlh->nlmsg_flags & NLM_F_ACK || err) {
 454                        /* Errors are delivered once the full batch has been
 455                         * processed, this avoids that the same error is
 456                         * reported several times when replaying the batch.
 457                         */
 458                        if (nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
 459                                /* We failed to enqueue an error, reset the
 460                                 * list of errors and send OOM to userspace
 461                                 * pointing to the batch header.
 462                                 */
 463                                nfnl_err_reset(&err_list);
 464                                netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM,
 465                                            NULL);
 466                                status |= NFNL_BATCH_FAILURE;
 467                                goto done;
 468                        }
 469                        /* We don't stop processing the batch on errors, thus,
 470                         * userspace gets all the errors that the batch
 471                         * triggers.
 472                         */
 473                        if (err)
 474                                status |= NFNL_BATCH_FAILURE;
 475                }
 476
 477                msglen = NLMSG_ALIGN(nlh->nlmsg_len);
 478                if (msglen > skb->len)
 479                        msglen = skb->len;
 480                skb_pull(skb, msglen);
 481        }
 482done:
 483        if (status & NFNL_BATCH_REPLAY) {
 484                ss->abort(net, oskb, NFNL_ABORT_AUTOLOAD);
 485                nfnl_err_reset(&err_list);
 486                kfree_skb(skb);
 487                module_put(ss->owner);
 488                goto replay;
 489        } else if (status == NFNL_BATCH_DONE) {
 490                err = ss->commit(net, oskb);
 491                if (err == -EAGAIN) {
 492                        status |= NFNL_BATCH_REPLAY;
 493                        goto done;
 494                } else if (err) {
 495                        ss->abort(net, oskb, NFNL_ABORT_NONE);
 496                        netlink_ack(oskb, nlmsg_hdr(oskb), err, NULL);
 497                }
 498        } else {
 499                enum nfnl_abort_action abort_action;
 500
 501                if (status & NFNL_BATCH_FAILURE)
 502                        abort_action = NFNL_ABORT_NONE;
 503                else
 504                        abort_action = NFNL_ABORT_VALIDATE;
 505
 506                err = ss->abort(net, oskb, abort_action);
 507                if (err == -EAGAIN) {
 508                        nfnl_err_reset(&err_list);
 509                        kfree_skb(skb);
 510                        module_put(ss->owner);
 511                        status |= NFNL_BATCH_FAILURE;
 512                        goto replay_abort;
 513                }
 514        }
 515        if (ss->cleanup)
 516                ss->cleanup(net);
 517
 518        nfnl_err_deliver(&err_list, oskb);
 519        kfree_skb(skb);
 520        module_put(ss->owner);
 521}
 522
 523static const struct nla_policy nfnl_batch_policy[NFNL_BATCH_MAX + 1] = {
 524        [NFNL_BATCH_GENID]      = { .type = NLA_U32 },
 525};
 526
 527static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
 528{
 529        int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 530        struct nlattr *attr = (void *)nlh + min_len;
 531        struct nlattr *cda[NFNL_BATCH_MAX + 1];
 532        int attrlen = nlh->nlmsg_len - min_len;
 533        struct nfgenmsg *nfgenmsg;
 534        int msglen, err;
 535        u32 gen_id = 0;
 536        u16 res_id;
 537
 538        msglen = NLMSG_ALIGN(nlh->nlmsg_len);
 539        if (msglen > skb->len)
 540                msglen = skb->len;
 541
 542        if (skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
 543                return;
 544
 545        err = nla_parse_deprecated(cda, NFNL_BATCH_MAX, attr, attrlen,
 546                                   nfnl_batch_policy, NULL);
 547        if (err < 0) {
 548                netlink_ack(skb, nlh, err, NULL);
 549                return;
 550        }
 551        if (cda[NFNL_BATCH_GENID])
 552                gen_id = ntohl(nla_get_be32(cda[NFNL_BATCH_GENID]));
 553
 554        nfgenmsg = nlmsg_data(nlh);
 555        skb_pull(skb, msglen);
 556        /* Work around old nft using host byte order */
 557        if (nfgenmsg->res_id == NFNL_SUBSYS_NFTABLES)
 558                res_id = NFNL_SUBSYS_NFTABLES;
 559        else
 560                res_id = ntohs(nfgenmsg->res_id);
 561
 562        nfnetlink_rcv_batch(skb, nlh, res_id, gen_id);
 563}
 564
 565static void nfnetlink_rcv(struct sk_buff *skb)
 566{
 567        struct nlmsghdr *nlh = nlmsg_hdr(skb);
 568
 569        if (skb->len < NLMSG_HDRLEN ||
 570            nlh->nlmsg_len < NLMSG_HDRLEN ||
 571            skb->len < nlh->nlmsg_len)
 572                return;
 573
 574        if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
 575                netlink_ack(skb, nlh, -EPERM, NULL);
 576                return;
 577        }
 578
 579        if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN)
 580                nfnetlink_rcv_skb_batch(skb, nlh);
 581        else
 582                netlink_rcv_skb(skb, nfnetlink_rcv_msg);
 583}
 584
 585#ifdef CONFIG_MODULES
 586static int nfnetlink_bind(struct net *net, int group)
 587{
 588        const struct nfnetlink_subsystem *ss;
 589        int type;
 590
 591        if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
 592                return 0;
 593
 594        type = nfnl_group2type[group];
 595
 596        rcu_read_lock();
 597        ss = nfnetlink_get_subsys(type << 8);
 598        rcu_read_unlock();
 599        if (!ss)
 600                request_module_nowait("nfnetlink-subsys-%d", type);
 601        return 0;
 602}
 603#endif
 604
 605static int __net_init nfnetlink_net_init(struct net *net)
 606{
 607        struct sock *nfnl;
 608        struct netlink_kernel_cfg cfg = {
 609                .groups = NFNLGRP_MAX,
 610                .input  = nfnetlink_rcv,
 611#ifdef CONFIG_MODULES
 612                .bind   = nfnetlink_bind,
 613#endif
 614        };
 615
 616        nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg);
 617        if (!nfnl)
 618                return -ENOMEM;
 619        net->nfnl_stash = nfnl;
 620        rcu_assign_pointer(net->nfnl, nfnl);
 621        return 0;
 622}
 623
 624static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
 625{
 626        struct net *net;
 627
 628        list_for_each_entry(net, net_exit_list, exit_list)
 629                RCU_INIT_POINTER(net->nfnl, NULL);
 630        synchronize_net();
 631        list_for_each_entry(net, net_exit_list, exit_list)
 632                netlink_kernel_release(net->nfnl_stash);
 633}
 634
 635static struct pernet_operations nfnetlink_net_ops = {
 636        .init           = nfnetlink_net_init,
 637        .exit_batch     = nfnetlink_net_exit_batch,
 638};
 639
 640static int __init nfnetlink_init(void)
 641{
 642        int i;
 643
 644        for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++)
 645                BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
 646
 647        for (i=0; i<NFNL_SUBSYS_COUNT; i++)
 648                mutex_init(&table[i].mutex);
 649
 650        return register_pernet_subsys(&nfnetlink_net_ops);
 651}
 652
 653static void __exit nfnetlink_exit(void)
 654{
 655        unregister_pernet_subsys(&nfnetlink_net_ops);
 656}
 657module_init(nfnetlink_init);
 658module_exit(nfnetlink_exit);
 659