* (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
* (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* Initial connection tracking via netlink development funded and
* generally made possible by Network Robots, Inc. (www.networkrobots.com)
nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
- NLA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
+ NLA_PUT_U8(skb, CTA_PROTO_NUM, tuple->dst.protonum);
if (likely(l4proto->tuple_to_nlattr))
ret = l4proto->tuple_to_nlattr(skb, tuple);
return -1;
}
-static inline int
+static int
ctnetlink_dump_tuples(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
static inline int
ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
{
- __be32 status = htonl((u_int32_t) ct->status);
- NLA_PUT(skb, CTA_STATUS, sizeof(status), &status);
+ NLA_PUT_BE32(skb, CTA_STATUS, htonl(ct->status));
return 0;
nla_put_failure:
static inline int
ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
{
- long timeout_l = ct->timeout.expires - jiffies;
- __be32 timeout;
+ long timeout = (ct->timeout.expires - jiffies) / HZ;
- if (timeout_l < 0)
+ if (timeout < 0)
timeout = 0;
- else
- timeout = htonl(timeout_l / HZ);
- NLA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
+ NLA_PUT_BE32(skb, CTA_TIMEOUT, htonl(timeout));
return 0;
nla_put_failure:
static inline int
ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
{
- struct nf_conntrack_l4proto *l4proto = nf_ct_l4proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
+ struct nf_conntrack_l4proto *l4proto;
struct nlattr *nest_proto;
int ret;
+ l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
if (!l4proto->to_nlattr) {
nf_ct_l4proto_put(l4proto);
return 0;
nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED);
if (!nest_helper)
goto nla_put_failure;
- NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name);
+ NLA_PUT_STRING(skb, CTA_HELP_NAME, helper->name);
if (helper->to_nlattr)
helper->to_nlattr(skb, ct);
}
#ifdef CONFIG_NF_CT_ACCT
-static inline int
+static int
ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
enum ip_conntrack_dir dir)
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nlattr *nest_count;
- __be32 tmp;
nest_count = nla_nest_start(skb, type | NLA_F_NESTED);
if (!nest_count)
goto nla_put_failure;
- tmp = htonl(ct->counters[dir].packets);
- NLA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
-
- tmp = htonl(ct->counters[dir].bytes);
- NLA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
+ NLA_PUT_BE32(skb, CTA_COUNTERS32_PACKETS,
+ htonl(ct->counters[dir].packets));
+ NLA_PUT_BE32(skb, CTA_COUNTERS32_BYTES,
+ htonl(ct->counters[dir].bytes));
nla_nest_end(skb, nest_count);
static inline int
ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
{
- __be32 mark = htonl(ct->mark);
-
- NLA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
+ NLA_PUT_BE32(skb, CTA_MARK, htonl(ct->mark));
return 0;
nla_put_failure:
#define ctnetlink_dump_mark(a, b) (0)
#endif
-#ifdef CONFIG_NF_NAT_NEEDED
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+static inline int
+ctnetlink_dump_secmark(struct sk_buff *skb, const struct nf_conn *ct)
+{
+ NLA_PUT_BE32(skb, CTA_SECMARK, htonl(ct->secmark));
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+#else
+#define ctnetlink_dump_secmark(a, b) (0)
+#endif
+
+#define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
+
static inline int
+ctnetlink_dump_master(struct sk_buff *skb, const struct nf_conn *ct)
+{
+ struct nlattr *nest_parms;
+
+ if (!(ct->status & IPS_EXPECTED))
+ return 0;
+
+ nest_parms = nla_nest_start(skb, CTA_TUPLE_MASTER | NLA_F_NESTED);
+ if (!nest_parms)
+ goto nla_put_failure;
+ if (ctnetlink_dump_tuples(skb, master_tuple(ct)) < 0)
+ goto nla_put_failure;
+ nla_nest_end(skb, nest_parms);
+
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+#ifdef CONFIG_NF_NAT_NEEDED
+static int
dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type)
{
- __be32 tmp;
struct nlattr *nest_parms;
nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
- tmp = htonl(natseq->correction_pos);
- NLA_PUT(skb, CTA_NAT_SEQ_CORRECTION_POS, sizeof(tmp), &tmp);
- tmp = htonl(natseq->offset_before);
- NLA_PUT(skb, CTA_NAT_SEQ_OFFSET_BEFORE, sizeof(tmp), &tmp);
- tmp = htonl(natseq->offset_after);
- NLA_PUT(skb, CTA_NAT_SEQ_OFFSET_AFTER, sizeof(tmp), &tmp);
+ NLA_PUT_BE32(skb, CTA_NAT_SEQ_CORRECTION_POS,
+ htonl(natseq->correction_pos));
+ NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_BEFORE,
+ htonl(natseq->offset_before));
+ NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_AFTER,
+ htonl(natseq->offset_after));
nla_nest_end(skb, nest_parms);
static inline int
ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
{
- __be32 id = htonl((unsigned long)ct);
- NLA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
+ NLA_PUT_BE32(skb, CTA_ID, htonl((unsigned long)ct));
return 0;
nla_put_failure:
static inline int
ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)
{
- __be32 use = htonl(atomic_read(&ct->ct_general.use));
-
- NLA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
+ NLA_PUT_BE32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use)));
return 0;
nla_put_failure:
nfmsg = NLMSG_DATA(nlh);
nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
- nfmsg->nfgen_family =
- ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+ nfmsg->nfgen_family = nf_ct_l3num(ct);
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0;
ctnetlink_dump_protoinfo(skb, ct) < 0 ||
ctnetlink_dump_helpinfo(skb, ct) < 0 ||
ctnetlink_dump_mark(skb, ct) < 0 ||
+ ctnetlink_dump_secmark(skb, ct) < 0 ||
ctnetlink_dump_id(skb, ct) < 0 ||
ctnetlink_dump_use(skb, ct) < 0 ||
+ ctnetlink_dump_master(skb, ct) < 0 ||
ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
goto nla_put_failure;
nfmsg = NLMSG_DATA(nlh);
nlh->nlmsg_flags = flags;
- nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+ nfmsg->nfgen_family = nf_ct_l3num(ct);
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0;
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
+ if (ctnetlink_dump_id(skb, ct) < 0)
+ goto nla_put_failure;
+
+ if (ctnetlink_dump_status(skb, ct) < 0)
+ goto nla_put_failure;
+
if (events & IPCT_DESTROY) {
if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
goto nla_put_failure;
} else {
- if (ctnetlink_dump_status(skb, ct) < 0)
- goto nla_put_failure;
-
if (ctnetlink_dump_timeout(skb, ct) < 0)
goto nla_put_failure;
&& ctnetlink_dump_helpinfo(skb, ct) < 0)
goto nla_put_failure;
-#ifdef CONFIG_NF_CONNTRACK_MARK
- if ((events & IPCT_MARK || ct->mark)
- && ctnetlink_dump_mark(skb, ct) < 0)
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+ if ((events & IPCT_SECMARK || ct->secmark)
+ && ctnetlink_dump_secmark(skb, ct) < 0)
goto nla_put_failure;
#endif
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0))
goto nla_put_failure;
+ if (events & IPCT_RELATED &&
+ ctnetlink_dump_master(skb, ct) < 0)
+ goto nla_put_failure;
+
if (events & IPCT_NATSEQADJ &&
ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
goto nla_put_failure;
}
+#ifdef CONFIG_NF_CONNTRACK_MARK
+ if ((events & IPCT_MARK || ct->mark)
+ && ctnetlink_dump_mark(skb, ct) < 0)
+ goto nla_put_failure;
+#endif
+
nlh->nlmsg_len = skb->tail - b;
nfnetlink_send(skb, 0, group, 0);
return NOTIFY_DONE;
return 0;
}
-#define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num
-
static int
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
- read_lock_bh(&nf_conntrack_lock);
+ rcu_read_lock();
last = (struct nf_conn *)cb->args[1];
for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
restart:
- hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],
- hnode) {
+ hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[cb->args[0]],
+ hnode) {
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue;
ct = nf_ct_tuplehash_to_ctrack(h);
/* Dump entries of a given L3 protocol number.
* If it is not specified, ie. l3proto == 0,
* then dump everything. */
- if (l3proto && L3PROTO(ct) != l3proto)
+ if (l3proto && nf_ct_l3num(ct) != l3proto)
continue;
if (cb->args[1]) {
if (ct != last)
cb->nlh->nlmsg_seq,
IPCTNL_MSG_CT_NEW,
1, ct) < 0) {
- nf_conntrack_get(&ct->ct_general);
+ if (!atomic_inc_not_zero(&ct->ct_general.use))
+ continue;
cb->args[1] = (unsigned long)ct;
goto out;
}
}
}
out:
- read_unlock_bh(&nf_conntrack_lock);
+ rcu_read_unlock();
if (last)
nf_ct_put(last);
if (!tb[CTA_PROTO_NUM])
return -EINVAL;
- tuple->dst.protonum = *(u_int8_t *)nla_data(tb[CTA_PROTO_NUM]);
+ tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
return ret;
}
-static inline int
+static int
ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple,
enum ctattr_tuple type, u_int8_t l3num)
{
struct nf_nat_range *range)
{
struct nlattr *tb[CTA_PROTONAT_MAX+1];
- struct nf_nat_protocol *npt;
+ const struct nf_nat_protocol *npt;
int err;
err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
if (err < 0)
return err;
- npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
-
- if (!npt->nlattr_to_range) {
- nf_nat_proto_put(npt);
- return 0;
- }
-
- /* nlattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
- if (npt->nlattr_to_range(tb, range) > 0)
- range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-
+ npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
+ if (npt->nlattr_to_range)
+ err = npt->nlattr_to_range(tb, range);
nf_nat_proto_put(npt);
-
- return 0;
+ return err;
}
static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
return err;
if (tb[CTA_NAT_MINIP])
- range->min_ip = *(__be32 *)nla_data(tb[CTA_NAT_MINIP]);
+ range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
if (!tb[CTA_NAT_MAXIP])
range->max_ip = range->min_ip;
else
- range->max_ip = *(__be32 *)nla_data(tb[CTA_NAT_MAXIP]);
+ range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
if (range->min_ip)
range->flags |= IP_NAT_RANGE_MAP_IPS;
ct = nf_ct_tuplehash_to_ctrack(h);
if (cda[CTA_ID]) {
- u_int32_t id = ntohl(*(__be32 *)nla_data(cda[CTA_ID]));
+ u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));
if (id != (u32)(unsigned long)ct) {
nf_ct_put(ct);
return -ENOENT;
}
}
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
nf_ct_put(ct);
return 0;
return err;
}
-static inline int
+static int
ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
{
unsigned long d;
- unsigned int status = ntohl(*(__be32 *)nla_data(cda[CTA_STATUS]));
+ unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
d = ct->status ^ status;
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
/* unchangeable */
- return -EINVAL;
+ return -EBUSY;
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
/* SEEN_REPLY bit can only be set */
- return -EINVAL;
-
+ return -EBUSY;
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
/* ASSURED bit can only be set */
- return -EINVAL;
+ return -EBUSY;
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
#ifndef CONFIG_NF_NAT_NEEDED
- return -EINVAL;
+ return -EOPNOTSUPP;
#else
struct nf_nat_range range;
if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct,
&range) < 0)
return -EINVAL;
- if (nf_nat_initialized(ct,
- HOOK2MANIP(NF_INET_PRE_ROUTING)))
+ if (nf_nat_initialized(ct, IP_NAT_MANIP_DST))
return -EEXIST;
- nf_nat_setup_info(ct, &range, NF_INET_PRE_ROUTING);
+ nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
}
if (cda[CTA_NAT_SRC]) {
if (nfnetlink_parse_nat(cda[CTA_NAT_SRC], ct,
&range) < 0)
return -EINVAL;
- if (nf_nat_initialized(ct,
- HOOK2MANIP(NF_INET_POST_ROUTING)))
+ if (nf_nat_initialized(ct, IP_NAT_MANIP_SRC))
return -EEXIST;
- nf_nat_setup_info(ct, &range, NF_INET_POST_ROUTING);
+ nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
}
#endif
}
/* don't change helper of sibling connections */
if (ct->master)
- return -EINVAL;
+ return -EBUSY;
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
if (err < 0)
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (help) {
if (help->helper == helper)
static inline int
ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[])
{
- u_int32_t timeout = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT]));
+ u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
if (!del_timer(&ct->timeout))
return -ETIME;
{
struct nlattr *tb[CTA_PROTOINFO_MAX+1], *attr = cda[CTA_PROTOINFO];
struct nf_conntrack_l4proto *l4proto;
- u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
- u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
int err = 0;
nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL);
- l4proto = nf_ct_l4proto_find_get(l3num, npt);
-
+ l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
if (l4proto->from_nlattr)
err = l4proto->from_nlattr(tb, ct);
nf_ct_l4proto_put(l4proto);
return -EINVAL;
natseq->correction_pos =
- ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_CORRECTION_POS]));
+ ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS]));
if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE])
return -EINVAL;
natseq->offset_before =
- ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_OFFSET_BEFORE]));
+ ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE]));
if (!cda[CTA_NAT_SEQ_OFFSET_AFTER])
return -EINVAL;
natseq->offset_after =
- ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_OFFSET_AFTER]));
+ ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER]));
return 0;
}
#if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK])
- ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK]));
+ ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
#endif
#ifdef CONFIG_NF_NAT_NEEDED
if (!cda[CTA_TIMEOUT])
goto err;
- ct->timeout.expires = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT]));
+ ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
ct->status |= IPS_CONFIRMED;
#if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK])
- ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK]));
+ ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
#endif
- helper = nf_ct_helper_find_get(rtuple);
+ rcu_read_lock();
+ helper = __nf_ct_helper_find(rtuple);
if (helper) {
help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
if (help == NULL) {
- nf_ct_helper_put(helper);
+ rcu_read_unlock();
err = -ENOMEM;
goto err;
}
add_timer(&ct->timeout);
nf_conntrack_hash_insert(ct);
-
- if (helper)
- nf_ct_helper_put(helper);
+ rcu_read_unlock();
return 0;
return err;
}
- write_lock_bh(&nf_conntrack_lock);
+ spin_lock_bh(&nf_conntrack_lock);
if (cda[CTA_TUPLE_ORIG])
- h = __nf_conntrack_find(&otuple, NULL);
+ h = __nf_conntrack_find(&otuple);
else if (cda[CTA_TUPLE_REPLY])
- h = __nf_conntrack_find(&rtuple, NULL);
+ h = __nf_conntrack_find(&rtuple);
if (h == NULL) {
struct nf_conntrack_tuple master;
CTA_TUPLE_MASTER,
u3);
if (err < 0)
- return err;
+ goto out_unlock;
- master_h = __nf_conntrack_find(&master, NULL);
+ master_h = __nf_conntrack_find(&master);
if (master_h == NULL) {
err = -ENOENT;
goto out_unlock;
atomic_inc(&master_ct->ct_general.use);
}
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda,
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
/* we only allow nat config for new conntracks */
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
/* can't link an existing conntrack to a master */
if (cda[CTA_TUPLE_MASTER]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
}
out_unlock:
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
return err;
}
return -1;
}
-static inline int
+static int
ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct nf_conntrack_expect *exp)
{
struct nf_conn *master = exp->master;
- __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ);
- __be32 id = htonl((unsigned long)exp);
+ long timeout = (exp->timeout.expires - jiffies) / HZ;
+
+ if (timeout < 0)
+ timeout = 0;
if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
goto nla_put_failure;
CTA_EXPECT_MASTER) < 0)
goto nla_put_failure;
- NLA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
- NLA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
+ NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
+ NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
return 0;
struct hlist_node *n;
u_int8_t l3proto = nfmsg->nfgen_family;
- read_lock_bh(&nf_conntrack_lock);
+ rcu_read_lock();
last = (struct nf_conntrack_expect *)cb->args[1];
for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
restart:
cb->nlh->nlmsg_seq,
IPCTNL_MSG_EXP_NEW,
1, exp) < 0) {
- atomic_inc(&exp->use);
+ if (!atomic_inc_not_zero(&exp->use))
+ continue;
cb->args[1] = (unsigned long)exp;
goto out;
}
}
}
out:
- read_unlock_bh(&nf_conntrack_lock);
+ rcu_read_unlock();
if (last)
nf_ct_expect_put(last);
return -ENOENT;
if (cda[CTA_EXPECT_ID]) {
- __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]);
+ __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
if (ntohl(id) != (u32)(unsigned long)exp) {
nf_ct_expect_put(exp);
return -ENOENT;
return -ENOENT;
if (cda[CTA_EXPECT_ID]) {
- __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]);
+ __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
if (ntohl(id) != (u32)(unsigned long)exp) {
nf_ct_expect_put(exp);
return -ENOENT;
struct nf_conn_help *m_help;
/* delete all expectations for this helper */
- write_lock_bh(&nf_conntrack_lock);
+ spin_lock_bh(&nf_conntrack_lock);
h = __nf_conntrack_helper_find_byname(name);
if (!h) {
- write_unlock_bh(&nf_conntrack_lock);
- return -EINVAL;
+ spin_unlock_bh(&nf_conntrack_lock);
+ return -EOPNOTSUPP;
}
for (i = 0; i < nf_ct_expect_hsize; i++) {
hlist_for_each_entry_safe(exp, n, next,
}
}
}
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
} else {
/* This basically means we have to flush everything*/
- write_lock_bh(&nf_conntrack_lock);
+ spin_lock_bh(&nf_conntrack_lock);
for (i = 0; i < nf_ct_expect_hsize; i++) {
hlist_for_each_entry_safe(exp, n, next,
&nf_ct_expect_hash[i],
}
}
}
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
}
return 0;
if (err < 0)
return err;
- write_lock_bh(&nf_conntrack_lock);
+ spin_lock_bh(&nf_conntrack_lock);
exp = __nf_ct_expect_find(&tuple);
if (!exp) {
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_expect(cda, u3);
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_expect(exp, cda);
- write_unlock_bh(&nf_conntrack_lock);
+ spin_unlock_bh(&nf_conntrack_lock);
return err;
}