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

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

Version: ~ [ linux-5.7 ] ~ [ linux-5.6.15 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.43 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.125 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.182 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.225 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.225 ] ~ [ 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.84 ] ~ [ 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-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 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
  4  * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
  5  */
  6 #include <linux/init.h>
  7 #include <linux/module.h>
  8 #include <linux/kernel.h>
  9 #include <linux/rculist.h>
 10 #include <linux/rculist_nulls.h>
 11 #include <linux/types.h>
 12 #include <linux/timer.h>
 13 #include <linux/security.h>
 14 #include <linux/skbuff.h>
 15 #include <linux/errno.h>
 16 #include <linux/netlink.h>
 17 #include <linux/spinlock.h>
 18 #include <linux/interrupt.h>
 19 #include <linux/slab.h>
 20 
 21 #include <linux/netfilter.h>
 22 #include <net/netlink.h>
 23 #include <net/sock.h>
 24 #include <net/netfilter/nf_conntrack.h>
 25 #include <net/netfilter/nf_conntrack_core.h>
 26 #include <net/netfilter/nf_conntrack_l4proto.h>
 27 #include <net/netfilter/nf_conntrack_tuple.h>
 28 #include <net/netfilter/nf_conntrack_timeout.h>
 29 
 30 #include <linux/netfilter/nfnetlink.h>
 31 #include <linux/netfilter/nfnetlink_cttimeout.h>
 32 
 33 MODULE_LICENSE("GPL");
 34 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
 35 MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
 36 
 37 static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
 38         [CTA_TIMEOUT_NAME]      = { .type = NLA_NUL_STRING,
 39                                     .len  = CTNL_TIMEOUT_NAME_MAX - 1},
 40         [CTA_TIMEOUT_L3PROTO]   = { .type = NLA_U16 },
 41         [CTA_TIMEOUT_L4PROTO]   = { .type = NLA_U8 },
 42         [CTA_TIMEOUT_DATA]      = { .type = NLA_NESTED },
 43 };
 44 
 45 static int
 46 ctnl_timeout_parse_policy(void *timeout,
 47                           const struct nf_conntrack_l4proto *l4proto,
 48                           struct net *net, const struct nlattr *attr)
 49 {
 50         struct nlattr **tb;
 51         int ret = 0;
 52 
 53         tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb),
 54                      GFP_KERNEL);
 55 
 56         if (!tb)
 57                 return -ENOMEM;
 58 
 59         ret = nla_parse_nested_deprecated(tb,
 60                                           l4proto->ctnl_timeout.nlattr_max,
 61                                           attr,
 62                                           l4proto->ctnl_timeout.nla_policy,
 63                                           NULL);
 64         if (ret < 0)
 65                 goto err;
 66 
 67         ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeout);
 68 
 69 err:
 70         kfree(tb);
 71         return ret;
 72 }
 73 
 74 static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
 75                                  struct sk_buff *skb,
 76                                  const struct nlmsghdr *nlh,
 77                                  const struct nlattr * const cda[],
 78                                  struct netlink_ext_ack *extack)
 79 {
 80         __u16 l3num;
 81         __u8 l4num;
 82         const struct nf_conntrack_l4proto *l4proto;
 83         struct ctnl_timeout *timeout, *matching = NULL;
 84         char *name;
 85         int ret;
 86 
 87         if (!cda[CTA_TIMEOUT_NAME] ||
 88             !cda[CTA_TIMEOUT_L3PROTO] ||
 89             !cda[CTA_TIMEOUT_L4PROTO] ||
 90             !cda[CTA_TIMEOUT_DATA])
 91                 return -EINVAL;
 92 
 93         name = nla_data(cda[CTA_TIMEOUT_NAME]);
 94         l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
 95         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
 96 
 97         list_for_each_entry(timeout, &net->nfct_timeout_list, head) {
 98                 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
 99                         continue;
100 
101                 if (nlh->nlmsg_flags & NLM_F_EXCL)
102                         return -EEXIST;
103 
104                 matching = timeout;
105                 break;
106         }
107 
108         if (matching) {
109                 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
110                         /* You cannot replace one timeout policy by another of
111                          * different kind, sorry.
112                          */
113                         if (matching->timeout.l3num != l3num ||
114                             matching->timeout.l4proto->l4proto != l4num)
115                                 return -EINVAL;
116 
117                         return ctnl_timeout_parse_policy(&matching->timeout.data,
118                                                          matching->timeout.l4proto,
119                                                          net, cda[CTA_TIMEOUT_DATA]);
120                 }
121 
122                 return -EBUSY;
123         }
124 
125         l4proto = nf_ct_l4proto_find(l4num);
126 
127         /* This protocol is not supportted, skip. */
128         if (l4proto->l4proto != l4num) {
129                 ret = -EOPNOTSUPP;
130                 goto err_proto_put;
131         }
132 
133         timeout = kzalloc(sizeof(struct ctnl_timeout) +
134                           l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
135         if (timeout == NULL) {
136                 ret = -ENOMEM;
137                 goto err_proto_put;
138         }
139 
140         ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto, net,
141                                         cda[CTA_TIMEOUT_DATA]);
142         if (ret < 0)
143                 goto err;
144 
145         strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
146         timeout->timeout.l3num = l3num;
147         timeout->timeout.l4proto = l4proto;
148         refcount_set(&timeout->refcnt, 1);
149         list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list);
150 
151         return 0;
152 err:
153         kfree(timeout);
154 err_proto_put:
155         return ret;
156 }
157 
158 static int
159 ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
160                        int event, struct ctnl_timeout *timeout)
161 {
162         struct nlmsghdr *nlh;
163         struct nfgenmsg *nfmsg;
164         unsigned int flags = portid ? NLM_F_MULTI : 0;
165         const struct nf_conntrack_l4proto *l4proto = timeout->timeout.l4proto;
166         struct nlattr *nest_parms;
167         int ret;
168 
169         event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
170         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
171         if (nlh == NULL)
172                 goto nlmsg_failure;
173 
174         nfmsg = nlmsg_data(nlh);
175         nfmsg->nfgen_family = AF_UNSPEC;
176         nfmsg->version = NFNETLINK_V0;
177         nfmsg->res_id = 0;
178 
179         if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
180             nla_put_be16(skb, CTA_TIMEOUT_L3PROTO,
181                          htons(timeout->timeout.l3num)) ||
182             nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto) ||
183             nla_put_be32(skb, CTA_TIMEOUT_USE,
184                          htonl(refcount_read(&timeout->refcnt))))
185                 goto nla_put_failure;
186 
187         nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
188         if (!nest_parms)
189                 goto nla_put_failure;
190 
191         ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->timeout.data);
192         if (ret < 0)
193                 goto nla_put_failure;
194 
195         nla_nest_end(skb, nest_parms);
196 
197         nlmsg_end(skb, nlh);
198         return skb->len;
199 
200 nlmsg_failure:
201 nla_put_failure:
202         nlmsg_cancel(skb, nlh);
203         return -1;
204 }
205 
206 static int
207 ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
208 {
209         struct net *net = sock_net(skb->sk);
210         struct ctnl_timeout *cur, *last;
211 
212         if (cb->args[2])
213                 return 0;
214 
215         last = (struct ctnl_timeout *)cb->args[1];
216         if (cb->args[1])
217                 cb->args[1] = 0;
218 
219         rcu_read_lock();
220         list_for_each_entry_rcu(cur, &net->nfct_timeout_list, head) {
221                 if (last) {
222                         if (cur != last)
223                                 continue;
224 
225                         last = NULL;
226                 }
227                 if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid,
228                                            cb->nlh->nlmsg_seq,
229                                            NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
230                                            IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) {
231                         cb->args[1] = (unsigned long)cur;
232                         break;
233                 }
234         }
235         if (!cb->args[1])
236                 cb->args[2] = 1;
237         rcu_read_unlock();
238         return skb->len;
239 }
240 
241 static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
242                                  struct sk_buff *skb,
243                                  const struct nlmsghdr *nlh,
244                                  const struct nlattr * const cda[],
245                                  struct netlink_ext_ack *extack)
246 {
247         int ret = -ENOENT;
248         char *name;
249         struct ctnl_timeout *cur;
250 
251         if (nlh->nlmsg_flags & NLM_F_DUMP) {
252                 struct netlink_dump_control c = {
253                         .dump = ctnl_timeout_dump,
254                 };
255                 return netlink_dump_start(ctnl, skb, nlh, &c);
256         }
257 
258         if (!cda[CTA_TIMEOUT_NAME])
259                 return -EINVAL;
260         name = nla_data(cda[CTA_TIMEOUT_NAME]);
261 
262         list_for_each_entry(cur, &net->nfct_timeout_list, head) {
263                 struct sk_buff *skb2;
264 
265                 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
266                         continue;
267 
268                 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
269                 if (skb2 == NULL) {
270                         ret = -ENOMEM;
271                         break;
272                 }
273 
274                 ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
275                                              nlh->nlmsg_seq,
276                                              NFNL_MSG_TYPE(nlh->nlmsg_type),
277                                              IPCTNL_MSG_TIMEOUT_NEW, cur);
278                 if (ret <= 0) {
279                         kfree_skb(skb2);
280                         break;
281                 }
282                 ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid,
283                                         MSG_DONTWAIT);
284                 if (ret > 0)
285                         ret = 0;
286 
287                 /* this avoids a loop in nfnetlink. */
288                 return ret == -EAGAIN ? -ENOBUFS : ret;
289         }
290         return ret;
291 }
292 
293 /* try to delete object, fail if it is still in use. */
294 static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
295 {
296         int ret = 0;
297 
298         /* We want to avoid races with ctnl_timeout_put. So only when the
299          * current refcnt is 1, we decrease it to 0.
300          */
301         if (refcount_dec_if_one(&timeout->refcnt)) {
302                 /* We are protected by nfnl mutex. */
303                 list_del_rcu(&timeout->head);
304                 nf_ct_untimeout(net, &timeout->timeout);
305                 kfree_rcu(timeout, rcu_head);
306         } else {
307                 ret = -EBUSY;
308         }
309         return ret;
310 }
311 
312 static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
313                                  struct sk_buff *skb,
314                                  const struct nlmsghdr *nlh,
315                                  const struct nlattr * const cda[],
316                                  struct netlink_ext_ack *extack)
317 {
318         struct ctnl_timeout *cur, *tmp;
319         int ret = -ENOENT;
320         char *name;
321 
322         if (!cda[CTA_TIMEOUT_NAME]) {
323                 list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list,
324                                          head)
325                         ctnl_timeout_try_del(net, cur);
326 
327                 return 0;
328         }
329         name = nla_data(cda[CTA_TIMEOUT_NAME]);
330 
331         list_for_each_entry(cur, &net->nfct_timeout_list, head) {
332                 if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
333                         continue;
334 
335                 ret = ctnl_timeout_try_del(net, cur);
336                 if (ret < 0)
337                         return ret;
338 
339                 break;
340         }
341         return ret;
342 }
343 
344 static int cttimeout_default_set(struct net *net, struct sock *ctnl,
345                                  struct sk_buff *skb,
346                                  const struct nlmsghdr *nlh,
347                                  const struct nlattr * const cda[],
348                                  struct netlink_ext_ack *extack)
349 {
350         const struct nf_conntrack_l4proto *l4proto;
351         __u8 l4num;
352         int ret;
353 
354         if (!cda[CTA_TIMEOUT_L3PROTO] ||
355             !cda[CTA_TIMEOUT_L4PROTO] ||
356             !cda[CTA_TIMEOUT_DATA])
357                 return -EINVAL;
358 
359         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
360         l4proto = nf_ct_l4proto_find(l4num);
361 
362         /* This protocol is not supported, skip. */
363         if (l4proto->l4proto != l4num) {
364                 ret = -EOPNOTSUPP;
365                 goto err;
366         }
367 
368         ret = ctnl_timeout_parse_policy(NULL, l4proto, net,
369                                         cda[CTA_TIMEOUT_DATA]);
370         if (ret < 0)
371                 goto err;
372 
373         return 0;
374 err:
375         return ret;
376 }
377 
378 static int
379 cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
380                             u32 seq, u32 type, int event, u16 l3num,
381                             const struct nf_conntrack_l4proto *l4proto,
382                             const unsigned int *timeouts)
383 {
384         struct nlmsghdr *nlh;
385         struct nfgenmsg *nfmsg;
386         unsigned int flags = portid ? NLM_F_MULTI : 0;
387         struct nlattr *nest_parms;
388         int ret;
389 
390         event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
391         nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
392         if (nlh == NULL)
393                 goto nlmsg_failure;
394 
395         nfmsg = nlmsg_data(nlh);
396         nfmsg->nfgen_family = AF_UNSPEC;
397         nfmsg->version = NFNETLINK_V0;
398         nfmsg->res_id = 0;
399 
400         if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l3num)) ||
401             nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
402                 goto nla_put_failure;
403 
404         nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
405         if (!nest_parms)
406                 goto nla_put_failure;
407 
408         ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
409         if (ret < 0)
410                 goto nla_put_failure;
411 
412         nla_nest_end(skb, nest_parms);
413 
414         nlmsg_end(skb, nlh);
415         return skb->len;
416 
417 nlmsg_failure:
418 nla_put_failure:
419         nlmsg_cancel(skb, nlh);
420         return -1;
421 }
422 
423 static int cttimeout_default_get(struct net *net, struct sock *ctnl,
424                                  struct sk_buff *skb,
425                                  const struct nlmsghdr *nlh,
426                                  const struct nlattr * const cda[],
427                                  struct netlink_ext_ack *extack)
428 {
429         const struct nf_conntrack_l4proto *l4proto;
430         unsigned int *timeouts = NULL;
431         struct sk_buff *skb2;
432         int ret, err;
433         __u16 l3num;
434         __u8 l4num;
435 
436         if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
437                 return -EINVAL;
438 
439         l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
440         l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
441         l4proto = nf_ct_l4proto_find(l4num);
442 
443         err = -EOPNOTSUPP;
444         if (l4proto->l4proto != l4num)
445                 goto err;
446 
447         switch (l4proto->l4proto) {
448         case IPPROTO_ICMP:
449                 timeouts = &nf_icmp_pernet(net)->timeout;
450                 break;
451         case IPPROTO_TCP:
452                 timeouts = nf_tcp_pernet(net)->timeouts;
453                 break;
454         case IPPROTO_UDP: /* fallthrough */
455         case IPPROTO_UDPLITE:
456                 timeouts = nf_udp_pernet(net)->timeouts;
457                 break;
458         case IPPROTO_DCCP:
459 #ifdef CONFIG_NF_CT_PROTO_DCCP
460                 timeouts = nf_dccp_pernet(net)->dccp_timeout;
461 #endif
462                 break;
463         case IPPROTO_ICMPV6:
464                 timeouts = &nf_icmpv6_pernet(net)->timeout;
465                 break;
466         case IPPROTO_SCTP:
467 #ifdef CONFIG_NF_CT_PROTO_SCTP
468                 timeouts = nf_sctp_pernet(net)->timeouts;
469 #endif
470                 break;
471         case IPPROTO_GRE:
472 #ifdef CONFIG_NF_CT_PROTO_GRE
473                 timeouts = nf_gre_pernet(net)->timeouts;
474 #endif
475                 break;
476         case 255:
477                 timeouts = &nf_generic_pernet(net)->timeout;
478                 break;
479         default:
480                 WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
481                 break;
482         }
483 
484         if (!timeouts)
485                 goto err;
486 
487         skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
488         if (skb2 == NULL) {
489                 err = -ENOMEM;
490                 goto err;
491         }
492 
493         ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
494                                           nlh->nlmsg_seq,
495                                           NFNL_MSG_TYPE(nlh->nlmsg_type),
496                                           IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
497                                           l3num, l4proto, timeouts);
498         if (ret <= 0) {
499                 kfree_skb(skb2);
500                 err = -ENOMEM;
501                 goto err;
502         }
503         ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
504         if (ret > 0)
505                 ret = 0;
506 
507         /* this avoids a loop in nfnetlink. */
508         return ret == -EAGAIN ? -ENOBUFS : ret;
509 err:
510         return err;
511 }
512 
513 static struct nf_ct_timeout *ctnl_timeout_find_get(struct net *net,
514                                                    const char *name)
515 {
516         struct ctnl_timeout *timeout, *matching = NULL;
517 
518         list_for_each_entry_rcu(timeout, &net->nfct_timeout_list, head) {
519                 if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
520                         continue;
521 
522                 if (!try_module_get(THIS_MODULE))
523                         goto err;
524 
525                 if (!refcount_inc_not_zero(&timeout->refcnt)) {
526                         module_put(THIS_MODULE);
527                         goto err;
528                 }
529                 matching = timeout;
530                 break;
531         }
532 err:
533         return matching ? &matching->timeout : NULL;
534 }
535 
536 static void ctnl_timeout_put(struct nf_ct_timeout *t)
537 {
538         struct ctnl_timeout *timeout =
539                 container_of(t, struct ctnl_timeout, timeout);
540 
541         if (refcount_dec_and_test(&timeout->refcnt))
542                 kfree_rcu(timeout, rcu_head);
543 
544         module_put(THIS_MODULE);
545 }
546 
547 static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
548         [IPCTNL_MSG_TIMEOUT_NEW]        = { .call = cttimeout_new_timeout,
549                                             .attr_count = CTA_TIMEOUT_MAX,
550                                             .policy = cttimeout_nla_policy },
551         [IPCTNL_MSG_TIMEOUT_GET]        = { .call = cttimeout_get_timeout,
552                                             .attr_count = CTA_TIMEOUT_MAX,
553                                             .policy = cttimeout_nla_policy },
554         [IPCTNL_MSG_TIMEOUT_DELETE]     = { .call = cttimeout_del_timeout,
555                                             .attr_count = CTA_TIMEOUT_MAX,
556                                             .policy = cttimeout_nla_policy },
557         [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
558                                             .attr_count = CTA_TIMEOUT_MAX,
559                                             .policy = cttimeout_nla_policy },
560         [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
561                                             .attr_count = CTA_TIMEOUT_MAX,
562                                             .policy = cttimeout_nla_policy },
563 };
564 
565 static const struct nfnetlink_subsystem cttimeout_subsys = {
566         .name                           = "conntrack_timeout",
567         .subsys_id                      = NFNL_SUBSYS_CTNETLINK_TIMEOUT,
568         .cb_count                       = IPCTNL_MSG_TIMEOUT_MAX,
569         .cb                             = cttimeout_cb,
570 };
571 
572 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
573 
574 static int __net_init cttimeout_net_init(struct net *net)
575 {
576         INIT_LIST_HEAD(&net->nfct_timeout_list);
577 
578         return 0;
579 }
580 
581 static void __net_exit cttimeout_net_exit(struct net *net)
582 {
583         struct ctnl_timeout *cur, *tmp;
584 
585         nf_ct_unconfirmed_destroy(net);
586         nf_ct_untimeout(net, NULL);
587 
588         list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) {
589                 list_del_rcu(&cur->head);
590 
591                 if (refcount_dec_and_test(&cur->refcnt))
592                         kfree_rcu(cur, rcu_head);
593         }
594 }
595 
596 static struct pernet_operations cttimeout_ops = {
597         .init   = cttimeout_net_init,
598         .exit   = cttimeout_net_exit,
599 };
600 
601 static int __init cttimeout_init(void)
602 {
603         int ret;
604 
605         ret = register_pernet_subsys(&cttimeout_ops);
606         if (ret < 0)
607                 return ret;
608 
609         ret = nfnetlink_subsys_register(&cttimeout_subsys);
610         if (ret < 0) {
611                 pr_err("cttimeout_init: cannot register cttimeout with "
612                         "nfnetlink.\n");
613                 goto err_out;
614         }
615         RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get);
616         RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put);
617         return 0;
618 
619 err_out:
620         unregister_pernet_subsys(&cttimeout_ops);
621         return ret;
622 }
623 
624 static void __exit cttimeout_exit(void)
625 {
626         nfnetlink_subsys_unregister(&cttimeout_subsys);
627 
628         unregister_pernet_subsys(&cttimeout_ops);
629         RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
630         RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
631         synchronize_rcu();
632 }
633 
634 module_init(cttimeout_init);
635 module_exit(cttimeout_exit);
636 

~ [ 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