Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad8fec17 authored by Sridhar Samudrala's avatar Sridhar Samudrala Committed by David S. Miller
Browse files

[SCTP]: Verify all the paths to a peer via heartbeat before using them.



This patch implements Path Initialization procedure as described in
Sec 2.36 of RFC4460.

Signed-off-by: default avatarSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cfdeef32
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -445,6 +445,7 @@ typedef struct sctp_sender_hb_info {
	struct sctp_paramhdr param_hdr;
	union sctp_addr daddr;
	unsigned long sent_at;
	__u64 hb_nonce;
} __attribute__((packed)) sctp_sender_hb_info_t;

/*
@@ -984,6 +985,9 @@ struct sctp_transport {
		 */
		char cacc_saw_newack;
	} cacc;

	/* 64-bit random number sent with heartbeat. */
	__u64 hb_nonce;
};

struct sctp_transport *sctp_transport_new(const union sctp_addr *,
+9 −0
Original line number Diff line number Diff line
@@ -560,9 +560,18 @@ struct sctp_paddrinfo {
} __attribute__((packed, aligned(4)));

/* Peer addresses's state. */
/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x]
 * calls.
 * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters.
 *              Not yet confirmed by a heartbeat and not available for data
 *		transfers.
 * ACTIVE : Peer address confirmed, active and available for data transfers.
 * INACTIVE: Peer address inactive and not available for data transfers.
 */
enum sctp_spinfo_state {
	SCTP_INACTIVE,
	SCTP_ACTIVE,
	SCTP_UNCONFIRMED,
	SCTP_UNKNOWN = 0xffff  /* Value used for transport state unknown */
};

+17 −10
Original line number Diff line number Diff line
@@ -441,7 +441,8 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
	/* If the primary path is changing, assume that the
	 * user wants to use this new path.
	 */
	if (transport->state != SCTP_INACTIVE)
	if ((transport->state == SCTP_ACTIVE) ||
	    (transport->state == SCTP_UNKNOWN))
		asoc->peer.active_path = transport;

	/*
@@ -532,11 +533,11 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	port = addr->v4.sin_port;

	SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_add_peer:association %p addr: ",
				 " port: %d state:%s\n",
				 " port: %d state:%d\n",
				 asoc,
				 addr,
				 addr->v4.sin_port,
				 peer_state == SCTP_UNKNOWN?"UNKNOWN":"ACTIVE");
				 peer_state);

	/* Set the port if it has not been set yet.  */
	if (0 == asoc->peer.port)
@@ -545,9 +546,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	/* Check to see if this is a duplicate. */
	peer = sctp_assoc_lookup_paddr(asoc, addr);
	if (peer) {
		if (peer_state == SCTP_ACTIVE &&
		    peer->state == SCTP_UNKNOWN)
		if (peer->state == SCTP_UNKNOWN) {
			if (peer_state == SCTP_ACTIVE)
				peer->state = SCTP_ACTIVE;
			if (peer_state == SCTP_UNCONFIRMED)
				peer->state = SCTP_UNCONFIRMED;
		}
		return peer;
	}

@@ -739,7 +743,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
	list_for_each(pos, &asoc->peer.transport_addr_list) {
		t = list_entry(pos, struct sctp_transport, transports);

		if (t->state == SCTP_INACTIVE)
		if ((t->state == SCTP_INACTIVE) ||
		    (t->state == SCTP_UNCONFIRMED))
			continue;
		if (!first || t->last_time_heard > first->last_time_heard) {
			second = first;
@@ -759,7 +764,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
	 * [If the primary is active but not most recent, bump the most
	 * recently used transport.]
	 */
	if (asoc->peer.primary_path->state != SCTP_INACTIVE &&
	if (((asoc->peer.primary_path->state == SCTP_ACTIVE) ||
	     (asoc->peer.primary_path->state == SCTP_UNKNOWN)) &&
	    first != asoc->peer.primary_path) {
		second = first;
		first = asoc->peer.primary_path;
@@ -1054,7 +1060,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
					   transports);
			if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr))
				sctp_assoc_add_peer(asoc, &trans->ipaddr,
						    GFP_ATOMIC, SCTP_ACTIVE);
						    GFP_ATOMIC, trans->state);
		}

		asoc->ctsn_ack_point = asoc->next_tsn - 1;
@@ -1094,7 +1100,8 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)

		/* Try to find an active transport. */

		if (t->state != SCTP_INACTIVE) {
		if ((t->state == SCTP_ACTIVE) ||
		    (t->state == SCTP_UNKNOWN)) {
			break;
		} else {
			/* Keep track of the next transport in case
+6 −3
Original line number Diff line number Diff line
@@ -691,7 +691,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)

		if (!new_transport) {
			new_transport = asoc->peer.active_path;
		} else if (new_transport->state == SCTP_INACTIVE) {
		} else if ((new_transport->state == SCTP_INACTIVE) ||
			   (new_transport->state == SCTP_UNCONFIRMED)) {
			/* If the chunk is Heartbeat or Heartbeat Ack,
			 * send it to chunk->transport, even if it's
			 * inactive.
@@ -848,7 +849,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
			 */
			new_transport = chunk->transport;
			if (!new_transport ||
			    new_transport->state == SCTP_INACTIVE)
			    ((new_transport->state == SCTP_INACTIVE) ||
			     (new_transport->state == SCTP_UNCONFIRMED)))
				new_transport = asoc->peer.active_path;

			/* Change packets if necessary.  */
@@ -1464,7 +1466,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
			/* Mark the destination transport address as
			 * active if it is not so marked.
			 */
			if (transport->state == SCTP_INACTIVE) {
			if ((transport->state == SCTP_INACTIVE) ||
			    (transport->state == SCTP_UNCONFIRMED)) {
				sctp_assoc_control_transport(
					transport->asoc,
					transport,
+2 −2
Original line number Diff line number Diff line
@@ -2017,7 +2017,7 @@ static int sctp_process_param(struct sctp_association *asoc,
		af->from_addr_param(&addr, param.addr, asoc->peer.port, 0);
		scope = sctp_scope(peer_addr);
		if (sctp_in_scope(&addr, scope))
			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_ACTIVE))
			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
				return 0;
		break;

@@ -2418,7 +2418,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc,
	 	 * Due to Resource Shortage'.
	 	 */

		peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_ACTIVE);
		peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED);
		if (!peer)
			return SCTP_ERROR_RSRC_LOW;

Loading