net/batman-adv/fragmentation.c

Source file repositories/reference/linux-study-clean/net/batman-adv/fragmentation.c

File Facts

System
Linux kernel
Corpus path
net/batman-adv/fragmentation.c
Extension
.c
Size
17501 bytes
Lines
605
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

if (!check_cb || check_cb(chain)) {
			batadv_frag_clear_chain(&chain->fragment_list, true);
			chain->size = 0;
		}

		spin_unlock_bh(&chain->lock);
	}
}

/**
 * batadv_frag_size_limit() - maximum possible size of packet to be fragmented
 *
 * Return: the maximum size of payload that can be fragmented.
 */
static size_t batadv_frag_size_limit(void)
{
	size_t limit = BATADV_FRAG_MAX_FRAG_SIZE;

	limit -= sizeof(struct batadv_frag_packet);
	limit *= BATADV_FRAG_MAX_FRAGMENTS;

	return limit;
}

/**
 * batadv_frag_init_chain() - check and prepare fragment chain for new fragment
 * @chain: chain in fragments table to init
 * @seqno: sequence number of the received fragment
 *
 * Make chain ready for a fragment with sequence number "seqno". Delete existing
 * entries if they have an "old" sequence number.
 *
 * Caller must hold chain->lock.
 *
 * Return: true if chain is empty and the caller can just insert the new
 * fragment without searching for the right position.
 */
static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain,
				   u16 seqno)
{
	lockdep_assert_held(&chain->lock);

	if (chain->seqno == seqno)
		return false;

	if (!hlist_empty(&chain->fragment_list))
		batadv_frag_clear_chain(&chain->fragment_list, true);

	chain->size = 0;
	chain->seqno = seqno;

	return true;
}

/**
 * batadv_frag_insert_packet() - insert a fragment into a fragment chain
 * @orig_node: originator that the fragment was received from
 * @skb: skb to insert
 * @chain_out: list head to attach complete chains of fragments to
 *
 * Insert a new fragment into the reverse ordered chain in the right table
 * entry. The hash table entry is cleared if "old" fragments exist in it.
 *
 * Return: true if skb is buffered, false on error. If the chain has all the
 * fragments needed to merge the packet, the chain is moved to the passed head
 * to avoid locking the chain in the table.
 */
static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
				      struct sk_buff *skb,
				      struct hlist_head *chain_out)
{
	struct batadv_frag_table_entry *chain;
	struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr;
	struct batadv_frag_list_entry *frag_entry_last = NULL;
	struct batadv_frag_packet *frag_packet;
	u8 bucket;
	u16 seqno, hdr_size = sizeof(struct batadv_frag_packet);
	bool overflow = false;
	bool ret = false;
	size_t data_len;

	/* Linearize packet to avoid linearizing 16 packets in a row when doing
	 * the later merge. Non-linear merge should be added to remove this
	 * linearization.
	 */
	if (skb_linearize(skb) < 0)
		goto err;

	frag_packet = (struct batadv_frag_packet *)skb->data;
	data_len = skb->len - hdr_size;

Annotation

Implementation Notes