net/sctp/outqueue.c

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

File Facts

System
Linux kernel
Corpus path
net/sctp/outqueue.c
Extension
.c
Size
57125 bytes
Lines
1925
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

struct sctp_flush_ctx {
	struct sctp_outq *q;
	/* Current transport being used. It's NOT the same as curr active one */
	struct sctp_transport *transport;
	/* These transports have chunks to send. */
	struct list_head transport_list;
	struct sctp_association *asoc;
	/* Packet on the current transport above */
	struct sctp_packet *packet;
	gfp_t gfp;
};

/* transport: current transport */
static void sctp_outq_select_transport(struct sctp_flush_ctx *ctx,
				       struct sctp_chunk *chunk)
{
	struct sctp_transport *new_transport = chunk->transport;

	if (!new_transport) {
		if (!sctp_chunk_is_data(chunk)) {
			/* If we have a prior transport pointer, see if
			 * the destination address of the chunk
			 * matches the destination address of the
			 * current transport.  If not a match, then
			 * try to look up the transport with a given
			 * destination address.  We do this because
			 * after processing ASCONFs, we may have new
			 * transports created.
			 */
			if (ctx->transport && sctp_cmp_addr_exact(&chunk->dest,
							&ctx->transport->ipaddr))
				new_transport = ctx->transport;
			else
				new_transport = sctp_assoc_lookup_paddr(ctx->asoc,
								  &chunk->dest);
		}

		/* if we still don't have a new transport, then
		 * use the current active path.
		 */
		if (!new_transport)
			new_transport = ctx->asoc->peer.active_path;
	} else {
		__u8 type;

		switch (new_transport->state) {
		case SCTP_INACTIVE:
		case SCTP_UNCONFIRMED:
		case SCTP_PF:
			/* If the chunk is Heartbeat or Heartbeat Ack,
			 * send it to chunk->transport, even if it's
			 * inactive.
			 *
			 * 3.3.6 Heartbeat Acknowledgement:
			 * ...
			 * A HEARTBEAT ACK is always sent to the source IP
			 * address of the IP datagram containing the
			 * HEARTBEAT chunk to which this ack is responding.
			 * ...
			 *
			 * ASCONF_ACKs also must be sent to the source.
			 */
			type = chunk->chunk_hdr->type;
			if (type != SCTP_CID_HEARTBEAT &&
			    type != SCTP_CID_HEARTBEAT_ACK &&
			    type != SCTP_CID_ASCONF_ACK)
				new_transport = ctx->asoc->peer.active_path;
			break;
		default:
			break;
		}
	}

	/* Are we switching transports? Take care of transport locks. */
	if (new_transport != ctx->transport) {
		ctx->transport = new_transport;
		ctx->packet = &ctx->transport->packet;

		if (list_empty(&ctx->transport->send_ready))
			list_add_tail(&ctx->transport->send_ready,
				      &ctx->transport_list);

		sctp_packet_config(ctx->packet,
				   ctx->asoc->peer.i.init_tag,
				   ctx->asoc->peer.ecn_capable);
		/* We've switched transports, so apply the
		 * Burst limit to the new transport.
		 */
		sctp_transport_burst_limited(ctx->transport);
	}

Annotation

Implementation Notes