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

Commit fee91672 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [SCTP]: Allow linger to abort 1-N style sockets.
  [SCTP]: Validate the parameter length in HB-ACK chunk.
  [SCTP]: Respect the real chunk length when walking parameters.
  [SCTP]: A better solution to fix the race between sctp_peeloff() and
  [SCTP]: Set sk_err so that poll wakes up after a non-blocking connect failure.
parents ae83e255 b89498a1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ typedef enum {
	SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */
	SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */
	SCTP_CMD_FORCE_PRIM_RETRAN,  /* Forces retrans. over primary path. */
	SCTP_CMD_SET_SK_ERR,	 /* Set sk_err */
	SCTP_CMD_LAST
} sctp_verb_t;

+3 −3
Original line number Diff line number Diff line
@@ -461,12 +461,12 @@ static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu)
 * there is room for a param header too.
 */
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params((pos), (chunk), WORD_ROUND(ntohs((chunk)->chunk_hdr.length)), member)
_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)

#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
     pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
     pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)) &&\
     pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
     ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
     pos.v += WORD_ROUND(ntohs(pos.p->length)))

@@ -477,7 +477,7 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
	    sizeof(sctp_chunkhdr_t));\
     (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
     (void *)err <= (void *)chunk_hdr + end - WORD_ROUND(ntohs(err->length)) &&\
     (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
     ntohs(err->length) >= sizeof(sctp_errhdr_t); \
     err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))

+81 −63
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ static struct sctp_association *__sctp_lookup_association(
					const union sctp_addr *peer,
					struct sctp_transport **pt);

static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb);


/* Calculate the SCTP checksum of an SCTP packet.  */
static inline int sctp_rcv_checksum(struct sk_buff *skb)
@@ -186,7 +188,6 @@ int sctp_rcv(struct sk_buff *skb)
	 */
	if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb)))
	{
		sock_put(sk);
		if (asoc) {
			sctp_association_put(asoc);
			asoc = NULL;
@@ -197,7 +198,6 @@ int sctp_rcv(struct sk_buff *skb)
		sk = sctp_get_ctl_sock();
		ep = sctp_sk(sk)->ep;
		sctp_endpoint_hold(ep);
		sock_hold(sk);
		rcvr = &ep->base;
	}

@@ -253,25 +253,18 @@ int sctp_rcv(struct sk_buff *skb)
	 */
	sctp_bh_lock_sock(sk);

	/* It is possible that the association could have moved to a different
	 * socket if it is peeled off. If so, update the sk.
	 */ 
	if (sk != rcvr->sk) {
		sctp_bh_lock_sock(rcvr->sk);
		sctp_bh_unlock_sock(sk);
		sk = rcvr->sk;
	}

	if (sock_owned_by_user(sk))
		sk_add_backlog(sk, skb);
		sctp_add_backlog(sk, skb);
	else
		sctp_backlog_rcv(sk, skb);
		sctp_inq_push(&chunk->rcvr->inqueue, chunk);

	/* Release the sock and the sock ref we took in the lookup calls.
	 * The asoc/ep ref will be released in sctp_backlog_rcv.
	 */
	sctp_bh_unlock_sock(sk);
	sock_put(sk);

	/* Release the asoc/ep ref we took in the lookup calls. */
	if (asoc)
		sctp_association_put(asoc);
	else
		sctp_endpoint_put(ep);

	return 0;

@@ -280,8 +273,7 @@ int sctp_rcv(struct sk_buff *skb)
	return 0;

discard_release:
	/* Release any structures we may be holding. */
	sock_put(sk);
	/* Release the asoc/ep ref we took in the lookup calls. */
	if (asoc)
		sctp_association_put(asoc);
	else
@@ -290,56 +282,87 @@ int sctp_rcv(struct sk_buff *skb)
	goto discard_it;
}

