net/sctp/chunk.c

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

File Facts

System
Linux kernel
Corpus path
net/sctp/chunk.c
Extension
.c
Size
9697 bytes
Lines
355
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 (!msg->send_failed) {
			sctp_chunk_put(chunk);
			continue;
		}

		asoc = chunk->asoc;
		error = msg->send_error ?: asoc->outqueue.error;
		sent = chunk->has_tsn ? SCTP_DATA_SENT : SCTP_DATA_UNSENT;

		if (sctp_ulpevent_type_enabled(asoc->subscribe,
					       SCTP_SEND_FAILED)) {
			ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
							    error, GFP_ATOMIC);
			if (ev)
				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
		}

		if (sctp_ulpevent_type_enabled(asoc->subscribe,
					       SCTP_SEND_FAILED_EVENT)) {
			ev = sctp_ulpevent_make_send_failed_event(asoc, chunk,
								  sent, error,
								  GFP_ATOMIC);
			if (ev)
				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
		}

		sctp_chunk_put(chunk);
	}

	SCTP_DBG_OBJCNT_DEC(datamsg);
	kfree(msg);
}

/* Hold a reference. */
static void sctp_datamsg_hold(struct sctp_datamsg *msg)
{
	refcount_inc(&msg->refcnt);
}

/* Release a reference. */
void sctp_datamsg_put(struct sctp_datamsg *msg)
{
	if (refcount_dec_and_test(&msg->refcnt))
		sctp_datamsg_destroy(msg);
}

/* Assign a chunk to this datamsg. */
static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
{
	sctp_datamsg_hold(msg);
	chunk->msg = msg;
}


/* A data chunk can have a maximum payload of (2^16 - 20).  Break
 * down any such message into smaller chunks.  Opportunistically, fragment
 * the chunks down to the current MTU constraints.  We may get refragmented
 * later if the PMTU changes, but it is _much better_ to fragment immediately
 * with a reasonable guess than always doing our fragmentation on the
 * soft-interrupt.
 */
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
					    struct sctp_sndrcvinfo *sinfo,
					    struct iov_iter *from)
{
	size_t len, first_len, max_data, remaining;
	size_t msg_len = iov_iter_count(from);
	struct sctp_shared_key *shkey = NULL;
	struct list_head *pos, *temp;
	struct sctp_chunk *chunk;
	struct sctp_datamsg *msg;
	int err;

	msg = sctp_datamsg_new(GFP_KERNEL);
	if (!msg)
		return ERR_PTR(-ENOMEM);

	/* Note: Calculate this outside of the loop, so that all fragments
	 * have the same expiration.
	 */
	if (asoc->peer.prsctp_capable && sinfo->sinfo_timetolive &&
	    (SCTP_PR_TTL_ENABLED(sinfo->sinfo_flags) ||
	     !SCTP_PR_POLICY(sinfo->sinfo_flags)))
		msg->expires_at = jiffies +
				  msecs_to_jiffies(sinfo->sinfo_timetolive);

	/* This is the biggest possible DATA chunk that can fit into
	 * the packet
	 */
	max_data = asoc->frag_point;

Annotation

Implementation Notes