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