/* Handle second half of inbound skb processing.  If the sock was busy,
 * we may have need to delay processing until later when the sock is
 * released (on the backlog).   If not busy, we call this routine
 * directly from the bottom half.
/* Process the backlog queue of the socket.  Every skb on
 * the backlog holds a ref on an association or endpoint.
 * We hold this ref throughout the state machine to make
 * sure that the structure we need is still around.
 */
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
	struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
 	struct sctp_inq *inqueue = NULL;
 	struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
 	struct sctp_ep_common *rcvr = NULL;
	int backloged = 0;

 	rcvr = chunk->rcvr;

	BUG_TRAP(rcvr->sk == sk);

	/* If the rcvr is dead then the association or endpoint
	 * has been deleted and we can safely drop the chunk
	 * and refs that we are holding.
	 */
	if (rcvr->dead) {
		sctp_chunk_free(chunk);
		goto done;
	}

	if (unlikely(rcvr->sk != sk)) {
		/* In this case, the association moved from one socket to
		 * another.  We are currently sitting on the backlog of the
		 * old socket, so we need to move.
		 * However, since we are here in the process context we
		 * need to take make sure that the user doesn't own
		 * the new socket when we process the packet.
		 * If the new socket is user-owned, queue the chunk to the
		 * backlog of the new socket without dropping any refs.
		 * Otherwise, we can safely push the chunk on the inqueue.
		 */

		sk = rcvr->sk;
		sctp_bh_lock_sock(sk);

		if (sock_owned_by_user(sk)) {
			sk_add_backlog(sk, skb);
			backloged = 1;
		} else
			sctp_inq_push(inqueue, chunk);

		sctp_bh_unlock_sock(sk);

		/* If the chunk was backloged again, don't drop refs */
		if (backloged)
			return 0;
	} else {
 		inqueue = &chunk->rcvr->inqueue;
		sctp_inq_push(inqueue, chunk);
	}

	/* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ 
done:
	/* Release the refs we took in sctp_add_backlog */
	if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
		sctp_association_put(sctp_assoc(rcvr));
 	else
	else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
		sctp_endpoint_put(sctp_ep(rcvr));
	else
		BUG();

        return 0;
}

void sctp_backlog_migrate(struct sctp_association *assoc, 
			  struct sock *oldsk, struct sock *newsk)
static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
{
	struct sk_buff *skb;
	struct sctp_chunk *chunk;

	skb = oldsk->sk_backlog.head;
	oldsk->sk_backlog.head = oldsk->sk_backlog.tail = NULL;
	while (skb != NULL) {
		struct sk_buff *next = skb->next;
	struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
	struct sctp_ep_common *rcvr = chunk->rcvr;

		chunk = SCTP_INPUT_CB(skb)->chunk;
		skb->next = NULL;
		if (&assoc->base == chunk->rcvr)
			sk_add_backlog(newsk, skb);
	/* Hold the assoc/ep while hanging on the backlog queue.
	 * This way, we know structures we need will not disappear from us
	 */
	if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
		sctp_association_hold(sctp_assoc(rcvr));
	else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
		sctp_endpoint_hold(sctp_ep(rcvr));
	else
			sk_add_backlog(oldsk, skb);
		skb = next;
	}
		BUG();

	sk_add_backlog(sk, skb);
}

/* Handle icmp frag needed error. */
@@ -412,7 +435,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
	union sctp_addr daddr;
	struct sctp_af *af;
	struct sock *sk = NULL;
	struct sctp_association *asoc = NULL;
	struct sctp_association *asoc;
	struct sctp_transport *transport = NULL;

	*app = NULL; *tpp = NULL;
@@ -453,7 +476,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
	return sk;

out:
	sock_put(sk);
	if (asoc)
		sctp_association_put(asoc);
	return NULL;
@@ -463,7 +485,6 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
{
	sctp_bh_unlock_sock(sk);
	sock_put(sk);
	if (asoc)
		sctp_association_put(asoc);
}
@@ -490,7 +511,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	struct sock *sk;
	struct sctp_association *asoc;
	struct sctp_association *asoc = NULL;
	struct sctp_transport *transport;
	struct inet_sock *inet;
	char *saveip, *savesctp;
