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