linux/net/netfilter/nf_conntrack_expect.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Expectation handling for nf_conntrack. */
   3
   4/* (C) 1999-2001 Paul `Rusty' Russell
   5 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   6 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
   7 * (c) 2005-2012 Patrick McHardy <kaber@trash.net>
   8 */
   9
  10#include <linux/types.h>
  11#include <linux/netfilter.h>
  12#include <linux/skbuff.h>
  13#include <linux/proc_fs.h>
  14#include <linux/seq_file.h>
  15#include <linux/stddef.h>
  16#include <linux/slab.h>
  17#include <linux/err.h>
  18#include <linux/percpu.h>
  19#include <linux/kernel.h>
  20#include <linux/jhash.h>
  21#include <linux/moduleparam.h>
  22#include <linux/export.h>
  23#include <net/net_namespace.h>
  24#include <net/netns/hash.h>
  25
  26#include <net/netfilter/nf_conntrack.h>
  27#include <net/netfilter/nf_conntrack_core.h>
  28#include <net/netfilter/nf_conntrack_ecache.h>
  29#include <net/netfilter/nf_conntrack_expect.h>
  30#include <net/netfilter/nf_conntrack_helper.h>
  31#include <net/netfilter/nf_conntrack_l4proto.h>
  32#include <net/netfilter/nf_conntrack_tuple.h>
  33#include <net/netfilter/nf_conntrack_zones.h>
  34
  35unsigned int nf_ct_expect_hsize __read_mostly;
  36EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
  37
  38struct hlist_head *nf_ct_expect_hash __read_mostly;
  39EXPORT_SYMBOL_GPL(nf_ct_expect_hash);
  40
  41unsigned int nf_ct_expect_max __read_mostly;
  42
  43static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
  44static unsigned int nf_ct_expect_hashrnd __read_mostly;
  45
  46/* nf_conntrack_expect helper functions */
  47void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
  48                                u32 portid, int report)
  49{
  50        struct nf_conn_help *master_help = nfct_help(exp->master);
  51        struct net *net = nf_ct_exp_net(exp);
  52
  53        WARN_ON(!master_help);
  54        WARN_ON(timer_pending(&exp->timeout));
  55
  56        hlist_del_rcu(&exp->hnode);
  57        net->ct.expect_count--;
  58
  59        hlist_del_rcu(&exp->lnode);
  60        master_help->expecting[exp->class]--;
  61
  62        nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
  63        nf_ct_expect_put(exp);
  64
  65        NF_CT_STAT_INC(net, expect_delete);
  66}
  67EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report);
  68
  69static void nf_ct_expectation_timed_out(struct timer_list *t)
  70{
  71        struct nf_conntrack_expect *exp = from_timer(exp, t, timeout);
  72
  73        spin_lock_bh(&nf_conntrack_expect_lock);
  74        nf_ct_unlink_expect(exp);
  75        spin_unlock_bh(&nf_conntrack_expect_lock);
  76        nf_ct_expect_put(exp);
  77}
  78
  79static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struct nf_conntrack_tuple *tuple)
  80{
  81        unsigned int hash, seed;
  82
  83        get_random_once(&nf_ct_expect_hashrnd, sizeof(nf_ct_expect_hashrnd));
  84
  85        seed = nf_ct_expect_hashrnd ^ net_hash_mix(n);
  86
  87        hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
  88                      (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
  89                       (__force __u16)tuple->dst.u.all) ^ seed);
  90
  91        return reciprocal_scale(hash, nf_ct_expect_hsize);
  92}
  93
  94static bool
  95nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
  96                const struct nf_conntrack_expect *i,
  97                const struct nf_conntrack_zone *zone,
  98                const struct net *net)
  99{
 100        return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
 101               net_eq(net, nf_ct_net(i->master)) &&
 102               nf_ct_zone_equal_any(i->master, zone);
 103}
 104
 105bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
 106{
 107        if (del_timer(&exp->timeout)) {
 108                nf_ct_unlink_expect(exp);
 109                nf_ct_expect_put(exp);
 110                return true;
 111        }
 112        return false;
 113}
 114EXPORT_SYMBOL_GPL(nf_ct_remove_expect);
 115
 116struct nf_conntrack_expect *
 117__nf_ct_expect_find(struct net *net,
 118                    const struct nf_conntrack_zone *zone,
 119                    const struct nf_conntrack_tuple *tuple)
 120{
 121        struct nf_conntrack_expect *i;
 122        unsigned int h;
 123
 124        if (!net->ct.expect_count)
 125                return NULL;
 126
 127        h = nf_ct_expect_dst_hash(net, tuple);
 128        hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) {
 129                if (nf_ct_exp_equal(tuple, i, zone, net))
 130                        return i;
 131        }
 132        return NULL;
 133}
 134EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
 135
 136/* Just find a expectation corresponding to a tuple. */
 137struct nf_conntrack_expect *
 138nf_ct_expect_find_get(struct net *net,
 139                      const struct nf_conntrack_zone *zone,
 140                      const struct nf_conntrack_tuple *tuple)
 141{
 142        struct nf_conntrack_expect *i;
 143
 144        rcu_read_lock();
 145        i = __nf_ct_expect_find(net, zone, tuple);
 146        if (i && !refcount_inc_not_zero(&i->use))
 147                i = NULL;
 148        rcu_read_unlock();
 149
 150        return i;
 151}
 152EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
 153
 154/* If an expectation for this connection is found, it gets delete from
 155 * global list then returned. */
 156struct nf_conntrack_expect *
 157nf_ct_find_expectation(struct net *net,
 158                       const struct nf_conntrack_zone *zone,
 159                       const struct nf_conntrack_tuple *tuple)
 160{
 161        struct nf_conntrack_expect *i, *exp = NULL;
 162        unsigned int h;
 163
 164        if (!net->ct.expect_count)
 165                return NULL;
 166
 167        h = nf_ct_expect_dst_hash(net, tuple);
 168        hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) {
 169                if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
 170                    nf_ct_exp_equal(tuple, i, zone, net)) {
 171                        exp = i;
 172                        break;
 173                }
 174        }
 175        if (!exp)
 176                return NULL;
 177
 178        /* If master is not in hash table yet (ie. packet hasn't left
 179           this machine yet), how can other end know about expected?
 180           Hence these are not the droids you are looking for (if
 181           master ct never got confirmed, we'd hold a reference to it
 182           and weird things would happen to future packets). */
 183        if (!nf_ct_is_confirmed(exp->master))
 184                return NULL;
 185
 186        /* Avoid race with other CPUs, that for exp->master ct, is
 187         * about to invoke ->destroy(), or nf_ct_delete() via timeout
 188         * or early_drop().
 189         *
 190         * The atomic_inc_not_zero() check tells:  If that fails, we
 191         * know that the ct is being destroyed.  If it succeeds, we
 192         * can be sure the ct cannot disappear underneath.
 193         */
 194        if (unlikely(nf_ct_is_dying(exp->master) ||
 195                     !atomic_inc_not_zero(&exp->master->ct_general.use)))
 196                return NULL;
 197
 198        if (exp->flags & NF_CT_EXPECT_PERMANENT) {
 199                refcount_inc(&exp->use);
 200                return exp;
 201        } else if (del_timer(&exp->timeout)) {
 202                nf_ct_unlink_expect(exp);
 203                return exp;
 204        }
 205        /* Undo exp->master refcnt increase, if del_timer() failed */
 206        nf_ct_put(exp->master);
 207
 208        return NULL;
 209}
 210
 211/* delete all expectations for this conntrack */
 212void nf_ct_remove_expectations(struct nf_conn *ct)
 213{
 214        struct nf_conn_help *help = nfct_help(ct);
 215        struct nf_conntrack_expect *exp;
 216        struct hlist_node *next;
 217
 218        /* Optimization: most connection never expect any others. */
 219        if (!help)
 220                return;
 221
 222        spin_lock_bh(&nf_conntrack_expect_lock);
 223        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
 224                nf_ct_remove_expect(exp);
 225        }
 226        spin_unlock_bh(&nf_conntrack_expect_lock);
 227}
 228EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
 229
 230/* Would two expected things clash? */
 231static inline int expect_clash(const struct nf_conntrack_expect *a,
 232                               const struct nf_conntrack_expect *b)
 233{
 234        /* Part covered by intersection of masks must be unequal,
 235           otherwise they clash */
 236        struct nf_conntrack_tuple_mask intersect_mask;
 237        int count;
 238
 239        intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
 240
 241        for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
 242                intersect_mask.src.u3.all[count] =
 243                        a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
 244        }
 245
 246        return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask) &&
 247               net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
 248               nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
 249}
 250
 251static inline int expect_matches(const struct nf_conntrack_expect *a,
 252                                 const struct nf_conntrack_expect *b)
 253{
 254        return nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
 255               nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
 256               net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) &&
 257               nf_ct_zone_equal_any(a->master, nf_ct_zone(b->master));
 258}
 259
 260static bool master_matches(const struct nf_conntrack_expect *a,
 261                           const struct nf_conntrack_expect *b,
 262                           unsigned int flags)
 263{
 264        if (flags & NF_CT_EXP_F_SKIP_MASTER)
 265                return true;
 266
 267        return a->master == b->master;
 268}
 269
 270/* Generally a bad idea to call this: could have matched already. */
 271void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
 272{
 273        spin_lock_bh(&nf_conntrack_expect_lock);
 274        nf_ct_remove_expect(exp);
 275        spin_unlock_bh(&nf_conntrack_expect_lock);
 276}
 277EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
 278
 279/* We don't increase the master conntrack refcount for non-fulfilled
 280 * conntracks. During the conntrack destruction, the expectations are
 281 * always killed before the conntrack itself */
 282struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
 283{
 284        struct nf_conntrack_expect *new;
 285
 286        new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
 287        if (!new)
 288                return NULL;
 289
 290        new->master = me;
 291        refcount_set(&new->use, 1);
 292        return new;
 293}
 294EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
 295
 296void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
 297                       u_int8_t family,
 298                       const union nf_inet_addr *saddr,
 299                       const union nf_inet_addr *daddr,
 300                       u_int8_t proto, const __be16 *src, const __be16 *dst)
 301{
 302        int len;
 303
 304        if (family == AF_INET)
 305                len = 4;
 306        else
 307                len = 16;
 308
 309        exp->flags = 0;
 310        exp->class = class;
 311        exp->expectfn = NULL;
 312        exp->helper = NULL;
 313        exp->tuple.src.l3num = family;
 314        exp->tuple.dst.protonum = proto;
 315
 316        if (saddr) {
 317                memcpy(&exp->tuple.src.u3, saddr, len);
 318                if (sizeof(exp->tuple.src.u3) > len)
 319                        /* address needs to be cleared for nf_ct_tuple_equal */
 320                        memset((void *)&exp->tuple.src.u3 + len, 0x00,
 321                               sizeof(exp->tuple.src.u3) - len);
 322                memset(&exp->mask.src.u3, 0xFF, len);
 323                if (sizeof(exp->mask.src.u3) > len)
 324                        memset((void *)&exp->mask.src.u3 + len, 0x00,
 325                               sizeof(exp->mask.src.u3) - len);
 326        } else {
 327                memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
 328                memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
 329        }
 330
 331        if (src) {
 332                exp->tuple.src.u.all = *src;
 333                exp->mask.src.u.all = htons(0xFFFF);
 334        } else {
 335                exp->tuple.src.u.all = 0;
 336                exp->mask.src.u.all = 0;
 337        }
 338
 339        memcpy(&exp->tuple.dst.u3, daddr, len);
 340        if (sizeof(exp->tuple.dst.u3) > len)
 341                /* address needs to be cleared for nf_ct_tuple_equal */
 342                memset((void *)&exp->tuple.dst.u3 + len, 0x00,
 343                       sizeof(exp->tuple.dst.u3) - len);
 344
 345        exp->tuple.dst.u.all = *dst;
 346
 347#if IS_ENABLED(CONFIG_NF_NAT)
 348        memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
 349        memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
 350#endif
 351}
 352EXPORT_SYMBOL_GPL(nf_ct_expect_init);
 353
 354static void nf_ct_expect_free_rcu(struct rcu_head *head)
 355{
 356        struct nf_conntrack_expect *exp;
 357
 358        exp = container_of(head, struct nf_conntrack_expect, rcu);
 359        kmem_cache_free(nf_ct_expect_cachep, exp);
 360}
 361
 362void nf_ct_expect_put(struct nf_conntrack_expect *exp)
 363{
 364        if (refcount_dec_and_test(&exp->use))
 365                call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
 366}
 367EXPORT_SYMBOL_GPL(nf_ct_expect_put);
 368
 369static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
 370{
 371        struct nf_conn_help *master_help = nfct_help(exp->master);
 372        struct nf_conntrack_helper *helper;
 373        struct net *net = nf_ct_exp_net(exp);
 374        unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple);
 375
 376        /* two references : one for hash insert, one for the timer */
 377        refcount_add(2, &exp->use);
 378
 379        timer_setup(&exp->timeout, nf_ct_expectation_timed_out, 0);
 380        helper = rcu_dereference_protected(master_help->helper,
 381                                           lockdep_is_held(&nf_conntrack_expect_lock));
 382        if (helper) {
 383                exp->timeout.expires = jiffies +
 384                        helper->expect_policy[exp->class].timeout * HZ;
 385        }
 386        add_timer(&exp->timeout);
 387
 388        hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
 389        master_help->expecting[exp->class]++;
 390
 391        hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
 392        net->ct.expect_count++;
 393
 394        NF_CT_STAT_INC(net, expect_create);
 395}
 396
 397/* Race with expectations being used means we could have none to find; OK. */
 398static void evict_oldest_expect(struct nf_conn *master,
 399                                struct nf_conntrack_expect *new)
 400{
 401        struct nf_conn_help *master_help = nfct_help(master);
 402        struct nf_conntrack_expect *exp, *last = NULL;
 403
 404        hlist_for_each_entry(exp, &master_help->expectations, lnode) {
 405                if (exp->class == new->class)
 406                        last = exp;
 407        }
 408
 409        if (last)
 410                nf_ct_remove_expect(last);
 411}
 412
 413static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
 414                                       unsigned int flags)
 415{
 416        const struct nf_conntrack_expect_policy *p;
 417        struct nf_conntrack_expect *i;
 418        struct nf_conn *master = expect->master;
 419        struct nf_conn_help *master_help = nfct_help(master);
 420        struct nf_conntrack_helper *helper;
 421        struct net *net = nf_ct_exp_net(expect);
 422        struct hlist_node *next;
 423        unsigned int h;
 424        int ret = 0;
 425
 426        if (!master_help) {
 427                ret = -ESHUTDOWN;
 428                goto out;
 429        }
 430        h = nf_ct_expect_dst_hash(net, &expect->tuple);
 431        hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
 432                if (master_matches(i, expect, flags) &&
 433                    expect_matches(i, expect)) {
 434                        if (i->class != expect->class ||
 435                            i->master != expect->master)
 436                                return -EALREADY;
 437
 438                        if (nf_ct_remove_expect(i))
 439                                break;
 440                } else if (expect_clash(i, expect)) {
 441                        ret = -EBUSY;
 442                        goto out;
 443                }
 444        }
 445        /* Will be over limit? */
 446        helper = rcu_dereference_protected(master_help->helper,
 447                                           lockdep_is_held(&nf_conntrack_expect_lock));
 448        if (helper) {
 449                p = &helper->expect_policy[expect->class];
 450                if (p->max_expected &&
 451                    master_help->expecting[expect->class] >= p->max_expected) {
 452                        evict_oldest_expect(master, expect);
 453                        if (master_help->expecting[expect->class]
 454                                                >= p->max_expected) {
 455                                ret = -EMFILE;
 456                                goto out;
 457                        }
 458                }
 459        }
 460
 461        if (net->ct.expect_count >= nf_ct_expect_max) {
 462                net_warn_ratelimited("nf_conntrack: expectation table full\n");
 463                ret = -EMFILE;
 464        }
 465out:
 466        return ret;
 467}
 468
 469int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
 470                                u32 portid, int report, unsigned int flags)
 471{
 472        int ret;
 473
 474        spin_lock_bh(&nf_conntrack_expect_lock);
 475        ret = __nf_ct_expect_check(expect, flags);
 476        if (ret < 0)
 477                goto out;
 478
 479        nf_ct_expect_insert(expect);
 480
 481        spin_unlock_bh(&nf_conntrack_expect_lock);
 482        nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
 483        return 0;
 484out:
 485        spin_unlock_bh(&nf_conntrack_expect_lock);
 486        return ret;
 487}
 488EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
 489
 490void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
 491                                  void *data)
 492{
 493        struct nf_conntrack_expect *exp;
 494        const struct hlist_node *next;
 495        unsigned int i;
 496
 497        spin_lock_bh(&nf_conntrack_expect_lock);
 498
 499        for (i = 0; i < nf_ct_expect_hsize; i++) {
 500                hlist_for_each_entry_safe(exp, next,
 501                                          &nf_ct_expect_hash[i],
 502                                          hnode) {
 503                        if (iter(exp, data) && del_timer(&exp->timeout)) {
 504                                nf_ct_unlink_expect(exp);
 505                                nf_ct_expect_put(exp);
 506                        }
 507                }
 508        }
 509
 510        spin_unlock_bh(&nf_conntrack_expect_lock);
 511}
 512EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_destroy);
 513
 514void nf_ct_expect_iterate_net(struct net *net,
 515                              bool (*iter)(struct nf_conntrack_expect *e, void *data),
 516                              void *data,
 517                              u32 portid, int report)
 518{
 519        struct nf_conntrack_expect *exp;
 520        const struct hlist_node *next;
 521        unsigned int i;
 522
 523        spin_lock_bh(&nf_conntrack_expect_lock);
 524
 525        for (i = 0; i < nf_ct_expect_hsize; i++) {
 526                hlist_for_each_entry_safe(exp, next,
 527                                          &nf_ct_expect_hash[i],
 528                                          hnode) {
 529
 530                        if (!net_eq(nf_ct_exp_net(exp), net))
 531                                continue;
 532
 533                        if (iter(exp, data) && del_timer(&exp->timeout)) {
 534                                nf_ct_unlink_expect_report(exp, portid, report);
 535                                nf_ct_expect_put(exp);
 536                        }
 537                }
 538        }
 539
 540        spin_unlock_bh(&nf_conntrack_expect_lock);
 541}
 542EXPORT_SYMBOL_GPL(nf_ct_expect_iterate_net);
 543
 544#ifdef CONFIG_NF_CONNTRACK_PROCFS
 545struct ct_expect_iter_state {
 546        struct seq_net_private p;
 547        unsigned int bucket;
 548};
 549
 550static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
 551{
 552        struct ct_expect_iter_state *st = seq->private;
 553        struct hlist_node *n;
 554
 555        for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
 556                n = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
 557                if (n)
 558                        return n;
 559        }
 560        return NULL;
 561}
 562
 563static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
 564                                             struct hlist_node *head)
 565{
 566        struct ct_expect_iter_state *st = seq->private;
 567
 568        head = rcu_dereference(hlist_next_rcu(head));
 569        while (head == NULL) {
 570                if (++st->bucket >= nf_ct_expect_hsize)
 571                        return NULL;
 572                head = rcu_dereference(hlist_first_rcu(&nf_ct_expect_hash[st->bucket]));
 573        }
 574        return head;
 575}
 576
 577static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
 578{
 579        struct hlist_node *head = ct_expect_get_first(seq);
 580
 581        if (head)
 582                while (pos && (head = ct_expect_get_next(seq, head)))
 583                        pos--;
 584        return pos ? NULL : head;
 585}
 586
 587static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
 588        __acquires(RCU)
 589{
 590        rcu_read_lock();
 591        return ct_expect_get_idx(seq, *pos);
 592}
 593
 594static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 595{
 596        (*pos)++;
 597        return ct_expect_get_next(seq, v);
 598}
 599
 600static void exp_seq_stop(struct seq_file *seq, void *v)
 601        __releases(RCU)
 602{
 603        rcu_read_unlock();
 604}
 605
 606static int exp_seq_show(struct seq_file *s, void *v)
 607{
 608        struct nf_conntrack_expect *expect;
 609        struct nf_conntrack_helper *helper;
 610        struct hlist_node *n = v;
 611        char *delim = "";
 612
 613        expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
 614
 615        if (expect->timeout.function)
 616                seq_printf(s, "%ld ", timer_pending(&expect->timeout)
 617                           ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
 618        else
 619                seq_puts(s, "- ");
 620        seq_printf(s, "l3proto = %u proto=%u ",
 621                   expect->tuple.src.l3num,
 622                   expect->tuple.dst.protonum);
 623        print_tuple(s, &expect->tuple,
 624                    nf_ct_l4proto_find(expect->tuple.dst.protonum));
 625
 626        if (expect->flags & NF_CT_EXPECT_PERMANENT) {
 627                seq_puts(s, "PERMANENT");
 628                delim = ",";
 629        }
 630        if (expect->flags & NF_CT_EXPECT_INACTIVE) {
 631                seq_printf(s, "%sINACTIVE", delim);
 632                delim = ",";
 633        }
 634        if (expect->flags & NF_CT_EXPECT_USERSPACE)
 635                seq_printf(s, "%sUSERSPACE", delim);
 636
 637        helper = rcu_dereference(nfct_help(expect->master)->helper);
 638        if (helper) {
 639                seq_printf(s, "%s%s", expect->flags ? " " : "", helper->name);
 640                if (helper->expect_policy[expect->class].name[0])
 641                        seq_printf(s, "/%s",
 642                                   helper->expect_policy[expect->class].name);
 643        }
 644
 645        seq_putc(s, '\n');
 646
 647        return 0;
 648}
 649
 650static const struct seq_operations exp_seq_ops = {
 651        .start = exp_seq_start,
 652        .next = exp_seq_next,
 653        .stop = exp_seq_stop,
 654        .show = exp_seq_show
 655};
 656#endif /* CONFIG_NF_CONNTRACK_PROCFS */
 657
 658static int exp_proc_init(struct net *net)
 659{
 660#ifdef CONFIG_NF_CONNTRACK_PROCFS
 661        struct proc_dir_entry *proc;
 662        kuid_t root_uid;
 663        kgid_t root_gid;
 664
 665        proc = proc_create_net("nf_conntrack_expect", 0440, net->proc_net,
 666                        &exp_seq_ops, sizeof(struct ct_expect_iter_state));
 667        if (!proc)
 668                return -ENOMEM;
 669
 670        root_uid = make_kuid(net->user_ns, 0);
 671        root_gid = make_kgid(net->user_ns, 0);
 672        if (uid_valid(root_uid) && gid_valid(root_gid))
 673                proc_set_user(proc, root_uid, root_gid);
 674#endif /* CONFIG_NF_CONNTRACK_PROCFS */
 675        return 0;
 676}
 677
 678static void exp_proc_remove(struct net *net)
 679{
 680#ifdef CONFIG_NF_CONNTRACK_PROCFS
 681        remove_proc_entry("nf_conntrack_expect", net->proc_net);
 682#endif /* CONFIG_NF_CONNTRACK_PROCFS */
 683}
 684
 685module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
 686
 687int nf_conntrack_expect_pernet_init(struct net *net)
 688{
 689        net->ct.expect_count = 0;
 690        return exp_proc_init(net);
 691}
 692
 693void nf_conntrack_expect_pernet_fini(struct net *net)
 694{
 695        exp_proc_remove(net);
 696}
 697
 698int nf_conntrack_expect_init(void)
 699{
 700        if (!nf_ct_expect_hsize) {
 701                nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
 702                if (!nf_ct_expect_hsize)
 703                        nf_ct_expect_hsize = 1;
 704        }
 705        nf_ct_expect_max = nf_ct_expect_hsize * 4;
 706        nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
 707                                sizeof(struct nf_conntrack_expect),
 708                                0, 0, NULL);
 709        if (!nf_ct_expect_cachep)
 710                return -ENOMEM;
 711
 712        nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0);
 713        if (!nf_ct_expect_hash) {
 714                kmem_cache_destroy(nf_ct_expect_cachep);
 715                return -ENOMEM;
 716        }
 717
 718        return 0;
 719}
 720
 721void nf_conntrack_expect_fini(void)
 722{
 723        rcu_barrier(); /* Wait for call_rcu() before destroy */
 724        kmem_cache_destroy(nf_ct_expect_cachep);
 725        kvfree(nf_ct_expect_hash);
 726}
 727