net/sctp/inqueue.c

Source file repositories/reference/linux-study-clean/net/sctp/inqueue.c

File Facts

System
Linux kernel
Corpus path
net/sctp/inqueue.c
Extension
.c
Size
6750 bytes
Lines
246
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 (chunk->head_skb == chunk->skb) {
				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
				goto new_skb;
			}
			if (chunk->skb->next) {
				chunk->skb = chunk->skb->next;
				goto new_skb;
			}

			sctp_inq_chunk_free(chunk);
			chunk = queue->in_progress = NULL;
		} else {
			/* Nothing to do. Next chunk in the packet, please. */
			ch = (struct sctp_chunkhdr *)chunk->chunk_end;
			/* Force chunk->skb->data to chunk->chunk_end.  */
			skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data);
			/* We are guaranteed to pull a SCTP header. */
		}
	}

	/* Do we need to take the next packet out of the queue to process? */
	if (!chunk) {
		struct list_head *entry;

next_chunk:
		/* Is the queue empty?  */
		entry = sctp_list_dequeue(&queue->in_chunk_list);
		if (!entry)
			return NULL;

		chunk = list_entry(entry, struct sctp_chunk, list);

		if (skb_is_gso(chunk->skb) && skb_is_gso_sctp(chunk->skb)) {
			/* GSO-marked skbs but without frags, handle
			 * them normally
			 */
			if (skb_shinfo(chunk->skb)->frag_list)
				chunk->head_skb = chunk->skb;

			/* skbs with "cover letter" */
			if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len) {
				if (WARN_ON(!skb_shinfo(chunk->skb)->frag_list)) {
					__SCTP_INC_STATS(dev_net(chunk->skb->dev),
							 SCTP_MIB_IN_PKT_DISCARDS);
					sctp_chunk_free(chunk);
					goto next_chunk;
				}
				chunk->skb = skb_shinfo(chunk->skb)->frag_list;
			}
		}

		if (chunk->asoc)
			sock_rps_save_rxhash(chunk->asoc->base.sk, chunk->skb);

		queue->in_progress = chunk;

new_skb:
		/* This is the first chunk in the packet.  */
		ch = (struct sctp_chunkhdr *)chunk->skb->data;
		chunk->singleton = 1;
		chunk->data_accepted = 0;
		chunk->pdiscard = 0;
		chunk->auth = 0;
		chunk->has_asconf = 0;
		chunk->end_of_packet = 0;
		if (chunk->head_skb) {
			struct sctp_input_cb
				*cb = SCTP_INPUT_CB(chunk->skb),
				*head_cb = SCTP_INPUT_CB(chunk->head_skb);

			cb->chunk = head_cb->chunk;
			cb->af = head_cb->af;
			cb->encap_port = head_cb->encap_port;
		}
	}

	chunk->chunk_hdr = ch;
	chunk->chunk_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
	skb_pull(chunk->skb, sizeof(*ch));
	chunk->subh.v = NULL; /* Subheader is no longer valid.  */

	if (chunk->chunk_end + sizeof(*ch) <= skb_tail_pointer(chunk->skb)) {
		/* This is not a singleton */
		chunk->singleton = 0;
	} else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) {
		/* Discard inside state machine. */
		chunk->pdiscard = 1;
		chunk->chunk_end = skb_tail_pointer(chunk->skb);
	} else {
		/* We are at the end of the packet, so mark the chunk

Annotation

Implementation Notes