@@ -716,7 +737,6 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l

hit:
	sctp_endpoint_hold(ep);
	sock_hold(epb->sk);
	read_unlock(&head->lock);
	return ep;
}
@@ -818,7 +838,6 @@ static struct sctp_association *__sctp_lookup_association(
hit:
	*pt = transport;
	sctp_association_hold(asoc);
	sock_hold(epb->sk);
	read_unlock(&head->lock);
	return asoc;
}
@@ -846,7 +865,6 @@ int sctp_has_association(const union sctp_addr *laddr,
	struct sctp_transport *transport;

	if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
		sock_put(asoc->base.sk);
		sctp_association_put(asoc);
		return 1;
	}
+12 −4
Original line number Diff line number Diff line
@@ -498,10 +498,6 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
			SCTP_STATE(SCTP_STATE_CLOSED));

	/* Set sk_err to ECONNRESET on a 1-1 style socket. */
	if (!sctp_style(asoc->base.sk, UDP))
		asoc->base.sk->sk_err = ECONNRESET; 

	/* SEND_FAILED sent later when cleaning up the association. */
	asoc->outqueue.error = error;
	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
@@ -838,6 +834,15 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
	return;
}

/* Helper function to set sk_err on a 1-1 style socket. */
static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error)
{
	struct sock *sk = asoc->base.sk;

	if (!sctp_style(sk, UDP))
		sk->sk_err = error;
}

/* These three macros allow us to pull the debugging code out of the
 * main flow of sctp_do_sm() to keep attention focused on the real
 * functionality there.
@@ -1458,6 +1463,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
			local_cork = 0;
			asoc->peer.retran_path = t;
			break;
		case SCTP_CMD_SET_SK_ERR:
			sctp_cmd_set_sk_err(asoc, cmd->obj.error);
			break;
		default:
			printk(KERN_WARNING "Impossible command: %u, %p\n",
			       cmd->verb, cmd->obj.ptr);
+54 −27
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);

static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
					   __u16 error,
					   __u16 error, int sk_err,
					   const struct sctp_association *asoc,
					   struct sctp_transport *transport);

@@ -448,7 +448,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
	__u32 init_tag;
	struct sctp_chunk *err_chunk;
	struct sctp_packet *packet;
	sctp_disposition_t ret;
	__u16 error;

	if (!sctp_vtag_verify(chunk, asoc))
		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -480,11 +480,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
			goto nomem;

		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
		sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
				SCTP_STATE(SCTP_STATE_CLOSED));
		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
		sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
		return SCTP_DISPOSITION_DELETE_TCB;
		return sctp_stop_t1_and_abort(commands, SCTP_ERROR_INV_PARAM,
					      ECONNREFUSED, asoc,
					      chunk->transport);
	}

	/* Verify the INIT chunk before processing it. */
@@ -511,27 +509,16 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
						SCTP_PACKET(packet));
				SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
				sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
						SCTP_STATE(SCTP_STATE_CLOSED));
				sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
						SCTP_NULL());
				return SCTP_DISPOSITION_CONSUME;
				error = SCTP_ERROR_INV_PARAM;
			} else {
				sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
						SCTP_STATE(SCTP_STATE_CLOSED));
				sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
						SCTP_NULL());
				return SCTP_DISPOSITION_NOMEM;
				error = SCTP_ERROR_NO_RESOURCE;
			}
		} else {
			ret = sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
						   commands);
			sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
					SCTP_STATE(SCTP_STATE_CLOSED));
			sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
					SCTP_NULL());
			return ret;
			sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
			error = SCTP_ERROR_INV_PARAM;
		}
		return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED,
						asoc, chunk->transport);
	}

	/* Tag the variable length parameters.  Note that we never
@@ -886,6 +873,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
	struct sctp_transport *transport = (struct sctp_transport *) arg;

	if (asoc->overall_error_count >= asoc->max_retrans) {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
@@ -1030,6 +1019,12 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
						  commands);

	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
	/* Make sure that the length of the parameter is what we expect */
	if (ntohs(hbinfo->param_hdr.length) !=
				    sizeof(sctp_sender_hb_info_t)) {
		return SCTP_DISPOSITION_DISCARD;
	}

	from_addr = hbinfo->daddr;
	link = sctp_assoc_lookup_paddr(asoc, &from_addr);

