xref: /openbmc/linux/net/sctp/sm_sideeffect.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
147505b8bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
260c778b2SVlad Yasevich /* SCTP kernel implementation
31da177e4SLinus Torvalds  * (C) Copyright IBM Corp. 2001, 2004
41da177e4SLinus Torvalds  * Copyright (c) 1999 Cisco, Inc.
51da177e4SLinus Torvalds  * Copyright (c) 1999-2001 Motorola, Inc.
61da177e4SLinus Torvalds  *
760c778b2SVlad Yasevich  * This file is part of the SCTP kernel implementation
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * These functions work with the state functions in sctp_sm_statefuns.c
101da177e4SLinus Torvalds  * to implement that state operations.  These functions implement the
111da177e4SLinus Torvalds  * steps which require modifying existing data structures.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * Please send any bug reports or fixes you make to the
141da177e4SLinus Torvalds  * email address(es):
1591705c61SDaniel Borkmann  *    lksctp developers <linux-sctp@vger.kernel.org>
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * Written or modified by:
181da177e4SLinus Torvalds  *    La Monte H.P. Yarroll <piggy@acm.org>
191da177e4SLinus Torvalds  *    Karl Knutson          <karl@athena.chicago.il.us>
201da177e4SLinus Torvalds  *    Jon Grimm             <jgrimm@austin.ibm.com>
211da177e4SLinus Torvalds  *    Hui Huang		    <hui.huang@nokia.com>
221da177e4SLinus Torvalds  *    Dajiang Zhang	    <dajiang.zhang@nokia.com>
231da177e4SLinus Torvalds  *    Daisy Chang	    <daisyc@us.ibm.com>
241da177e4SLinus Torvalds  *    Sridhar Samudrala	    <sri@us.ibm.com>
251da177e4SLinus Torvalds  *    Ardelle Fan	    <ardelle.fan@intel.com>
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
28145ce502SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29145ce502SJoe Perches 
301da177e4SLinus Torvalds #include <linux/skbuff.h>
311da177e4SLinus Torvalds #include <linux/types.h>
321da177e4SLinus Torvalds #include <linux/socket.h>
331da177e4SLinus Torvalds #include <linux/ip.h>
345a0e3ad6STejun Heo #include <linux/gfp.h>
351da177e4SLinus Torvalds #include <net/sock.h>
361da177e4SLinus Torvalds #include <net/sctp/sctp.h>
371da177e4SLinus Torvalds #include <net/sctp/sm.h>
385bbbbe32SMarcelo Ricardo Leitner #include <net/sctp/stream_sched.h>
391da177e4SLinus Torvalds 
4088ee48c1SXin Long static int sctp_cmd_interpreter(enum sctp_event_type event_type,
41bfc6f827SXin Long 				union sctp_subtype subtype,
4252106019SXin Long 				enum sctp_state state,
431da177e4SLinus Torvalds 				struct sctp_endpoint *ep,
441da177e4SLinus Torvalds 				struct sctp_association *asoc,
451da177e4SLinus Torvalds 				void *event_arg,
46172a1599SXin Long 				enum sctp_disposition status,
47a85bbeb2SXin Long 				struct sctp_cmd_seq *commands,
48dd0fc66fSAl Viro 				gfp_t gfp);
4988ee48c1SXin Long static int sctp_side_effects(enum sctp_event_type event_type,
50bfc6f827SXin Long 			     union sctp_subtype subtype,
5152106019SXin Long 			     enum sctp_state state,
521da177e4SLinus Torvalds 			     struct sctp_endpoint *ep,
53649621e3SMarcelo Ricardo Leitner 			     struct sctp_association **asoc,
541da177e4SLinus Torvalds 			     void *event_arg,
55172a1599SXin Long 			     enum sctp_disposition status,
56a85bbeb2SXin Long 			     struct sctp_cmd_seq *commands,
57dd0fc66fSAl Viro 			     gfp_t gfp);
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /********************************************************************
601da177e4SLinus Torvalds  * Helper functions
611da177e4SLinus Torvalds  ********************************************************************/
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /* A helper function for delayed processing of INET ECN CE bit. */
sctp_do_ecn_ce_work(struct sctp_association * asoc,__u32 lowest_tsn)641da177e4SLinus Torvalds static void sctp_do_ecn_ce_work(struct sctp_association *asoc,
651da177e4SLinus Torvalds 				__u32 lowest_tsn)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	/* Save the TSN away for comparison when we receive CWR */
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	asoc->last_ecne_tsn = lowest_tsn;
701da177e4SLinus Torvalds 	asoc->need_ecne = 1;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /* Helper function for delayed processing of SCTP ECNE chunk.  */
741da177e4SLinus Torvalds /* RFC 2960 Appendix A
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  * RFC 2481 details a specific bit for a sender to send in
771da177e4SLinus Torvalds  * the header of its next outbound TCP segment to indicate to
781da177e4SLinus Torvalds  * its peer that it has reduced its congestion window.  This
791da177e4SLinus Torvalds  * is termed the CWR bit.  For SCTP the same indication is made
801da177e4SLinus Torvalds  * by including the CWR chunk.  This chunk contains one data
811da177e4SLinus Torvalds  * element, i.e. the TSN number that was sent in the ECNE chunk.
821da177e4SLinus Torvalds  * This element represents the lowest TSN number in the datagram
831da177e4SLinus Torvalds  * that was originally marked with the CE bit.
841da177e4SLinus Torvalds  */
sctp_do_ecn_ecne_work(struct sctp_association * asoc,__u32 lowest_tsn,struct sctp_chunk * chunk)851da177e4SLinus Torvalds static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc,
861da177e4SLinus Torvalds 						__u32 lowest_tsn,
871da177e4SLinus Torvalds 						struct sctp_chunk *chunk)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	struct sctp_chunk *repl;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	/* Our previously transmitted packet ran into some congestion
921da177e4SLinus Torvalds 	 * so we should take action by reducing cwnd and ssthresh
931da177e4SLinus Torvalds 	 * and then ACK our peer that we we've done so by
941da177e4SLinus Torvalds 	 * sending a CWR.
951da177e4SLinus Torvalds 	 */
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	/* First, try to determine if we want to actually lower
981da177e4SLinus Torvalds 	 * our cwnd variables.  Only lower them if the ECNE looks more
991da177e4SLinus Torvalds 	 * recent than the last response.
1001da177e4SLinus Torvalds 	 */
1011da177e4SLinus Torvalds 	if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
1021da177e4SLinus Torvalds 		struct sctp_transport *transport;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 		/* Find which transport's congestion variables
1051da177e4SLinus Torvalds 		 * need to be adjusted.
1061da177e4SLinus Torvalds 		 */
1071da177e4SLinus Torvalds 		transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 		/* Update the congestion variables. */
1101da177e4SLinus Torvalds 		if (transport)
1111da177e4SLinus Torvalds 			sctp_transport_lower_cwnd(transport,
1121da177e4SLinus Torvalds 						  SCTP_LOWER_CWND_ECNE);
1131da177e4SLinus Torvalds 		asoc->last_cwr_tsn = lowest_tsn;
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	/* Always try to quiet the other end.  In case of lost CWR,
1171da177e4SLinus Torvalds 	 * resend last_cwr_tsn.
1181da177e4SLinus Torvalds 	 */
1191da177e4SLinus Torvalds 	repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	/* If we run out of memory, it will look like a lost CWR.  We'll
1221da177e4SLinus Torvalds 	 * get back in sync eventually.
1231da177e4SLinus Torvalds 	 */
1241da177e4SLinus Torvalds 	return repl;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds /* Helper function to do delayed processing of ECN CWR chunk.  */
sctp_do_ecn_cwr_work(struct sctp_association * asoc,__u32 lowest_tsn)1281da177e4SLinus Torvalds static void sctp_do_ecn_cwr_work(struct sctp_association *asoc,
1291da177e4SLinus Torvalds 				 __u32 lowest_tsn)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 	/* Turn off ECNE getting auto-prepended to every outgoing
1321da177e4SLinus Torvalds 	 * packet
1331da177e4SLinus Torvalds 	 */
1341da177e4SLinus Torvalds 	asoc->need_ecne = 0;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds /* Generate SACK if necessary.  We call this at the end of a packet.  */
sctp_gen_sack(struct sctp_association * asoc,int force,struct sctp_cmd_seq * commands)1381da177e4SLinus Torvalds static int sctp_gen_sack(struct sctp_association *asoc, int force,
139a85bbeb2SXin Long 			 struct sctp_cmd_seq *commands)
1401da177e4SLinus Torvalds {
141172a1599SXin Long 	struct sctp_transport *trans = asoc->peer.last_data_from;
1421da177e4SLinus Torvalds 	__u32 ctsn, max_tsn_seen;
1431da177e4SLinus Torvalds 	struct sctp_chunk *sack;
1441da177e4SLinus Torvalds 	int error = 0;
1451da177e4SLinus Torvalds 
14652ccb8e9SFrank Filz 	if (force ||
14752ccb8e9SFrank Filz 	    (!trans && (asoc->param_flags & SPP_SACKDELAY_DISABLE)) ||
14852ccb8e9SFrank Filz 	    (trans && (trans->param_flags & SPP_SACKDELAY_DISABLE)))
1491da177e4SLinus Torvalds 		asoc->peer.sack_needed = 1;
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds 	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
1521da177e4SLinus Torvalds 	max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	/* From 12.2 Parameters necessary per association (i.e. the TCB):
1551da177e4SLinus Torvalds 	 *
1561da177e4SLinus Torvalds 	 * Ack State : This flag indicates if the next received packet
1571da177e4SLinus Torvalds 	 * 	     : is to be responded to with a SACK. ...
1581da177e4SLinus Torvalds 	 *	     : When DATA chunks are out of order, SACK's
1591da177e4SLinus Torvalds 	 *           : are not delayed (see Section 6).
1601da177e4SLinus Torvalds 	 *
1611da177e4SLinus Torvalds 	 * [This is actually not mentioned in Section 6, but we
1621da177e4SLinus Torvalds 	 * implement it here anyway. --piggy]
1631da177e4SLinus Torvalds 	 */
1641da177e4SLinus Torvalds 	if (max_tsn_seen != ctsn)
1651da177e4SLinus Torvalds 		asoc->peer.sack_needed = 1;
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	/* From 6.2  Acknowledgement on Reception of DATA Chunks:
1681da177e4SLinus Torvalds 	 *
1691da177e4SLinus Torvalds 	 * Section 4.2 of [RFC2581] SHOULD be followed. Specifically,
1701da177e4SLinus Torvalds 	 * an acknowledgement SHOULD be generated for at least every
1711da177e4SLinus Torvalds 	 * second packet (not every second DATA chunk) received, and
1721da177e4SLinus Torvalds 	 * SHOULD be generated within 200 ms of the arrival of any
1731da177e4SLinus Torvalds 	 * unacknowledged DATA chunk. ...
1741da177e4SLinus Torvalds 	 */
1751da177e4SLinus Torvalds 	if (!asoc->peer.sack_needed) {
176d364d927SWei Yongjun 		asoc->peer.sack_cnt++;
17752ccb8e9SFrank Filz 
17852ccb8e9SFrank Filz 		/* Set the SACK delay timeout based on the
17952ccb8e9SFrank Filz 		 * SACK delay for the last transport
18052ccb8e9SFrank Filz 		 * data was received from, or the default
18152ccb8e9SFrank Filz 		 * for the association.
18252ccb8e9SFrank Filz 		 */
183d364d927SWei Yongjun 		if (trans) {
184d364d927SWei Yongjun 			/* We will need a SACK for the next packet.  */
185d364d927SWei Yongjun 			if (asoc->peer.sack_cnt >= trans->sackfreq - 1)
186d364d927SWei Yongjun 				asoc->peer.sack_needed = 1;
187d364d927SWei Yongjun 
18852ccb8e9SFrank Filz 			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
18952ccb8e9SFrank Filz 				trans->sackdelay;
190d364d927SWei Yongjun 		} else {
191d364d927SWei Yongjun 			/* We will need a SACK for the next packet.  */
192d364d927SWei Yongjun 			if (asoc->peer.sack_cnt >= asoc->sackfreq - 1)
193d364d927SWei Yongjun 				asoc->peer.sack_needed = 1;
194d364d927SWei Yongjun 
19552ccb8e9SFrank Filz 			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
19652ccb8e9SFrank Filz 				asoc->sackdelay;
197d364d927SWei Yongjun 		}
19852ccb8e9SFrank Filz 
19952ccb8e9SFrank Filz 		/* Restart the SACK timer. */
20052ccb8e9SFrank Filz 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
20152ccb8e9SFrank Filz 				SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
2021da177e4SLinus Torvalds 	} else {
20307b4d6a1SMarcelo Ricardo Leitner 		__u32 old_a_rwnd = asoc->a_rwnd;
20407b4d6a1SMarcelo Ricardo Leitner 
2051da177e4SLinus Torvalds 		asoc->a_rwnd = asoc->rwnd;
2061da177e4SLinus Torvalds 		sack = sctp_make_sack(asoc);
20707b4d6a1SMarcelo Ricardo Leitner 		if (!sack) {
20807b4d6a1SMarcelo Ricardo Leitner 			asoc->a_rwnd = old_a_rwnd;
2091da177e4SLinus Torvalds 			goto nomem;
21007b4d6a1SMarcelo Ricardo Leitner 		}
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 		asoc->peer.sack_needed = 0;
213d364d927SWei Yongjun 		asoc->peer.sack_cnt = 0;
2141da177e4SLinus Torvalds 
215732ba35eSVlad Yasevich 		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 		/* Stop the SACK timer.  */
2181da177e4SLinus Torvalds 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
2191da177e4SLinus Torvalds 				SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
2201da177e4SLinus Torvalds 	}
22152ccb8e9SFrank Filz 
2221da177e4SLinus Torvalds 	return error;
2231da177e4SLinus Torvalds nomem:
2241da177e4SLinus Torvalds 	error = -ENOMEM;
2251da177e4SLinus Torvalds 	return error;
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds /* When the T3-RTX timer expires, it calls this function to create the
2291da177e4SLinus Torvalds  * relevant state machine event.
2301da177e4SLinus Torvalds  */
sctp_generate_t3_rtx_event(struct timer_list * t)2319c3b5751SKees Cook void sctp_generate_t3_rtx_event(struct timer_list *t)
2321da177e4SLinus Torvalds {
2339c3b5751SKees Cook 	struct sctp_transport *transport =
2349c3b5751SKees Cook 		from_timer(transport, t, T3_rtx_timer);
2351da177e4SLinus Torvalds 	struct sctp_association *asoc = transport->asoc;
236635682a1SKarl Heiss 	struct sock *sk = asoc->base.sk;
237635682a1SKarl Heiss 	struct net *net = sock_net(sk);
238172a1599SXin Long 	int error;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	/* Check whether a task is in the sock.  */
2411da177e4SLinus Torvalds 
242635682a1SKarl Heiss 	bh_lock_sock(sk);
243635682a1SKarl Heiss 	if (sock_owned_by_user(sk)) {
244bb33381dSDaniel Borkmann 		pr_debug("%s: sock is busy\n", __func__);
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 		/* Try again later.  */
2471da177e4SLinus Torvalds 		if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
2481da177e4SLinus Torvalds 			sctp_transport_hold(transport);
2491da177e4SLinus Torvalds 		goto out_unlock;
2501da177e4SLinus Torvalds 	}
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	/* Run through the state machine.  */
25355e26eb9SEric W. Biederman 	error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
2541da177e4SLinus Torvalds 			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX),
2551da177e4SLinus Torvalds 			   asoc->state,
2561da177e4SLinus Torvalds 			   asoc->ep, asoc,
2571da177e4SLinus Torvalds 			   transport, GFP_ATOMIC);
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	if (error)
260635682a1SKarl Heiss 		sk->sk_err = -error;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds out_unlock:
263635682a1SKarl Heiss 	bh_unlock_sock(sk);
2641da177e4SLinus Torvalds 	sctp_transport_put(transport);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds /* This is a sa interface for producing timeout events.  It works
2681da177e4SLinus Torvalds  * for timeouts which use the association as their parameter.
2691da177e4SLinus Torvalds  */
sctp_generate_timeout_event(struct sctp_association * asoc,enum sctp_event_timeout timeout_type)2701da177e4SLinus Torvalds static void sctp_generate_timeout_event(struct sctp_association *asoc,
27119cd1592SXin Long 					enum sctp_event_timeout timeout_type)
2721da177e4SLinus Torvalds {
273635682a1SKarl Heiss 	struct sock *sk = asoc->base.sk;
274635682a1SKarl Heiss 	struct net *net = sock_net(sk);
2751da177e4SLinus Torvalds 	int error = 0;
2761da177e4SLinus Torvalds 
277635682a1SKarl Heiss 	bh_lock_sock(sk);
278635682a1SKarl Heiss 	if (sock_owned_by_user(sk)) {
279bb33381dSDaniel Borkmann 		pr_debug("%s: sock is busy: timer %d\n", __func__,
2801da177e4SLinus Torvalds 			 timeout_type);
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 		/* Try again later.  */
2831da177e4SLinus Torvalds 		if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20)))
2841da177e4SLinus Torvalds 			sctp_association_hold(asoc);
2851da177e4SLinus Torvalds 		goto out_unlock;
2861da177e4SLinus Torvalds 	}
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	/* Is this association really dead and just waiting around for
2891da177e4SLinus Torvalds 	 * the timer to let go of the reference?
2901da177e4SLinus Torvalds 	 */
2911da177e4SLinus Torvalds 	if (asoc->base.dead)
2921da177e4SLinus Torvalds 		goto out_unlock;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	/* Run through the state machine.  */
29555e26eb9SEric W. Biederman 	error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
2961da177e4SLinus Torvalds 			   SCTP_ST_TIMEOUT(timeout_type),
2971da177e4SLinus Torvalds 			   asoc->state, asoc->ep, asoc,
2981da177e4SLinus Torvalds 			   (void *)timeout_type, GFP_ATOMIC);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	if (error)
301635682a1SKarl Heiss 		sk->sk_err = -error;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds out_unlock:
304635682a1SKarl Heiss 	bh_unlock_sock(sk);
3051da177e4SLinus Torvalds 	sctp_association_put(asoc);
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds 
sctp_generate_t1_cookie_event(struct timer_list * t)3089c3b5751SKees Cook static void sctp_generate_t1_cookie_event(struct timer_list *t)
3091da177e4SLinus Torvalds {
3109c3b5751SKees Cook 	struct sctp_association *asoc =
3119c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T1_COOKIE]);
3129c3b5751SKees Cook 
3131da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
sctp_generate_t1_init_event(struct timer_list * t)3169c3b5751SKees Cook static void sctp_generate_t1_init_event(struct timer_list *t)
3171da177e4SLinus Torvalds {
3189c3b5751SKees Cook 	struct sctp_association *asoc =
3199c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T1_INIT]);
3209c3b5751SKees Cook 
3211da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
sctp_generate_t2_shutdown_event(struct timer_list * t)3249c3b5751SKees Cook static void sctp_generate_t2_shutdown_event(struct timer_list *t)
3251da177e4SLinus Torvalds {
3269c3b5751SKees Cook 	struct sctp_association *asoc =
3279c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN]);
3289c3b5751SKees Cook 
3291da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
sctp_generate_t4_rto_event(struct timer_list * t)3329c3b5751SKees Cook static void sctp_generate_t4_rto_event(struct timer_list *t)
3331da177e4SLinus Torvalds {
3349c3b5751SKees Cook 	struct sctp_association *asoc =
3359c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_T4_RTO]);
3369c3b5751SKees Cook 
3371da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO);
3381da177e4SLinus Torvalds }
3391da177e4SLinus Torvalds 
sctp_generate_t5_shutdown_guard_event(struct timer_list * t)3409c3b5751SKees Cook static void sctp_generate_t5_shutdown_guard_event(struct timer_list *t)
3411da177e4SLinus Torvalds {
3429c3b5751SKees Cook 	struct sctp_association *asoc =
3439c3b5751SKees Cook 		from_timer(asoc, t,
3449c3b5751SKees Cook 			   timers[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]);
3459c3b5751SKees Cook 
3461da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc,
3471da177e4SLinus Torvalds 				    SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds } /* sctp_generate_t5_shutdown_guard_event() */
3501da177e4SLinus Torvalds 
sctp_generate_autoclose_event(struct timer_list * t)3519c3b5751SKees Cook static void sctp_generate_autoclose_event(struct timer_list *t)
3521da177e4SLinus Torvalds {
3539c3b5751SKees Cook 	struct sctp_association *asoc =
3549c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]);
3559c3b5751SKees Cook 
3561da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds /* Generate a heart beat event.  If the sock is busy, reschedule.   Make
3601da177e4SLinus Torvalds  * sure that the transport is still valid.
3611da177e4SLinus Torvalds  */
sctp_generate_heartbeat_event(struct timer_list * t)3629c3b5751SKees Cook void sctp_generate_heartbeat_event(struct timer_list *t)
3631da177e4SLinus Torvalds {
3649c3b5751SKees Cook 	struct sctp_transport *transport = from_timer(transport, t, hb_timer);
3651da177e4SLinus Torvalds 	struct sctp_association *asoc = transport->asoc;
366635682a1SKarl Heiss 	struct sock *sk = asoc->base.sk;
367635682a1SKarl Heiss 	struct net *net = sock_net(sk);
368ba6f5e33SMarcelo Ricardo Leitner 	u32 elapsed, timeout;
369172a1599SXin Long 	int error = 0;
3701da177e4SLinus Torvalds 
371635682a1SKarl Heiss 	bh_lock_sock(sk);
372635682a1SKarl Heiss 	if (sock_owned_by_user(sk)) {
373bb33381dSDaniel Borkmann 		pr_debug("%s: sock is busy\n", __func__);
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 		/* Try again later.  */
3761da177e4SLinus Torvalds 		if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
3771da177e4SLinus Torvalds 			sctp_transport_hold(transport);
3781da177e4SLinus Torvalds 		goto out_unlock;
3791da177e4SLinus Torvalds 	}
3801da177e4SLinus Torvalds 
381ba6f5e33SMarcelo Ricardo Leitner 	/* Check if we should still send the heartbeat or reschedule */
382ba6f5e33SMarcelo Ricardo Leitner 	elapsed = jiffies - transport->last_time_sent;
383ba6f5e33SMarcelo Ricardo Leitner 	timeout = sctp_transport_timeout(transport);
384ba6f5e33SMarcelo Ricardo Leitner 	if (elapsed < timeout) {
385ba6f5e33SMarcelo Ricardo Leitner 		elapsed = timeout - elapsed;
386ba6f5e33SMarcelo Ricardo Leitner 		if (!mod_timer(&transport->hb_timer, jiffies + elapsed))
387ba6f5e33SMarcelo Ricardo Leitner 			sctp_transport_hold(transport);
388ba6f5e33SMarcelo Ricardo Leitner 		goto out_unlock;
389ba6f5e33SMarcelo Ricardo Leitner 	}
390ba6f5e33SMarcelo Ricardo Leitner 
39155e26eb9SEric W. Biederman 	error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
3921da177e4SLinus Torvalds 			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
3931da177e4SLinus Torvalds 			   asoc->state, asoc->ep, asoc,
3941da177e4SLinus Torvalds 			   transport, GFP_ATOMIC);
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	if (error)
397635682a1SKarl Heiss 		sk->sk_err = -error;
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds out_unlock:
400635682a1SKarl Heiss 	bh_unlock_sock(sk);
4011da177e4SLinus Torvalds 	sctp_transport_put(transport);
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds 
40450b5d6adSVlad Yasevich /* Handle the timeout of the ICMP protocol unreachable timer.  Trigger
40550b5d6adSVlad Yasevich  * the correct state machine transition that will close the association.
40650b5d6adSVlad Yasevich  */
sctp_generate_proto_unreach_event(struct timer_list * t)4079c3b5751SKees Cook void sctp_generate_proto_unreach_event(struct timer_list *t)
40850b5d6adSVlad Yasevich {
4099c3b5751SKees Cook 	struct sctp_transport *transport =
4109c3b5751SKees Cook 		from_timer(transport, t, proto_unreach_timer);
41150b5d6adSVlad Yasevich 	struct sctp_association *asoc = transport->asoc;
412635682a1SKarl Heiss 	struct sock *sk = asoc->base.sk;
413635682a1SKarl Heiss 	struct net *net = sock_net(sk);
41450b5d6adSVlad Yasevich 
415635682a1SKarl Heiss 	bh_lock_sock(sk);
416635682a1SKarl Heiss 	if (sock_owned_by_user(sk)) {
417bb33381dSDaniel Borkmann 		pr_debug("%s: sock is busy\n", __func__);
41850b5d6adSVlad Yasevich 
41950b5d6adSVlad Yasevich 		/* Try again later.  */
42050b5d6adSVlad Yasevich 		if (!mod_timer(&transport->proto_unreach_timer,
42150b5d6adSVlad Yasevich 				jiffies + (HZ/20)))
422057a10faSXin Long 			sctp_transport_hold(transport);
42350b5d6adSVlad Yasevich 		goto out_unlock;
42450b5d6adSVlad Yasevich 	}
42550b5d6adSVlad Yasevich 
42650b5d6adSVlad Yasevich 	/* Is this structure just waiting around for us to actually
42750b5d6adSVlad Yasevich 	 * get destroyed?
42850b5d6adSVlad Yasevich 	 */
42950b5d6adSVlad Yasevich 	if (asoc->base.dead)
43050b5d6adSVlad Yasevich 		goto out_unlock;
43150b5d6adSVlad Yasevich 
43255e26eb9SEric W. Biederman 	sctp_do_sm(net, SCTP_EVENT_T_OTHER,
43350b5d6adSVlad Yasevich 		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
43450b5d6adSVlad Yasevich 		   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
43550b5d6adSVlad Yasevich 
43650b5d6adSVlad Yasevich out_unlock:
437635682a1SKarl Heiss 	bh_unlock_sock(sk);
438057a10faSXin Long 	sctp_transport_put(transport);
43950b5d6adSVlad Yasevich }
44050b5d6adSVlad Yasevich 
4417b9438deSXin Long  /* Handle the timeout of the RE-CONFIG timer. */
sctp_generate_reconf_event(struct timer_list * t)4429c3b5751SKees Cook void sctp_generate_reconf_event(struct timer_list *t)
4437b9438deSXin Long {
4449c3b5751SKees Cook 	struct sctp_transport *transport =
4459c3b5751SKees Cook 		from_timer(transport, t, reconf_timer);
4467b9438deSXin Long 	struct sctp_association *asoc = transport->asoc;
4477b9438deSXin Long 	struct sock *sk = asoc->base.sk;
4487b9438deSXin Long 	struct net *net = sock_net(sk);
4497b9438deSXin Long 	int error = 0;
4507b9438deSXin Long 
4517b9438deSXin Long 	bh_lock_sock(sk);
4527b9438deSXin Long 	if (sock_owned_by_user(sk)) {
4537b9438deSXin Long 		pr_debug("%s: sock is busy\n", __func__);
4547b9438deSXin Long 
4557b9438deSXin Long 		/* Try again later.  */
4567b9438deSXin Long 		if (!mod_timer(&transport->reconf_timer, jiffies + (HZ / 20)))
4577b9438deSXin Long 			sctp_transport_hold(transport);
4587b9438deSXin Long 		goto out_unlock;
4597b9438deSXin Long 	}
4607b9438deSXin Long 
461165e3e17SXin Long 	/* This happens when the response arrives after the timer is triggered. */
462165e3e17SXin Long 	if (!asoc->strreset_chunk)
463165e3e17SXin Long 		goto out_unlock;
464165e3e17SXin Long 
4657b9438deSXin Long 	error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
4667b9438deSXin Long 			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_RECONF),
4677b9438deSXin Long 			   asoc->state, asoc->ep, asoc,
4687b9438deSXin Long 			   transport, GFP_ATOMIC);
4697b9438deSXin Long 
4707b9438deSXin Long 	if (error)
4717b9438deSXin Long 		sk->sk_err = -error;
4727b9438deSXin Long 
4737b9438deSXin Long out_unlock:
4747b9438deSXin Long 	bh_unlock_sock(sk);
4757b9438deSXin Long 	sctp_transport_put(transport);
4767b9438deSXin Long }
47750b5d6adSVlad Yasevich 
47892548ec2SXin Long /* Handle the timeout of the probe timer. */
sctp_generate_probe_event(struct timer_list * t)47992548ec2SXin Long void sctp_generate_probe_event(struct timer_list *t)
48092548ec2SXin Long {
48192548ec2SXin Long 	struct sctp_transport *transport = from_timer(transport, t, probe_timer);
48292548ec2SXin Long 	struct sctp_association *asoc = transport->asoc;
48392548ec2SXin Long 	struct sock *sk = asoc->base.sk;
48492548ec2SXin Long 	struct net *net = sock_net(sk);
48592548ec2SXin Long 	int error = 0;
48692548ec2SXin Long 
48792548ec2SXin Long 	bh_lock_sock(sk);
48892548ec2SXin Long 	if (sock_owned_by_user(sk)) {
48992548ec2SXin Long 		pr_debug("%s: sock is busy\n", __func__);
49092548ec2SXin Long 
49192548ec2SXin Long 		/* Try again later.  */
49292548ec2SXin Long 		if (!mod_timer(&transport->probe_timer, jiffies + (HZ / 20)))
49392548ec2SXin Long 			sctp_transport_hold(transport);
49492548ec2SXin Long 		goto out_unlock;
49592548ec2SXin Long 	}
49692548ec2SXin Long 
49792548ec2SXin Long 	error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
49892548ec2SXin Long 			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_PROBE),
49992548ec2SXin Long 			   asoc->state, asoc->ep, asoc,
50092548ec2SXin Long 			   transport, GFP_ATOMIC);
50192548ec2SXin Long 
50292548ec2SXin Long 	if (error)
50392548ec2SXin Long 		sk->sk_err = -error;
50492548ec2SXin Long 
50592548ec2SXin Long out_unlock:
50692548ec2SXin Long 	bh_unlock_sock(sk);
50792548ec2SXin Long 	sctp_transport_put(transport);
50892548ec2SXin Long }
50992548ec2SXin Long 
5101da177e4SLinus Torvalds /* Inject a SACK Timeout event into the state machine.  */
sctp_generate_sack_event(struct timer_list * t)5119c3b5751SKees Cook static void sctp_generate_sack_event(struct timer_list *t)
5121da177e4SLinus Torvalds {
5139c3b5751SKees Cook 	struct sctp_association *asoc =
5149c3b5751SKees Cook 		from_timer(asoc, t, timers[SCTP_EVENT_TIMEOUT_SACK]);
5159c3b5751SKees Cook 
5161da177e4SLinus Torvalds 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
5171da177e4SLinus Torvalds }
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
5209c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_NONE] =		NULL,
5219c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T1_COOKIE] =	sctp_generate_t1_cookie_event,
5229c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T1_INIT] =		sctp_generate_t1_init_event,
5239c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =	sctp_generate_t2_shutdown_event,
5249c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T3_RTX] =		NULL,
5259c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T4_RTO] =		sctp_generate_t4_rto_event,
5269c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] =
5271da177e4SLinus Torvalds 					sctp_generate_t5_shutdown_guard_event,
5289c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_HEARTBEAT] =	NULL,
5299c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_RECONF] =		NULL,
5309c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_SACK] =		sctp_generate_sack_event,
5319c3b5751SKees Cook 	[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =	sctp_generate_autoclose_event,
5321da177e4SLinus Torvalds };
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds /* RFC 2960 8.2 Path Failure Detection
5361da177e4SLinus Torvalds  *
5371da177e4SLinus Torvalds  * When its peer endpoint is multi-homed, an endpoint should keep a
5381da177e4SLinus Torvalds  * error counter for each of the destination transport addresses of the
5391da177e4SLinus Torvalds  * peer endpoint.
5401da177e4SLinus Torvalds  *
5411da177e4SLinus Torvalds  * Each time the T3-rtx timer expires on any address, or when a
5421da177e4SLinus Torvalds  * HEARTBEAT sent to an idle address is not acknowledged within a RTO,
5431da177e4SLinus Torvalds  * the error counter of that destination address will be incremented.
5441da177e4SLinus Torvalds  * When the value in the error counter exceeds the protocol parameter
5451da177e4SLinus Torvalds  * 'Path.Max.Retrans' of that destination address, the endpoint should
5461da177e4SLinus Torvalds  * mark the destination transport address as inactive, and a
5471da177e4SLinus Torvalds  * notification SHOULD be sent to the upper layer.
5481da177e4SLinus Torvalds  *
5491da177e4SLinus Torvalds  */
sctp_do_8_2_transport_strike(struct sctp_cmd_seq * commands,struct sctp_association * asoc,struct sctp_transport * transport,int is_hb)550a85bbeb2SXin Long static void sctp_do_8_2_transport_strike(struct sctp_cmd_seq *commands,
5515aa93bcfSNeil Horman 					 struct sctp_association *asoc,
5527e99013aSVlad Yasevich 					 struct sctp_transport *transport,
5537e99013aSVlad Yasevich 					 int is_hb)
5541da177e4SLinus Torvalds {
5551da177e4SLinus Torvalds 	/* The check for association's overall error counter exceeding the
5561da177e4SLinus Torvalds 	 * threshold is done in the state function.
5571da177e4SLinus Torvalds 	 */
558b9f84786SVlad Yasevich 	/* We are here due to a timer expiration.  If the timer was
559b9f84786SVlad Yasevich 	 * not a HEARTBEAT, then normal error tracking is done.
560b9f84786SVlad Yasevich 	 * If the timer was a heartbeat, we only increment error counts
561b9f84786SVlad Yasevich 	 * when we already have an outstanding HEARTBEAT that has not
562b9f84786SVlad Yasevich 	 * been acknowledged.
56325985edcSLucas De Marchi 	 * Additionally, some tranport states inhibit error increments.
564ad8fec17SSridhar Samudrala 	 */
565b9f84786SVlad Yasevich 	if (!is_hb) {
566b9f84786SVlad Yasevich 		asoc->overall_error_count++;
567b9f84786SVlad Yasevich 		if (transport->state != SCTP_INACTIVE)
568b9f84786SVlad Yasevich 			transport->error_count++;
569b9f84786SVlad Yasevich 	 } else if (transport->hb_sent) {
570ad8fec17SSridhar Samudrala 		if (transport->state != SCTP_UNCONFIRMED)
5711da177e4SLinus Torvalds 			asoc->overall_error_count++;
572b9f84786SVlad Yasevich 		if (transport->state != SCTP_INACTIVE)
573b9f84786SVlad Yasevich 			transport->error_count++;
574b9f84786SVlad Yasevich 	}
5751da177e4SLinus Torvalds 
5765aa93bcfSNeil Horman 	/* If the transport error count is greater than the pf_retrans
5777cce3b75SMatija Glavinic Pecotic 	 * threshold, and less than pathmaxrtx, and if the current state
5788c2eab90SKarl Heiss 	 * is SCTP_ACTIVE, then mark this transport as Partially Failed,
5798c2eab90SKarl Heiss 	 * see SCTP Quick Failover Draft, section 5.1
5805aa93bcfSNeil Horman 	 */
5814e7696d9SXin Long 	if (asoc->base.net->sctp.pf_enable &&
5824e7696d9SXin Long 	    transport->state == SCTP_ACTIVE &&
5834e7696d9SXin Long 	    transport->error_count < transport->pathmaxrxt &&
5844e7696d9SXin Long 	    transport->error_count > transport->pf_retrans) {
5855aa93bcfSNeil Horman 
5865aa93bcfSNeil Horman 		sctp_assoc_control_transport(asoc, transport,
5875aa93bcfSNeil Horman 					     SCTP_TRANSPORT_PF,
5885aa93bcfSNeil Horman 					     0);
5895aa93bcfSNeil Horman 
5905aa93bcfSNeil Horman 		/* Update the hb timer to resend a heartbeat every rto */
591ba6f5e33SMarcelo Ricardo Leitner 		sctp_transport_reset_hb_timer(transport);
5925aa93bcfSNeil Horman 	}
5935aa93bcfSNeil Horman 
5943f7a87d2SFrank Filz 	if (transport->state != SCTP_INACTIVE &&
595b9f84786SVlad Yasevich 	    (transport->error_count > transport->pathmaxrxt)) {
596bb33381dSDaniel Borkmann 		pr_debug("%s: association:%p transport addr:%pISpc failed\n",
597bb33381dSDaniel Borkmann 			 __func__, asoc, &transport->ipaddr.sa);
598bb33381dSDaniel Borkmann 
5991da177e4SLinus Torvalds 		sctp_assoc_control_transport(asoc, transport,
6001da177e4SLinus Torvalds 					     SCTP_TRANSPORT_DOWN,
6011da177e4SLinus Torvalds 					     SCTP_FAILED_THRESHOLD);
6021da177e4SLinus Torvalds 	}
6031da177e4SLinus Torvalds 
60434515e94SXin Long 	if (transport->error_count > transport->ps_retrans &&
60534515e94SXin Long 	    asoc->peer.primary_path == transport &&
60634515e94SXin Long 	    asoc->peer.active_path != transport)
60734515e94SXin Long 		sctp_assoc_set_primary(asoc, asoc->peer.active_path);
60834515e94SXin Long 
6091da177e4SLinus Torvalds 	/* E2) For the destination address for which the timer
6101da177e4SLinus Torvalds 	 * expires, set RTO <- RTO * 2 ("back off the timer").  The
6111da177e4SLinus Torvalds 	 * maximum value discussed in rule C7 above (RTO.max) may be
6121da177e4SLinus Torvalds 	 * used to provide an upper bound to this doubling operation.
613faee47cdSVlad Yasevich 	 *
614faee47cdSVlad Yasevich 	 * Special Case:  the first HB doesn't trigger exponential backoff.
6153ad2f3fbSDaniel Mack 	 * The first unacknowledged HB triggers it.  We do this with a flag
616faee47cdSVlad Yasevich 	 * that indicates that we have an outstanding HB.
6171da177e4SLinus Torvalds 	 */
6187e99013aSVlad Yasevich 	if (!is_hb || transport->hb_sent) {
6191da177e4SLinus Torvalds 		transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
620196d6759SMichele Baldessari 		sctp_max_rto(asoc, transport);
6211da177e4SLinus Torvalds 	}
622faee47cdSVlad Yasevich }
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds /* Worker routine to handle INIT command failure.  */
sctp_cmd_init_failed(struct sctp_cmd_seq * commands,struct sctp_association * asoc,unsigned int error)625a85bbeb2SXin Long static void sctp_cmd_init_failed(struct sctp_cmd_seq *commands,
6261da177e4SLinus Torvalds 				 struct sctp_association *asoc,
62795c96174SEric Dumazet 				 unsigned int error)
6281da177e4SLinus Torvalds {
6291da177e4SLinus Torvalds 	struct sctp_ulpevent *event;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_CANT_STR_ASSOC,
632a5a35e76SVlad Yasevich 						(__u16)error, 0, 0, NULL,
6331da177e4SLinus Torvalds 						GFP_ATOMIC);
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	if (event)
6361da177e4SLinus Torvalds 		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
6371da177e4SLinus Torvalds 				SCTP_ULPEVENT(event));
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
6401da177e4SLinus Torvalds 			SCTP_STATE(SCTP_STATE_CLOSED));
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds 	/* SEND_FAILED sent later when cleaning up the association. */
6431da177e4SLinus Torvalds 	asoc->outqueue.error = error;
6441da177e4SLinus Torvalds 	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
6451da177e4SLinus Torvalds }
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds /* Worker routine to handle SCTP_CMD_ASSOC_FAILED.  */
sctp_cmd_assoc_failed(struct sctp_cmd_seq * commands,struct sctp_association * asoc,enum sctp_event_type event_type,union sctp_subtype subtype,struct sctp_chunk * chunk,unsigned int error)648a85bbeb2SXin Long static void sctp_cmd_assoc_failed(struct sctp_cmd_seq *commands,
6491da177e4SLinus Torvalds 				  struct sctp_association *asoc,
65088ee48c1SXin Long 				  enum sctp_event_type event_type,
651bfc6f827SXin Long 				  union sctp_subtype subtype,
6521da177e4SLinus Torvalds 				  struct sctp_chunk *chunk,
65395c96174SEric Dumazet 				  unsigned int error)
6541da177e4SLinus Torvalds {
6551da177e4SLinus Torvalds 	struct sctp_ulpevent *event;
656de4594a5SNeil Horman 	struct sctp_chunk *abort;
657172a1599SXin Long 
6581da177e4SLinus Torvalds 	/* Cancel any partial delivery in progress. */
65965f5e357SXin Long 	asoc->stream.si->abort_pd(&asoc->ulpq, GFP_ATOMIC);
6601da177e4SLinus Torvalds 
661a5a35e76SVlad Yasevich 	if (event_type == SCTP_EVENT_T_CHUNK && subtype.chunk == SCTP_CID_ABORT)
6621da177e4SLinus Torvalds 		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
663a5a35e76SVlad Yasevich 						(__u16)error, 0, 0, chunk,
664a5a35e76SVlad Yasevich 						GFP_ATOMIC);
665a5a35e76SVlad Yasevich 	else
666a5a35e76SVlad Yasevich 		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
667a5a35e76SVlad Yasevich 						(__u16)error, 0, 0, NULL,
6681da177e4SLinus Torvalds 						GFP_ATOMIC);
6691da177e4SLinus Torvalds 	if (event)
6701da177e4SLinus Torvalds 		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
6711da177e4SLinus Torvalds 				SCTP_ULPEVENT(event));
6721da177e4SLinus Torvalds 
673de4594a5SNeil Horman 	if (asoc->overall_error_count >= asoc->max_retrans) {
674de4594a5SNeil Horman 		abort = sctp_make_violation_max_retrans(asoc, chunk);
675de4594a5SNeil Horman 		if (abort)
676de4594a5SNeil Horman 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
677de4594a5SNeil Horman 					SCTP_CHUNK(abort));
678de4594a5SNeil Horman 	}
679de4594a5SNeil Horman 
6801da177e4SLinus Torvalds 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
6811da177e4SLinus Torvalds 			SCTP_STATE(SCTP_STATE_CLOSED));
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	/* SEND_FAILED sent later when cleaning up the association. */
6841da177e4SLinus Torvalds 	asoc->outqueue.error = error;
6851da177e4SLinus Torvalds 	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds /* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
6891da177e4SLinus Torvalds  * inside the cookie.  In reality, this is only used for INIT-ACK processing
6901da177e4SLinus Torvalds  * since all other cases use "temporary" associations and can do all
6911da177e4SLinus Torvalds  * their work in statefuns directly.
6921da177e4SLinus Torvalds  */
sctp_cmd_process_init(struct sctp_cmd_seq * commands,struct sctp_association * asoc,struct sctp_chunk * chunk,struct sctp_init_chunk * peer_init,gfp_t gfp)693a85bbeb2SXin Long static int sctp_cmd_process_init(struct sctp_cmd_seq *commands,
6941da177e4SLinus Torvalds 				 struct sctp_association *asoc,
6951da177e4SLinus Torvalds 				 struct sctp_chunk *chunk,
69601a992beSXin Long 				 struct sctp_init_chunk *peer_init,
697dd0fc66fSAl Viro 				 gfp_t gfp)
6981da177e4SLinus Torvalds {
6991da177e4SLinus Torvalds 	int error;
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	/* We only process the init as a sideeffect in a single
7021da177e4SLinus Torvalds 	 * case.   This is when we process the INIT-ACK.   If we
7031da177e4SLinus Torvalds 	 * fail during INIT processing (due to malloc problems),
7041da177e4SLinus Torvalds 	 * just return the error and stop processing the stack.
7051da177e4SLinus Torvalds 	 */
706de6becdcSWei Yongjun 	if (!sctp_process_init(asoc, chunk, sctp_source(chunk), peer_init, gfp))
7071da177e4SLinus Torvalds 		error = -ENOMEM;
7081da177e4SLinus Torvalds 	else
7091da177e4SLinus Torvalds 		error = 0;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	return error;
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds /* Helper function to break out starting up of heartbeat timers.  */
sctp_cmd_hb_timers_start(struct sctp_cmd_seq * cmds,struct sctp_association * asoc)715a85bbeb2SXin Long static void sctp_cmd_hb_timers_start(struct sctp_cmd_seq *cmds,
7161da177e4SLinus Torvalds 				     struct sctp_association *asoc)
7171da177e4SLinus Torvalds {
7181da177e4SLinus Torvalds 	struct sctp_transport *t;
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 	/* Start a heartbeat timer for each transport on the association.
7211da177e4SLinus Torvalds 	 * hold a reference on the transport to make sure none of
7221da177e4SLinus Torvalds 	 * the needed data structures go away.
7231da177e4SLinus Torvalds 	 */
724ba6f5e33SMarcelo Ricardo Leitner 	list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
725ba6f5e33SMarcelo Ricardo Leitner 		sctp_transport_reset_hb_timer(t);
7261da177e4SLinus Torvalds }
7271da177e4SLinus Torvalds 
sctp_cmd_hb_timers_stop(struct sctp_cmd_seq * cmds,struct sctp_association * asoc)728a85bbeb2SXin Long static void sctp_cmd_hb_timers_stop(struct sctp_cmd_seq *cmds,
7291da177e4SLinus Torvalds 				    struct sctp_association *asoc)
7301da177e4SLinus Torvalds {
7311da177e4SLinus Torvalds 	struct sctp_transport *t;
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	/* Stop all heartbeat timers. */
7341da177e4SLinus Torvalds 
7359dbc15f0SRobert P. J. Day 	list_for_each_entry(t, &asoc->peer.transport_addr_list,
7369dbc15f0SRobert P. J. Day 			transports) {
7371da177e4SLinus Torvalds 		if (del_timer(&t->hb_timer))
7381da177e4SLinus Torvalds 			sctp_transport_put(t);
7391da177e4SLinus Torvalds 	}
7401da177e4SLinus Torvalds }
7411da177e4SLinus Torvalds 
7421da177e4SLinus Torvalds /* Helper function to stop any pending T3-RTX timers */
sctp_cmd_t3_rtx_timers_stop(struct sctp_cmd_seq * cmds,struct sctp_association * asoc)743a85bbeb2SXin Long static void sctp_cmd_t3_rtx_timers_stop(struct sctp_cmd_seq *cmds,
7441da177e4SLinus Torvalds 					struct sctp_association *asoc)
7451da177e4SLinus Torvalds {
7461da177e4SLinus Torvalds 	struct sctp_transport *t;
7471da177e4SLinus Torvalds 
7489dbc15f0SRobert P. J. Day 	list_for_each_entry(t, &asoc->peer.transport_addr_list,
7499dbc15f0SRobert P. J. Day 			transports) {
75025cc4ae9SYing Xue 		if (del_timer(&t->T3_rtx_timer))
7511da177e4SLinus Torvalds 			sctp_transport_put(t);
7521da177e4SLinus Torvalds 	}
7531da177e4SLinus Torvalds }
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds /* Helper function to handle the reception of an HEARTBEAT ACK.  */
sctp_cmd_transport_on(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,struct sctp_transport * t,struct sctp_chunk * chunk)757a85bbeb2SXin Long static void sctp_cmd_transport_on(struct sctp_cmd_seq *cmds,
7581da177e4SLinus Torvalds 				  struct sctp_association *asoc,
7591da177e4SLinus Torvalds 				  struct sctp_transport *t,
7601da177e4SLinus Torvalds 				  struct sctp_chunk *chunk)
7611da177e4SLinus Torvalds {
762edf903f8SXin Long 	struct sctp_sender_hb_info *hbinfo;
76334d2d89fSMichio Honda 	int was_unconfirmed = 0;
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 	/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
7661da177e4SLinus Torvalds 	 * HEARTBEAT should clear the error counter of the destination
7671da177e4SLinus Torvalds 	 * transport address to which the HEARTBEAT was sent.
7681da177e4SLinus Torvalds 	 */
7691da177e4SLinus Torvalds 	t->error_count = 0;
770f8d96052SThomas Graf 
771f8d96052SThomas Graf 	/*
772f8d96052SThomas Graf 	 * Although RFC4960 specifies that the overall error count must
773f8d96052SThomas Graf 	 * be cleared when a HEARTBEAT ACK is received, we make an
774f8d96052SThomas Graf 	 * exception while in SHUTDOWN PENDING. If the peer keeps its
775f8d96052SThomas Graf 	 * window shut forever, we may never be able to transmit our
776f8d96052SThomas Graf 	 * outstanding data and rely on the retransmission limit be reached
777f8d96052SThomas Graf 	 * to shutdown the association.
778f8d96052SThomas Graf 	 */
779f648f807Slucien 	if (t->asoc->state < SCTP_STATE_SHUTDOWN_PENDING)
7801da177e4SLinus Torvalds 		t->asoc->overall_error_count = 0;
7811da177e4SLinus Torvalds 
782faee47cdSVlad Yasevich 	/* Clear the hb_sent flag to signal that we had a good
783faee47cdSVlad Yasevich 	 * acknowledgement.
784faee47cdSVlad Yasevich 	 */
785faee47cdSVlad Yasevich 	t->hb_sent = 0;
786faee47cdSVlad Yasevich 
7871da177e4SLinus Torvalds 	/* Mark the destination transport address as active if it is not so
7881da177e4SLinus Torvalds 	 * marked.
7891da177e4SLinus Torvalds 	 */
79034d2d89fSMichio Honda 	if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED)) {
79134d2d89fSMichio Honda 		was_unconfirmed = 1;
7921da177e4SLinus Torvalds 		sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
7931da177e4SLinus Torvalds 					     SCTP_HEARTBEAT_SUCCESS);
79434d2d89fSMichio Honda 	}
7951da177e4SLinus Torvalds 
7965aa93bcfSNeil Horman 	if (t->state == SCTP_PF)
7975aa93bcfSNeil Horman 		sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
7985aa93bcfSNeil Horman 					     SCTP_HEARTBEAT_SUCCESS);
7995aa93bcfSNeil Horman 
8008c2f414aSDaniel Borkmann 	/* HB-ACK was received for a the proper HB.  Consider this
8018c2f414aSDaniel Borkmann 	 * forward progress.
8028c2f414aSDaniel Borkmann 	 */
8038c2f414aSDaniel Borkmann 	if (t->dst)
804c86a773cSJulian Anastasov 		sctp_transport_dst_confirm(t);
8058c2f414aSDaniel Borkmann 
8061da177e4SLinus Torvalds 	/* The receiver of the HEARTBEAT ACK should also perform an
8071da177e4SLinus Torvalds 	 * RTT measurement for that destination transport address
8081da177e4SLinus Torvalds 	 * using the time value carried in the HEARTBEAT ACK chunk.
809e533ca16SVlad Yasevich 	 * If the transport's rto_pending variable has been cleared,
810e533ca16SVlad Yasevich 	 * it was most likely due to a retransmit.  However, we want
811e533ca16SVlad Yasevich 	 * to re-enable it to properly update the rto.
8121da177e4SLinus Torvalds 	 */
813e533ca16SVlad Yasevich 	if (t->rto_pending == 0)
814e533ca16SVlad Yasevich 		t->rto_pending = 1;
815e533ca16SVlad Yasevich 
816edf903f8SXin Long 	hbinfo = (struct sctp_sender_hb_info *)chunk->skb->data;
8171da177e4SLinus Torvalds 	sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at));
818ad8fec17SSridhar Samudrala 
819ad8fec17SSridhar Samudrala 	/* Update the heartbeat timer.  */
820ba6f5e33SMarcelo Ricardo Leitner 	sctp_transport_reset_hb_timer(t);
82134d2d89fSMichio Honda 
82234d2d89fSMichio Honda 	if (was_unconfirmed && asoc->peer.transport_count == 1)
82334d2d89fSMichio Honda 		sctp_transport_immediate_rtx(t);
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds /* Helper function to process the process SACK command.  */
sctp_cmd_process_sack(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,struct sctp_chunk * chunk)828a85bbeb2SXin Long static int sctp_cmd_process_sack(struct sctp_cmd_seq *cmds,
8291da177e4SLinus Torvalds 				 struct sctp_association *asoc,
830edfee033SNicolas Dichtel 				 struct sctp_chunk *chunk)
8311da177e4SLinus Torvalds {
8322e3216cdSVlad Yasevich 	int err = 0;
8331da177e4SLinus Torvalds 
834edfee033SNicolas Dichtel 	if (sctp_outq_sack(&asoc->outqueue, chunk)) {
8351da177e4SLinus Torvalds 		/* There are no more TSNs awaiting SACK.  */
8364e7696d9SXin Long 		err = sctp_do_sm(asoc->base.net, SCTP_EVENT_T_OTHER,
8371da177e4SLinus Torvalds 				 SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
8381da177e4SLinus Torvalds 				 asoc->state, asoc->ep, asoc, NULL,
8391da177e4SLinus Torvalds 				 GFP_ATOMIC);
8401da177e4SLinus Torvalds 	}
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	return err;
8431da177e4SLinus Torvalds }
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
8461da177e4SLinus Torvalds  * the transport for a shutdown chunk.
8471da177e4SLinus Torvalds  */
sctp_cmd_setup_t2(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,struct sctp_chunk * chunk)848a85bbeb2SXin Long static void sctp_cmd_setup_t2(struct sctp_cmd_seq *cmds,
8491da177e4SLinus Torvalds 			      struct sctp_association *asoc,
8501da177e4SLinus Torvalds 			      struct sctp_chunk *chunk)
8511da177e4SLinus Torvalds {
8521da177e4SLinus Torvalds 	struct sctp_transport *t;
8531da177e4SLinus Torvalds 
854c17b02b3SVlad Yasevich 	if (chunk->transport)
855c17b02b3SVlad Yasevich 		t = chunk->transport;
856c17b02b3SVlad Yasevich 	else {
8579919b455SWei Yongjun 		t = sctp_assoc_choose_alter_transport(asoc,
8589919b455SWei Yongjun 					      asoc->shutdown_last_sent_to);
859c17b02b3SVlad Yasevich 		chunk->transport = t;
860c17b02b3SVlad Yasevich 	}
8611da177e4SLinus Torvalds 	asoc->shutdown_last_sent_to = t;
8621da177e4SLinus Torvalds 	asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
8631da177e4SLinus Torvalds }
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds /* Helper function to change the state of an association. */
sctp_cmd_new_state(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,enum sctp_state state)866a85bbeb2SXin Long static void sctp_cmd_new_state(struct sctp_cmd_seq *cmds,
8671da177e4SLinus Torvalds 			       struct sctp_association *asoc,
86852106019SXin Long 			       enum sctp_state state)
8691da177e4SLinus Torvalds {
8701da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	asoc->state = state;
8731da177e4SLinus Torvalds 
874bb33381dSDaniel Borkmann 	pr_debug("%s: asoc:%p[%s]\n", __func__, asoc, sctp_state_tbl[state]);
8753f7a87d2SFrank Filz 
8761da177e4SLinus Torvalds 	if (sctp_style(sk, TCP)) {
8771da177e4SLinus Torvalds 		/* Change the sk->sk_state of a TCP-style socket that has
878af901ca1SAndré Goddard Rosa 		 * successfully completed a connect() call.
8791da177e4SLinus Torvalds 		 */
8801da177e4SLinus Torvalds 		if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
881cbabf463SYafang Shao 			inet_sk_set_state(sk, SCTP_SS_ESTABLISHED);
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 		/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
8841da177e4SLinus Torvalds 		if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
885d46e416cSXin Long 		    sctp_sstate(sk, ESTABLISHED)) {
886cbabf463SYafang Shao 			inet_sk_set_state(sk, SCTP_SS_CLOSING);
8871da177e4SLinus Torvalds 			sk->sk_shutdown |= RCV_SHUTDOWN;
8881da177e4SLinus Torvalds 		}
889d46e416cSXin Long 	}
8901da177e4SLinus Torvalds 
8913f7a87d2SFrank Filz 	if (sctp_state(asoc, COOKIE_WAIT)) {
8923f7a87d2SFrank Filz 		/* Reset init timeouts since they may have been
8933f7a87d2SFrank Filz 		 * increased due to timer expirations.
8943f7a87d2SFrank Filz 		 */
8953f7a87d2SFrank Filz 		asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
8961e7d3d90SVladislav Yasevich 						asoc->rto_initial;
8973f7a87d2SFrank Filz 		asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
8981e7d3d90SVladislav Yasevich 						asoc->rto_initial;
8993f7a87d2SFrank Filz 	}
9003f7a87d2SFrank Filz 
9010a8dd9f6SNeil Horman 	if (sctp_state(asoc, ESTABLISHED)) {
9020a8dd9f6SNeil Horman 		kfree(asoc->peer.cookie);
9030a8dd9f6SNeil Horman 		asoc->peer.cookie = NULL;
9040a8dd9f6SNeil Horman 	}
9050a8dd9f6SNeil Horman 
9061da177e4SLinus Torvalds 	if (sctp_state(asoc, ESTABLISHED) ||
9071da177e4SLinus Torvalds 	    sctp_state(asoc, CLOSED) ||
9081da177e4SLinus Torvalds 	    sctp_state(asoc, SHUTDOWN_RECEIVED)) {
9091da177e4SLinus Torvalds 		/* Wake up any processes waiting in the asoc's wait queue in
9101da177e4SLinus Torvalds 		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf().
9111da177e4SLinus Torvalds 		 */
9121da177e4SLinus Torvalds 		if (waitqueue_active(&asoc->wait))
9131da177e4SLinus Torvalds 			wake_up_interruptible(&asoc->wait);
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 		/* Wake up any processes waiting in the sk's sleep queue of
9161da177e4SLinus Torvalds 		 * a TCP-style or UDP-style peeled-off socket in
9171da177e4SLinus Torvalds 		 * sctp_wait_for_accept() or sctp_wait_for_packet().
9181da177e4SLinus Torvalds 		 * For a UDP-style socket, the waiters are woken up by the
9191da177e4SLinus Torvalds 		 * notifications.
9201da177e4SLinus Torvalds 		 */
9211da177e4SLinus Torvalds 		if (!sctp_style(sk, UDP))
9221da177e4SLinus Torvalds 			sk->sk_state_change(sk);
9231da177e4SLinus Torvalds 	}
924b7018d0bSXin Long 
925b7018d0bSXin Long 	if (sctp_state(asoc, SHUTDOWN_PENDING) &&
926b7018d0bSXin Long 	    !sctp_outq_is_empty(&asoc->outqueue))
927b7018d0bSXin Long 		sctp_outq_uncork(&asoc->outqueue, GFP_ATOMIC);
9281da177e4SLinus Torvalds }
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds /* Helper function to delete an association. */
sctp_cmd_delete_tcb(struct sctp_cmd_seq * cmds,struct sctp_association * asoc)931a85bbeb2SXin Long static void sctp_cmd_delete_tcb(struct sctp_cmd_seq *cmds,
9321da177e4SLinus Torvalds 				struct sctp_association *asoc)
9331da177e4SLinus Torvalds {
9341da177e4SLinus Torvalds 	struct sock *sk = asoc->base.sk;
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	/* If it is a non-temporary association belonging to a TCP-style
9371da177e4SLinus Torvalds 	 * listening socket that is not closed, do not free it so that accept()
9381da177e4SLinus Torvalds 	 * can pick it up later.
9391da177e4SLinus Torvalds 	 */
9401da177e4SLinus Torvalds 	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&
9411da177e4SLinus Torvalds 	    (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
9421da177e4SLinus Torvalds 		return;
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	sctp_association_free(asoc);
9451da177e4SLinus Torvalds }
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds /*
9481da177e4SLinus Torvalds  * ADDIP Section 4.1 ASCONF Chunk Procedures
9491da177e4SLinus Torvalds  * A4) Start a T-4 RTO timer, using the RTO value of the selected
9501da177e4SLinus Torvalds  * destination address (we use active path instead of primary path just
9511da177e4SLinus Torvalds  * because primary path may be inactive.
9521da177e4SLinus Torvalds  */
sctp_cmd_setup_t4(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,struct sctp_chunk * chunk)953a85bbeb2SXin Long static void sctp_cmd_setup_t4(struct sctp_cmd_seq *cmds,
9541da177e4SLinus Torvalds 			      struct sctp_association *asoc,
9551da177e4SLinus Torvalds 			      struct sctp_chunk *chunk)
9561da177e4SLinus Torvalds {
9571da177e4SLinus Torvalds 	struct sctp_transport *t;
9581da177e4SLinus Torvalds 
9599919b455SWei Yongjun 	t = sctp_assoc_choose_alter_transport(asoc, chunk->transport);
9601da177e4SLinus Torvalds 	asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;
9611da177e4SLinus Torvalds 	chunk->transport = t;
9621da177e4SLinus Torvalds }
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds /* Process an incoming Operation Error Chunk. */
sctp_cmd_process_operr(struct sctp_cmd_seq * cmds,struct sctp_association * asoc,struct sctp_chunk * chunk)965a85bbeb2SXin Long static void sctp_cmd_process_operr(struct sctp_cmd_seq *cmds,
9661da177e4SLinus Torvalds 				   struct sctp_association *asoc,
9671da177e4SLinus Torvalds 				   struct sctp_chunk *chunk)
9681da177e4SLinus Torvalds {
9691da177e4SLinus Torvalds 	struct sctp_errhdr *err_hdr;
9703df26787SWei Yongjun 	struct sctp_ulpevent *ev;
9711da177e4SLinus Torvalds 
9723df26787SWei Yongjun 	while (chunk->chunk_end > chunk->skb->data) {
9733df26787SWei Yongjun 		err_hdr = (struct sctp_errhdr *)(chunk->skb->data);
9743df26787SWei Yongjun 
9753df26787SWei Yongjun 		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
9763df26787SWei Yongjun 						     GFP_ATOMIC);
9773df26787SWei Yongjun 		if (!ev)
9783df26787SWei Yongjun 			return;
9793df26787SWei Yongjun 
9809162e0edSXin Long 		asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds 		switch (err_hdr->cause) {
9831da177e4SLinus Torvalds 		case SCTP_ERROR_UNKNOWN_CHUNK:
9841da177e4SLinus Torvalds 		{
985922dbc5bSXin Long 			struct sctp_chunkhdr *unk_chunk_hdr;
9861da177e4SLinus Torvalds 
9879789c1c6SXin Long 			unk_chunk_hdr = (struct sctp_chunkhdr *)(err_hdr + 1);
9881da177e4SLinus Torvalds 			switch (unk_chunk_hdr->type) {
9893df26787SWei Yongjun 			/* ADDIP 4.1 A9) If the peer responds to an ASCONF with
9903df26787SWei Yongjun 			 * an ERROR chunk reporting that it did not recognized
9913df26787SWei Yongjun 			 * the ASCONF chunk type, the sender of the ASCONF MUST
9923df26787SWei Yongjun 			 * NOT send any further ASCONF chunks and MUST stop its
9933df26787SWei Yongjun 			 * T-4 timer.
9941da177e4SLinus Torvalds 			 */
9951da177e4SLinus Torvalds 			case SCTP_CID_ASCONF:
9963df26787SWei Yongjun 				if (asoc->peer.asconf_capable == 0)
9973df26787SWei Yongjun 					break;
9983df26787SWei Yongjun 
9991da177e4SLinus Torvalds 				asoc->peer.asconf_capable = 0;
10001da177e4SLinus Torvalds 				sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
10011da177e4SLinus Torvalds 					SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
10021da177e4SLinus Torvalds 				break;
10031da177e4SLinus Torvalds 			default:
10041da177e4SLinus Torvalds 				break;
10051da177e4SLinus Torvalds 			}
10061da177e4SLinus Torvalds 			break;
10071da177e4SLinus Torvalds 		}
10081da177e4SLinus Torvalds 		default:
10091da177e4SLinus Torvalds 			break;
10101da177e4SLinus Torvalds 		}
10111da177e4SLinus Torvalds 	}
10123df26787SWei Yongjun }
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds /* Helper function to remove the association non-primary peer
10151da177e4SLinus Torvalds  * transports.
10161da177e4SLinus Torvalds  */
sctp_cmd_del_non_primary(struct sctp_association * asoc)10171da177e4SLinus Torvalds static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
10181da177e4SLinus Torvalds {
10191da177e4SLinus Torvalds 	struct sctp_transport *t;
10201da177e4SLinus Torvalds 	struct list_head *temp;
1021172a1599SXin Long 	struct list_head *pos;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
10241da177e4SLinus Torvalds 		t = list_entry(pos, struct sctp_transport, transports);
10255f242a13SAl Viro 		if (!sctp_cmp_addr_exact(&t->ipaddr,
1026acd2bc96SAl Viro 					 &asoc->peer.primary_addr)) {
102773e67420SVlad Yasevich 			sctp_assoc_rm_peer(asoc, t);
10281da177e4SLinus Torvalds 		}
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds 
10328de8c873SSridhar Samudrala /* Helper function to set sk_err on a 1-1 style socket. */
sctp_cmd_set_sk_err(struct sctp_association * asoc,int error)10338de8c873SSridhar Samudrala static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error)
10348de8c873SSridhar Samudrala {
10358de8c873SSridhar Samudrala 	struct sock *sk = asoc->base.sk;
10368de8c873SSridhar Samudrala 
10378de8c873SSridhar Samudrala 	if (!sctp_style(sk, UDP))
10388de8c873SSridhar Samudrala 		sk->sk_err = error;
10398de8c873SSridhar Samudrala }
10408de8c873SSridhar Samudrala 
104107d93967SVlad Yasevich /* Helper function to generate an association change event */
sctp_cmd_assoc_change(struct sctp_cmd_seq * commands,struct sctp_association * asoc,u8 state)1042a85bbeb2SXin Long static void sctp_cmd_assoc_change(struct sctp_cmd_seq *commands,
104307d93967SVlad Yasevich 				  struct sctp_association *asoc,
104407d93967SVlad Yasevich 				  u8 state)
104507d93967SVlad Yasevich {
104607d93967SVlad Yasevich 	struct sctp_ulpevent *ev;
104707d93967SVlad Yasevich 
104807d93967SVlad Yasevich 	ev = sctp_ulpevent_make_assoc_change(asoc, 0, state, 0,
104907d93967SVlad Yasevich 					    asoc->c.sinit_num_ostreams,
105007d93967SVlad Yasevich 					    asoc->c.sinit_max_instreams,
105107d93967SVlad Yasevich 					    NULL, GFP_ATOMIC);
105207d93967SVlad Yasevich 	if (ev)
10539162e0edSXin Long 		asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
105407d93967SVlad Yasevich }
105507d93967SVlad Yasevich 
sctp_cmd_peer_no_auth(struct sctp_cmd_seq * commands,struct sctp_association * asoc)105630f6ebf6SXin Long static void sctp_cmd_peer_no_auth(struct sctp_cmd_seq *commands,
105730f6ebf6SXin Long 				  struct sctp_association *asoc)
105830f6ebf6SXin Long {
105930f6ebf6SXin Long 	struct sctp_ulpevent *ev;
106030f6ebf6SXin Long 
106130f6ebf6SXin Long 	ev = sctp_ulpevent_make_authkey(asoc, 0, SCTP_AUTH_NO_AUTH, GFP_ATOMIC);
106230f6ebf6SXin Long 	if (ev)
106330f6ebf6SXin Long 		asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
106430f6ebf6SXin Long }
106530f6ebf6SXin Long 
106607d93967SVlad Yasevich /* Helper function to generate an adaptation indication event */
sctp_cmd_adaptation_ind(struct sctp_cmd_seq * commands,struct sctp_association * asoc)1067a85bbeb2SXin Long static void sctp_cmd_adaptation_ind(struct sctp_cmd_seq *commands,
106807d93967SVlad Yasevich 				    struct sctp_association *asoc)
106907d93967SVlad Yasevich {
107007d93967SVlad Yasevich 	struct sctp_ulpevent *ev;
107107d93967SVlad Yasevich 
107207d93967SVlad Yasevich 	ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
107307d93967SVlad Yasevich 
107407d93967SVlad Yasevich 	if (ev)
10759162e0edSXin Long 		asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
107607d93967SVlad Yasevich }
107707d93967SVlad Yasevich 
107896cd0d3dSVlad Yasevich 
sctp_cmd_t1_timer_update(struct sctp_association * asoc,enum sctp_event_timeout timer,char * name)107996cd0d3dSVlad Yasevich static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
108019cd1592SXin Long 				     enum sctp_event_timeout timer,
108196cd0d3dSVlad Yasevich 				     char *name)
108296cd0d3dSVlad Yasevich {
108396cd0d3dSVlad Yasevich 	struct sctp_transport *t;
108496cd0d3dSVlad Yasevich 
108596cd0d3dSVlad Yasevich 	t = asoc->init_last_sent_to;
108696cd0d3dSVlad Yasevich 	asoc->init_err_counter++;
108796cd0d3dSVlad Yasevich 
108896cd0d3dSVlad Yasevich 	if (t->init_sent_count > (asoc->init_cycle + 1)) {
108996cd0d3dSVlad Yasevich 		asoc->timeouts[timer] *= 2;
109096cd0d3dSVlad Yasevich 		if (asoc->timeouts[timer] > asoc->max_init_timeo) {
109196cd0d3dSVlad Yasevich 			asoc->timeouts[timer] = asoc->max_init_timeo;
109296cd0d3dSVlad Yasevich 		}
109396cd0d3dSVlad Yasevich 		asoc->init_cycle++;
1094bb33381dSDaniel Borkmann 
1095bb33381dSDaniel Borkmann 		pr_debug("%s: T1[%s] timeout adjustment init_err_counter:%d"
1096bb33381dSDaniel Borkmann 			 " cycle:%d timeout:%ld\n", __func__, name,
1097bb33381dSDaniel Borkmann 			 asoc->init_err_counter, asoc->init_cycle,
109896cd0d3dSVlad Yasevich 			 asoc->timeouts[timer]);
109996cd0d3dSVlad Yasevich 	}
110096cd0d3dSVlad Yasevich 
110196cd0d3dSVlad Yasevich }
110296cd0d3dSVlad Yasevich 
11039c5c62beSVlad Yasevich /* Send the whole message, chunk by chunk, to the outqueue.
11049c5c62beSVlad Yasevich  * This way the whole message is queued up and bundling if
11059c5c62beSVlad Yasevich  * encouraged for small fragments.
11069c5c62beSVlad Yasevich  */
sctp_cmd_send_msg(struct sctp_association * asoc,struct sctp_datamsg * msg,gfp_t gfp)110766388f2cSXin Long static void sctp_cmd_send_msg(struct sctp_association *asoc,
1108cea8768fSMarcelo Ricardo Leitner 			      struct sctp_datamsg *msg, gfp_t gfp)
11099c5c62beSVlad Yasevich {
11109c5c62beSVlad Yasevich 	struct sctp_chunk *chunk;
11119c5c62beSVlad Yasevich 
111266388f2cSXin Long 	list_for_each_entry(chunk, &msg->chunks, frag_list)
111366388f2cSXin Long 		sctp_outq_tail(&asoc->outqueue, chunk, gfp);
11145bbbbe32SMarcelo Ricardo Leitner 
11155bbbbe32SMarcelo Ricardo Leitner 	asoc->outqueue.sched->enqueue(&asoc->outqueue, msg);
11169c5c62beSVlad Yasevich }
11179c5c62beSVlad Yasevich 
11189c5c62beSVlad Yasevich 
11191da177e4SLinus Torvalds /* These three macros allow us to pull the debugging code out of the
11201da177e4SLinus Torvalds  * main flow of sctp_do_sm() to keep attention focused on the real
11211da177e4SLinus Torvalds  * functionality there.
11221da177e4SLinus Torvalds  */
1123bb33381dSDaniel Borkmann #define debug_pre_sfn() \
1124bb33381dSDaniel Borkmann 	pr_debug("%s[pre-fn]: ep:%p, %s, %s, asoc:%p[%s], %s\n", __func__, \
1125bb33381dSDaniel Borkmann 		 ep, sctp_evttype_tbl[event_type], (*debug_fn)(subtype),   \
1126bb33381dSDaniel Borkmann 		 asoc, sctp_state_tbl[state], state_fn->name)
11271da177e4SLinus Torvalds 
1128bb33381dSDaniel Borkmann #define debug_post_sfn() \
1129bb33381dSDaniel Borkmann 	pr_debug("%s[post-fn]: asoc:%p, status:%s\n", __func__, asoc, \
1130bb33381dSDaniel Borkmann 		 sctp_status_tbl[status])
11311da177e4SLinus Torvalds 
1132bb33381dSDaniel Borkmann #define debug_post_sfx() \
1133bb33381dSDaniel Borkmann 	pr_debug("%s[post-sfx]: error:%d, asoc:%p[%s]\n", __func__, error, \
1134bb33381dSDaniel Borkmann 		 asoc, sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \
11351da177e4SLinus Torvalds 		 sctp_assoc2id(asoc))) ? asoc->state : SCTP_STATE_CLOSED])
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds /*
11381da177e4SLinus Torvalds  * This is the master state machine processing function.
11391da177e4SLinus Torvalds  *
11401da177e4SLinus Torvalds  * If you want to understand all of lksctp, this is a
11411da177e4SLinus Torvalds  * good place to start.
11421da177e4SLinus Torvalds  */
sctp_do_sm(struct net * net,enum sctp_event_type event_type,union sctp_subtype subtype,enum sctp_state state,struct sctp_endpoint * ep,struct sctp_association * asoc,void * event_arg,gfp_t gfp)114388ee48c1SXin Long int sctp_do_sm(struct net *net, enum sctp_event_type event_type,
1144bfc6f827SXin Long 	       union sctp_subtype subtype, enum sctp_state state,
114561f0eb07SXin Long 	       struct sctp_endpoint *ep, struct sctp_association *asoc,
114661f0eb07SXin Long 	       void *event_arg, gfp_t gfp)
11471da177e4SLinus Torvalds {
1148bfc6f827SXin Long 	typedef const char *(printfn_t)(union sctp_subtype);
11491da177e4SLinus Torvalds 	static printfn_t *table[] = {
11501da177e4SLinus Torvalds 		NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname,
11511da177e4SLinus Torvalds 	};
11521da177e4SLinus Torvalds 	printfn_t *debug_fn  __attribute__ ((unused)) = table[event_type];
1153172a1599SXin Long 	const struct sctp_sm_table_entry *state_fn;
1154172a1599SXin Long 	struct sctp_cmd_seq commands;
1155172a1599SXin Long 	enum sctp_disposition status;
1156172a1599SXin Long 	int error = 0;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	/* Look up the state function, run it, and then process the
11591da177e4SLinus Torvalds 	 * side effects.  These three steps are the heart of lksctp.
11601da177e4SLinus Torvalds 	 */
116155e26eb9SEric W. Biederman 	state_fn = sctp_sm_lookup_event(net, event_type, state, subtype);
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 	sctp_init_cmd_seq(&commands);
11641da177e4SLinus Torvalds 
1165bb33381dSDaniel Borkmann 	debug_pre_sfn();
1166131334d0Swangweidong 	status = state_fn->fn(net, ep, asoc, subtype, event_arg, &commands);
1167bb33381dSDaniel Borkmann 	debug_post_sfn();
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 	error = sctp_side_effects(event_type, subtype, state,
1170649621e3SMarcelo Ricardo Leitner 				  ep, &asoc, event_arg, status,
11711da177e4SLinus Torvalds 				  &commands, gfp);
1172bb33381dSDaniel Borkmann 	debug_post_sfx();
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	return error;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds /*****************************************************************
11781da177e4SLinus Torvalds  * This the master state function side effect processing function.
11791da177e4SLinus Torvalds  *****************************************************************/
sctp_side_effects(enum sctp_event_type event_type,union sctp_subtype subtype,enum sctp_state state,struct sctp_endpoint * ep,struct sctp_association ** asoc,void * event_arg,enum sctp_disposition status,struct sctp_cmd_seq * commands,gfp_t gfp)118088ee48c1SXin Long static int sctp_side_effects(enum sctp_event_type event_type,
1181bfc6f827SXin Long 			     union sctp_subtype subtype,
118252106019SXin Long 			     enum sctp_state state,
11831da177e4SLinus Torvalds 			     struct sctp_endpoint *ep,
1184649621e3SMarcelo Ricardo Leitner 			     struct sctp_association **asoc,
11851da177e4SLinus Torvalds 			     void *event_arg,
1186172a1599SXin Long 			     enum sctp_disposition status,
1187a85bbeb2SXin Long 			     struct sctp_cmd_seq *commands,
1188dd0fc66fSAl Viro 			     gfp_t gfp)
11891da177e4SLinus Torvalds {
11901da177e4SLinus Torvalds 	int error;
11911da177e4SLinus Torvalds 
11921da177e4SLinus Torvalds 	/* FIXME - Most of the dispositions left today would be categorized
11931da177e4SLinus Torvalds 	 * as "exceptional" dispositions.  For those dispositions, it
11941da177e4SLinus Torvalds 	 * may not be proper to run through any of the commands at all.
11951da177e4SLinus Torvalds 	 * For example, the command interpreter might be run only with
11961da177e4SLinus Torvalds 	 * disposition SCTP_DISPOSITION_CONSUME.
11971da177e4SLinus Torvalds 	 */
11981da177e4SLinus Torvalds 	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
1199649621e3SMarcelo Ricardo Leitner 					       ep, *asoc,
12001da177e4SLinus Torvalds 					       event_arg, status,
12011da177e4SLinus Torvalds 					       commands, gfp)))
12021da177e4SLinus Torvalds 		goto bail;
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 	switch (status) {
12051da177e4SLinus Torvalds 	case SCTP_DISPOSITION_DISCARD:
1206bb33381dSDaniel Borkmann 		pr_debug("%s: ignored sctp protocol event - state:%d, "
1207bb33381dSDaniel Borkmann 			 "event_type:%d, event_id:%d\n", __func__, state,
1208bb33381dSDaniel Borkmann 			 event_type, subtype.chunk);
12091da177e4SLinus Torvalds 		break;
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	case SCTP_DISPOSITION_NOMEM:
12121da177e4SLinus Torvalds 		/* We ran out of memory, so we need to discard this
12131da177e4SLinus Torvalds 		 * packet.
12141da177e4SLinus Torvalds 		 */
12151da177e4SLinus Torvalds 		/* BUG--we should now recover some memory, probably by
12161da177e4SLinus Torvalds 		 * reneging...
12171da177e4SLinus Torvalds 		 */
12181da177e4SLinus Torvalds 		error = -ENOMEM;
12191da177e4SLinus Torvalds 		break;
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds 	case SCTP_DISPOSITION_DELETE_TCB:
1222649621e3SMarcelo Ricardo Leitner 	case SCTP_DISPOSITION_ABORT:
12231da177e4SLinus Torvalds 		/* This should now be a command. */
1224649621e3SMarcelo Ricardo Leitner 		*asoc = NULL;
12251da177e4SLinus Torvalds 		break;
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	case SCTP_DISPOSITION_CONSUME:
12281da177e4SLinus Torvalds 		/*
12291da177e4SLinus Torvalds 		 * We should no longer have much work to do here as the
12301da177e4SLinus Torvalds 		 * real work has been done as explicit commands above.
12311da177e4SLinus Torvalds 		 */
12321da177e4SLinus Torvalds 		break;
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	case SCTP_DISPOSITION_VIOLATION:
1235e87cc472SJoe Perches 		net_err_ratelimited("protocol violation state %d chunkid %d\n",
1236145ce502SJoe Perches 				    state, subtype.chunk);
12371da177e4SLinus Torvalds 		break;
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds 	case SCTP_DISPOSITION_NOT_IMPL:
1240145ce502SJoe Perches 		pr_warn("unimplemented feature in state %d, event_type %d, event_id %d\n",
12411da177e4SLinus Torvalds 			state, event_type, subtype.chunk);
12421da177e4SLinus Torvalds 		break;
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	case SCTP_DISPOSITION_BUG:
1245145ce502SJoe Perches 		pr_err("bug in state %d, event_type %d, event_id %d\n",
12461da177e4SLinus Torvalds 		       state, event_type, subtype.chunk);
12471da177e4SLinus Torvalds 		BUG();
12481da177e4SLinus Torvalds 		break;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	default:
1251145ce502SJoe Perches 		pr_err("impossible disposition %d in state %d, event_type %d, event_id %d\n",
12521da177e4SLinus Torvalds 		       status, state, event_type, subtype.chunk);
1253*a0067dfcSDan Carpenter 		error = status;
1254*a0067dfcSDan Carpenter 		if (error >= 0)
1255*a0067dfcSDan Carpenter 			error = -EINVAL;
1256*a0067dfcSDan Carpenter 		WARN_ON_ONCE(1);
12571da177e4SLinus Torvalds 		break;
12583ff50b79SStephen Hemminger 	}
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds bail:
12611da177e4SLinus Torvalds 	return error;
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds /********************************************************************
12651da177e4SLinus Torvalds  * 2nd Level Abstractions
12661da177e4SLinus Torvalds  ********************************************************************/
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds /* This is the side-effect interpreter.  */
sctp_cmd_interpreter(enum sctp_event_type event_type,union sctp_subtype subtype,enum sctp_state state,struct sctp_endpoint * ep,struct sctp_association * asoc,void * event_arg,enum sctp_disposition status,struct sctp_cmd_seq * commands,gfp_t gfp)126988ee48c1SXin Long static int sctp_cmd_interpreter(enum sctp_event_type event_type,
1270bfc6f827SXin Long 				union sctp_subtype subtype,
127152106019SXin Long 				enum sctp_state state,
12721da177e4SLinus Torvalds 				struct sctp_endpoint *ep,
12731da177e4SLinus Torvalds 				struct sctp_association *asoc,
12741da177e4SLinus Torvalds 				void *event_arg,
1275172a1599SXin Long 				enum sctp_disposition status,
1276a85bbeb2SXin Long 				struct sctp_cmd_seq *commands,
1277dd0fc66fSAl Viro 				gfp_t gfp)
12781da177e4SLinus Torvalds {
1279172a1599SXin Long 	struct sctp_sock *sp = sctp_sk(ep->base.sk);
1280172a1599SXin Long 	struct sctp_chunk *chunk = NULL, *new_obj;
1281172a1599SXin Long 	struct sctp_packet *packet;
1282172a1599SXin Long 	struct sctp_sackhdr sackh;
1283172a1599SXin Long 	struct timer_list *timer;
1284172a1599SXin Long 	struct sctp_transport *t;
1285172a1599SXin Long 	unsigned long timeout;
1286172a1599SXin Long 	struct sctp_cmd *cmd;
1287172a1599SXin Long 	int local_cork = 0;
12881da177e4SLinus Torvalds 	int error = 0;
12891da177e4SLinus Torvalds 	int force;
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 	if (SCTP_EVENT_T_TIMEOUT != event_type)
1292ea110733SJoe Perches 		chunk = event_arg;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 	/* Note:  This whole file is a huge candidate for rework.
12951da177e4SLinus Torvalds 	 * For example, each command could either have its own handler, so
12961da177e4SLinus Torvalds 	 * the loop would look like:
12971da177e4SLinus Torvalds 	 *     while (cmds)
12981da177e4SLinus Torvalds 	 *         cmd->handle(x, y, z)
12991da177e4SLinus Torvalds 	 * --jgrimm
13001da177e4SLinus Torvalds 	 */
13011da177e4SLinus Torvalds 	while (NULL != (cmd = sctp_next_cmd(commands))) {
13021da177e4SLinus Torvalds 		switch (cmd->verb) {
13031da177e4SLinus Torvalds 		case SCTP_CMD_NOP:
13041da177e4SLinus Torvalds 			/* Do nothing. */
13051da177e4SLinus Torvalds 			break;
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds 		case SCTP_CMD_NEW_ASOC:
13081da177e4SLinus Torvalds 			/* Register a new association.  */
13091da177e4SLinus Torvalds 			if (local_cork) {
1310cea8768fSMarcelo Ricardo Leitner 				sctp_outq_uncork(&asoc->outqueue, gfp);
13111da177e4SLinus Torvalds 				local_cork = 0;
13121da177e4SLinus Torvalds 			}
1313f9e42b85SDaniel Borkmann 
13141da177e4SLinus Torvalds 			/* Register with the endpoint.  */
1315f9e42b85SDaniel Borkmann 			asoc = cmd->obj.asoc;
1316f9e42b85SDaniel Borkmann 			BUG_ON(asoc->peer.primary_path == NULL);
13171da177e4SLinus Torvalds 			sctp_endpoint_add_asoc(ep, asoc);
13181da177e4SLinus Torvalds 			break;
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds 		case SCTP_CMD_PURGE_OUTQUEUE:
13211da177e4SLinus Torvalds 		       sctp_outq_teardown(&asoc->outqueue);
13221da177e4SLinus Torvalds 		       break;
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 		case SCTP_CMD_DELETE_TCB:
13251da177e4SLinus Torvalds 			if (local_cork) {
1326cea8768fSMarcelo Ricardo Leitner 				sctp_outq_uncork(&asoc->outqueue, gfp);
13271da177e4SLinus Torvalds 				local_cork = 0;
13281da177e4SLinus Torvalds 			}
13291da177e4SLinus Torvalds 			/* Delete the current association.  */
13301da177e4SLinus Torvalds 			sctp_cmd_delete_tcb(commands, asoc);
13311da177e4SLinus Torvalds 			asoc = NULL;
13321da177e4SLinus Torvalds 			break;
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 		case SCTP_CMD_NEW_STATE:
13351da177e4SLinus Torvalds 			/* Enter a new state.  */
13361da177e4SLinus Torvalds 			sctp_cmd_new_state(commands, asoc, cmd->obj.state);
13371da177e4SLinus Torvalds 			break;
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 		case SCTP_CMD_REPORT_TSN:
13401da177e4SLinus Torvalds 			/* Record the arrival of a TSN.  */
13418e1ee18cSVlad Yasevich 			error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
13424244854dSNeil Horman 						 cmd->obj.u32, NULL);
13431da177e4SLinus Torvalds 			break;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 		case SCTP_CMD_REPORT_FWDTSN:
134647b20a88SXin Long 			asoc->stream.si->report_ftsn(&asoc->ulpq, cmd->obj.u32);
13471da177e4SLinus Torvalds 			break;
13481da177e4SLinus Torvalds 
13491da177e4SLinus Torvalds 		case SCTP_CMD_PROCESS_FWDTSN:
1350de60fe91SXin Long 			asoc->stream.si->handle_ftsn(&asoc->ulpq,
1351de60fe91SXin Long 						     cmd->obj.chunk);
13521da177e4SLinus Torvalds 			break;
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 		case SCTP_CMD_GEN_SACK:
13551da177e4SLinus Torvalds 			/* Generate a Selective ACK.
13561da177e4SLinus Torvalds 			 * The argument tells us whether to just count
13571da177e4SLinus Torvalds 			 * the packet and MAYBE generate a SACK, or
13581da177e4SLinus Torvalds 			 * force a SACK out.
13591da177e4SLinus Torvalds 			 */
13601da177e4SLinus Torvalds 			force = cmd->obj.i32;
13611da177e4SLinus Torvalds 			error = sctp_gen_sack(asoc, force, commands);
13621da177e4SLinus Torvalds 			break;
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		case SCTP_CMD_PROCESS_SACK:
13651da177e4SLinus Torvalds 			/* Process an inbound SACK.  */
13661da177e4SLinus Torvalds 			error = sctp_cmd_process_sack(commands, asoc,
1367b26ddd81SNeil Horman 						      cmd->obj.chunk);
13681da177e4SLinus Torvalds 			break;
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 		case SCTP_CMD_GEN_INIT_ACK:
13711da177e4SLinus Torvalds 			/* Generate an INIT ACK chunk.  */
13721da177e4SLinus Torvalds 			new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC,
13731da177e4SLinus Torvalds 						     0);
1374be7a7729SXin Long 			if (!new_obj) {
1375be7a7729SXin Long 				error = -ENOMEM;
1376be7a7729SXin Long 				break;
1377be7a7729SXin Long 			}
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
13801da177e4SLinus Torvalds 					SCTP_CHUNK(new_obj));
13811da177e4SLinus Torvalds 			break;
13821da177e4SLinus Torvalds 
13831da177e4SLinus Torvalds 		case SCTP_CMD_PEER_INIT:
13841da177e4SLinus Torvalds 			/* Process a unified INIT from the peer.
13851da177e4SLinus Torvalds 			 * Note: Only used during INIT-ACK processing.  If
13861da177e4SLinus Torvalds 			 * there is an error just return to the outter
13871da177e4SLinus Torvalds 			 * layer which will bail.
13881da177e4SLinus Torvalds 			 */
13891da177e4SLinus Torvalds 			error = sctp_cmd_process_init(commands, asoc, chunk,
1390b26ddd81SNeil Horman 						      cmd->obj.init, gfp);
13911da177e4SLinus Torvalds 			break;
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds 		case SCTP_CMD_GEN_COOKIE_ECHO:
13941da177e4SLinus Torvalds 			/* Generate a COOKIE ECHO chunk.  */
13951da177e4SLinus Torvalds 			new_obj = sctp_make_cookie_echo(asoc, chunk);
13961da177e4SLinus Torvalds 			if (!new_obj) {
1397b26ddd81SNeil Horman 				if (cmd->obj.chunk)
1398b26ddd81SNeil Horman 					sctp_chunk_free(cmd->obj.chunk);
1399be7a7729SXin Long 				error = -ENOMEM;
1400be7a7729SXin Long 				break;
14011da177e4SLinus Torvalds 			}
14021da177e4SLinus Torvalds 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
14031da177e4SLinus Torvalds 					SCTP_CHUNK(new_obj));
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 			/* If there is an ERROR chunk to be sent along with
14061da177e4SLinus Torvalds 			 * the COOKIE_ECHO, send it, too.
14071da177e4SLinus Torvalds 			 */
1408b26ddd81SNeil Horman 			if (cmd->obj.chunk)
14091da177e4SLinus Torvalds 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
1410b26ddd81SNeil Horman 						SCTP_CHUNK(cmd->obj.chunk));
14111da177e4SLinus Torvalds 
141296cd0d3dSVlad Yasevich 			if (new_obj->transport) {
141396cd0d3dSVlad Yasevich 				new_obj->transport->init_sent_count++;
141496cd0d3dSVlad Yasevich 				asoc->init_last_sent_to = new_obj->transport;
141596cd0d3dSVlad Yasevich 			}
141696cd0d3dSVlad Yasevich 
14171da177e4SLinus Torvalds 			/* FIXME - Eventually come up with a cleaner way to
14181da177e4SLinus Torvalds 			 * enabling COOKIE-ECHO + DATA bundling during
14191da177e4SLinus Torvalds 			 * multihoming stale cookie scenarios, the following
14201da177e4SLinus Torvalds 			 * command plays with asoc->peer.retran_path to
14211da177e4SLinus Torvalds 			 * avoid the problem of sending the COOKIE-ECHO and
14221da177e4SLinus Torvalds 			 * DATA in different paths, which could result
14231da177e4SLinus Torvalds 			 * in the association being ABORTed if the DATA chunk
14241da177e4SLinus Torvalds 			 * is processed first by the server.  Checking the
14251da177e4SLinus Torvalds 			 * init error counter simply causes this command
14261da177e4SLinus Torvalds 			 * to be executed only during failed attempts of
14271da177e4SLinus Torvalds 			 * association establishment.
14281da177e4SLinus Torvalds 			 */
14291da177e4SLinus Torvalds 			if ((asoc->peer.retran_path !=
14301da177e4SLinus Torvalds 			     asoc->peer.primary_path) &&
14313f7a87d2SFrank Filz 			    (asoc->init_err_counter > 0)) {
14321da177e4SLinus Torvalds 				sctp_add_cmd_sf(commands,
14331da177e4SLinus Torvalds 						SCTP_CMD_FORCE_PRIM_RETRAN,
14341da177e4SLinus Torvalds 						SCTP_NULL());
14351da177e4SLinus Torvalds 			}
14361da177e4SLinus Torvalds 
14371da177e4SLinus Torvalds 			break;
14381da177e4SLinus Torvalds 
14391da177e4SLinus Torvalds 		case SCTP_CMD_GEN_SHUTDOWN:
14401da177e4SLinus Torvalds 			/* Generate SHUTDOWN when in SHUTDOWN_SENT state.
14411da177e4SLinus Torvalds 			 * Reset error counts.
14421da177e4SLinus Torvalds 			 */
14431da177e4SLinus Torvalds 			asoc->overall_error_count = 0;
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 			/* Generate a SHUTDOWN chunk.  */
14461da177e4SLinus Torvalds 			new_obj = sctp_make_shutdown(asoc, chunk);
1447be7a7729SXin Long 			if (!new_obj) {
1448be7a7729SXin Long 				error = -ENOMEM;
1449be7a7729SXin Long 				break;
1450be7a7729SXin Long 			}
14511da177e4SLinus Torvalds 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
14521da177e4SLinus Torvalds 					SCTP_CHUNK(new_obj));
14531da177e4SLinus Torvalds 			break;
14541da177e4SLinus Torvalds 
14551da177e4SLinus Torvalds 		case SCTP_CMD_CHUNK_ULP:
14561da177e4SLinus Torvalds 			/* Send a chunk to the sockets layer.  */
1457bb33381dSDaniel Borkmann 			pr_debug("%s: sm_sideff: chunk_up:%p, ulpq:%p\n",
1458bb33381dSDaniel Borkmann 				 __func__, cmd->obj.chunk, &asoc->ulpq);
1459bb33381dSDaniel Borkmann 
1460bd4d627dSXin Long 			asoc->stream.si->ulpevent_data(&asoc->ulpq,
1461bd4d627dSXin Long 						       cmd->obj.chunk,
14621da177e4SLinus Torvalds 						       GFP_ATOMIC);
14631da177e4SLinus Torvalds 			break;
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 		case SCTP_CMD_EVENT_ULP:
14661da177e4SLinus Torvalds 			/* Send a notification to the sockets layer.  */
1467bb33381dSDaniel Borkmann 			pr_debug("%s: sm_sideff: event_up:%p, ulpq:%p\n",
1468bb33381dSDaniel Borkmann 				 __func__, cmd->obj.ulpevent, &asoc->ulpq);
1469bb33381dSDaniel Borkmann 
14709162e0edSXin Long 			asoc->stream.si->enqueue_event(&asoc->ulpq,
14719162e0edSXin Long 						       cmd->obj.ulpevent);
14721da177e4SLinus Torvalds 			break;
14731da177e4SLinus Torvalds 
14741da177e4SLinus Torvalds 		case SCTP_CMD_REPLY:
14751da177e4SLinus Torvalds 			/* If an caller has not already corked, do cork. */
14761da177e4SLinus Torvalds 			if (!asoc->outqueue.cork) {
14771da177e4SLinus Torvalds 				sctp_outq_cork(&asoc->outqueue);
14781da177e4SLinus Torvalds 				local_cork = 1;
14791da177e4SLinus Torvalds 			}
14801da177e4SLinus Torvalds 			/* Send a chunk to our peer.  */
148183dbc3d4SXin Long 			sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk, gfp);
14821da177e4SLinus Torvalds 			break;
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 		case SCTP_CMD_SEND_PKT:
14851da177e4SLinus Torvalds 			/* Send a full packet to our peer.  */
1486b26ddd81SNeil Horman 			packet = cmd->obj.packet;
1487cea8768fSMarcelo Ricardo Leitner 			sctp_packet_transmit(packet, gfp);
14881da177e4SLinus Torvalds 			sctp_ootb_pkt_free(packet);
14891da177e4SLinus Torvalds 			break;
14901da177e4SLinus Torvalds 
1491b6157d8eSVlad Yasevich 		case SCTP_CMD_T1_RETRAN:
1492b6157d8eSVlad Yasevich 			/* Mark a transport for retransmission.  */
1493b6157d8eSVlad Yasevich 			sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
1494b6157d8eSVlad Yasevich 					SCTP_RTXR_T1_RTX);
1495b6157d8eSVlad Yasevich 			break;
1496b6157d8eSVlad Yasevich 
14971da177e4SLinus Torvalds 		case SCTP_CMD_RETRAN:
14981da177e4SLinus Torvalds 			/* Mark a transport for retransmission.  */
14991da177e4SLinus Torvalds 			sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
15001da177e4SLinus Torvalds 					SCTP_RTXR_T3_RTX);
15011da177e4SLinus Torvalds 			break;
15021da177e4SLinus Torvalds 
15031da177e4SLinus Torvalds 		case SCTP_CMD_ECN_CE:
15041da177e4SLinus Torvalds 			/* Do delayed CE processing.   */
15051da177e4SLinus Torvalds 			sctp_do_ecn_ce_work(asoc, cmd->obj.u32);
15061da177e4SLinus Torvalds 			break;
15071da177e4SLinus Torvalds 
15081da177e4SLinus Torvalds 		case SCTP_CMD_ECN_ECNE:
15091da177e4SLinus Torvalds 			/* Do delayed ECNE processing. */
15101da177e4SLinus Torvalds 			new_obj = sctp_do_ecn_ecne_work(asoc, cmd->obj.u32,
15111da177e4SLinus Torvalds 							chunk);
15121da177e4SLinus Torvalds 			if (new_obj)
15131da177e4SLinus Torvalds 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
15141da177e4SLinus Torvalds 						SCTP_CHUNK(new_obj));
15151da177e4SLinus Torvalds 			break;
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 		case SCTP_CMD_ECN_CWR:
15181da177e4SLinus Torvalds 			/* Do delayed CWR processing.  */
15191da177e4SLinus Torvalds 			sctp_do_ecn_cwr_work(asoc, cmd->obj.u32);
15201da177e4SLinus Torvalds 			break;
15211da177e4SLinus Torvalds 
15221da177e4SLinus Torvalds 		case SCTP_CMD_SETUP_T2:
1523b26ddd81SNeil Horman 			sctp_cmd_setup_t2(commands, asoc, cmd->obj.chunk);
15241da177e4SLinus Torvalds 			break;
15251da177e4SLinus Torvalds 
1526f8d96052SThomas Graf 		case SCTP_CMD_TIMER_START_ONCE:
1527f8d96052SThomas Graf 			timer = &asoc->timers[cmd->obj.to];
1528f8d96052SThomas Graf 
1529f8d96052SThomas Graf 			if (timer_pending(timer))
1530f8d96052SThomas Graf 				break;
1531df561f66SGustavo A. R. Silva 			fallthrough;
1532f8d96052SThomas Graf 
15331da177e4SLinus Torvalds 		case SCTP_CMD_TIMER_START:
15341da177e4SLinus Torvalds 			timer = &asoc->timers[cmd->obj.to];
15351da177e4SLinus Torvalds 			timeout = asoc->timeouts[cmd->obj.to];
153609a62660SKris Katterjohn 			BUG_ON(!timeout);
15371da177e4SLinus Torvalds 
153820a785aaSNeil Horman 			/*
153920a785aaSNeil Horman 			 * SCTP has a hard time with timer starts.  Because we process
154020a785aaSNeil Horman 			 * timer starts as side effects, it can be hard to tell if we
154120a785aaSNeil Horman 			 * have already started a timer or not, which leads to BUG
154220a785aaSNeil Horman 			 * halts when we call add_timer. So here, instead of just starting
154320a785aaSNeil Horman 			 * a timer, if the timer is already started, and just mod
154420a785aaSNeil Horman 			 * the timer with the shorter of the two expiration times
154520a785aaSNeil Horman 			 */
154620a785aaSNeil Horman 			if (!timer_pending(timer))
15471da177e4SLinus Torvalds 				sctp_association_hold(asoc);
154820a785aaSNeil Horman 			timer_reduce(timer, jiffies + timeout);
15491da177e4SLinus Torvalds 			break;
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds 		case SCTP_CMD_TIMER_RESTART:
15521da177e4SLinus Torvalds 			timer = &asoc->timers[cmd->obj.to];
15531da177e4SLinus Torvalds 			timeout = asoc->timeouts[cmd->obj.to];
15541da177e4SLinus Torvalds 			if (!mod_timer(timer, jiffies + timeout))
15551da177e4SLinus Torvalds 				sctp_association_hold(asoc);
15561da177e4SLinus Torvalds 			break;
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 		case SCTP_CMD_TIMER_STOP:
15591da177e4SLinus Torvalds 			timer = &asoc->timers[cmd->obj.to];
156025cc4ae9SYing Xue 			if (del_timer(timer))
15611da177e4SLinus Torvalds 				sctp_association_put(asoc);
15621da177e4SLinus Torvalds 			break;
15631da177e4SLinus Torvalds 
15643f7a87d2SFrank Filz 		case SCTP_CMD_INIT_CHOOSE_TRANSPORT:
1565b26ddd81SNeil Horman 			chunk = cmd->obj.chunk;
15669919b455SWei Yongjun 			t = sctp_assoc_choose_alter_transport(asoc,
15679919b455SWei Yongjun 						asoc->init_last_sent_to);
15683f7a87d2SFrank Filz 			asoc->init_last_sent_to = t;
15693f7a87d2SFrank Filz 			chunk->transport = t;
15703f7a87d2SFrank Filz 			t->init_sent_count++;
1571e0e9db17SVlad Yasevich 			/* Set the new transport as primary */
1572e0e9db17SVlad Yasevich 			sctp_assoc_set_primary(asoc, t);
15733f7a87d2SFrank Filz 			break;
15743f7a87d2SFrank Filz 
15751da177e4SLinus Torvalds 		case SCTP_CMD_INIT_RESTART:
15761da177e4SLinus Torvalds 			/* Do the needed accounting and updates
15771da177e4SLinus Torvalds 			 * associated with restarting an initialization
15783f7a87d2SFrank Filz 			 * timer. Only multiply the timeout by two if
15793f7a87d2SFrank Filz 			 * all transports have been tried at the current
15803f7a87d2SFrank Filz 			 * timeout.
15811da177e4SLinus Torvalds 			 */
158296cd0d3dSVlad Yasevich 			sctp_cmd_t1_timer_update(asoc,
158396cd0d3dSVlad Yasevich 						SCTP_EVENT_TIMEOUT_T1_INIT,
158496cd0d3dSVlad Yasevich 						"INIT");
15853f7a87d2SFrank Filz 
15863f7a87d2SFrank Filz 			sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
15873f7a87d2SFrank Filz 					SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
15883f7a87d2SFrank Filz 			break;
15893f7a87d2SFrank Filz 
15903f7a87d2SFrank Filz 		case SCTP_CMD_COOKIEECHO_RESTART:
15913f7a87d2SFrank Filz 			/* Do the needed accounting and updates
15923f7a87d2SFrank Filz 			 * associated with restarting an initialization
15933f7a87d2SFrank Filz 			 * timer. Only multiply the timeout by two if
15943f7a87d2SFrank Filz 			 * all transports have been tried at the current
15953f7a87d2SFrank Filz 			 * timeout.
15963f7a87d2SFrank Filz 			 */
159796cd0d3dSVlad Yasevich 			sctp_cmd_t1_timer_update(asoc,
159896cd0d3dSVlad Yasevich 						SCTP_EVENT_TIMEOUT_T1_COOKIE,
159996cd0d3dSVlad Yasevich 						"COOKIE");
16001da177e4SLinus Torvalds 
16011da177e4SLinus Torvalds 			/* If we've sent any data bundled with
16021da177e4SLinus Torvalds 			 * COOKIE-ECHO we need to resend.
16031da177e4SLinus Torvalds 			 */
16049dbc15f0SRobert P. J. Day 			list_for_each_entry(t, &asoc->peer.transport_addr_list,
16059dbc15f0SRobert P. J. Day 					transports) {
1606b6157d8eSVlad Yasevich 				sctp_retransmit_mark(&asoc->outqueue, t,
1607b6157d8eSVlad Yasevich 					    SCTP_RTXR_T1_RTX);
16081da177e4SLinus Torvalds 			}
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 			sctp_add_cmd_sf(commands,
16111da177e4SLinus Torvalds 					SCTP_CMD_TIMER_RESTART,
16123f7a87d2SFrank Filz 					SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
16131da177e4SLinus Torvalds 			break;
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds 		case SCTP_CMD_INIT_FAILED:
1616b6df8c81SPetr Malat 			sctp_cmd_init_failed(commands, asoc, cmd->obj.u16);
16171da177e4SLinus Torvalds 			break;
16181da177e4SLinus Torvalds 
16191da177e4SLinus Torvalds 		case SCTP_CMD_ASSOC_FAILED:
16201da177e4SLinus Torvalds 			sctp_cmd_assoc_failed(commands, asoc, event_type,
1621b6df8c81SPetr Malat 					      subtype, chunk, cmd->obj.u16);
16221da177e4SLinus Torvalds 			break;
16231da177e4SLinus Torvalds 
16243f7a87d2SFrank Filz 		case SCTP_CMD_INIT_COUNTER_INC:
16253f7a87d2SFrank Filz 			asoc->init_err_counter++;
16261da177e4SLinus Torvalds 			break;
16271da177e4SLinus Torvalds 
16283f7a87d2SFrank Filz 		case SCTP_CMD_INIT_COUNTER_RESET:
16293f7a87d2SFrank Filz 			asoc->init_err_counter = 0;
16303f7a87d2SFrank Filz 			asoc->init_cycle = 0;
163196cd0d3dSVlad Yasevich 			list_for_each_entry(t, &asoc->peer.transport_addr_list,
163296cd0d3dSVlad Yasevich 					    transports) {
163396cd0d3dSVlad Yasevich 				t->init_sent_count = 0;
163496cd0d3dSVlad Yasevich 			}
16351da177e4SLinus Torvalds 			break;
16361da177e4SLinus Torvalds 
16371da177e4SLinus Torvalds 		case SCTP_CMD_REPORT_DUP:
16381da177e4SLinus Torvalds 			sctp_tsnmap_mark_dup(&asoc->peer.tsn_map,
16391da177e4SLinus Torvalds 					     cmd->obj.u32);
16401da177e4SLinus Torvalds 			break;
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 		case SCTP_CMD_REPORT_BAD_TAG:
1643bb33381dSDaniel Borkmann 			pr_debug("%s: vtag mismatch!\n", __func__);
16441da177e4SLinus Torvalds 			break;
16451da177e4SLinus Torvalds 
16461da177e4SLinus Torvalds 		case SCTP_CMD_STRIKE:
16471da177e4SLinus Torvalds 			/* Mark one strike against a transport.  */
16485aa93bcfSNeil Horman 			sctp_do_8_2_transport_strike(commands, asoc,
16495aa93bcfSNeil Horman 						    cmd->obj.transport, 0);
16501da177e4SLinus Torvalds 			break;
16511da177e4SLinus Torvalds 
16527e99013aSVlad Yasevich 		case SCTP_CMD_TRANSPORT_IDLE:
16531da177e4SLinus Torvalds 			t = cmd->obj.transport;
16547e99013aSVlad Yasevich 			sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
16557e99013aSVlad Yasevich 			break;
16567e99013aSVlad Yasevich 
16577e99013aSVlad Yasevich 		case SCTP_CMD_TRANSPORT_HB_SENT:
16587e99013aSVlad Yasevich 			t = cmd->obj.transport;
16595aa93bcfSNeil Horman 			sctp_do_8_2_transport_strike(commands, asoc,
16605aa93bcfSNeil Horman 						     t, 1);
16617e99013aSVlad Yasevich 			t->hb_sent = 1;
16621da177e4SLinus Torvalds 			break;
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 		case SCTP_CMD_TRANSPORT_ON:
16651da177e4SLinus Torvalds 			t = cmd->obj.transport;
16661da177e4SLinus Torvalds 			sctp_cmd_transport_on(commands, asoc, t, chunk);
16671da177e4SLinus Torvalds 			break;
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 		case SCTP_CMD_HB_TIMERS_START:
16701da177e4SLinus Torvalds 			sctp_cmd_hb_timers_start(commands, asoc);
16711da177e4SLinus Torvalds 			break;
16721da177e4SLinus Torvalds 
16731da177e4SLinus Torvalds 		case SCTP_CMD_HB_TIMER_UPDATE:
16741da177e4SLinus Torvalds 			t = cmd->obj.transport;
1675ba6f5e33SMarcelo Ricardo Leitner 			sctp_transport_reset_hb_timer(t);
16761da177e4SLinus Torvalds 			break;
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 		case SCTP_CMD_HB_TIMERS_STOP:
16791da177e4SLinus Torvalds 			sctp_cmd_hb_timers_stop(commands, asoc);
16801da177e4SLinus Torvalds 			break;
16811da177e4SLinus Torvalds 
168292548ec2SXin Long 		case SCTP_CMD_PROBE_TIMER_UPDATE:
168392548ec2SXin Long 			t = cmd->obj.transport;
168492548ec2SXin Long 			sctp_transport_reset_probe_timer(t);
168592548ec2SXin Long 			break;
168692548ec2SXin Long 
16871da177e4SLinus Torvalds 		case SCTP_CMD_REPORT_ERROR:
16881da177e4SLinus Torvalds 			error = cmd->obj.error;
16891da177e4SLinus Torvalds 			break;
16901da177e4SLinus Torvalds 
16911da177e4SLinus Torvalds 		case SCTP_CMD_PROCESS_CTSN:
16921da177e4SLinus Torvalds 			/* Dummy up a SACK for processing. */
16932178eda8SAl Viro 			sackh.cum_tsn_ack = cmd->obj.be32;
1694f6fc6bc0SXin Long 			sackh.a_rwnd = htonl(asoc->peer.rwnd +
1695f6fc6bc0SXin Long 					     asoc->outqueue.outstanding_bytes);
16961da177e4SLinus Torvalds 			sackh.num_gap_ack_blocks = 0;
16971da177e4SLinus Torvalds 			sackh.num_dup_tsns = 0;
1698f6e80abeSZijie Pan 			chunk->subh.sack_hdr = &sackh;
16991da177e4SLinus Torvalds 			sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
1700f6e80abeSZijie Pan 					SCTP_CHUNK(chunk));
17011da177e4SLinus Torvalds 			break;
17021da177e4SLinus Torvalds 
17031da177e4SLinus Torvalds 		case SCTP_CMD_DISCARD_PACKET:
17042e3216cdSVlad Yasevich 			/* We need to discard the whole packet.
17052e3216cdSVlad Yasevich 			 * Uncork the queue since there might be
17062e3216cdSVlad Yasevich 			 * responses pending
17072e3216cdSVlad Yasevich 			 */
17081da177e4SLinus Torvalds 			chunk->pdiscard = 1;
17092e3216cdSVlad Yasevich 			if (asoc) {
1710cea8768fSMarcelo Ricardo Leitner 				sctp_outq_uncork(&asoc->outqueue, gfp);
17112e3216cdSVlad Yasevich 				local_cork = 0;
17122e3216cdSVlad Yasevich 			}
17131da177e4SLinus Torvalds 			break;
17141da177e4SLinus Torvalds 
17151da177e4SLinus Torvalds 		case SCTP_CMD_RTO_PENDING:
17161da177e4SLinus Torvalds 			t = cmd->obj.transport;
17171da177e4SLinus Torvalds 			t->rto_pending = 1;
17181da177e4SLinus Torvalds 			break;
17191da177e4SLinus Torvalds 
17201da177e4SLinus Torvalds 		case SCTP_CMD_PART_DELIVER:
1721be4e0ce1SXin Long 			asoc->stream.si->start_pd(&asoc->ulpq, GFP_ATOMIC);
17221da177e4SLinus Torvalds 			break;
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds 		case SCTP_CMD_RENEGE:
172594014e8dSXin Long 			asoc->stream.si->renege_events(&asoc->ulpq,
172694014e8dSXin Long 						       cmd->obj.chunk,
17271da177e4SLinus Torvalds 						       GFP_ATOMIC);
17281da177e4SLinus Torvalds 			break;
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds 		case SCTP_CMD_SETUP_T4:
1731b26ddd81SNeil Horman 			sctp_cmd_setup_t4(commands, asoc, cmd->obj.chunk);
17321da177e4SLinus Torvalds 			break;
17331da177e4SLinus Torvalds 
17341da177e4SLinus Torvalds 		case SCTP_CMD_PROCESS_OPERR:
17351da177e4SLinus Torvalds 			sctp_cmd_process_operr(commands, asoc, chunk);
17361da177e4SLinus Torvalds 			break;
17371da177e4SLinus Torvalds 		case SCTP_CMD_CLEAR_INIT_TAG:
17381da177e4SLinus Torvalds 			asoc->peer.i.init_tag = 0;
17391da177e4SLinus Torvalds 			break;
17401da177e4SLinus Torvalds 		case SCTP_CMD_DEL_NON_PRIMARY:
17411da177e4SLinus Torvalds 			sctp_cmd_del_non_primary(asoc);
17421da177e4SLinus Torvalds 			break;
17431da177e4SLinus Torvalds 		case SCTP_CMD_T3_RTX_TIMERS_STOP:
17441da177e4SLinus Torvalds 			sctp_cmd_t3_rtx_timers_stop(commands, asoc);
17451da177e4SLinus Torvalds 			break;
17461da177e4SLinus Torvalds 		case SCTP_CMD_FORCE_PRIM_RETRAN:
17471da177e4SLinus Torvalds 			t = asoc->peer.retran_path;
17481da177e4SLinus Torvalds 			asoc->peer.retran_path = asoc->peer.primary_path;
174983dbc3d4SXin Long 			sctp_outq_uncork(&asoc->outqueue, gfp);
17501da177e4SLinus Torvalds 			local_cork = 0;
17511da177e4SLinus Torvalds 			asoc->peer.retran_path = t;
17521da177e4SLinus Torvalds 			break;
17538de8c873SSridhar Samudrala 		case SCTP_CMD_SET_SK_ERR:
17548de8c873SSridhar Samudrala 			sctp_cmd_set_sk_err(asoc, cmd->obj.error);
17558de8c873SSridhar Samudrala 			break;
175607d93967SVlad Yasevich 		case SCTP_CMD_ASSOC_CHANGE:
175707d93967SVlad Yasevich 			sctp_cmd_assoc_change(commands, asoc,
175807d93967SVlad Yasevich 					      cmd->obj.u8);
175907d93967SVlad Yasevich 			break;
176007d93967SVlad Yasevich 		case SCTP_CMD_ADAPTATION_IND:
176107d93967SVlad Yasevich 			sctp_cmd_adaptation_ind(commands, asoc);
176207d93967SVlad Yasevich 			break;
176330f6ebf6SXin Long 		case SCTP_CMD_PEER_NO_AUTH:
176430f6ebf6SXin Long 			sctp_cmd_peer_no_auth(commands, asoc);
176530f6ebf6SXin Long 			break;
176607d93967SVlad Yasevich 
1767730fc3d0SVlad Yasevich 		case SCTP_CMD_ASSOC_SHKEY:
1768730fc3d0SVlad Yasevich 			error = sctp_auth_asoc_init_active_key(asoc,
1769730fc3d0SVlad Yasevich 						GFP_ATOMIC);
1770730fc3d0SVlad Yasevich 			break;
1771f4ad85caSGui Jianfeng 		case SCTP_CMD_UPDATE_INITTAG:
1772f4ad85caSGui Jianfeng 			asoc->peer.i.init_tag = cmd->obj.u32;
1773f4ad85caSGui Jianfeng 			break;
17749c5c62beSVlad Yasevich 		case SCTP_CMD_SEND_MSG:
17759c5c62beSVlad Yasevich 			if (!asoc->outqueue.cork) {
17769c5c62beSVlad Yasevich 				sctp_outq_cork(&asoc->outqueue);
17779c5c62beSVlad Yasevich 				local_cork = 1;
17789c5c62beSVlad Yasevich 			}
177966388f2cSXin Long 			sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp);
17809c5c62beSVlad Yasevich 			break;
1781a000c01eSWei Yongjun 		case SCTP_CMD_PURGE_ASCONF_QUEUE:
1782a000c01eSWei Yongjun 			sctp_asconf_queue_teardown(asoc);
1783a000c01eSWei Yongjun 			break;
1784d5ccd496SMax Matveev 
1785d5ccd496SMax Matveev 		case SCTP_CMD_SET_ASOC:
17868cd5c25fSXin Long 			if (asoc && local_cork) {
17878cd5c25fSXin Long 				sctp_outq_uncork(&asoc->outqueue, gfp);
17888cd5c25fSXin Long 				local_cork = 0;
17898cd5c25fSXin Long 			}
1790d5ccd496SMax Matveev 			asoc = cmd->obj.asoc;
1791d5ccd496SMax Matveev 			break;
1792d5ccd496SMax Matveev 
17931da177e4SLinus Torvalds 		default:
1794b26ddd81SNeil Horman 			pr_warn("Impossible command: %u\n",
1795b26ddd81SNeil Horman 				cmd->verb);
17961da177e4SLinus Torvalds 			break;
17973ff50b79SStephen Hemminger 		}
17983ff50b79SStephen Hemminger 
1799be7a7729SXin Long 		if (error) {
1800be7a7729SXin Long 			cmd = sctp_next_cmd(commands);
1801be7a7729SXin Long 			while (cmd) {
1802be7a7729SXin Long 				if (cmd->verb == SCTP_CMD_REPLY)
1803be7a7729SXin Long 					sctp_chunk_free(cmd->obj.chunk);
1804be7a7729SXin Long 				cmd = sctp_next_cmd(commands);
1805be7a7729SXin Long 			}
18061da177e4SLinus Torvalds 			break;
18071da177e4SLinus Torvalds 		}
1808be7a7729SXin Long 	}
18091da177e4SLinus Torvalds 
18102e3216cdSVlad Yasevich 	/* If this is in response to a received chunk, wait until
18112e3216cdSVlad Yasevich 	 * we are done with the packet to open the queue so that we don't
18122e3216cdSVlad Yasevich 	 * send multiple packets in response to a single request.
18132e3216cdSVlad Yasevich 	 */
18142e3216cdSVlad Yasevich 	if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) {
18152e3216cdSVlad Yasevich 		if (chunk->end_of_packet || chunk->singleton)
181683dbc3d4SXin Long 			sctp_outq_uncork(&asoc->outqueue, gfp);
18172e3216cdSVlad Yasevich 	} else if (local_cork)
181883dbc3d4SXin Long 		sctp_outq_uncork(&asoc->outqueue, gfp);
1819fb586f25SMarcelo Ricardo Leitner 
18200970f5b3SMarcelo Ricardo Leitner 	if (sp->data_ready_signalled)
18210970f5b3SMarcelo Ricardo Leitner 		sp->data_ready_signalled = 0;
18220970f5b3SMarcelo Ricardo Leitner 
18231da177e4SLinus Torvalds 	return error;
18241da177e4SLinus Torvalds }
1825