150978462SPablo Neira Ayuso /* 250978462SPablo Neira Ayuso * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 350978462SPablo Neira Ayuso * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> 450978462SPablo Neira Ayuso * 550978462SPablo Neira Ayuso * This program is free software; you can redistribute it and/or modify 650978462SPablo Neira Ayuso * it under the terms of the GNU General Public License version 2 as 750978462SPablo Neira Ayuso * published by the Free Software Foundation (or any later at your option). 850978462SPablo Neira Ayuso */ 950978462SPablo Neira Ayuso #include <linux/init.h> 1050978462SPablo Neira Ayuso #include <linux/module.h> 1150978462SPablo Neira Ayuso #include <linux/kernel.h> 1250978462SPablo Neira Ayuso #include <linux/rculist.h> 1350978462SPablo Neira Ayuso #include <linux/rculist_nulls.h> 1450978462SPablo Neira Ayuso #include <linux/types.h> 1550978462SPablo Neira Ayuso #include <linux/timer.h> 1650978462SPablo Neira Ayuso #include <linux/security.h> 1750978462SPablo Neira Ayuso #include <linux/skbuff.h> 1850978462SPablo Neira Ayuso #include <linux/errno.h> 1950978462SPablo Neira Ayuso #include <linux/netlink.h> 2050978462SPablo Neira Ayuso #include <linux/spinlock.h> 2150978462SPablo Neira Ayuso #include <linux/interrupt.h> 2250978462SPablo Neira Ayuso #include <linux/slab.h> 2350978462SPablo Neira Ayuso 2450978462SPablo Neira Ayuso #include <linux/netfilter.h> 2550978462SPablo Neira Ayuso #include <net/netlink.h> 2650978462SPablo Neira Ayuso #include <net/sock.h> 2750978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack.h> 2850978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_core.h> 2950978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_l3proto.h> 3050978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_l4proto.h> 3150978462SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_tuple.h> 3250978462SPablo Neira Ayuso 3350978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink.h> 3450978462SPablo Neira Ayuso #include <linux/netfilter/nfnetlink_cttimeout.h> 3550978462SPablo Neira Ayuso 3650978462SPablo Neira Ayuso MODULE_LICENSE("GPL"); 3750978462SPablo Neira Ayuso MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 3850978462SPablo Neira Ayuso MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); 3950978462SPablo Neira Ayuso 4050978462SPablo Neira Ayuso struct ctnl_timeout { 4150978462SPablo Neira Ayuso struct list_head head; 4250978462SPablo Neira Ayuso struct rcu_head rcu_head; 4350978462SPablo Neira Ayuso atomic_t refcnt; 4450978462SPablo Neira Ayuso char name[CTNL_TIMEOUT_NAME_MAX]; 4550978462SPablo Neira Ayuso __u16 l3num; 4650978462SPablo Neira Ayuso __u8 l4num; 4750978462SPablo Neira Ayuso char data[0]; 4850978462SPablo Neira Ayuso }; 4950978462SPablo Neira Ayuso 5050978462SPablo Neira Ayuso static LIST_HEAD(cttimeout_list); 5150978462SPablo Neira Ayuso 5250978462SPablo Neira Ayuso static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { 5350978462SPablo Neira Ayuso [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, 5450978462SPablo Neira Ayuso [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, 5550978462SPablo Neira Ayuso [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, 5650978462SPablo Neira Ayuso [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, 5750978462SPablo Neira Ayuso }; 5850978462SPablo Neira Ayuso 5950978462SPablo Neira Ayuso static int 6050978462SPablo Neira Ayuso ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, 6150978462SPablo Neira Ayuso struct nf_conntrack_l4proto *l4proto, 6250978462SPablo Neira Ayuso const struct nlattr *attr) 6350978462SPablo Neira Ayuso { 6450978462SPablo Neira Ayuso int ret = 0; 6550978462SPablo Neira Ayuso 6650978462SPablo Neira Ayuso if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { 6750978462SPablo Neira Ayuso struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; 6850978462SPablo Neira Ayuso 6950978462SPablo Neira Ayuso nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, 7050978462SPablo Neira Ayuso attr, l4proto->ctnl_timeout.nla_policy); 7150978462SPablo Neira Ayuso 7250978462SPablo Neira Ayuso ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data); 7350978462SPablo Neira Ayuso } 7450978462SPablo Neira Ayuso return ret; 7550978462SPablo Neira Ayuso } 7650978462SPablo Neira Ayuso 7750978462SPablo Neira Ayuso static int 7850978462SPablo Neira Ayuso cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, 7950978462SPablo Neira Ayuso const struct nlmsghdr *nlh, 8050978462SPablo Neira Ayuso const struct nlattr * const cda[]) 8150978462SPablo Neira Ayuso { 8250978462SPablo Neira Ayuso __u16 l3num; 8350978462SPablo Neira Ayuso __u8 l4num; 8450978462SPablo Neira Ayuso struct nf_conntrack_l4proto *l4proto; 8550978462SPablo Neira Ayuso struct ctnl_timeout *timeout, *matching = NULL; 8650978462SPablo Neira Ayuso char *name; 8750978462SPablo Neira Ayuso int ret; 8850978462SPablo Neira Ayuso 8950978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME] || 9050978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_L3PROTO] || 9150978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_L4PROTO] || 9250978462SPablo Neira Ayuso !cda[CTA_TIMEOUT_DATA]) 9350978462SPablo Neira Ayuso return -EINVAL; 9450978462SPablo Neira Ayuso 9550978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]); 9650978462SPablo Neira Ayuso l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); 9750978462SPablo Neira Ayuso l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); 9850978462SPablo Neira Ayuso 9950978462SPablo Neira Ayuso list_for_each_entry(timeout, &cttimeout_list, head) { 10050978462SPablo Neira Ayuso if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 10150978462SPablo Neira Ayuso continue; 10250978462SPablo Neira Ayuso 10350978462SPablo Neira Ayuso if (nlh->nlmsg_flags & NLM_F_EXCL) 10450978462SPablo Neira Ayuso return -EEXIST; 10550978462SPablo Neira Ayuso 10650978462SPablo Neira Ayuso matching = timeout; 10750978462SPablo Neira Ayuso break; 10850978462SPablo Neira Ayuso } 10950978462SPablo Neira Ayuso 11050978462SPablo Neira Ayuso l4proto = __nf_ct_l4proto_find(l3num, l4num); 11150978462SPablo Neira Ayuso 11250978462SPablo Neira Ayuso /* This protocol is not supportted, skip. */ 11350978462SPablo Neira Ayuso if (l4proto->l4proto != l4num) 11450978462SPablo Neira Ayuso return -EOPNOTSUPP; 11550978462SPablo Neira Ayuso 11650978462SPablo Neira Ayuso if (matching) { 11750978462SPablo Neira Ayuso if (nlh->nlmsg_flags & NLM_F_REPLACE) { 11850978462SPablo Neira Ayuso /* You cannot replace one timeout policy by another of 11950978462SPablo Neira Ayuso * different kind, sorry. 12050978462SPablo Neira Ayuso */ 12150978462SPablo Neira Ayuso if (matching->l3num != l3num || 12250978462SPablo Neira Ayuso matching->l4num != l4num) 12350978462SPablo Neira Ayuso return -EINVAL; 12450978462SPablo Neira Ayuso 12550978462SPablo Neira Ayuso ret = ctnl_timeout_parse_policy(matching, l4proto, 12650978462SPablo Neira Ayuso cda[CTA_TIMEOUT_DATA]); 12750978462SPablo Neira Ayuso return ret; 12850978462SPablo Neira Ayuso } 12950978462SPablo Neira Ayuso return -EBUSY; 13050978462SPablo Neira Ayuso } 13150978462SPablo Neira Ayuso 13250978462SPablo Neira Ayuso timeout = kzalloc(sizeof(struct ctnl_timeout) + 13350978462SPablo Neira Ayuso l4proto->ctnl_timeout.obj_size, GFP_KERNEL); 13450978462SPablo Neira Ayuso if (timeout == NULL) 13550978462SPablo Neira Ayuso return -ENOMEM; 13650978462SPablo Neira Ayuso 13750978462SPablo Neira Ayuso ret = ctnl_timeout_parse_policy(timeout, l4proto, 13850978462SPablo Neira Ayuso cda[CTA_TIMEOUT_DATA]); 13950978462SPablo Neira Ayuso if (ret < 0) 14050978462SPablo Neira Ayuso goto err; 14150978462SPablo Neira Ayuso 14250978462SPablo Neira Ayuso strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); 14350978462SPablo Neira Ayuso timeout->l3num = l3num; 14450978462SPablo Neira Ayuso timeout->l4num = l4num; 14550978462SPablo Neira Ayuso atomic_set(&timeout->refcnt, 1); 14650978462SPablo Neira Ayuso list_add_tail_rcu(&timeout->head, &cttimeout_list); 14750978462SPablo Neira Ayuso 14850978462SPablo Neira Ayuso return 0; 14950978462SPablo Neira Ayuso err: 15050978462SPablo Neira Ayuso kfree(timeout); 15150978462SPablo Neira Ayuso return ret; 15250978462SPablo Neira Ayuso } 15350978462SPablo Neira Ayuso 15450978462SPablo Neira Ayuso static int 15550978462SPablo Neira Ayuso ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, 15650978462SPablo Neira Ayuso int event, struct ctnl_timeout *timeout) 15750978462SPablo Neira Ayuso { 15850978462SPablo Neira Ayuso struct nlmsghdr *nlh; 15950978462SPablo Neira Ayuso struct nfgenmsg *nfmsg; 16050978462SPablo Neira Ayuso unsigned int flags = pid ? NLM_F_MULTI : 0; 16150978462SPablo Neira Ayuso struct nf_conntrack_l4proto *l4proto; 16250978462SPablo Neira Ayuso 16350978462SPablo Neira Ayuso event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; 16450978462SPablo Neira Ayuso nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); 16550978462SPablo Neira Ayuso if (nlh == NULL) 16650978462SPablo Neira Ayuso goto nlmsg_failure; 16750978462SPablo Neira Ayuso 16850978462SPablo Neira Ayuso nfmsg = nlmsg_data(nlh); 16950978462SPablo Neira Ayuso nfmsg->nfgen_family = AF_UNSPEC; 17050978462SPablo Neira Ayuso nfmsg->version = NFNETLINK_V0; 17150978462SPablo Neira Ayuso nfmsg->res_id = 0; 17250978462SPablo Neira Ayuso 17350978462SPablo Neira Ayuso NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); 17450978462SPablo Neira Ayuso NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); 17550978462SPablo Neira Ayuso NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); 17650978462SPablo Neira Ayuso NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, 17750978462SPablo Neira Ayuso htonl(atomic_read(&timeout->refcnt))); 17850978462SPablo Neira Ayuso 17950978462SPablo Neira Ayuso l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); 18050978462SPablo Neira Ayuso 18150978462SPablo Neira Ayuso /* If the timeout object does not match the layer 4 protocol tracker, 18250978462SPablo Neira Ayuso * then skip dumping the data part since we don't know how to 18350978462SPablo Neira Ayuso * interpret it. This may happen for UPDlite, SCTP and DCCP since 18450978462SPablo Neira Ayuso * you can unload the module. 18550978462SPablo Neira Ayuso */ 18650978462SPablo Neira Ayuso if (timeout->l4num != l4proto->l4proto) 18750978462SPablo Neira Ayuso goto out; 18850978462SPablo Neira Ayuso 18950978462SPablo Neira Ayuso if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { 19050978462SPablo Neira Ayuso struct nlattr *nest_parms; 19150978462SPablo Neira Ayuso int ret; 19250978462SPablo Neira Ayuso 19350978462SPablo Neira Ayuso nest_parms = nla_nest_start(skb, 19450978462SPablo Neira Ayuso CTA_TIMEOUT_DATA | NLA_F_NESTED); 19550978462SPablo Neira Ayuso if (!nest_parms) 19650978462SPablo Neira Ayuso goto nla_put_failure; 19750978462SPablo Neira Ayuso 19850978462SPablo Neira Ayuso ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); 19950978462SPablo Neira Ayuso if (ret < 0) 20050978462SPablo Neira Ayuso goto nla_put_failure; 20150978462SPablo Neira Ayuso 20250978462SPablo Neira Ayuso nla_nest_end(skb, nest_parms); 20350978462SPablo Neira Ayuso } 20450978462SPablo Neira Ayuso out: 20550978462SPablo Neira Ayuso nlmsg_end(skb, nlh); 20650978462SPablo Neira Ayuso return skb->len; 20750978462SPablo Neira Ayuso 20850978462SPablo Neira Ayuso nlmsg_failure: 20950978462SPablo Neira Ayuso nla_put_failure: 21050978462SPablo Neira Ayuso nlmsg_cancel(skb, nlh); 21150978462SPablo Neira Ayuso return -1; 21250978462SPablo Neira Ayuso } 21350978462SPablo Neira Ayuso 21450978462SPablo Neira Ayuso static int 21550978462SPablo Neira Ayuso ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) 21650978462SPablo Neira Ayuso { 21750978462SPablo Neira Ayuso struct ctnl_timeout *cur, *last; 21850978462SPablo Neira Ayuso 21950978462SPablo Neira Ayuso if (cb->args[2]) 22050978462SPablo Neira Ayuso return 0; 22150978462SPablo Neira Ayuso 22250978462SPablo Neira Ayuso last = (struct ctnl_timeout *)cb->args[1]; 22350978462SPablo Neira Ayuso if (cb->args[1]) 22450978462SPablo Neira Ayuso cb->args[1] = 0; 22550978462SPablo Neira Ayuso 22650978462SPablo Neira Ayuso rcu_read_lock(); 22750978462SPablo Neira Ayuso list_for_each_entry_rcu(cur, &cttimeout_list, head) { 22850978462SPablo Neira Ayuso if (last && cur != last) 22950978462SPablo Neira Ayuso continue; 23050978462SPablo Neira Ayuso 23150978462SPablo Neira Ayuso if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).pid, 23250978462SPablo Neira Ayuso cb->nlh->nlmsg_seq, 23350978462SPablo Neira Ayuso NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 23450978462SPablo Neira Ayuso IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { 23550978462SPablo Neira Ayuso cb->args[1] = (unsigned long)cur; 23650978462SPablo Neira Ayuso break; 23750978462SPablo Neira Ayuso } 23850978462SPablo Neira Ayuso } 23950978462SPablo Neira Ayuso if (!cb->args[1]) 24050978462SPablo Neira Ayuso cb->args[2] = 1; 24150978462SPablo Neira Ayuso rcu_read_unlock(); 24250978462SPablo Neira Ayuso return skb->len; 24350978462SPablo Neira Ayuso } 24450978462SPablo Neira Ayuso 24550978462SPablo Neira Ayuso static int 24650978462SPablo Neira Ayuso cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb, 24750978462SPablo Neira Ayuso const struct nlmsghdr *nlh, 24850978462SPablo Neira Ayuso const struct nlattr * const cda[]) 24950978462SPablo Neira Ayuso { 25050978462SPablo Neira Ayuso int ret = -ENOENT; 25150978462SPablo Neira Ayuso char *name; 25250978462SPablo Neira Ayuso struct ctnl_timeout *cur; 25350978462SPablo Neira Ayuso 25450978462SPablo Neira Ayuso if (nlh->nlmsg_flags & NLM_F_DUMP) { 25550978462SPablo Neira Ayuso struct netlink_dump_control c = { 25650978462SPablo Neira Ayuso .dump = ctnl_timeout_dump, 25750978462SPablo Neira Ayuso }; 25850978462SPablo Neira Ayuso return netlink_dump_start(ctnl, skb, nlh, &c); 25950978462SPablo Neira Ayuso } 26050978462SPablo Neira Ayuso 26150978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME]) 26250978462SPablo Neira Ayuso return -EINVAL; 26350978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]); 26450978462SPablo Neira Ayuso 26550978462SPablo Neira Ayuso list_for_each_entry(cur, &cttimeout_list, head) { 26650978462SPablo Neira Ayuso struct sk_buff *skb2; 26750978462SPablo Neira Ayuso 26850978462SPablo Neira Ayuso if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 26950978462SPablo Neira Ayuso continue; 27050978462SPablo Neira Ayuso 27150978462SPablo Neira Ayuso skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 27250978462SPablo Neira Ayuso if (skb2 == NULL) { 27350978462SPablo Neira Ayuso ret = -ENOMEM; 27450978462SPablo Neira Ayuso break; 27550978462SPablo Neira Ayuso } 27650978462SPablo Neira Ayuso 27750978462SPablo Neira Ayuso ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).pid, 27850978462SPablo Neira Ayuso nlh->nlmsg_seq, 27950978462SPablo Neira Ayuso NFNL_MSG_TYPE(nlh->nlmsg_type), 28050978462SPablo Neira Ayuso IPCTNL_MSG_TIMEOUT_NEW, cur); 28150978462SPablo Neira Ayuso if (ret <= 0) { 28250978462SPablo Neira Ayuso kfree_skb(skb2); 28350978462SPablo Neira Ayuso break; 28450978462SPablo Neira Ayuso } 28550978462SPablo Neira Ayuso ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, 28650978462SPablo Neira Ayuso MSG_DONTWAIT); 28750978462SPablo Neira Ayuso if (ret > 0) 28850978462SPablo Neira Ayuso ret = 0; 28950978462SPablo Neira Ayuso 29050978462SPablo Neira Ayuso /* this avoids a loop in nfnetlink. */ 29150978462SPablo Neira Ayuso return ret == -EAGAIN ? -ENOBUFS : ret; 29250978462SPablo Neira Ayuso } 29350978462SPablo Neira Ayuso return ret; 29450978462SPablo Neira Ayuso } 29550978462SPablo Neira Ayuso 29650978462SPablo Neira Ayuso /* try to delete object, fail if it is still in use. */ 29750978462SPablo Neira Ayuso static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) 29850978462SPablo Neira Ayuso { 29950978462SPablo Neira Ayuso int ret = 0; 30050978462SPablo Neira Ayuso 30150978462SPablo Neira Ayuso /* we want to avoid races with nf_ct_timeout_find_get. */ 30250978462SPablo Neira Ayuso if (atomic_dec_and_test(&timeout->refcnt)) { 30350978462SPablo Neira Ayuso /* We are protected by nfnl mutex. */ 30450978462SPablo Neira Ayuso list_del_rcu(&timeout->head); 30550978462SPablo Neira Ayuso kfree_rcu(timeout, rcu_head); 30650978462SPablo Neira Ayuso } else { 30750978462SPablo Neira Ayuso /* still in use, restore reference counter. */ 30850978462SPablo Neira Ayuso atomic_inc(&timeout->refcnt); 30950978462SPablo Neira Ayuso ret = -EBUSY; 31050978462SPablo Neira Ayuso } 31150978462SPablo Neira Ayuso return ret; 31250978462SPablo Neira Ayuso } 31350978462SPablo Neira Ayuso 31450978462SPablo Neira Ayuso static int 31550978462SPablo Neira Ayuso cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, 31650978462SPablo Neira Ayuso const struct nlmsghdr *nlh, 31750978462SPablo Neira Ayuso const struct nlattr * const cda[]) 31850978462SPablo Neira Ayuso { 31950978462SPablo Neira Ayuso char *name; 32050978462SPablo Neira Ayuso struct ctnl_timeout *cur; 32150978462SPablo Neira Ayuso int ret = -ENOENT; 32250978462SPablo Neira Ayuso 32350978462SPablo Neira Ayuso if (!cda[CTA_TIMEOUT_NAME]) { 32450978462SPablo Neira Ayuso list_for_each_entry(cur, &cttimeout_list, head) 32550978462SPablo Neira Ayuso ctnl_timeout_try_del(cur); 32650978462SPablo Neira Ayuso 32750978462SPablo Neira Ayuso return 0; 32850978462SPablo Neira Ayuso } 32950978462SPablo Neira Ayuso name = nla_data(cda[CTA_TIMEOUT_NAME]); 33050978462SPablo Neira Ayuso 33150978462SPablo Neira Ayuso list_for_each_entry(cur, &cttimeout_list, head) { 33250978462SPablo Neira Ayuso if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) 33350978462SPablo Neira Ayuso continue; 33450978462SPablo Neira Ayuso 33550978462SPablo Neira Ayuso ret = ctnl_timeout_try_del(cur); 33650978462SPablo Neira Ayuso if (ret < 0) 33750978462SPablo Neira Ayuso return ret; 33850978462SPablo Neira Ayuso 33950978462SPablo Neira Ayuso break; 34050978462SPablo Neira Ayuso } 34150978462SPablo Neira Ayuso return ret; 34250978462SPablo Neira Ayuso } 34350978462SPablo Neira Ayuso 34450978462SPablo Neira Ayuso static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { 34550978462SPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, 34650978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX, 34750978462SPablo Neira Ayuso .policy = cttimeout_nla_policy }, 34850978462SPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, 34950978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX, 35050978462SPablo Neira Ayuso .policy = cttimeout_nla_policy }, 35150978462SPablo Neira Ayuso [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, 35250978462SPablo Neira Ayuso .attr_count = CTA_TIMEOUT_MAX, 35350978462SPablo Neira Ayuso .policy = cttimeout_nla_policy }, 35450978462SPablo Neira Ayuso }; 35550978462SPablo Neira Ayuso 35650978462SPablo Neira Ayuso static const struct nfnetlink_subsystem cttimeout_subsys = { 35750978462SPablo Neira Ayuso .name = "conntrack_timeout", 35850978462SPablo Neira Ayuso .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, 35950978462SPablo Neira Ayuso .cb_count = IPCTNL_MSG_TIMEOUT_MAX, 36050978462SPablo Neira Ayuso .cb = cttimeout_cb, 36150978462SPablo Neira Ayuso }; 36250978462SPablo Neira Ayuso 36350978462SPablo Neira Ayuso MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); 36450978462SPablo Neira Ayuso 36550978462SPablo Neira Ayuso static int __init cttimeout_init(void) 36650978462SPablo Neira Ayuso { 36750978462SPablo Neira Ayuso int ret; 36850978462SPablo Neira Ayuso 36950978462SPablo Neira Ayuso ret = nfnetlink_subsys_register(&cttimeout_subsys); 37050978462SPablo Neira Ayuso if (ret < 0) { 37150978462SPablo Neira Ayuso pr_err("cttimeout_init: cannot register cttimeout with " 37250978462SPablo Neira Ayuso "nfnetlink.\n"); 37350978462SPablo Neira Ayuso goto err_out; 37450978462SPablo Neira Ayuso } 37550978462SPablo Neira Ayuso return 0; 37650978462SPablo Neira Ayuso 37750978462SPablo Neira Ayuso err_out: 37850978462SPablo Neira Ayuso return ret; 37950978462SPablo Neira Ayuso } 38050978462SPablo Neira Ayuso 38150978462SPablo Neira Ayuso static void __exit cttimeout_exit(void) 38250978462SPablo Neira Ayuso { 38350978462SPablo Neira Ayuso struct ctnl_timeout *cur, *tmp; 38450978462SPablo Neira Ayuso 38550978462SPablo Neira Ayuso pr_info("cttimeout: unregistering from nfnetlink.\n"); 38650978462SPablo Neira Ayuso 38750978462SPablo Neira Ayuso nfnetlink_subsys_unregister(&cttimeout_subsys); 38850978462SPablo Neira Ayuso list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) { 38950978462SPablo Neira Ayuso list_del_rcu(&cur->head); 39050978462SPablo Neira Ayuso /* We are sure that our objects have no clients at this point, 39150978462SPablo Neira Ayuso * it's safe to release them all without checking refcnt. 39250978462SPablo Neira Ayuso */ 39350978462SPablo Neira Ayuso kfree_rcu(cur, rcu_head); 39450978462SPablo Neira Ayuso } 39550978462SPablo Neira Ayuso } 39650978462SPablo Neira Ayuso 39750978462SPablo Neira Ayuso module_init(cttimeout_init); 39850978462SPablo Neira Ayuso module_exit(cttimeout_exit); 399