Skip to content

Commit

Permalink
Merge branch 'sctp-sender-side-stream-reconf-ssn-reset-request-chunk'
Browse files Browse the repository at this point in the history
Xin Long says:

====================
sctp: add sender-side procedures for stream reconf ssn reset request chunk

Patch 6/6 is to implement sender-side procedures for the Outgoing
and Incoming SSN Reset Request Parameter described in rfc6525
section 5.1.2 and 5.1.3

Patches 1-5/6 are ahead of it to define some apis and asoc members
for it.

Note that with this patchset, asoc->reconf_enable has no chance yet to
be set, until the patch "sctp: add get and set sockopt for reconf_enable"
is applied in the future. As we can not just enable it when sctp is not
capable of processing reconf chunk yet.

v1->v2:
  - put these into a smaller group.
  - rename some temporary variables in the codes.
  - rename the titles of the commits and improve some changelogs.
v2->v3:
  - re-split the patchset and make sure it has no dead codes for review.
v3->v4:
  - move sctp_make_reconf() into patch 1/6 to avoid kbuild warning.
  - drop unused struct sctp_strreset_req.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 18, 2017
2 parents b16ed2b + 7f9d68a commit 1ce463d
Show file tree
Hide file tree
Showing 19 changed files with 583 additions and 16 deletions.
27 changes: 27 additions & 0 deletions include/linux/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ typedef enum {
/* Use hex, as defined in ADDIP sec. 3.1 */
SCTP_CID_ASCONF = 0xC1,
SCTP_CID_ASCONF_ACK = 0x80,
SCTP_CID_RECONF = 0x82,
} sctp_cid_t; /* enum */


Expand Down Expand Up @@ -199,6 +200,13 @@ typedef enum {
SCTP_PARAM_SUCCESS_REPORT = cpu_to_be16(0xc005),
SCTP_PARAM_ADAPTATION_LAYER_IND = cpu_to_be16(0xc006),

/* RE-CONFIG. Section 4 */
SCTP_PARAM_RESET_OUT_REQUEST = cpu_to_be16(0x000d),
SCTP_PARAM_RESET_IN_REQUEST = cpu_to_be16(0x000e),
SCTP_PARAM_RESET_TSN_REQUEST = cpu_to_be16(0x000f),
SCTP_PARAM_RESET_RESPONSE = cpu_to_be16(0x0010),
SCTP_PARAM_RESET_ADD_OUT_STREAMS = cpu_to_be16(0x0011),
SCTP_PARAM_RESET_ADD_IN_STREAMS = cpu_to_be16(0x0012),
} sctp_param_t; /* enum */


Expand Down Expand Up @@ -710,4 +718,23 @@ struct sctp_infox {
struct sctp_association *asoc;
};

struct sctp_reconf_chunk {
sctp_chunkhdr_t chunk_hdr;
__u8 params[0];
} __packed;

struct sctp_strreset_outreq {
sctp_paramhdr_t param_hdr;
__u32 request_seq;
__u32 response_seq;
__u32 send_reset_at_tsn;
__u16 list_of_streams[0];
} __packed;

struct sctp_strreset_inreq {
sctp_paramhdr_t param_hdr;
__u32 request_seq;
__u16 list_of_streams[0];
} __packed;

#endif /* __LINUX_SCTP_H__ */
3 changes: 3 additions & 0 deletions include/net/netns/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ struct netns_sctp {
/* Flag to indicate if PR-SCTP is enabled. */
int prsctp_enable;

/* Flag to indicate if PR-CONFIG is enabled. */
int reconf_enable;

/* Flag to idicate if SCTP-AUTH is enabled */
int auth_enable;

Expand Down
4 changes: 3 additions & 1 deletion include/net/sctp/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ typedef enum {
SCTP_EVENT_TIMEOUT_T4_RTO,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
SCTP_EVENT_TIMEOUT_HEARTBEAT,
SCTP_EVENT_TIMEOUT_RECONF,
SCTP_EVENT_TIMEOUT_SACK,
SCTP_EVENT_TIMEOUT_AUTOCLOSE,
} sctp_event_timeout_t;
Expand All @@ -113,9 +114,10 @@ typedef enum {
SCTP_PRIMITIVE_SEND,
SCTP_PRIMITIVE_REQUESTHEARTBEAT,
SCTP_PRIMITIVE_ASCONF,
SCTP_PRIMITIVE_RECONF,
} sctp_event_primitive_t;

#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_ASCONF
#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_RECONF
#define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1)

/* We define here a utility type for manipulating subtypes.
Expand Down
8 changes: 8 additions & 0 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ int sctp_primitive_ABORT(struct net *, struct sctp_association *, void *arg);
int sctp_primitive_SEND(struct net *, struct sctp_association *, void *arg);
int sctp_primitive_REQUESTHEARTBEAT(struct net *, struct sctp_association *, void *arg);
int sctp_primitive_ASCONF(struct net *, struct sctp_association *, void *arg);
int sctp_primitive_RECONF(struct net *net, struct sctp_association *asoc,
void *arg);

/*
* sctp/input.c
Expand Down Expand Up @@ -191,6 +193,12 @@ void sctp_remaddr_proc_exit(struct net *net);
*/
int sctp_offload_init(void);

/*
* sctp/stream.c
*/
int sctp_send_reset_streams(struct sctp_association *asoc,
struct sctp_reset_streams *params);

/*
* Module global variables
*/
Expand Down
8 changes: 7 additions & 1 deletion include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ sctp_state_fn_t sctp_sf_error_shutdown;
sctp_state_fn_t sctp_sf_ignore_primitive;
sctp_state_fn_t sctp_sf_do_prm_requestheartbeat;
sctp_state_fn_t sctp_sf_do_prm_asconf;
sctp_state_fn_t sctp_sf_do_prm_reconf;

/* Prototypes for other event state functions. */
sctp_state_fn_t sctp_sf_do_no_pending_tsn;
Expand All @@ -167,6 +168,7 @@ sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;

/* Prototypes for timeout event state functions. */
sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
sctp_state_fn_t sctp_sf_send_reconf;
sctp_state_fn_t sctp_sf_do_6_2_sack;
sctp_state_fn_t sctp_sf_autoclose_timer_expire;

Expand Down Expand Up @@ -259,7 +261,10 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
__u32 new_cum_tsn, size_t nstreams,
struct sctp_fwdtsn_skip *skiplist);
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc);

