~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/nf_conntrack_expect.c

Version: ~ [ linux-5.3 ] ~ [ linux-5.2.15 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.73 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.144 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.193 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.193 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.73 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp