Skip to content

Commit 7b9438d

Browse files
lxindavem330
authored andcommitted
sctp: add stream reconf timer
This patch is to add a per transport timer based on sctp timer frame for stream reconf chunk retransmission. It would start after sending a reconf request chunk, and stop after receiving the response chunk. If the timer expires, besides retransmitting the reconf request chunk, it would also do the same thing with data RTO timer. like to increase the appropriate error counts, and perform threshold management, possibly destroying the asoc if sctp retransmission thresholds are exceeded, just as section 5.1.1 describes. This patch is also to add asoc strreset_chunk, it is used to save the reconf request chunk, so that it can be retransmitted, and to check if the response is really for this request by comparing the information inside with the response chunk as well. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent cc16f00 commit 7b9438d

File tree

8 files changed

+113
-2
lines changed

8 files changed

+113
-2
lines changed

include/net/sctp/constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ typedef enum {
9090
SCTP_EVENT_TIMEOUT_T4_RTO,
9191
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
9292
SCTP_EVENT_TIMEOUT_HEARTBEAT,
93+
SCTP_EVENT_TIMEOUT_RECONF,
9394
SCTP_EVENT_TIMEOUT_SACK,
9495
SCTP_EVENT_TIMEOUT_AUTOCLOSE,
9596
} sctp_event_timeout_t;

include/net/sctp/sm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
167167

168168
/* Prototypes for timeout event state functions. */
169169
sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
170+
sctp_state_fn_t sctp_sf_send_reconf;
170171
sctp_state_fn_t sctp_sf_do_6_2_sack;
171172
sctp_state_fn_t sctp_sf_autoclose_timer_expire;
172173

@@ -278,6 +279,7 @@ int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype,
278279
/* 2nd level prototypes */
279280
void sctp_generate_t3_rtx_event(unsigned long peer);
280281
void sctp_generate_heartbeat_event(unsigned long peer);
282+
void sctp_generate_reconf_event(unsigned long peer);
281283
void sctp_generate_proto_unreach_event(unsigned long peer);
282284

283285
void sctp_ootb_pkt_free(struct sctp_packet *);

include/net/sctp/structs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,9 @@ struct sctp_transport {
877877
/* Timer to handle ICMP proto unreachable envets */
878878
struct timer_list proto_unreach_timer;
879879

880+
/* Timer to handler reconf chunk rtx */
881+
struct timer_list reconf_timer;
882+
880883
/* Since we're using per-destination retransmission timers
881884
* (see above), we're also using per-destination "transmitted"
882885
* queues. This probably ought to be a private struct
@@ -935,6 +938,7 @@ void sctp_transport_pmtu(struct sctp_transport *, struct sock *sk);
935938
void sctp_transport_free(struct sctp_transport *);
936939
void sctp_transport_reset_t3_rtx(struct sctp_transport *);
937940
void sctp_transport_reset_hb_timer(struct sctp_transport *);
941+
void sctp_transport_reset_reconf_timer(struct sctp_transport *transport);
938942
int sctp_transport_hold(struct sctp_transport *);
939943
void sctp_transport_put(struct sctp_transport *);
940944
void sctp_transport_update_rto(struct sctp_transport *, __u32);
@@ -1868,6 +1872,8 @@ struct sctp_association {
18681872
__u32 strreset_outseq; /* Update after receiving response */
18691873
__u32 strreset_inseq; /* Update after receiving request */
18701874

1875+
struct sctp_chunk *strreset_chunk; /* save request chunk */
1876+
18711877
struct sctp_priv_assoc_stats stats;
18721878

18731879
int sent_cnt_removable;

net/sctp/associola.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ void sctp_association_free(struct sctp_association *asoc)
362362
/* Free stream information. */
363363
sctp_stream_free(asoc->stream);
364364

365+
if (asoc->strreset_chunk)
366+
sctp_chunk_free(asoc->strreset_chunk);
367+
365368
/* Clean up the bound address list. */
366369
sctp_bind_addr_free(&asoc->base.bind_addr);
367370

@@ -520,6 +523,12 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
520523
if (asoc->peer.last_data_from == peer)
521524
asoc->peer.last_data_from = transport;
522525

526+
if (asoc->strreset_chunk &&
527+
asoc->strreset_chunk->transport == peer) {
528+
asoc->strreset_chunk->transport = transport;
529+
sctp_transport_reset_reconf_timer(transport);
530+
}
531+
523532
/* If we remove the transport an INIT was last sent to, set it to
524533
* NULL. Combined with the update of the retran path above, this
525534
* will cause the next INIT to be sent to the next available

net/sctp/sm_sideeffect.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,37 @@ void sctp_generate_proto_unreach_event(unsigned long data)
436436
sctp_association_put(asoc);
437437
}
438438

439+
/* Handle the timeout of the RE-CONFIG timer. */
440+
void sctp_generate_reconf_event(unsigned long data)
441+
{
442+
struct sctp_transport *transport = (struct sctp_transport *)data;
443+
struct sctp_association *asoc = transport->asoc;
444+
struct sock *sk = asoc->base.sk;
445+
struct net *net = sock_net(sk);
446+
int error = 0;
447+
448+
bh_lock_sock(sk);
449+
if (sock_owned_by_user(sk)) {
450+
pr_debug("%s: sock is busy\n", __func__);
451+
452+
/* Try again later. */
453+
if (!mod_timer(&transport->reconf_timer, jiffies + (HZ / 20)))
454+
sctp_transport_hold(transport);
455+
goto out_unlock;
456+
}
457+
458+
error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
459+
SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_RECONF),
460+
asoc->state, asoc->ep, asoc,
461+
transport, GFP_ATOMIC);
462+
463+
if (error)
464+
sk->sk_err = -error;
465+
466+
out_unlock:
467+
bh_unlock_sock(sk);
468+
sctp_transport_put(transport);
469+
}
439470

440471
/* Inject a SACK Timeout event into the state machine. */
441472
static void sctp_generate_sack_event(unsigned long data)
@@ -453,6 +484,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
453484
sctp_generate_t4_rto_event,
454485
sctp_generate_t5_shutdown_guard_event,
455486
NULL,
487+
NULL,
456488
sctp_generate_sack_event,
457489
sctp_generate_autoclose_event,
458490
};

net/sctp/sm_statefuns.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,34 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(struct net *net,
10211021
return SCTP_DISPOSITION_CONSUME;
10221022
}
10231023

1024+
/* resend asoc strreset_chunk. */
1025+
sctp_disposition_t sctp_sf_send_reconf(struct net *net,
1026+
const struct sctp_endpoint *ep,
1027+
const struct sctp_association *asoc,
1028+
const sctp_subtype_t type, void *arg,
1029+
sctp_cmd_seq_t *commands)
1030+
{
1031+
struct sctp_transport *transport = arg;
1032+
1033+
if (asoc->overall_error_count >= asoc->max_retrans) {
1034+
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
1035+
SCTP_ERROR(ETIMEDOUT));
1036+
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
1037+
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
1038+
SCTP_PERR(SCTP_ERROR_NO_ERROR));
1039+
SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
1040+
SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
1041+
return SCTP_DISPOSITION_DELETE_TCB;
1042+
}
1043+
1044+
sctp_chunk_hold(asoc->strreset_chunk);
1045+
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
1046+
SCTP_CHUNK(asoc->strreset_chunk));
1047+
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
1048+
1049+
return SCTP_DISPOSITION_CONSUME;
1050+
}
1051+
10241052
/*
10251053
* Process an heartbeat request.
10261054
*

net/sctp/sm_statetable.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,25 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
888888
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
889889
}
890890

891+
#define TYPE_SCTP_EVENT_TIMEOUT_RECONF { \
892+
/* SCTP_STATE_CLOSED */ \
893+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
894+
/* SCTP_STATE_COOKIE_WAIT */ \
895+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
896+
/* SCTP_STATE_COOKIE_ECHOED */ \
897+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
898+
/* SCTP_STATE_ESTABLISHED */ \
899+
TYPE_SCTP_FUNC(sctp_sf_send_reconf), \
900+
/* SCTP_STATE_SHUTDOWN_PENDING */ \
901+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
902+
/* SCTP_STATE_SHUTDOWN_SENT */ \
903+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
904+
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
905+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
906+
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
907+
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
908+
}
909+
891910
static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
892911
TYPE_SCTP_EVENT_TIMEOUT_NONE,
893912
TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
@@ -897,6 +916,7 @@ static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][S
897916
TYPE_SCTP_EVENT_TIMEOUT_T4_RTO,
898917
TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
899918
TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT,
919+
TYPE_SCTP_EVENT_TIMEOUT_RECONF,
900920
TYPE_SCTP_EVENT_TIMEOUT_SACK,
901921
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
902922
};

net/sctp/transport.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ static struct sctp_transport *sctp_transport_init(struct net *net,
8888
INIT_LIST_HEAD(&peer->transports);
8989

9090
setup_timer(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event,
91-
(unsigned long)peer);
91+
(unsigned long)peer);
9292
setup_timer(&peer->hb_timer, sctp_generate_heartbeat_event,
93-
(unsigned long)peer);
93+
(unsigned long)peer);
94+
setup_timer(&peer->reconf_timer, sctp_generate_reconf_event,
95+
(unsigned long)peer);
9496
setup_timer(&peer->proto_unreach_timer,
9597
sctp_generate_proto_unreach_event, (unsigned long)peer);
9698

@@ -144,6 +146,9 @@ void sctp_transport_free(struct sctp_transport *transport)
144146
if (del_timer(&transport->T3_rtx_timer))
145147
sctp_transport_put(transport);
146148

149+
if (del_timer(&transport->reconf_timer))
150+
sctp_transport_put(transport);
151+
147152
/* Delete the ICMP proto unreachable timer if it's active. */
148153
if (del_timer(&transport->proto_unreach_timer))
149154
sctp_association_put(transport->asoc);
@@ -211,6 +216,14 @@ void sctp_transport_reset_hb_timer(struct sctp_transport *transport)
211216
sctp_transport_hold(transport);
212217
}
213218

219+
void sctp_transport_reset_reconf_timer(struct sctp_transport *transport)
220+
{
221+
if (!timer_pending(&transport->reconf_timer))
222+
if (!mod_timer(&transport->reconf_timer,
223+
jiffies + transport->rto))
224+
sctp_transport_hold(transport);
225+
}
226+
214227
/* This transport has been assigned to an association.
215228
* Initialize fields from the association or from the sock itself.
216229
* Register the reference count in the association.

0 commit comments

Comments
 (0)