struct sctp_chunk *sctp_make_strreset_req(
const struct sctp_association *asoc,
__u16 stream_num, __u16 *stream_list,
bool out, bool in);
void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *);

Expand All @@ -275,6 +280,7 @@ int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype,
/* 2nd level prototypes */
void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer);
void sctp_generate_reconf_event(unsigned long peer);
void sctp_generate_proto_unreach_event(unsigned long peer);

void sctp_ootb_pkt_free(struct sctp_packet *);
Expand Down
21 changes: 19 additions & 2 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,9 @@ struct sctp_transport {
/* Timer to handle ICMP proto unreachable envets */
struct timer_list proto_unreach_timer;

/* Timer to handler reconf chunk rtx */
struct timer_list reconf_timer;

/* Since we're using per-destination retransmission timers
* (see above), we're also using per-destination "transmitted"
* queues. This probably ought to be a private struct
Expand Down Expand Up @@ -935,6 +938,7 @@ void sctp_transport_pmtu(struct sctp_transport *, struct sock *sk);
void sctp_transport_free(struct sctp_transport *);
void sctp_transport_reset_t3_rtx(struct sctp_transport *);
void sctp_transport_reset_hb_timer(struct sctp_transport *);
void sctp_transport_reset_reconf_timer(struct sctp_transport *transport);
int sctp_transport_hold(struct sctp_transport *);
void sctp_transport_put(struct sctp_transport *);
void sctp_transport_update_rto(struct sctp_transport *, __u32);
Expand Down Expand Up @@ -1251,7 +1255,10 @@ struct sctp_endpoint {
struct list_head endpoint_shared_keys;
__u16 active_key_id;
__u8 auth_enable:1,
prsctp_enable:1;
prsctp_enable:1,
reconf_enable:1;

__u8 strreset_enable;
};

/* Recover the outter endpoint structure. */
Expand Down Expand Up @@ -1504,6 +1511,7 @@ struct sctp_association {
hostname_address:1, /* Peer understands DNS addresses? */
asconf_capable:1, /* Does peer support ADDIP? */
prsctp_capable:1, /* Can peer do PR-SCTP? */
reconf_capable:1, /* Can peer do RE-CONFIG? */
auth_capable:1; /* Is peer doing SCTP-AUTH? */

/* sack_needed : This flag indicates if the next received
Expand Down Expand Up @@ -1863,7 +1871,16 @@ struct sctp_association {

__u8 need_ecne:1, /* Need to send an ECNE Chunk? */
temp:1, /* Is it a temporary association? */
prsctp_enable:1;
prsctp_enable:1,
reconf_enable:1;

__u8 strreset_enable;
__u8 strreset_outstanding; /* request param count on the fly */

__u32 strreset_outseq; /* Update after receiving response */
__u32 strreset_inseq; /* Update after receiving request */

struct sctp_chunk *strreset_chunk; /* save request chunk */

struct sctp_priv_assoc_stats stats;

Expand Down
18 changes: 18 additions & 0 deletions include/uapi/linux/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ typedef __s32 sctp_assoc_t;
#define SCTP_PR_SUPPORTED 113
#define SCTP_DEFAULT_PRINFO 114
#define SCTP_PR_ASSOC_STATUS 115
#define SCTP_ENABLE_STREAM_RESET 118
#define SCTP_RESET_STREAMS 119

/* PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000
Expand All @@ -138,6 +140,15 @@ typedef __s32 sctp_assoc_t;
#define SCTP_PR_RTX_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_RTX)
#define SCTP_PR_PRIO_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_PRIO)

/* For enable stream reset */
#define SCTP_ENABLE_RESET_STREAM_REQ 0x01
#define SCTP_ENABLE_RESET_ASSOC_REQ 0x02
#define SCTP_ENABLE_CHANGE_ASSOC_REQ 0x04
#define SCTP_ENABLE_STRRESET_MASK 0x07

#define SCTP_STREAM_RESET_INCOMING 0x01
#define SCTP_STREAM_RESET_OUTGOING 0x02

/* These are bit fields for msghdr->msg_flags. See section 5.1. */
/* On user space Linux, these live in <bits/socket.h> as an enum. */
enum sctp_msg_flags {
Expand Down Expand Up @@ -1008,4 +1019,11 @@ struct sctp_info {
__u32 __reserved3;
};

struct sctp_reset_streams {
sctp_assoc_t srs_assoc_id;
uint16_t srs_flags;
uint16_t srs_number_streams; /* 0 == ALL */
uint16_t srs_stream_list[]; /* list if srs_num_streams is not 0 */
};

#endif /* _UAPI_SCTP_H */
12 changes: 12 additions & 0 deletions net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
* association to the same value as the initial TSN.
*/
asoc->addip_serial = asoc->c.initial_tsn;
asoc->strreset_outseq = asoc->c.initial_tsn;

INIT_LIST_HEAD(&asoc->addip_chunk_list);
INIT_LIST_HEAD(&asoc->asconf_ack_list);
Expand Down Expand Up @@ -269,6 +270,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a

asoc->active_key_id = ep->active_key_id;
asoc->prsctp_enable = ep->prsctp_enable;
asoc->reconf_enable = ep->reconf_enable;
asoc->strreset_enable = ep->strreset_enable;

/* Save the hmacs and chunks list into this association */
if (ep->auth_hmacs_list)
Expand Down Expand Up @@ -361,6 +364,9 @@ void sctp_association_free(struct sctp_association *asoc)
/* Free stream information. */
sctp_stream_free(asoc->stream);

if (asoc->strreset_chunk)
sctp_chunk_free(asoc->strreset_chunk);

/* Clean up the bound address list. */
sctp_bind_addr_free(&asoc->base.bind_addr);

Expand Down Expand Up @@ -519,6 +525,12 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
if (asoc->peer.last_data_from == peer)
asoc->peer.last_data_from = transport;

if (asoc->strreset_chunk &&
asoc->strreset_chunk->transport == peer) {
asoc->strreset_chunk->transport = transport;
sctp_transport_reset_reconf_timer(transport);
}

/* If we remove the transport an INIT was last sent to, set it to
* NULL. Combined with the update of the retran path above, this
* will cause the next INIT to be sent to the next available
Expand Down
1 change: 1 addition & 0 deletions net/sctp/endpointola.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
ep->auth_hmacs_list = auth_hmacs;
ep->auth_chunk_list = auth_chunks;
ep->prsctp_enable = net->sctp.prsctp_enable;
ep->reconf_enable = net->sctp.reconf_enable;

return ep;

Expand Down
33 changes: 23 additions & 10 deletions net/sctp/outqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,22 +915,28 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ASCONF:
case SCTP_CID_FWD_TSN:
case SCTP_CID_RECONF:
status = sctp_packet_transmit_chunk(packet, chunk,
one_packet, gfp);
if (status != SCTP_XMIT_OK) {
/* put the chunk back */
list_add(&chunk->list, &q->control_chunk_list);
} else {
asoc->stats.octrlchunks++;
/* PR-SCTP C5) If a FORWARD TSN is sent, the
* sender MUST assure that at least one T3-rtx
* timer is running.
*/
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
sctp_transport_reset_t3_rtx(transport);
transport->last_time_sent = jiffies;
}
break;
}

asoc->stats.octrlchunks++;
/* PR-SCTP C5) If a FORWARD TSN is sent, the
* sender MUST assure that at least one T3-rtx
* timer is running.
*/
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
sctp_transport_reset_t3_rtx(transport);
transport->last_time_sent = jiffies;
}

