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                      int flags)
 153{
 154        return netlink_unicast(net->nfnl, skb, portid, flags);
 155}
 156EXPORT_SYMBOL_GPL(nfnetlink_unicast);
 157
 158/* Process one complete nfnetlink message. */
 159static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
 160                             struct netlink_ext_ack *extack)
 161{
 162        struct net *net = sock_net(skb->sk);
 163        const struct nfnl_callback *nc;
 164        const struct nfnetlink_subsystem *ss;
 165        int type, err;
 166
 167        /* All the messages must at least contain nfgenmsg */
 168        if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
 169                return 0;
 170
 171        type = nlh->nlmsg_type;
 172replay:
 173        rcu_read_lock();
 174        ss = nfnetlink_get_subsys(type);
 175        if (!ss) {
 176#ifdef CONFIG_MODULES
 177                rcu_read_unlock();
 178                request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
 179                rcu_read_lock();
 180                ss = nfnetlink_get_subsys(type);
 181                if (!ss)
 182#endif
 183                {
 184                        rcu_read_unlock();
 185                        return -EINVAL;
 186                }
 187        }
 188
 189        nc = nfnetlink_find_client(type, ss);
 190        if (!nc) {
 191                rcu_read_unlock();
 192                return -EINVAL;
 193        }
 194
 195        {
 196                int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 197                u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
 198                struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
 199                struct nlattr *attr = (void *)nlh + min_len;
 200                int attrlen = nlh->nlmsg_len - min_len;
 201                __u8 subsys_id = NFNL_SUBSYS_ID(type);
 202
 203                /* Sanity-check NFNL_MAX_ATTR_COUNT */
 204                if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
 205                        rcu_read_unlock();
 206                        return -ENOMEM;
 207                }
 208
 209                err = nla_parse_deprecated(cda, ss->cb[cb_id].attr_count,
 210                                           attr, attrlen,
 211                                           ss->cb[cb_id].policy, extack);
 212                if (err < 0) {
 213                        rcu_read_unlock();
 214                        return err;
 215                }
 216
 217                if (nc->call_rcu) {
 218                        err = nc->call_rcu(net, net->nfnl, skb, nlh,
 219                                           (const struct nlattr **)cda,
 220                                           extack);
 221                        rcu_read_unlock();
 222                } else {
 223                        rcu_read_unlock();
 224                        nfnl_lock(subsys_id);
 225                        if (nfnl_dereference_protected(subsys_id) != ss ||
 226                            nfnetlink_find_client(type, ss) != nc)
 227                                err = -EAGAIN;
 228                        else if (nc->call)
 229                                err = nc->call(net, net->nfnl, skb, nlh,
 230                                               (const struct nlattr **)cda,
 231                                               extack);
 232                        else
 233                                err = -EINVAL;
 234                        nfnl_unlock(subsys_id);
 235                }
 236                if (err == -EAGAIN)
 237                        goto replay;
 238                return err;
 239        }
 240}
 241
 242struct nfnl_err {
 243        struct list_head        head;
 244        struct nlmsghdr         *nlh;
 245        int                     err;
 246        struct netlink_ext_ack  extack;
 247};
 248
 249static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err,
 250                        const struct netlink_ext_ack *extack)
 251{
 252        struct nfnl_err *nfnl_err;
 253
 254        nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL);
 255        if (nfnl_err == NULL)
 256                return -ENOMEM;
 257
 258        nfnl_err->nlh = nlh;
 259        nfnl_err->err = err;
 260        nfnl_err->extack = *extack;
 261        list_add_tail(&nfnl_err->head, list);
 262
 263        return 0;
 264}
 265
 266static void nfnl_err_del(struct nfnl_err *nfnl_err)
 267{
 268        list_del(&nfnl_err->head);
 269        kfree(nfnl_err);
 270}
 271
 272static void nfnl_err_reset(struct list_head *err_list)
 273{
 274        struct nfnl_err *nfnl_err, *next;
 275
 276        list_for_each_entry_safe(nfnl_err, next, err_list, head)
 277                nfnl_err_del(nfnl_err);
 278}
 279
 280static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
 281{
 282        struct nfnl_err *nfnl_err, *next;
 283
 284        list_for_each_entry_safe(nfnl_err, next, err_list, head) {
 285                netlink_ack(skb, nfnl_err->nlh, nfnl_err->err,
 286                            &nfnl_err->extack);
 287                nfnl_err_del(nfnl_err);
 288        }
 289}
 290
 291enum {
 292        NFNL_BATCH_FAILURE      = (1 << 0),
 293        NFNL_BATCH_DONE         = (1 << 1),
 294        NFNL_BATCH_REPLAY       = (1 << 2),
 295};
 296
 297static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
 298                                u16 subsys_id, u32 genid)
 299{
 300        struct sk_buff *oskb = skb;
 301        struct net *net = sock_net(skb->sk);
 302        const struct nfnetlink_subsystem *ss;
 303        const struct nfnl_callback *nc;
 304        struct netlink_ext_ack extack;
 305        LIST_HEAD(err_list);
 306        u32 status;
 307        int err;
 308
 309        if (subsys_id >= NFNL_SUBSYS_COUNT)
 310                return netlink_ack(skb, nlh, -EINVAL, NULL);
 311replay:
 312        status = 0;
 313
 314        skb = netlink_skb_clone(oskb, GFP_KERNEL);
 315        if (!skb)
 316                return netlink_ack(oskb, nlh, -ENOMEM, NULL);
 317
 318        nfnl_lock(subsys_id);
 319        ss = nfnl_dereference_protected(subsys_id);
 320        if (!ss) {
 321#ifdef CONFIG_MODULES
 322                nfnl_unlock(subsys_id);
 323                request_module("nfnetlink-subsys-%d", subsys_id);
 324                nfnl_lock(subsys_id);
 325                ss = nfnl_dereference_protected(subsys_id);
 326                if (!ss)
 327#endif
 328                {
 329                        nfnl_unlock(subsys_id);
 330                        netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
 331                        return kfree_skb(skb);
 332                }
 333        }
 334
 335        if (!ss->commit || !ss->abort) {
 336                nfnl_unlock(subsys_id);
 337                netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
 338                return kfree_skb(skb);
 339        }
 340
 341        if (genid && ss->valid_genid && !ss->valid_genid(net, genid)) {
 342                nfnl_unlock(subsys_id);
 343                netlink_ack(oskb, nlh, -ERESTART, NULL);
 344                return kfree_skb(skb);
 345        }
 346
 347        while (skb->len >= nlmsg_total_size(0)) {
 348                int msglen, type;
 349
 350                if (fatal_signal_pending(current)) {
 351                        nfnl_err_reset(&err_list);
 352                        err = -EINTR;
 353                        status = NFNL_BATCH_FAILURE;
 354                        goto done;
 355                }
 356
 357                memset(&extack, 0, sizeof(extack));
 358                nlh = nlmsg_hdr(skb);
 359                err = 0;
 360
 361                if (nlh->nlmsg_len < NLMSG_HDRLEN ||
 362                    skb->len < nlh->nlmsg_len ||
 363                    nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
 364                        nfnl_err_reset(&err_list);
 365                        status |= NFNL_BATCH_FAILURE;
 366                        goto done;
 367                }
 368
 369                /* Only requests are handled by the kernel */
 370                if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
 371                        err = -EINVAL;
 372                        goto ack;
 373                }
 374
 375                type = nlh->nlmsg_type;
 376                if (type == NFNL_MSG_BATCH_BEGIN) {
 377                        /* Malformed: Batch begin twice */
 378                        nfnl_err_reset(&err_list);
 379                        status |= NFNL_BATCH_FAILURE;
 380                        goto done;
 381                } else if (type == NFNL_MSG_BATCH_END) {
 382                        status |= NFNL_BATCH_DONE;
 383                        goto done;
 384                } else if (type < NLMSG_MIN_TYPE) {
 385                        err = -EINVAL;
 386                        goto ack;
 387                }
 388
 389                /* We only accept a batch with messages for the same
 390                 * subsystem.
 391                 */
 392                if (NFNL_SUBSYS_ID(type) != subsys_id) {
 393                        err = -EINVAL;
 394                        goto ack;
 395                }
 396
 397                nc = nfnetlink_find_client(type, ss);
 398                if (!nc) {
 399                        err = -EINVAL;
 400                        goto ack;
 401                }
 402
 403                {
 404                        int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 405                        u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
 406                        struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
 407                        struct nlattr *attr = (void *)nlh + min_len;
 408                        int attrlen = nlh->nlmsg_len - min_len;
 409
 410                        /* Sanity-check NFTA_MAX_ATTR */
 411                        if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
 412                                err = -ENOMEM;
 413                                goto ack;
 414                        }
 415
 416                        err = nla_parse_deprecated(cda,
 417                                                   ss->cb[cb_id].attr_count,
 418                                                   attr, attrlen,
 419                                                   ss->cb[cb_id].policy, NULL);
 420                        if (err < 0)
 421                                goto ack;
 422
 423                        if (nc->call_batch) {
 424                                err = nc->call_batch(net, net->nfnl, skb, nlh,
 425                                                     (const struct nlattr **)cda,
 426                                                     &extack);
 427                        }
 428
 429                        /* The lock was released to autoload some module, we
 430                         * have to abort and start from scratch using the
 431                         * original skb.
 432                         */
 433                        if (err == -EAGAIN) {
 434                                status |= NFNL_BATCH_REPLAY;
 435                                goto done;
 436                        }
 437                }
 438ack:
 439                if (nlh->nlmsg_flags & NLM_F_ACK || err) {
 440                        /* Errors are delivered once the full batch has been
 441                         * processed, this avoids that the same error is
 442                         * reported several times when replaying the batch.
 443                         */
 444                        if (nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
 445                                /* We failed to enqueue an error, reset the
 446                                 * list of errors and send OOM to userspace
 447                                 * pointing to the batch header.
 448                                 */
 449                                nfnl_err_reset(&err_list);
 450                                netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM,
 451                                            NULL);
 452                                status |= NFNL_BATCH_FAILURE;
 453                                goto done;
 454                        }
 455                        /* We don't stop processing the batch on errors, thus,
 456                         * userspace gets all the errors that the batch
 457                         * triggers.
 458                         */
 459                        if (err)
 460                                status |= NFNL_BATCH_FAILURE;
 461                }
 462
 463                msglen = NLMSG_ALIGN(nlh->nlmsg_len);
 464                if (msglen > skb->len)
 465                        msglen = skb->len;
 466                skb_pull(skb, msglen);
 467        }
 468done:
 469        if (status & NFNL_BATCH_REPLAY) {
 470                const struct nfnetlink_subsystem *ss2;
 471
 472                ss2 = nfnl_dereference_protected(subsys_id);
 473                if (ss2 == ss)
 474                        ss->abort(net, oskb);
 475                nfnl_err_reset(&err_list);
 476                nfnl_unlock(subsys_id);
 477                kfree_skb(skb);
 478                goto replay;
 479        } else if (status == NFNL_BATCH_DONE) {
 480                err = ss->commit(net, oskb);
 481                if (err == -EAGAIN) {
 482                        status |= NFNL_BATCH_REPLAY;
 483                        goto done;
 484                } else if (err) {
 485                        ss->abort(net, oskb);
 486                        netlink_ack(oskb, nlmsg_hdr(oskb), err, NULL);
 487                }
 488        } else {
 489                ss->abort(net, oskb);
 490        }
 491        if (ss->cleanup)
 492                ss->cleanup(net);
 493
 494        nfnl_err_deliver(&err_list, oskb);
 495        nfnl_unlock(subsys_id);
 496        kfree_skb(skb);
 497}
 498
 499static const struct nla_policy nfnl_batch_policy[NFNL_BATCH_MAX + 1] = {
 500        [NFNL_BATCH_GENID]      = { .type = NLA_U32 },
 501};
 502
 503static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
 504{
 505        int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
 506        struct nlattr *attr = (void *)nlh + min_len;
 507        struct nlattr *cda[NFNL_BATCH_MAX + 1];
 508        int attrlen = nlh->nlmsg_len - min_len;
 509        struct nfgenmsg *nfgenmsg;
 510        int msglen, err;
 511        u32 gen_id = 0;
 512        u16 res_id;
 513
 514        msglen = NLMSG_ALIGN(nlh->nlmsg_len);
 515        if (msglen > skb->len)
 516                msglen = skb->len;
 517
 518        if (skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
 519                return;
 520
 521        err = nla_parse_deprecated(cda, NFNL_BATCH_MAX, attr, attrlen,
 522                                   nfnl_batch_policy, NULL);
 523        if (err < 0) {
 524                netlink_ack(skb, nlh, err, NULL);
 525                return;
 526        }
 527        if (cda[NFNL_BATCH_GENID])
 528                gen_id = ntohl(nla_get_be32(cda[NFNL_BATCH_GENID]));
 529
 530        nfgenmsg = nlmsg_data(nlh);
 531        skb_pull(skb, msglen);
 532        /* Work around old nft using host byte order */
 533        if (nfgenmsg->res_id == NFNL_SUBSYS_NFTABLES)
 534                res_id = NFNL_SUBSYS_NFTABLES;
 535        else
 536                res_id = ntohs(nfgenmsg->res_id);
 537
 538        nfnetlink_rcv_batch(skb, nlh, res_id, gen_id);
 539}
 540
 541static void nfnetlink_rcv(struct sk_buff *skb)
 542{
 543        struct nlmsghdr *nlh = nlmsg_hdr(skb);
 544
 545        if (skb->len < NLMSG_HDRLEN ||
 546            nlh->nlmsg_len < NLMSG_HDRLEN ||
 547            skb->len < nlh->nlmsg_len)
 548                return;
 549
 550        if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
 551                netlink_ack(skb, nlh, -EPERM, NULL);
 552                return;
 553        }
 554
 555        if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN)
 556                nfnetlink_rcv_skb_batch(skb, nlh);
 557        else
 558                netlink_rcv_skb(skb, nfnetlink_rcv_msg);
 559}
 560
 561#ifdef CONFIG_MODULES
 562static int nfnetlink_bind(struct net *net, int group)
 563{
 564        const struct nfnetlink_subsystem *ss;
 565        int type;
 566
 567        if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
 568                return 0;
 569
 570        type = nfnl_group2type[group];
 571
 572        rcu_read_lock();
 573        ss = nfnetlink_get_subsys(type << 8);
 574        rcu_read_unlock();
 575        if (!ss)
 576                request_module_nowait("nfnetlink-subsys-%d", type);
 577        return 0;
 578}
 579#endif
 580
 581static int __net_init nfnetlink_net_init(struct net *net)
 582{
 583        struct sock *nfnl;
 584        struct netlink_kernel_cfg cfg = {
 585                .groups = NFNLGRP_MAX,
 586                .input  = nfnetlink_rcv,
 587#ifdef CONFIG_MODULES
 588                .bind   = nfnetlink_bind,
 589#endif
 590        };
 591
 592        nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg);
 593        if (!nfnl)
 594                return -ENOMEM;
 595        net->nfnl_stash = nfnl;
 596        rcu_assign_pointer(net->nfnl, nfnl);
 597        return 0;
 598}
 599
 600static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
 601{
 602        struct net *net;
 603
 604        list_for_each_entry(net, net_exit_list, exit_list)
 605                RCU_INIT_POINTER(net->nfnl, NULL);
 606        synchronize_net();
 607        list_for_each_entry(net, net_exit_list, exit_list)
 608                netlink_kernel_release(net->nfnl_stash);
 609}
 610
 611static struct pernet_operations nfnetlink_net_ops = {
 612        .init           = nfnetlink_net_init,
 613        .exit_batch     = nfnetlink_net_exit_batch,
 614};
 615
 616static int __init nfnetlink_init(void)
 617{
 618        int i;
 619
 620        for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++)
 621                BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
 622
 623        for (i=0; i<NFNL_SUBSYS_COUNT; i++)
 624                mutex_init(&table[i].mutex);
 625
 626        return register_pernet_subsys(&nfnetlink_net_ops);
 627}
 628
 629static void __exit nfnetlink_exit(void)
 630{
 631        unregister_pernet_subsys(&nfnetlink_net_ops);
 632}
 633module_init(nfnetlink_init);
 634module_exit(nfnetlink_exit);
 635