net/netfilter/nf_conntrack_helper.c

Source file repositories/reference/linux-study-clean/net/netfilter/nf_conntrack_helper.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nf_conntrack_helper.c
Extension
.c
Size
15095 bytes
Lines
593
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
			if (strcmp(h->name, name))
				continue;

			if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
			    h->tuple.src.l3num != l3num)
				continue;

			if (h->tuple.dst.protonum == protonum)
				return h;
		}
	}
	return NULL;
}
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);

struct nf_conntrack_helper *
nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
{
	struct nf_conntrack_helper *h;

	rcu_read_lock();

	h = __nf_conntrack_helper_find(name, l3num, protonum);
#ifdef CONFIG_MODULES
	if (h == NULL) {
		rcu_read_unlock();
		if (request_module("nfct-helper-%s", name) == 0) {
			rcu_read_lock();
			h = __nf_conntrack_helper_find(name, l3num, protonum);
		} else {
			return h;
		}
	}
#endif
	if (h != NULL && !try_module_get(h->me))
		h = NULL;
	if (h != NULL && !refcount_inc_not_zero(&h->ct_refcnt)) {
		module_put(h->me);
		h = NULL;
	}

	rcu_read_unlock();

	return h;
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);

void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
{
	module_put(helper->me);
	if (refcount_dec_and_test(&helper->ct_refcnt))
		kfree_rcu(helper, rcu);
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);

static struct nf_conntrack_nat_helper *
nf_conntrack_nat_helper_find(const char *mod_name)
{
	struct nf_conntrack_nat_helper *cur;
	bool found = false;

	list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
		if (!strcmp(cur->mod_name, mod_name)) {
			found = true;
			break;
		}
	}
	return found ? cur : NULL;
}

int
nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
{
	struct nf_conntrack_helper *h;
	struct nf_conntrack_nat_helper *nat;
	char mod_name[NF_CT_HELPER_NAME_LEN];
	int ret = 0;

	rcu_read_lock();
	h = __nf_conntrack_helper_find(name, l3num, protonum);
	if (!h) {
		rcu_read_unlock();
		return -ENOENT;
	}

	nat = nf_conntrack_nat_helper_find(h->nat_mod_name);
	if (!nat) {
		snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
		rcu_read_unlock();

Annotation

Implementation Notes