x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / net / netfilter / nfnetlink_cthelper.c
1 /*
2  * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation (or any later at your option).
7  *
8  * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
9  */
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/skbuff.h>
14 #include <linux/netlink.h>
15 #include <linux/rculist.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <net/netlink.h>
21 #include <net/sock.h>
22
23 #include <net/netfilter/nf_conntrack_helper.h>
24 #include <net/netfilter/nf_conntrack_expect.h>
25 #include <net/netfilter/nf_conntrack_ecache.h>
26
27 #include <linux/netfilter/nfnetlink.h>
28 #include <linux/netfilter/nfnetlink_conntrack.h>
29 #include <linux/netfilter/nfnetlink_cthelper.h>
30
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
33 MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
34
35 static int
36 nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
37                         struct nf_conn *ct, enum ip_conntrack_info ctinfo)
38 {
39         const struct nf_conn_help *help;
40         struct nf_conntrack_helper *helper;
41
42         help = nfct_help(ct);
43         if (help == NULL)
44                 return NF_DROP;
45
46         /* rcu_read_lock()ed by nf_hook_thresh */
47         helper = rcu_dereference(help->helper);
48         if (helper == NULL)
49                 return NF_DROP;
50
51         /* This is an user-space helper not yet configured, skip. */
52         if ((helper->flags &
53             (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
54              NF_CT_HELPER_F_USERSPACE)
55                 return NF_ACCEPT;
56
57         /* If the user-space helper is not available, don't block traffic. */
58         return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
59 }
60
61 static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
62         [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
63         [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
64 };
65
66 static int
67 nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
68                           const struct nlattr *attr)
69 {
70         int err;
71         struct nlattr *tb[NFCTH_TUPLE_MAX+1];
72
73         err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol);
74         if (err < 0)
75                 return err;
76
77         if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
78                 return -EINVAL;
79
80         /* Not all fields are initialized so first zero the tuple */
81         memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
82
83         tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
84         tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
85
86         return 0;
87 }
88
89 static int
90 nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
91 {
92         struct nf_conn_help *help = nfct_help(ct);
93
94         if (attr == NULL)
95                 return -EINVAL;
96
97         if (help->helper->data_len == 0)
98                 return -EINVAL;
99
100         memcpy(help->data, nla_data(attr), help->helper->data_len);
101         return 0;
102 }
103
104 static int
105 nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
106 {
107         const struct nf_conn_help *help = nfct_help(ct);
108
109         if (help->helper->data_len &&
110             nla_put(skb, CTA_HELP_INFO, help->helper->data_len, &help->data))
111                 goto nla_put_failure;
112
113         return 0;
114
115 nla_put_failure:
116         return -ENOSPC;
117 }
118
119 static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
120         [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
121                                 .len = NF_CT_HELPER_NAME_LEN-1 },
122         [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
123         [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
124 };
125
126 static int
127 nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
128                             const struct nlattr *attr)
129 {
130         int err;
131         struct nlattr *tb[NFCTH_POLICY_MAX+1];
132
133         err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol);
134         if (err < 0)
135                 return err;
136
137         if (!tb[NFCTH_POLICY_NAME] ||
138             !tb[NFCTH_POLICY_EXPECT_MAX] ||
139             !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
140                 return -EINVAL;
141
142         strncpy(expect_policy->name,
143                 nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN);
144         expect_policy->max_expected =
145                 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
146         expect_policy->timeout =
147                 ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
148
149         return 0;
150 }
151
152 static const struct nla_policy
153 nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
154         [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
155 };
156
157 static int
158 nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
159                                   const struct nlattr *attr)
160 {
161         int i, ret;
162         struct nf_conntrack_expect_policy *expect_policy;
163         struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
164
165         ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
166                                nfnl_cthelper_expect_policy_set);
167         if (ret < 0)
168                 return ret;
169
170         if (!tb[NFCTH_POLICY_SET_NUM])
171                 return -EINVAL;
172
173         helper->expect_class_max =
174                 ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
175
176         if (helper->expect_class_max != 0 &&
177             helper->expect_class_max > NF_CT_MAX_EXPECT_CLASSES)
178                 return -EOVERFLOW;
179
180         expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) *
181                                 helper->expect_class_max, GFP_KERNEL);
182         if (expect_policy == NULL)
183                 return -ENOMEM;
184
185         for (i=0; i<helper->expect_class_max; i++) {
186                 if (!tb[NFCTH_POLICY_SET+i])
187                         goto err;
188
189                 ret = nfnl_cthelper_expect_policy(&expect_policy[i],
190                                                   tb[NFCTH_POLICY_SET+i]);
191                 if (ret < 0)
192                         goto err;
193         }
194         helper->expect_policy = expect_policy;
195         return 0;
196 err:
197         kfree(expect_policy);
198         return -EINVAL;
199 }
200
201 static int
202 nfnl_cthelper_create(const struct nlattr * const tb[],
203                      struct nf_conntrack_tuple *tuple)
204 {
205         struct nf_conntrack_helper *helper;
206         int ret;
207
208         if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
209                 return -EINVAL;
210
211         helper = kzalloc(sizeof(struct nf_conntrack_helper), GFP_KERNEL);
212         if (helper == NULL)
213                 return -ENOMEM;
214
215         ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
216         if (ret < 0)
217                 goto err;
218
219         strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN);
220         helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
221         helper->flags |= NF_CT_HELPER_F_USERSPACE;
222         memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
223
224         helper->me = THIS_MODULE;
225         helper->help = nfnl_userspace_cthelper;
226         helper->from_nlattr = nfnl_cthelper_from_nlattr;
227         helper->to_nlattr = nfnl_cthelper_to_nlattr;
228
229         /* Default to queue number zero, this can be updated at any time. */
230         if (tb[NFCTH_QUEUE_NUM])
231                 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
232
233         if (tb[NFCTH_STATUS]) {
234                 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
235
236                 switch(status) {
237                 case NFCT_HELPER_STATUS_ENABLED:
238                         helper->flags |= NF_CT_HELPER_F_CONFIGURED;
239                         break;
240                 case NFCT_HELPER_STATUS_DISABLED:
241                         helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
242                         break;
243                 }
244         }
245
246         ret = nf_conntrack_helper_register(helper);
247         if (ret < 0)
248                 goto err;
249
250         return 0;
251 err:
252         kfree(helper);
253         return ret;
254 }
255
256 static int
257 nfnl_cthelper_update(const struct nlattr * const tb[],
258                      struct nf_conntrack_helper *helper)
259 {
260         int ret;
261
262         if (tb[NFCTH_PRIV_DATA_LEN])
263                 return -EBUSY;
264
265         if (tb[NFCTH_POLICY]) {
266                 ret = nfnl_cthelper_parse_expect_policy(helper,
267                                                         tb[NFCTH_POLICY]);
268                 if (ret < 0)
269                         return ret;
270         }
271         if (tb[NFCTH_QUEUE_NUM])
272                 helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
273
274         if (tb[NFCTH_STATUS]) {
275                 int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
276
277                 switch(status) {
278                 case NFCT_HELPER_STATUS_ENABLED:
279                         helper->flags |= NF_CT_HELPER_F_CONFIGURED;
280                         break;
281                 case NFCT_HELPER_STATUS_DISABLED:
282                         helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
283                         break;
284                 }
285         }
286         return 0;
287 }
288
289 static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
290                              struct sk_buff *skb, const struct nlmsghdr *nlh,
291                              const struct nlattr * const tb[])
292 {
293         const char *helper_name;
294         struct nf_conntrack_helper *cur, *helper = NULL;
295         struct nf_conntrack_tuple tuple;
296         int ret = 0, i;
297
298         if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
299                 return -EINVAL;
300
301         helper_name = nla_data(tb[NFCTH_NAME]);
302
303         ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
304         if (ret < 0)
305                 return ret;
306
307         rcu_read_lock();
308         for (i = 0; i < nf_ct_helper_hsize && !helper; i++) {
309                 hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) {
310
311                         /* skip non-userspace conntrack helpers. */
312                         if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
313                                 continue;
314
315                         if (strncmp(cur->name, helper_name,
316                                         NF_CT_HELPER_NAME_LEN) != 0)
317                                 continue;
318
319                         if ((tuple.src.l3num != cur->tuple.src.l3num ||
320                              tuple.dst.protonum != cur->tuple.dst.protonum))
321                                 continue;
322
323                         if (nlh->nlmsg_flags & NLM_F_EXCL) {
324                                 ret = -EEXIST;
325                                 goto err;
326                         }
327                         helper = cur;
328                         break;
329                 }
330         }
331         rcu_read_unlock();
332
333         if (helper == NULL)
334                 ret = nfnl_cthelper_create(tb, &tuple);
335         else
336                 ret = nfnl_cthelper_update(tb, helper);
337
338         return ret;
339 err:
340         rcu_read_unlock();
341         return ret;
342 }
343
344 static int
345 nfnl_cthelper_dump_tuple(struct sk_buff *skb,
346                          struct nf_conntrack_helper *helper)
347 {
348         struct nlattr *nest_parms;
349
350         nest_parms = nla_nest_start(skb, NFCTH_TUPLE | NLA_F_NESTED);
351         if (nest_parms == NULL)
352                 goto nla_put_failure;
353
354         if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
355                          htons(helper->tuple.src.l3num)))
356                 goto nla_put_failure;
357
358         if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
359                 goto nla_put_failure;
360
361         nla_nest_end(skb, nest_parms);
362         return 0;
363
364 nla_put_failure:
365         return -1;
366 }
367
368 static int
369 nfnl_cthelper_dump_policy(struct sk_buff *skb,
370                         struct nf_conntrack_helper *helper)
371 {
372         int i;
373         struct nlattr *nest_parms1, *nest_parms2;
374
375         nest_parms1 = nla_nest_start(skb, NFCTH_POLICY | NLA_F_NESTED);
376         if (nest_parms1 == NULL)
377                 goto nla_put_failure;
378
379         if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
380                          htonl(helper->expect_class_max)))
381                 goto nla_put_failure;
382
383         for (i=0; i<helper->expect_class_max; i++) {
384                 nest_parms2 = nla_nest_start(skb,
385                                 (NFCTH_POLICY_SET+i) | NLA_F_NESTED);
386                 if (nest_parms2 == NULL)
387                         goto nla_put_failure;
388
389                 if (nla_put_string(skb, NFCTH_POLICY_NAME,
390                                    helper->expect_policy[i].name))
391                         goto nla_put_failure;
392
393                 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
394                                  htonl(helper->expect_policy[i].max_expected)))
395                         goto nla_put_failure;
396
397                 if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
398                                  htonl(helper->expect_policy[i].timeout)))
399                         goto nla_put_failure;
400
401                 nla_nest_end(skb, nest_parms2);
402         }
403         nla_nest_end(skb, nest_parms1);
404         return 0;
405
406 nla_put_failure:
407         return -1;
408 }
409
410 static int
411 nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
412                         int event, struct nf_conntrack_helper *helper)
413 {
414         struct nlmsghdr *nlh;
415         struct nfgenmsg *nfmsg;
416         unsigned int flags = portid ? NLM_F_MULTI : 0;
417         int status;
418
419         event |= NFNL_SUBSYS_CTHELPER << 8;
420         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
421         if (nlh == NULL)
422                 goto nlmsg_failure;
423
424         nfmsg = nlmsg_data(nlh);
425         nfmsg->nfgen_family = AF_UNSPEC;
426         nfmsg->version = NFNETLINK_V0;
427         nfmsg->res_id = 0;
428
429         if (nla_put_string(skb, NFCTH_NAME, helper->name))
430                 goto nla_put_failure;
431
432         if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
433                 goto nla_put_failure;
434
435         if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
436                 goto nla_put_failure;
437
438         if (nfnl_cthelper_dump_policy(skb, helper) < 0)
439                 goto nla_put_failure;
440
441         if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
442                 goto nla_put_failure;
443
444         if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
445                 status = NFCT_HELPER_STATUS_ENABLED;
446         else
447                 status = NFCT_HELPER_STATUS_DISABLED;
448
449         if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
450                 goto nla_put_failure;
451
452         nlmsg_end(skb, nlh);
453         return skb->len;
454
455 nlmsg_failure:
456 nla_put_failure:
457         nlmsg_cancel(skb, nlh);
458         return -1;
459 }
460
461 static int
462 nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
463 {
464         struct nf_conntrack_helper *cur, *last;
465
466         rcu_read_lock();
467         last = (struct nf_conntrack_helper *)cb->args[1];
468         for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
469 restart:
470                 hlist_for_each_entry_rcu(cur,
471                                 &nf_ct_helper_hash[cb->args[0]], hnode) {
472
473                         /* skip non-userspace conntrack helpers. */
474                         if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
475                                 continue;
476
477                         if (cb->args[1]) {
478                                 if (cur != last)
479                                         continue;
480                                 cb->args[1] = 0;
481                         }
482                         if (nfnl_cthelper_fill_info(skb,
483                                             NETLINK_CB(cb->skb).portid,
484                                             cb->nlh->nlmsg_seq,
485                                             NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
486                                             NFNL_MSG_CTHELPER_NEW, cur) < 0) {
487                                 cb->args[1] = (unsigned long)cur;
488                                 goto out;
489                         }
490                 }
491         }
492         if (cb->args[1]) {
493                 cb->args[1] = 0;
494                 goto restart;
495         }
496 out:
497         rcu_read_unlock();
498         return skb->len;
499 }
500
501 static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
502                              struct sk_buff *skb, const struct nlmsghdr *nlh,
503                              const struct nlattr * const tb[])
504 {
505         int ret = -ENOENT, i;
506         struct nf_conntrack_helper *cur;
507         struct sk_buff *skb2;
508         char *helper_name = NULL;
509         struct nf_conntrack_tuple tuple;
510         bool tuple_set = false;
511
512         if (nlh->nlmsg_flags & NLM_F_DUMP) {
513                 struct netlink_dump_control c = {
514                         .dump = nfnl_cthelper_dump_table,
515                 };
516                 return netlink_dump_start(nfnl, skb, nlh, &c);
517         }
518
519         if (tb[NFCTH_NAME])
520                 helper_name = nla_data(tb[NFCTH_NAME]);
521
522         if (tb[NFCTH_TUPLE]) {
523                 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
524                 if (ret < 0)
525                         return ret;
526
527                 tuple_set = true;
528         }
529
530         for (i = 0; i < nf_ct_helper_hsize; i++) {
531                 hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) {
532
533                         /* skip non-userspace conntrack helpers. */
534                         if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
535                                 continue;
536
537                         if (helper_name && strncmp(cur->name, helper_name,
538                                                 NF_CT_HELPER_NAME_LEN) != 0) {
539                                 continue;
540                         }
541                         if (tuple_set &&
542                             (tuple.src.l3num != cur->tuple.src.l3num ||
543                              tuple.dst.protonum != cur->tuple.dst.protonum))
544                                 continue;
545
546                         skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
547                         if (skb2 == NULL) {
548                                 ret = -ENOMEM;
549                                 break;
550                         }
551
552                         ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
553                                                 nlh->nlmsg_seq,
554                                                 NFNL_MSG_TYPE(nlh->nlmsg_type),
555                                                 NFNL_MSG_CTHELPER_NEW, cur);
556                         if (ret <= 0) {
557                                 kfree_skb(skb2);
558                                 break;
559                         }
560
561                         ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
562                                                 MSG_DONTWAIT);
563                         if (ret > 0)
564                                 ret = 0;
565
566                         /* this avoids a loop in nfnetlink. */
567                         return ret == -EAGAIN ? -ENOBUFS : ret;
568                 }
569         }
570         return ret;
571 }
572
573 static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
574                              struct sk_buff *skb, const struct nlmsghdr *nlh,
575                              const struct nlattr * const tb[])
576 {
577         char *helper_name = NULL;
578         struct nf_conntrack_helper *cur;
579         struct hlist_node *tmp;
580         struct nf_conntrack_tuple tuple;
581         bool tuple_set = false, found = false;
582         int i, j = 0, ret;
583
584         if (tb[NFCTH_NAME])
585                 helper_name = nla_data(tb[NFCTH_NAME]);
586
587         if (tb[NFCTH_TUPLE]) {
588                 ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
589                 if (ret < 0)
590                         return ret;
591
592                 tuple_set = true;
593         }
594
595         for (i = 0; i < nf_ct_helper_hsize; i++) {
596                 hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i],
597                                                                 hnode) {
598                         /* skip non-userspace conntrack helpers. */
599                         if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
600                                 continue;
601
602                         j++;
603
604                         if (helper_name && strncmp(cur->name, helper_name,
605                                                 NF_CT_HELPER_NAME_LEN) != 0) {
606                                 continue;
607                         }
608                         if (tuple_set &&
609                             (tuple.src.l3num != cur->tuple.src.l3num ||
610                              tuple.dst.protonum != cur->tuple.dst.protonum))
611                                 continue;
612
613                         found = true;
614                         nf_conntrack_helper_unregister(cur);
615                 }
616         }
617         /* Make sure we return success if we flush and there is no helpers */
618         return (found || j == 0) ? 0 : -ENOENT;
619 }
620
621 static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
622         [NFCTH_NAME] = { .type = NLA_NUL_STRING,
623                          .len = NF_CT_HELPER_NAME_LEN-1 },
624         [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
625 };
626
627 static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
628         [NFNL_MSG_CTHELPER_NEW]         = { .call = nfnl_cthelper_new,
629                                             .attr_count = NFCTH_MAX,
630                                             .policy = nfnl_cthelper_policy },
631         [NFNL_MSG_CTHELPER_GET]         = { .call = nfnl_cthelper_get,
632                                             .attr_count = NFCTH_MAX,
633                                             .policy = nfnl_cthelper_policy },
634         [NFNL_MSG_CTHELPER_DEL]         = { .call = nfnl_cthelper_del,
635                                             .attr_count = NFCTH_MAX,
636                                             .policy = nfnl_cthelper_policy },
637 };
638
639 static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
640         .name                           = "cthelper",
641         .subsys_id                      = NFNL_SUBSYS_CTHELPER,
642         .cb_count                       = NFNL_MSG_CTHELPER_MAX,
643         .cb                             = nfnl_cthelper_cb,
644 };
645
646 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
647
648 static int __init nfnl_cthelper_init(void)
649 {
650         int ret;
651
652         ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
653         if (ret < 0) {
654                 pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
655                 goto err_out;
656         }
657         return 0;
658 err_out:
659         return ret;
660 }
661
662 static void __exit nfnl_cthelper_exit(void)
663 {
664         struct nf_conntrack_helper *cur;
665         struct hlist_node *tmp;
666         int i;
667
668         nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
669
670         for (i=0; i<nf_ct_helper_hsize; i++) {
671                 hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i],
672                                                                         hnode) {
673                         /* skip non-userspace conntrack helpers. */
674                         if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
675                                 continue;
676
677                         nf_conntrack_helper_unregister(cur);
678                 }
679         }
680 }
681
682 module_init(nfnl_cthelper_init);
683 module_exit(nfnl_cthelper_exit);