@@ -2126,6 +2121,8 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
	int attempts = asoc->init_err_counter + 1;

	if (attempts > asoc->max_init_attempts) {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
				SCTP_U32(SCTP_ERROR_STALE_COOKIE));
		return SCTP_DISPOSITION_DELETE_TCB;
@@ -2262,6 +2259,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;

	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET));
 	/* ASSOC_FAILED will DELETE_TCB. */
	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
	SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
@@ -2306,7 +2304,8 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;

	return sctp_stop_t1_and_abort(commands, error, asoc, chunk->transport);
	return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, asoc,
				      chunk->transport);
}

/*
@@ -2318,7 +2317,8 @@ sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep
					void *arg,
					sctp_cmd_seq_t *commands)
{
	return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR, asoc,
	return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR,
				      ENOPROTOOPT, asoc,
				      (struct sctp_transport *)arg);
}

@@ -2343,7 +2343,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
 * This is common code called by several sctp_sf_*_abort() functions above.
 */
static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
					   __u16 error,
					   __u16 error, int sk_err,
					   const struct sctp_association *asoc,
					   struct sctp_transport *transport)
{
@@ -2353,6 +2353,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
	SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(sk_err));
	/* CMD_INIT_FAILED will DELETE_TCB. */
	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
			SCTP_U32(error));
@@ -3336,6 +3337,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
				SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			        SCTP_ERROR(ECONNABORTED));
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_ASCONF_ACK));
		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
@@ -3362,6 +3365,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
		 * processing the rest of the chunks in the packet.
		 */
		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			        SCTP_ERROR(ECONNABORTED));
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_ASCONF_ACK));
		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
@@ -3714,9 +3719,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
	if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
				SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ECONNREFUSED));
		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
	} else {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			        SCTP_ERROR(ECONNABORTED));
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
		SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
@@ -4034,6 +4043,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
	 * TCB.  This is a departure from our typical NOMEM handling.
	 */

	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			SCTP_ERROR(ECONNABORTED));
	/* Delete the established association. */
	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
			SCTP_U32(SCTP_ERROR_USER_ABORT));
@@ -4175,6 +4186,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
	 * TCB.  This is a departure from our typical NOMEM handling.
	 */

	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			SCTP_ERROR(ECONNREFUSED));
	/* Delete the established association. */
	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
			SCTP_U32(SCTP_ERROR_USER_ABORT));
@@ -4543,6 +4556,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
	struct sctp_transport *transport = arg;

	if (asoc->overall_error_count >= asoc->max_retrans) {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
@@ -4662,6 +4677,8 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
		SCTP_DEBUG_PRINTK("Giving up on INIT, attempts: %d"
				  " max_init_attempts: %d\n",
				  attempts, asoc->max_init_attempts);
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
		return SCTP_DISPOSITION_DELETE_TCB;
@@ -4711,6 +4728,8 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep

		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
	} else {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
		return SCTP_DISPOSITION_DELETE_TCB;
@@ -4742,6 +4761,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,

	SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
	if (asoc->overall_error_count >= asoc->max_retrans) {
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		/* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
@@ -4817,6 +4838,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
	if (asoc->overall_error_count >= asoc->max_retrans) {
		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
				SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ETIMEDOUT));
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_NO_ERROR));
		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
@@ -4870,6 +4893,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
		goto nomem;

	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
	sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
			SCTP_ERROR(ETIMEDOUT));
	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
			SCTP_U32(SCTP_ERROR_NO_ERROR));

@@ -5309,6 +5334,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
		 * processing the rest of the chunks in the packet.
		 */
		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
				SCTP_ERROR(ECONNABORTED));
		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
				SCTP_U32(SCTP_ERROR_NO_DATA));
		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
Loading