Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eaae44d2 authored by David S. Miller's avatar David S. Miller
Browse files
parents 5b548140 3dd5d7e3
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -56,6 +56,18 @@ static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
	return is_a_nulls(h->first);
}

static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
					struct hlist_nulls_head *h)
{
	struct hlist_nulls_node *first = h->first;

	n->next = first;
	n->pprev = &h->first;
	h->first = n;
	if (!is_a_nulls(first))
		first->pprev = &n->next;
}

static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
{
	struct hlist_nulls_node *next = n->next;
@@ -65,6 +77,12 @@ static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
		next->pprev = pprev;
}

static inline void hlist_nulls_del(struct hlist_nulls_node *n)
{
	__hlist_nulls_del(n);
	n->pprev = LIST_POISON2;
}

/**
 * hlist_nulls_for_each_entry	- iterate over list of given type
 * @tpos:	the type * to use as a loop cursor.
+2 −0
Original line number Diff line number Diff line
@@ -201,6 +201,8 @@ extern struct nf_conntrack_tuple_hash *
__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple);

extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern void nf_ct_delete_from_lists(struct nf_conn *ct);
extern void nf_ct_insert_dying_list(struct nf_conn *ct);

extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report);

+105 −70
Original line number Diff line number Diff line
@@ -6,61 +6,54 @@
#define _NF_CONNTRACK_ECACHE_H
#include <net/netfilter/nf_conntrack.h>

#include <linux/interrupt.h>
#include <net/net_namespace.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <net/netfilter/nf_conntrack_extend.h>

/* Connection tracking event bits */
/* Connection tracking event types */
enum ip_conntrack_events
{
	/* New conntrack */
	IPCT_NEW_BIT = 0,
	IPCT_NEW = (1 << IPCT_NEW_BIT),

	/* Expected connection */
	IPCT_RELATED_BIT = 1,
	IPCT_RELATED = (1 << IPCT_RELATED_BIT),

	/* Destroyed conntrack */
	IPCT_DESTROY_BIT = 2,
	IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),

	/* Status has changed */
	IPCT_STATUS_BIT = 3,
	IPCT_STATUS = (1 << IPCT_STATUS_BIT),
	IPCT_NEW		= 0,	/* new conntrack */
	IPCT_RELATED		= 1,	/* related conntrack */
	IPCT_DESTROY		= 2,	/* destroyed conntrack */
	IPCT_STATUS		= 3,	/* status has changed */
	IPCT_PROTOINFO		= 4,	/* protocol information has changed */
	IPCT_HELPER		= 5,	/* new helper has been set */
	IPCT_MARK		= 6,	/* new mark has been set */
	IPCT_NATSEQADJ		= 7,	/* NAT is doing sequence adjustment */
	IPCT_SECMARK		= 8,	/* new security mark has been set */
};

	/* Update of protocol info */
	IPCT_PROTOINFO_BIT = 4,
	IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
enum ip_conntrack_expect_events {
	IPEXP_NEW		= 0,	/* new expectation */
};

	/* New helper for conntrack */
	IPCT_HELPER_BIT = 5,
	IPCT_HELPER = (1 << IPCT_HELPER_BIT),
struct nf_conntrack_ecache {
	unsigned long cache;		/* bitops want long */
	unsigned long missed;		/* missed events */
	u32 pid;			/* netlink pid of destroyer */
};

	/* Mark is set */
	IPCT_MARK_BIT = 6,
	IPCT_MARK = (1 << IPCT_MARK_BIT),
static inline struct nf_conntrack_ecache *
nf_ct_ecache_find(const struct nf_conn *ct)
{
	return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE);
}

	/* NAT sequence adjustment */
	IPCT_NATSEQADJ_BIT = 7,
	IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT),
static inline struct nf_conntrack_ecache *
nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
{
	struct net *net = nf_ct_net(ct);

	/* Secmark is set */
	IPCT_SECMARK_BIT = 8,
	IPCT_SECMARK = (1 << IPCT_SECMARK_BIT),
};
	if (!net->ct.sysctl_events)
		return NULL;

enum ip_conntrack_expect_events {
	IPEXP_NEW_BIT = 0,
	IPEXP_NEW = (1 << IPEXP_NEW_BIT),
	return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
};

#ifdef CONFIG_NF_CONNTRACK_EVENTS
struct nf_conntrack_ecache {
	struct nf_conn *ct;
	unsigned int events;
};

/* This structure is passed to event handler */
struct nf_ct_event {
	struct nf_conn *ct;
@@ -76,53 +69,88 @@ extern struct nf_ct_event_notifier *nf_conntrack_event_cb;
extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb);
extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb);

extern void nf_ct_deliver_cached_events(const struct nf_conn *ct);
extern void __nf_ct_event_cache_init(struct nf_conn *ct);
extern void nf_ct_event_cache_flush(struct net *net);
extern void nf_ct_deliver_cached_events(struct nf_conn *ct);