if (chunk == asoc->strreset_chunk)
sctp_transport_reset_reconf_timer(transport);

break;

default:
Expand Down Expand Up @@ -1016,6 +1022,8 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)

/* Finally, transmit new packets. */
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
__u32 sid = ntohs(chunk->subh.data_hdr->stream);

/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
*/
Expand All @@ -1038,6 +1046,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
continue;
}

if (asoc->stream->out[sid].state == SCTP_STREAM_CLOSED) {
sctp_outq_head_data(q, chunk);
goto sctp_flush_out;
}

/* If there is a specified transport, use it.
* Otherwise, we want to use the active path.
*/
Expand Down
3 changes: 3 additions & 0 deletions net/sctp/primitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,6 @@ DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
*/

DECLARE_PRIMITIVE(ASCONF);

/* RE-CONFIG 5.1 */
DECLARE_PRIMITIVE(RECONF);
3 changes: 3 additions & 0 deletions net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,9 @@ static int __net_init sctp_defaults_init(struct net *net)
/* Enable PR-SCTP by default. */
net->sctp.prsctp_enable = 1;

/* Disable RECONF by default. */
net->sctp.reconf_enable = 0;

/* Disable AUTH by default. */
net->sctp.auth_enable = 0;

Expand Down
Loading

0 comments on commit 1ce463d

Please sign in to comment.