Merge branch 'sctp-sender-side-stream-reconf-ssn-reset-request-chunk'
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>
This commit is contained in:
commit
1ce463dd75
@ -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 */
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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__ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
@ -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.
|
||||
|
@ -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
|
||||
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
|
||||
@ -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 *);
|
||||
|
||||
@ -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 *);
|
||||
|
@ -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
|
||||
@ -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);
|
||||
@ -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. */
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
|
@ -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
|
||||
@ -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 {
|
||||
@ -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 */
|
||||
|
@ -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);
|
||||
@ -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)
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
@ -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.
|
||||
*/
|
||||
@ -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.
|
||||
*/
|
||||
|
@ -211,3 +211,6 @@ DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
|
||||
*/
|
||||
|
||||
DECLARE_PRIMITIVE(ASCONF);
|
||||
|
||||
/* RE-CONFIG 5.1 */
|
||||
DECLARE_PRIMITIVE(RECONF);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -270,6 +270,11 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
|
||||
num_ext += 2;
|
||||
}
|
||||
|
||||
if (asoc->reconf_enable) {
|
||||
extensions[num_ext] = SCTP_CID_RECONF;
|
||||
num_ext += 1;
|
||||
}
|
||||
|
||||
if (sp->adaptation_ind)
|
||||
chunksize += sizeof(aiparam);
|
||||
|
||||
@ -434,6 +439,11 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
|
||||
num_ext += 2;
|
||||
}
|
||||
|
||||
if (asoc->peer.reconf_capable) {
|
||||
extensions[num_ext] = SCTP_CID_RECONF;
|
||||
num_ext += 1;
|
||||
}
|
||||
|
||||
if (sp->adaptation_ind)
|
||||
chunksize += sizeof(aiparam);
|
||||
|
||||
@ -1844,6 +1854,7 @@ no_hmac:
|
||||
retval->next_tsn = retval->c.initial_tsn;
|
||||
retval->ctsn_ack_point = retval->next_tsn - 1;
|
||||
retval->addip_serial = retval->c.initial_tsn;
|
||||
retval->strreset_outseq = retval->c.initial_tsn;
|
||||
retval->adv_peer_ack_point = retval->ctsn_ack_point;
|
||||
retval->peer.prsctp_capable = retval->c.prsctp_capable;
|
||||
retval->peer.adaptation_ind = retval->c.adaptation_ind;
|
||||
@ -2011,6 +2022,11 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
switch (param.ext->chunks[i]) {
|
||||
case SCTP_CID_RECONF:
|
||||
if (asoc->reconf_enable &&
|
||||
!asoc->peer.reconf_capable)
|
||||
asoc->peer.reconf_capable = 1;
|
||||
break;
|
||||
case SCTP_CID_FWD_TSN:
|
||||
if (asoc->prsctp_enable && !asoc->peer.prsctp_capable)
|
||||
asoc->peer.prsctp_capable = 1;
|
||||
@ -2387,6 +2403,8 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
|
||||
asoc->peer.i.initial_tsn =
|
||||
ntohl(peer_init->init_hdr.initial_tsn);
|
||||
|
||||
asoc->strreset_inseq = asoc->peer.i.initial_tsn;
|
||||
|
||||
/* Apply the upper bounds for output streams based on peer's
|
||||
* number of inbound streams.
|
||||
*/
|
||||
@ -3524,3 +3542,121 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* RE-CONFIG 3.1 (RE-CONFIG chunk)
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Type = 130 | Chunk Flags | Chunk Length |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* \ \
|
||||
* / Re-configuration Parameter /
|
||||
* \ \
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* \ \
|
||||
* / Re-configuration Parameter (optional) /
|
||||
* \ \
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
static struct sctp_chunk *sctp_make_reconf(
|
||||
const struct sctp_association *asoc,
|
||||
int length)
|
||||
{
|
||||
struct sctp_reconf_chunk *reconf;
|
||||
struct sctp_chunk *retval;
|
||||
|
||||
retval = sctp_make_control(asoc, SCTP_CID_RECONF, 0, length,
|
||||
GFP_ATOMIC);
|
||||
if (!retval)
|
||||
return NULL;
|
||||
|
||||
reconf = (struct sctp_reconf_chunk *)retval->chunk_hdr;
|
||||
retval->param_hdr.v = reconf->params;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* RE-CONFIG 4.1 (STREAM OUT RESET)
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Parameter Type = 13 | Parameter Length = 16 + 2 * N |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Re-configuration Request Sequence Number |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Re-configuration Response Sequence Number |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Sender's Last Assigned TSN |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Stream Number 1 (optional) | Stream Number 2 (optional) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* / ...... /
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Stream Number N-1 (optional) | Stream Number N (optional) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* RE-CONFIG 4.2 (STREAM IN RESET)
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Parameter Type = 14 | Parameter Length = 8 + 2 * N |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Re-configuration Request Sequence Number |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Stream Number 1 (optional) | Stream Number 2 (optional) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* / ...... /
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Stream Number N-1 (optional) | Stream Number N (optional) |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
struct sctp_chunk *sctp_make_strreset_req(
|
||||
const struct sctp_association *asoc,
|
||||
__u16 stream_num, __u16 *stream_list,
|
||||
bool out, bool in)
|
||||
{
|
||||
struct sctp_strreset_outreq outreq;
|
||||
__u16 stream_len = stream_num * 2;
|
||||
struct sctp_strreset_inreq inreq;
|
||||
struct sctp_chunk *retval;
|
||||
__u16 outlen, inlen, i;
|
||||
|
||||
outlen = (sizeof(outreq) + stream_len) * out;
|
||||
inlen = (sizeof(inreq) + stream_len) * in;
|
||||
|
||||
retval = sctp_make_reconf(asoc, outlen + inlen);
|
||||
if (!retval)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < stream_num; i++)
|
||||
stream_list[i] = htons(stream_list[i]);
|
||||
|
||||
if (outlen) {
|
||||
outreq.param_hdr.type = SCTP_PARAM_RESET_OUT_REQUEST;
|
||||
outreq.param_hdr.length = htons(outlen);
|
||||
outreq.request_seq = htonl(asoc->strreset_outseq);
|
||||
outreq.response_seq = htonl(asoc->strreset_inseq - 1);
|
||||
outreq.send_reset_at_tsn = htonl(asoc->next_tsn - 1);
|
||||
|
||||
sctp_addto_chunk(retval, sizeof(outreq), &outreq);
|
||||
|
||||
if (stream_len)
|
||||
sctp_addto_chunk(retval, stream_len, stream_list);
|
||||
}
|
||||
|
||||
if (inlen) {
|
||||
inreq.param_hdr.type = SCTP_PARAM_RESET_IN_REQUEST;
|
||||
inreq.param_hdr.length = htons(inlen);
|
||||
inreq.request_seq = htonl(asoc->strreset_outseq + out);
|
||||
|
||||
sctp_addto_chunk(retval, sizeof(inreq), &inreq);
|
||||
|
||||
if (stream_len)
|
||||
sctp_addto_chunk(retval, stream_len, stream_list);
|
||||
}
|
||||
|
||||
for (i = 0; i < stream_num; i++)
|
||||
stream_list[i] = ntohs(stream_list[i]);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -436,6 +436,37 @@ out_unlock:
|
||||
sctp_association_put(asoc);
|
||||
}
|
||||
|
||||
/* Handle the timeout of the RE-CONFIG timer. */
|
||||
void sctp_generate_reconf_event(unsigned long data)
|
||||
{
|
||||
struct sctp_transport *transport = (struct sctp_transport *)data;
|
||||
struct sctp_association *asoc = transport->asoc;
|
||||
struct sock *sk = asoc->base.sk;
|
||||
struct net *net = sock_net(sk);
|
||||
int error = 0;
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (sock_owned_by_user(sk)) {
|
||||
pr_debug("%s: sock is busy\n", __func__);
|
||||
|
||||
/* Try again later. */
|
||||
if (!mod_timer(&transport->reconf_timer, jiffies + (HZ / 20)))
|
||||
sctp_transport_hold(transport);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
|
||||
SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_RECONF),
|
||||
asoc->state, asoc->ep, asoc,
|
||||
transport, GFP_ATOMIC);
|
||||
|
||||
if (error)
|
||||
sk->sk_err = -error;
|
||||
|
||||
out_unlock:
|
||||
bh_unlock_sock(sk);
|
||||
sctp_transport_put(transport);
|
||||
}
|
||||
|
||||
/* Inject a SACK Timeout event into the state machine. */
|
||||
static void sctp_generate_sack_event(unsigned long data)
|
||||
@ -453,6 +484,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
|
||||
sctp_generate_t4_rto_event,
|
||||
sctp_generate_t5_shutdown_guard_event,
|
||||
NULL,
|
||||
NULL,
|
||||
sctp_generate_sack_event,
|
||||
sctp_generate_autoclose_event,
|
||||
};
|
||||
|
@ -1021,6 +1021,34 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(struct net *net,
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
}
|
||||
|
||||
/* resend asoc strreset_chunk. */
|
||||
sctp_disposition_t sctp_sf_send_reconf(struct net *net,
|
||||
const struct sctp_endpoint *ep,
|
||||
const struct sctp_association *asoc,
|
||||
const sctp_subtype_t type, void *arg,
|
||||
sctp_cmd_seq_t *commands)
|
||||
{
|
||||
struct sctp_transport *transport = arg;
|
||||
|
||||
if (asoc->overall_error_count >= asoc->max_retrans) {
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
|
||||
SCTP_ERROR(ETIMEDOUT));
|
||||
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
|
||||
SCTP_PERR(SCTP_ERROR_NO_ERROR));
|
||||
SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
|
||||
SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
|
||||
return SCTP_DISPOSITION_DELETE_TCB;
|
||||
}
|
||||
|
||||
sctp_chunk_hold(asoc->strreset_chunk);
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
|
||||
SCTP_CHUNK(asoc->strreset_chunk));
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
|
||||
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an heartbeat request.
|
||||
*
|
||||
@ -5157,6 +5185,19 @@ sctp_disposition_t sctp_sf_do_prm_asconf(struct net *net,
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
}
|
||||
|
||||
/* RE-CONFIG Section 5.1 RECONF Chunk Procedures */
|
||||
sctp_disposition_t sctp_sf_do_prm_reconf(struct net *net,
|
||||
const struct sctp_endpoint *ep,
|
||||
const struct sctp_association *asoc,
|
||||
const sctp_subtype_t type,
|
||||
void *arg, sctp_cmd_seq_t *commands)
|
||||
{
|
||||
struct sctp_chunk *chunk = arg;
|
||||
|
||||
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk));
|
||||
return SCTP_DISPOSITION_CONSUME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore the primitive event
|
||||
*
|
||||
|
@ -643,6 +643,25 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
|
||||
TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \
|
||||
} /* TYPE_SCTP_PRIMITIVE_ASCONF */
|
||||
|
||||
#define TYPE_SCTP_PRIMITIVE_RECONF { \
|
||||
/* SCTP_STATE_CLOSED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
|
||||
/* SCTP_STATE_COOKIE_WAIT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
|
||||
/* SCTP_STATE_COOKIE_ECHOED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_error_closed), \
|
||||
/* SCTP_STATE_ESTABLISHED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_do_prm_reconf), \
|
||||
/* SCTP_STATE_SHUTDOWN_PENDING */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_do_prm_reconf), \
|
||||
/* SCTP_STATE_SHUTDOWN_SENT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_do_prm_reconf), \
|
||||
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_do_prm_reconf), \
|
||||
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \
|
||||
} /* TYPE_SCTP_PRIMITIVE_RECONF */
|
||||
|
||||
/* The primary index for this table is the primitive type.
|
||||
* The secondary index for this table is the state.
|
||||
*/
|
||||
@ -653,6 +672,7 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE
|
||||
TYPE_SCTP_PRIMITIVE_SEND,
|
||||
TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT,
|
||||
TYPE_SCTP_PRIMITIVE_ASCONF,
|
||||
TYPE_SCTP_PRIMITIVE_RECONF,
|
||||
};
|
||||
|
||||
#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \
|
||||
@ -888,6 +908,25 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
}
|
||||
|
||||
#define TYPE_SCTP_EVENT_TIMEOUT_RECONF { \
|
||||
/* SCTP_STATE_CLOSED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_COOKIE_WAIT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_COOKIE_ECHOED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_ESTABLISHED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_send_reconf), \
|
||||
/* SCTP_STATE_SHUTDOWN_PENDING */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_SHUTDOWN_SENT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
|
||||
TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
|
||||
}
|
||||
|
||||
static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
|
||||
TYPE_SCTP_EVENT_TIMEOUT_NONE,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
|
||||
@ -897,6 +936,7 @@ static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][S
|
||||
TYPE_SCTP_EVENT_TIMEOUT_T4_RTO,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_RECONF,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_SACK,
|
||||
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
|
||||
};
|
||||
|
@ -3750,6 +3750,68 @@ out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sctp_setsockopt_enable_strreset(struct sock *sk,
|
||||
char __user *optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
struct sctp_assoc_value params;
|
||||
struct sctp_association *asoc;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (optlen != sizeof(params))
|
||||
goto out;
|
||||
|
||||
if (copy_from_user(¶ms, optval, optlen)) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (params.assoc_value & (~SCTP_ENABLE_STRRESET_MASK))
|
||||
goto out;
|
||||
|
||||
asoc = sctp_id2assoc(sk, params.assoc_id);
|
||||
if (asoc) {
|
||||
asoc->strreset_enable = params.assoc_value;
|
||||
} else if (!params.assoc_id) {
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
|
||||
sp->ep->strreset_enable = params.assoc_value;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sctp_setsockopt_reset_streams(struct sock *sk,
|
||||
char __user *optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
struct sctp_reset_streams *params;
|
||||
struct sctp_association *asoc;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (optlen < sizeof(struct sctp_reset_streams))
|
||||
return -EINVAL;
|
||||
|
||||
params = memdup_user(optval, optlen);
|
||||
if (IS_ERR(params))
|
||||
return PTR_ERR(params);
|
||||
|
||||
asoc = sctp_id2assoc(sk, params->srs_assoc_id);
|
||||
if (!asoc)
|
||||
goto out;
|
||||
|
||||
retval = sctp_send_reset_streams(asoc, params);
|
||||
|
||||
out:
|
||||
kfree(params);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* API 6.2 setsockopt(), getsockopt()
|
||||
*
|
||||
* Applications use setsockopt() and getsockopt() to set or retrieve
|
||||
@ -3916,6 +3978,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
|
||||
case SCTP_DEFAULT_PRINFO:
|
||||
retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);
|
||||
break;
|
||||
case SCTP_ENABLE_STREAM_RESET:
|
||||
retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);
|
||||
break;
|
||||
case SCTP_RESET_STREAMS:
|
||||
retval = sctp_setsockopt_reset_streams(sk, optval, optlen);
|
||||
break;
|
||||
default:
|
||||
retval = -ENOPROTOOPT;
|
||||
break;
|
||||
@ -6400,6 +6468,47 @@ out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,
|
||||
char __user *optval,
|
||||
int __user *optlen)
|
||||
{
|
||||
struct sctp_assoc_value params;
|
||||
struct sctp_association *asoc;
|
||||
int retval = -EFAULT;
|
||||
|
||||
if (len < sizeof(params)) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = sizeof(params);
|
||||
if (copy_from_user(¶ms, optval, len))
|
||||
goto out;
|
||||
|
||||
asoc = sctp_id2assoc(sk, params.assoc_id);
|
||||
if (asoc) {
|
||||
params.assoc_value = asoc->strreset_enable;
|
||||
} else if (!params.assoc_id) {
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
|
||||
params.assoc_value = sp->ep->strreset_enable;
|
||||
} else {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (put_user(len, optlen))
|
||||
goto out;
|
||||
|
||||
if (copy_to_user(optval, ¶ms, len))
|
||||
goto out;
|
||||
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sctp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
@ -6567,6 +6676,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
|
||||
retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,
|
||||
optlen);
|
||||
break;
|
||||
case SCTP_ENABLE_STREAM_RESET:
|
||||
retval = sctp_getsockopt_enable_strreset(sk, len, optval,
|
||||
optlen);
|
||||
break;
|
||||
default:
|
||||
retval = -ENOPROTOOPT;
|
||||
break;
|
||||
|
@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
#include <net/sctp/sctp.h>
|
||||
#include <net/sctp/sm.h>
|
||||
|
||||
struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp)
|
||||
{
|
||||
@ -83,3 +84,81 @@ void sctp_stream_clear(struct sctp_stream *stream)
|
||||
for (i = 0; i < stream->incnt; i++)
|
||||
stream->in[i].ssn = 0;
|
||||
}
|
||||
|
||||
static int sctp_send_reconf(struct sctp_association *asoc,
|
||||
struct sctp_chunk *chunk)
|
||||
{
|
||||
struct net *net = sock_net(asoc->base.sk);
|
||||
int retval = 0;
|
||||
|
||||
retval = sctp_primitive_RECONF(net, asoc, chunk);
|
||||
if (retval)
|
||||
sctp_chunk_free(chunk);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int sctp_send_reset_streams(struct sctp_association *asoc,
|
||||
struct sctp_reset_streams *params)
|
||||
{
|
||||
struct sctp_stream *stream = asoc->stream;
|
||||
__u16 i, str_nums, *str_list;
|
||||
struct sctp_chunk *chunk;
|
||||
int retval = -EINVAL;
|
||||
bool out, in;
|
||||
|
||||
if (!asoc->peer.reconf_capable ||
|
||||
!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) {
|
||||
retval = -ENOPROTOOPT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asoc->strreset_outstanding) {
|
||||
retval = -EINPROGRESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out = params->srs_flags & SCTP_STREAM_RESET_OUTGOING;
|
||||
in = params->srs_flags & SCTP_STREAM_RESET_INCOMING;
|
||||
if (!out && !in)
|
||||
goto out;
|
||||
|
||||
str_nums = params->srs_number_streams;
|
||||
str_list = params->srs_stream_list;
|
||||
if (out && str_nums)
|
||||
for (i = 0; i < str_nums; i++)
|
||||
if (str_list[i] >= stream->outcnt)
|
||||
goto out;
|
||||
|
||||
if (in && str_nums)
|
||||
for (i = 0; i < str_nums; i++)
|
||||
if (str_list[i] >= stream->incnt)
|
||||
goto out;
|
||||
|
||||
chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
|
||||
if (!chunk)
|
||||
goto out;
|
||||
|
||||
if (out) {
|
||||
if (str_nums)
|
||||
for (i = 0; i < str_nums; i++)
|
||||
stream->out[str_list[i]].state =
|
||||
SCTP_STREAM_CLOSED;
|
||||
else
|
||||
for (i = 0; i < stream->outcnt; i++)
|
||||
stream->out[i].state = SCTP_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
asoc->strreset_outstanding = out + in;
|
||||
asoc->strreset_chunk = chunk;
|
||||
sctp_chunk_hold(asoc->strreset_chunk);
|
||||
|
||||
retval = sctp_send_reconf(asoc, chunk);
|
||||
if (retval) {
|
||||
sctp_chunk_put(asoc->strreset_chunk);
|
||||
asoc->strreset_chunk = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
@ -88,9 +88,11 @@ static struct sctp_transport *sctp_transport_init(struct net *net,
|
||||
INIT_LIST_HEAD(&peer->transports);
|
||||
|
||||
setup_timer(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event,
|
||||
(unsigned long)peer);
|
||||
(unsigned long)peer);
|
||||
setup_timer(&peer->hb_timer, sctp_generate_heartbeat_event,
|
||||
(unsigned long)peer);
|
||||
(unsigned long)peer);
|
||||
setup_timer(&peer->reconf_timer, sctp_generate_reconf_event,
|
||||
(unsigned long)peer);
|
||||
setup_timer(&peer->proto_unreach_timer,
|
||||
sctp_generate_proto_unreach_event, (unsigned long)peer);
|
||||
|
||||
@ -144,6 +146,9 @@ void sctp_transport_free(struct sctp_transport *transport)
|
||||
if (del_timer(&transport->T3_rtx_timer))
|
||||
sctp_transport_put(transport);
|
||||
|
||||
if (del_timer(&transport->reconf_timer))
|
||||
sctp_transport_put(transport);
|
||||
|
||||
/* Delete the ICMP proto unreachable timer if it's active. */
|
||||
if (del_timer(&transport->proto_unreach_timer))
|
||||
sctp_association_put(transport->asoc);
|
||||
@ -211,6 +216,14 @@ void sctp_transport_reset_hb_timer(struct sctp_transport *transport)
|
||||
sctp_transport_hold(transport);
|
||||
}
|
||||
|
||||
void sctp_transport_reset_reconf_timer(struct sctp_transport *transport)
|
||||
{
|
||||
if (!timer_pending(&transport->reconf_timer))
|
||||
if (!mod_timer(&transport->reconf_timer,
|
||||
jiffies + transport->rto))
|
||||
sctp_transport_hold(transport);
|
||||
}
|
||||
|
||||
/* This transport has been assigned to an association.
|
||||
* Initialize fields from the association or from the sock itself.
|
||||
* Register the reference count in the association.
|
||||
|
Loading…
x
Reference in New Issue
Block a user