net/ipv4/ip_fragment.c

Source file repositories/reference/linux-study-clean/net/ipv4/ip_fragment.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/ip_fragment.c
Extension
.c
Size
18395 bytes
Lines
751
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

struct ipq {
	struct inet_frag_queue q;

	u8		ecn; /* RFC3168 support */
	u16		max_df_size; /* largest frag with DF set seen */
	int             iif;
	unsigned int    rid;
	struct inet_peer *peer;
};

static u8 ip4_frag_ecn(u8 tos)
{
	return 1 << (tos & INET_ECN_MASK);
}

static struct inet_frags ip4_frags;

static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
			 struct sk_buff *prev_tail, struct net_device *dev,
			 int *refs);


static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
{
	struct ipq *qp = container_of(q, struct ipq, q);
	const struct frag_v4_compare_key *key = a;
	struct net *net = q->fqdir->net;
	struct inet_peer *p = NULL;

	q->key.v4 = *key;
	qp->ecn = 0;
	if (q->fqdir->max_dist) {
		rcu_read_lock();
		p = inet_getpeer_v4(net->ipv4.peers, key->saddr, key->vif);
		if (p && !refcount_inc_not_zero(&p->refcnt))
			p = NULL;
		rcu_read_unlock();
	}
	qp->peer = p;
}

static void ip4_frag_free(struct inet_frag_queue *q)
{
	struct ipq *qp;

	qp = container_of(q, struct ipq, q);
	if (qp->peer)
		inet_putpeer(qp->peer);
}

static bool frag_expire_skip_icmp(u32 user)
{
	return user == IP_DEFRAG_AF_PACKET ||
	       ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_IN,
					 __IP_DEFRAG_CONNTRACK_IN_END) ||
	       ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_BRIDGE_IN,
					 __IP_DEFRAG_CONNTRACK_BRIDGE_IN);
}

/*
 * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
 */
static void ip_expire(struct timer_list *t)
{
	enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT;
	struct inet_frag_queue *frag = timer_container_of(frag, t, timer);
	const struct iphdr *iph;
	struct sk_buff *head = NULL;
	struct net *net;
	struct ipq *qp;
	int refs = 1;

	qp = container_of(frag, struct ipq, q);
	net = qp->q.fqdir->net;

	rcu_read_lock();
	spin_lock(&qp->q.lock);

	if (qp->q.flags & INET_FRAG_COMPLETE)
		goto out;

	qp->q.flags |= INET_FRAG_DROP;
	inet_frag_kill(&qp->q, &refs);

	/* Paired with WRITE_ONCE() in fqdir_pre_exit(). */
	if (READ_ONCE(qp->q.fqdir->dead)) {
		inet_frag_queue_flush(&qp->q, 0);
		goto out;
	}

Annotation

Implementation Notes