static inline void
nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
{
	struct net *net = nf_ct_net(ct);
	struct nf_conntrack_ecache *ecache;

	local_bh_disable();
	ecache = per_cpu_ptr(net->ct.ecache, raw_smp_processor_id());
	if (ct != ecache->ct)
		__nf_ct_event_cache_init(ct);
	ecache->events |= event;
	local_bh_enable();
	struct nf_conntrack_ecache *e;

	if (nf_conntrack_event_cb == NULL)
		return;

	e = nf_ct_ecache_find(ct);
	if (e == NULL)
		return;

	set_bit(event, &e->cache);
}

static inline void
nf_conntrack_event_report(enum ip_conntrack_events event,
static inline int
nf_conntrack_eventmask_report(unsigned int eventmask,
			      struct nf_conn *ct,
			      u32 pid,
			      int report)
{
	int ret = 0;
	struct net *net = nf_ct_net(ct);
	struct nf_ct_event_notifier *notify;
	struct nf_conntrack_ecache *e;

	rcu_read_lock();
	notify = rcu_dereference(nf_conntrack_event_cb);
	if (notify == NULL)
		goto out_unlock;

	if (!net->ct.sysctl_events)
		goto out_unlock;

	e = nf_ct_ecache_find(ct);
	if (e == NULL)
		goto out_unlock;

	if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) {
		struct nf_ct_event item = {
			.ct 	= ct,
			.pid	= pid,
			.pid	= e->pid ? e->pid : pid,
			.report = report
		};
		notify->fcn(event, &item);
		/* This is a resent of a destroy event? If so, skip missed */
		unsigned long missed = e->pid ? 0 : e->missed;

		ret = notify->fcn(eventmask | missed, &item);
		if (unlikely(ret < 0 || missed)) {
			spin_lock_bh(&ct->lock);
			if (ret < 0) {
				/* This is a destroy event that has been
				 * triggered by a process, we store the PID
				 * to include it in the retransmission. */
				if (eventmask & (1 << IPCT_DESTROY) &&
				    e->pid == 0 && pid != 0)
					e->pid = pid;
				else
					e->missed |= eventmask;
			} else
				e->missed &= ~missed;
			spin_unlock_bh(&ct->lock);
		}
	}
out_unlock:
	rcu_read_unlock();
	return ret;
}

static inline void
static inline int
nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
			  u32 pid, int report)
{
	return nf_conntrack_eventmask_report(1 << event, ct, pid, report);
}

static inline int
nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
{
	nf_conntrack_event_report(event, ct, 0, 0);
	return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
}

struct nf_exp_event {
@@ -145,6 +173,7 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
			  u32 pid,
			  int report)
{
	struct net *net = nf_ct_exp_net(exp);
	struct nf_exp_event_notifier *notify;

	rcu_read_lock();
@@ -152,13 +181,16 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
	if (notify == NULL)
		goto out_unlock;

	if (!net->ct.sysctl_events)
		goto out_unlock;

	{
		struct nf_exp_event item = {
			.exp	= exp,
			.pid	= pid,
			.report = report
		};
		notify->fcn(event, &item);
		notify->fcn(1 << event, &item);
	}
out_unlock:
	rcu_read_unlock();
@@ -178,12 +210,16 @@ extern void nf_conntrack_ecache_fini(struct net *net);

static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
					    struct nf_conn *ct) {}
static inline void nf_conntrack_event(enum ip_conntrack_events event,
				      struct nf_conn *ct) {}
static inline void nf_conntrack_event_report(enum ip_conntrack_events event,
static inline int nf_conntrack_eventmask_report(unsigned int eventmask,
						struct nf_conn *ct,
						u32 pid,
					     int report) {}
						int report) { return 0; }
static inline int nf_conntrack_event(enum ip_conntrack_events event,
				     struct nf_conn *ct) { return 0; }
static inline int nf_conntrack_event_report(enum ip_conntrack_events event,
					    struct nf_conn *ct,
					    u32 pid,
					    int report) { return 0; }
static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
				      struct nf_conntrack_expect *exp) {}
@@ -191,7 +227,6 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
					     struct nf_conntrack_expect *exp,
 					     u32 pid,
 					     int report) {}
static inline void nf_ct_event_cache_flush(struct net *net) {}

static inline int nf_conntrack_ecache_init(struct net *net)
{
+2 −0
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@ enum nf_ct_ext_id
	NF_CT_EXT_HELPER,
	NF_CT_EXT_NAT,
	NF_CT_EXT_ACCT,
	NF_CT_EXT_ECACHE,
	NF_CT_EXT_NUM,
};

#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache

/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
+2 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);

extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags);

extern void nf_ct_helper_destroy(struct nf_conn *ct);

static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
{
	return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
Loading