From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:00
This patch is to add streamout and streamin arrays in asoc, initialize
them in sctp_process_init and free them in sctp_association_free.
Stream arrays are used to replace ssnmap to save more stream things in
the next patch.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/structs.h | 18 ++++++++++++++++++
net/sctp/associola.c | 19 +++++++++++++++++++
net/sctp/sm_make_chunk.c | 17 ++++++++++++++++-
3 files changed, 53 insertions(+), 1 deletion(-)
@@ -1331,6 +1331,18 @@ struct sctp_inithdr_host {__u32initial_tsn;};+structsctp_stream_out{+__u16ssn;+__u8state;+};++structsctp_stream_in{+__u16ssn;+};++#define SCTP_STREAM_CLOSED 0x00+#define SCTP_STREAM_OPEN 0x01+/* SCTP_GET_ASSOC_STATS counters */structsctp_priv_assoc_stats{/* Maximum observed rto in the association during subsequent
@@ -1879,6 +1891,12 @@ struct sctp_association {temp:1,/* Is it a temporary association? */prsctp_enable:1;+/* stream arrays */+structsctp_stream_out*streamout;+structsctp_stream_in*streamin;+__u16streamoutcnt;+__u16streamincnt;+structsctp_priv_assoc_statsstats;intsent_cnt_removable;
@@ -1139,6 +1145,12 @@ void sctp_assoc_update(struct sctp_association *asoc,*/sctp_ssnmap_clear(asoc->ssnmap);+for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].ssn=0;++for(i=0;i<asoc->streamincnt;i++)+asoc->streamin[i].ssn=0;+/* Flush the ULP reassembly and ordered queue.*Anydatatherewillnowbestaleandwill*causeproblems.
@@ -1168,6 +1180,13 @@ void sctp_assoc_update(struct sctp_association *asoc,new->ssnmap=NULL;}+if(!asoc->streamin&&!asoc->streamout){+asoc->streamout=new->streamout;+asoc->streamin=new->streamin;+new->streamout=NULL;+new->streamin=NULL;+}+if(!asoc->assoc_id){/* get a new association id since we don't have one*yet.
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:09
Stream arrays are used to save per stream information, which includes
ssn for each stream already.
This patch is to replace ssnmap with asoc stream arrays.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/structs.h | 19 ++++++-------------
net/sctp/associola.c | 10 ----------
net/sctp/sm_make_chunk.c | 11 ++---------
net/sctp/sm_statefuns.c | 3 +--
net/sctp/ulpqueue.c | 33 +++++++++++----------------------
5 files changed, 20 insertions(+), 56 deletions(-)
@@ -407,23 +407,16 @@ void sctp_ssnmap_free(struct sctp_ssnmap *map);voidsctp_ssnmap_clear(structsctp_ssnmap*map);/* What is the current SSN number for this stream? */-staticinline__u16sctp_ssn_peek(structsctp_stream*stream,__u16id)-{-returnstream->ssn[id];-}+#define sctp_ssn_peek(asoc, type, sid) \+((asoc)->stream##type[sid].ssn)/* Return the next SSN number for this stream. */-staticinline__u16sctp_ssn_next(structsctp_stream*stream,__u16id)-{-returnstream->ssn[id]++;-}+#define sctp_ssn_next(asoc, type, sid) \+((asoc)->stream##type[sid].ssn++)/* Skip over this ssn and all below. */-staticinlinevoidsctp_ssn_skip(structsctp_stream*stream,__u16id,-__u16ssn)-{-stream->ssn[id]=ssn+1;-}+#define sctp_ssn_skip(asoc, type, sid, ssn) \+((asoc)->stream##type[sid].ssn=ssn+1)/**PointerstoaddressrelatedSCTPfunctions.
@@ -1143,8 +1140,6 @@ void sctp_assoc_update(struct sctp_association *asoc,/* Reinitialize SSN for both local streams*andpeer'sstreams.*/-sctp_ssnmap_clear(asoc->ssnmap);-for(i=0;i<asoc->streamoutcnt;i++)asoc->streamout[i].ssn=0;
@@ -1536,7 +1535,6 @@ void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)/* All fragments will be on the same stream */sid=ntohs(chunk->subh.data_hdr->stream);-stream=&chunk->asoc->ssnmap->out;/* Now assign the sequence number to the entire message.*Allfragmentsmusthavethesamestreamsequencenumber.
@@ -6274,9 +6274,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,*andisinvalid.*/ssn=ntohs(data_hdr->ssn);-if(ordered&&SSN_lt(ssn,sctp_ssn_peek(&asoc->ssnmap->in,sid))){+if(ordered&&SSN_lt(ssn,sctp_ssn_peek(asoc,in,sid)))returnSCTP_IERROR_PROTO_VIOLATION;-}/* Send the data up to the user. Note: Schedule the*SCTP_CMD_CHUNK_ULPcmdbeforetheSCTP_CMD_GEN_SACK,astheSACK
@@ -782,11 +780,11 @@ static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,if(csid<sid)continue;-if(cssn!=sctp_ssn_peek(in,sid))+if(cssn!=sctp_ssn_peek(ulpq->asoc,in,sid))break;-/* Found it, so mark in the ssnmap. */-sctp_ssn_next(in,sid);+/* Found it, so mark in stream array. */+sctp_ssn_next(ulpq->asoc,in,sid);__skb_unlink(pos,&ulpq->lobby);
@@ -849,7 +847,6 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,structsctp_ulpevent*event){__u16sid,ssn;-structsctp_stream*in;/* Check if this message needs ordering. */if(SCTP_DATA_UNORDERED&event->msg_flags)
@@ -858,10 +855,9 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,/* Note: The stream ID must be verified before this routine. */sid=event->stream;ssn=event->ssn;-in=&ulpq->asoc->ssnmap->in;/* Is this the expected SSN for this stream ID? */-if(ssn!=sctp_ssn_peek(in,sid)){+if(ssn!=sctp_ssn_peek(ulpq->asoc,in,sid)){/* We've received something out of order, so find where it*needstobeplaced.WeorderbystreamandthenbySSN.*/
@@ -870,7 +866,7 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,}/* Mark that the next chunk has been found. */-sctp_ssn_next(in,sid);+sctp_ssn_next(ulpq->asoc,in,sid);/* Go find any other chunks that were waiting for*ordering.
@@ -888,13 +884,10 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)structsk_buff*pos,*tmp;structsctp_ulpevent*cevent;structsctp_ulpevent*event;-structsctp_stream*in;structsk_buff_headtemp;structsk_buff_head*lobby=&ulpq->lobby;__u16csid,cssn;-in=&ulpq->asoc->ssnmap->in;-/* We are holding the chunks by stream, by SSN. */skb_queue_head_init(&temp);event=NULL;
@@ -912,7 +905,7 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)continue;/* see if this ssn has been marked by skipping */-if(!SSN_lt(cssn,sctp_ssn_peek(in,csid)))+if(!SSN_lt(cssn,sctp_ssn_peek(ulpq->asoc,in,csid)))break;__skb_unlink(pos,lobby);
@@ -955,17 +949,12 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)*/voidsctp_ulpq_skip(structsctp_ulpq*ulpq,__u16sid,__u16ssn){-structsctp_stream*in;--/* Note: The stream ID must be verified before this routine. */-in=&ulpq->asoc->ssnmap->in;-/* Is this an old SSN? If so ignore. */-if(SSN_lt(ssn,sctp_ssn_peek(in,sid)))+if(SSN_lt(ssn,sctp_ssn_peek(ulpq->asoc,in,sid)))return;/* Mark that we are no longer expecting this SSN or lower. */-sctp_ssn_skip(in,sid,ssn);+sctp_ssn_skip(ulpq->asoc,in,sid,ssn);/* Go find any other chunks that were waiting for*orderinganddeliverthemifneeded.
@@ -377,35 +376,6 @@ typedef struct sctp_sender_hb_info {__u64hb_nonce;}__packedsctp_sender_hb_info_t;-/*-*RFC29601.3.2SequencedDeliverywithinStreams-*-*Theterm"stream"isusedinSCTPtorefertoasequenceofuser-*messagesthataretobedeliveredtotheupper-layerprotocolin-*orderwithrespecttoothermessageswithinthesamestream.Thisis-*incontrasttoitsusageinTCP,whereitreferstoasequenceof-*bytes(inthisdocumentabyteisassumedtobeeightbits).-*...-*-*Thisisthestructureweusetotrackbothouroutboundandinbound-*SSN,orStreamSequenceNumbers.-*/--structsctp_stream{-__u16*ssn;-unsignedintlen;-};--structsctp_ssnmap{-structsctp_streamin;-structsctp_streamout;-};--structsctp_ssnmap*sctp_ssnmap_new(__u16in,__u16out,-gfp_tgfp);-voidsctp_ssnmap_free(structsctp_ssnmap*map);-voidsctp_ssnmap_clear(structsctp_ssnmap*map);-/* What is the current SSN number for this stream? */#define sctp_ssn_peek(asoc, type, sid) \((asoc)->stream##type[sid].ssn)
@@ -1751,9 +1721,6 @@ struct sctp_association {/* Default receive parameters */__u32default_rcv_context;-/* This tracks outbound ssn for a given stream. */-structsctp_ssnmap*ssnmap;-/* All outbound chunks go through this structure. */structsctp_outqoutqueue;
@@ -1,125 +0,0 @@-/* SCTP kernel implementation- * Copyright (c) 2003 International Business Machines, Corp.- *- * This file is part of the SCTP kernel implementation- *- * These functions manipulate sctp SSN tracker.- *- * This SCTP implementation is free software;- * you can redistribute it and/or modify it under the terms of- * the GNU General Public License as published by- * the Free Software Foundation; either version 2, or (at your option)- * any later version.- *- * This SCTP implementation is distributed in the hope that it- * will be useful, but WITHOUT ANY WARRANTY; without even the implied- * ************************- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.- * See the GNU General Public License for more details.- *- * You should have received a copy of the GNU General Public License- * along with GNU CC; see the file COPYING. If not, see- * <http://www.gnu.org/licenses/>.- *- * Please send any bug reports or fixes you make to the- * email address(es):- * lksctp developers <linux-sctp@vger.kernel.org>- *- * Written or modified by:- * Jon Grimm <jgrimm@us.ibm.com>- */--#include <linux/types.h>-#include <linux/slab.h>-#include <net/sctp/sctp.h>-#include <net/sctp/sm.h>--static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,- __u16 out);--/* Storage size needed for map includes 2 headers and then the- * specific needs of in or out streams.- */-static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)-{- return sizeof(struct sctp_ssnmap) + (in + out) * sizeof(__u16);-}---/* Create a new sctp_ssnmap.- * Allocate room to store at least 'len' contiguous TSNs.- */-struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,- gfp_t gfp)-{- struct sctp_ssnmap *retval;- int size;-- size = sctp_ssnmap_size(in, out);- if (size <= KMALLOC_MAX_SIZE)- retval = kmalloc(size, gfp);- else- retval = (struct sctp_ssnmap *)- __get_free_pages(gfp, get_order(size));- if (!retval)- goto fail;-- if (!sctp_ssnmap_init(retval, in, out))- goto fail_map;-- SCTP_DBG_OBJCNT_INC(ssnmap);-- return retval;--fail_map:- if (size <= KMALLOC_MAX_SIZE)- kfree(retval);- else- free_pages((unsigned long)retval, get_order(size));-fail:- return NULL;-}---/* Initialize a block of memory as a ssnmap. */-static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,- __u16 out)-{- memset(map, 0x00, sctp_ssnmap_size(in, out));-- /* Start 'in' stream just after the map header. */- map->in.ssn = (__u16 *)&map[1];- map->in.len = in;-- /* Start 'out' stream just after 'in'. */- map->out.ssn = &map->in.ssn[in];- map->out.len = out;-- return map;-}--/* Clear out the ssnmap streams. */-void sctp_ssnmap_clear(struct sctp_ssnmap *map)-{- size_t size;-- size = (map->in.len + map->out.len) * sizeof(__u16);- memset(map->in.ssn, 0x00, size);-}--/* Dispose of a ssnmap. */-void sctp_ssnmap_free(struct sctp_ssnmap *map)-{- int size;-- if (unlikely(!map))- return;-- size = sctp_ssnmap_size(map->in.len, map->out.len);- if (size <= KMALLOC_MAX_SIZE)- kfree(map);- else- free_pages((unsigned long)map, get_order(size));-- SCTP_DBG_OBJCNT_DEC(ssnmap);-}
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:24
This patch is to define the reconf chunk as the section 3.1 descibes.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/sctp.h | 6 ++++++
net/sctp/sm_make_chunk.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
@@ -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 */
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:33
This patch is to add asoc strreset_outseq and strreset_inseq for
saving the reconf request sequence, initialize them when create
assoc and process init, and also to define Incoming and Outgoing
SSN Reset Request Parameter described in section 4.1 and 4.2, As
they can be in one same chunk as section 3.1-3 describes, it makes
them in one function.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/sctp.h | 26 ++++++++++++++
include/net/sctp/sm.h | 5 ++-
include/net/sctp/structs.h | 3 ++
net/sctp/associola.c | 1 +
net/sctp/sm_make_chunk.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 122 insertions(+), 1 deletion(-)
@@ -2385,6 +2386,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*numberofinboundstreams.*/
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:49
This patch is to define Re-configuration Response Parameter described
in section 4.4. As optional fields are only for SSN/TSN Reset Request
Parameter, it uses another function to make that.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/sctp.h | 24 ++++++++++++++++
include/net/sctp/sm.h | 7 +++++
net/sctp/sm_make_chunk.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 105 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:21:56
This patch is to define Add Incoming/Outgoing Streams Request
Parameter described in section 4.5 and 4.6. They can be in one
same chunk trunk as section 3.1-7 describes, so make them in
one function.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/linux/sctp.h | 7 +++++++
include/net/sctp/sm.h | 3 +++
net/sctp/sm_make_chunk.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:04
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>
---
include/net/sctp/constants.h | 1 +
include/net/sctp/sm.h | 2 ++
include/net/sctp/structs.h | 6 ++++++
net/sctp/associola.c | 3 +++
net/sctp/sm_sideeffect.c | 32 ++++++++++++++++++++++++++++++++
net/sctp/sm_statefuns.c | 28 ++++++++++++++++++++++++++++
net/sctp/sm_statetable.c | 20 ++++++++++++++++++++
net/sctp/transport.c | 17 +++++++++++++++--
8 files changed, 107 insertions(+), 2 deletions(-)
@@ -436,6 +436,37 @@ void sctp_generate_proto_unreach_event(unsigned long data)sctp_association_put(asoc);}+/* Handle the timeout of the RE-CONFIG timer. */+voidsctp_generate_reconf_event(unsignedlongdata)+{+structsctp_transport*transport=(structsctp_transport*)data;+structsctp_association*asoc=transport->asoc;+structsock*sk=asoc->base.sk;+structnet*net=sock_net(sk);+interror=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);+gotoout_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. */staticvoidsctp_generate_sack_event(unsignedlongdata)
@@ -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,-(unsignedlong)peer);+(unsignedlong)peer);setup_timer(&peer->hb_timer,sctp_generate_heartbeat_event,-(unsignedlong)peer);+(unsignedlong)peer);+setup_timer(&peer->reconf_timer,sctp_generate_reconf_event,+(unsignedlong)peer);setup_timer(&peer->proto_unreach_timer,sctp_generate_proto_unreach_event,(unsignedlong)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);}+voidsctp_transport_reset_reconf_timer(structsctp_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.*Initializefieldsfromtheassociationorfromthesockitself.*Registerthereferencecountintheassociation.
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:12
This patch is to add a primitive based on sctp primitive frame for
sending stream reconf request. It works as the other primitives,
and create a SCTP_CMD_REPLY command to send the request chunk out.
sctp_primitive_RECONF would be the api to send a reconf request
chunk.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/constants.h | 3 ++-
include/net/sctp/sctp.h | 2 ++
include/net/sctp/sm.h | 1 +
net/sctp/primitive.c | 3 +++
net/sctp/sm_statefuns.c | 13 +++++++++++++
net/sctp/sm_statetable.c | 20 ++++++++++++++++++++
6 files changed, 41 insertions(+), 1 deletion(-)
@@ -114,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.
@@ -157,6 +157,7 @@ sctp_state_fn_t sctp_sf_error_shutdown;sctp_state_fn_tsctp_sf_ignore_primitive;sctp_state_fn_tsctp_sf_do_prm_requestheartbeat;sctp_state_fn_tsctp_sf_do_prm_asconf;+sctp_state_fn_tsctp_sf_do_prm_reconf;/* Prototypes for other event state functions. */sctp_state_fn_tsctp_sf_do_no_pending_tsn;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:20
This patch is to add reconf_enable field in all of asoc ep and netns
to indicate if they support stream reset.
When initializing, asoc reconf_enable get the default value from ep
reconf_enable which is from netns netns reconf_enable by default.
It is also to add reconf_capable in asoc peer part to know if peer
supports reconf_enable, the value is set if ext params have reconf
chunk support when processing init chunk, just as rfc6525 section
5.1.1 demands.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/netns/sctp.h | 3 +++
include/net/sctp/structs.h | 7 +++++--
net/sctp/associola.c | 1 +
net/sctp/endpointola.c | 1 +
net/sctp/sm_make_chunk.c | 15 +++++++++++++++
net/sctp/sysctl.c | 7 +++++++
6 files changed, 32 insertions(+), 2 deletions(-)
@@ -118,6 +118,9 @@ struct netns_sctp {/* Flag to indicate if PR-SCTP is enabled. */intprsctp_enable;+/* Flag to indicate if PR-CONFIG is enabled. */+intreconf_enable;+/* Flag to idicate if SCTP-AUTH is enabled */intauth_enable;
@@ -1497,6 +1498,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
@@ -1853,7 +1855,8 @@ struct sctp_association {__u8need_ecne:1,/* Need to send an ECNE Chunk? */temp:1,/* Is it a temporary association? */-prsctp_enable:1;+prsctp_enable:1,+reconf_enable:1;/* stream arrays */structsctp_stream_out*streamout;
@@ -270,6 +270,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *aasoc->active_key_id=ep->active_key_id;asoc->prsctp_enable=ep->prsctp_enable;+asoc->reconf_enable=ep->reconf_enable;/* Save the hmacs and chunks list into this association */if(ep->auth_hmacs_list)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:28
This patchset is to add SCTP_RECONFIG_SUPPORTED sockopt, it would
set and get asoc reconf_enable value when asoc_id is set, or it
would set and get ep reconf_enalbe value if asoc_id is 0.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/uapi/linux/sctp.h | 1 +
net/sctp/socket.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
@@ -3751,6 +3751,39 @@ static int sctp_setsockopt_default_prinfo(struct sock *sk,returnretval;}+staticintsctp_setsockopt_reconfig_supported(structsock*sk,+char__user*optval,+unsignedintoptlen)+{+structsctp_assoc_valueparams;+structsctp_association*asoc;+intretval=-EINVAL;++if(optlen!=sizeof(params))+gotoout;++if(copy_from_user(¶ms,optval,optlen)){+retval=-EFAULT;+gotoout;+}++asoc=sctp_id2assoc(sk,params.assoc_id);+if(asoc){+asoc->reconf_enable=!!params.assoc_value;+}elseif(!params.assoc_id){+structsctp_sock*sp=sctp_sk(sk);++sp->ep->reconf_enable=!!params.assoc_value;+}else{+gotoout;+}++retval=0;++out:+returnretval;+}+/* API 6.2 setsockopt(), getsockopt()**Applicationsusesetsockopt()andgetsockopt()tosetorretrieve
@@ -3917,6 +3950,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,caseSCTP_DEFAULT_PRINFO:retval=sctp_setsockopt_default_prinfo(sk,optval,optlen);break;+caseSCTP_RECONFIG_SUPPORTED:+retval=sctp_setsockopt_reconfig_supported(sk,optval,optlen);+break;default:retval=-ENOPROTOOPT;break;
@@ -6401,6 +6437,47 @@ static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len,returnretval;}+staticintsctp_getsockopt_reconfig_supported(structsock*sk,intlen,+char__user*optval,+int__user*optlen)+{+structsctp_assoc_valueparams;+structsctp_association*asoc;+intretval=-EFAULT;++if(len<sizeof(params)){+retval=-EINVAL;+gotoout;+}++len=sizeof(params);+if(copy_from_user(¶ms,optval,len))+gotoout;++asoc=sctp_id2assoc(sk,params.assoc_id);+if(asoc){+params.assoc_value=asoc->reconf_enable;+}elseif(!params.assoc_id){+structsctp_sock*sp=sctp_sk(sk);++params.assoc_value=sp->ep->reconf_enable;+}else{+retval=-EINVAL;+gotoout;+}++if(put_user(len,optlen))+gotoout;++if(copy_to_user(optval,¶ms,len))+gotoout;++retval=0;++out:+returnretval;+}+staticintsctp_getsockopt(structsock*sk,intlevel,intoptname,char__user*optval,int__user*optlen){
@@ -6568,6 +6645,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,retval=sctp_getsockopt_pr_assocstatus(sk,len,optval,optlen);break;+caseSCTP_RECONFIG_SUPPORTED:+retval=sctp_getsockopt_reconfig_supported(sk,len,optval,+optlen);+break;default:retval=-ENOPROTOOPT;break;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:37
This patch is to add sockopt SCTP_ENABLE_STREAM_RESET to set
strreset_enable to indicate which reconf request type it supports,
which is described in section 6.3.1.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/structs.h | 4 +++
include/uapi/linux/sctp.h | 7 ++++
net/sctp/associola.c | 1 +
net/sctp/socket.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 96 insertions(+)
@@ -139,6 +140,12 @@ 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+/* 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. */enumsctp_msg_flags{
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *aasoc->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)
@@ -3784,6 +3784,42 @@ static int sctp_setsockopt_reconfig_supported(struct sock *sk,returnretval;}+staticintsctp_setsockopt_enable_strreset(structsock*sk,+char__user*optval,+unsignedintoptlen)+{+structsctp_assoc_valueparams;+structsctp_association*asoc;+intretval=-EINVAL;++if(optlen!=sizeof(params))+gotoout;++if(copy_from_user(¶ms,optval,optlen)){+retval=-EFAULT;+gotoout;+}++if(params.assoc_value&(~SCTP_ENABLE_STRRESET_MASK))+gotoout;++asoc=sctp_id2assoc(sk,params.assoc_id);+if(asoc){+asoc->strreset_enable=params.assoc_value;+}elseif(!params.assoc_id){+structsctp_sock*sp=sctp_sk(sk);++sp->ep->strreset_enable=params.assoc_value;+}else{+gotoout;+}++retval=0;++out:+returnretval;+}+/* API 6.2 setsockopt(), getsockopt()**Applicationsusesetsockopt()andgetsockopt()tosetorretrieve
@@ -3953,6 +3989,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,caseSCTP_RECONFIG_SUPPORTED:retval=sctp_setsockopt_reconfig_supported(sk,optval,optlen);break;+caseSCTP_ENABLE_STREAM_RESET:+retval=sctp_setsockopt_enable_strreset(sk,optval,optlen);+break;default:retval=-ENOPROTOOPT;break;
@@ -6478,6 +6517,47 @@ static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len,returnretval;}+staticintsctp_getsockopt_enable_strreset(structsock*sk,intlen,+char__user*optval,+int__user*optlen)+{+structsctp_assoc_valueparams;+structsctp_association*asoc;+intretval=-EFAULT;++if(len<sizeof(params)){+retval=-EINVAL;+gotoout;+}++len=sizeof(params);+if(copy_from_user(¶ms,optval,len))+gotoout;++asoc=sctp_id2assoc(sk,params.assoc_id);+if(asoc){+params.assoc_value=asoc->strreset_enable;+}elseif(!params.assoc_id){+structsctp_sock*sp=sctp_sk(sk);++params.assoc_value=sp->ep->strreset_enable;+}else{+retval=-EINVAL;+gotoout;+}++if(put_user(len,optlen))+gotoout;++if(copy_to_user(optval,¶ms,len))+gotoout;++retval=0;++out:+returnretval;+}+staticintsctp_getsockopt(structsock*sk,intlevel,intoptname,char__user*optval,int__user*optlen){
@@ -6649,6 +6729,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,retval=sctp_getsockopt_reconfig_supported(sk,len,optval,optlen);break;+caseSCTP_ENABLE_STREAM_RESET:+retval=sctp_getsockopt_enable_strreset(sk,len,optval,+optlen);+break;default:retval=-ENOPROTOOPT;break;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:45
This patch is to implement sender-side procedures for the Outgoing
and Incoming SSN Reset Request Parameter described in section 5.1.2
and 5.1.3.
It is also add sockopt SCTP_RESET_STREAMS in section 6.3.2 for users.
Note that the new asoc member strreset_outstanding is to make sure
only one reconf request chunk on the fly as section 5.1.1 demands.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/structs.h | 1 +
include/uapi/linux/sctp.h | 11 ++++++
net/sctp/outqueue.c | 33 +++++++++++-----
net/sctp/socket.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 132 insertions(+), 10 deletions(-)
@@ -146,6 +147,9 @@ typedef __s32 sctp_assoc_t;#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. */enumsctp_msg_flags{
@@ -1016,4 +1020,11 @@ struct sctp_info {__u32__reserved3;};+structsctp_reset_streams{+sctp_assoc_tsrs_assoc_id;+uint16_tsrs_flags;+uint16_tsrs_number_streams;/* 0 == ALL */+uint16_tsrs_stream_list[];/* list if srs_num_streams is not 0 */+};+#endif /* _UAPI_SCTP_H */
@@ -915,22 +915,28 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)caseSCTP_CID_ECN_ECNE:caseSCTP_CID_ASCONF:caseSCTP_CID_FWD_TSN:+caseSCTP_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-*senderMUSTassurethatatleastoneT3-rtx-*timerisrunning.-*/-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+*senderMUSTassurethatatleastoneT3-rtx+*timerisrunning.+*/+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){+__u32sid=ntohs(chunk->subh.data_hdr->stream);+/* RFC 2960 6.5 Every DATA chunk MUST carry a valid*streamidentifier.*/
@@ -1038,6 +1046,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)continue;}+if(asoc->streamout[sid].state==SCTP_STREAM_CLOSED){+sctp_outq_head_data(q,chunk);+gotosctp_flush_out;+}+/* If there is a specified transport, use it.*Otherwise,wewanttousetheactivepath.*/
@@ -434,6 +434,19 @@ static int sctp_send_asconf(struct sctp_association *asoc,returnretval;}+staticintsctp_send_reconf(structsctp_association*asoc,+structsctp_chunk*chunk)+{+structnet*net=sock_net(asoc->base.sk);+intretval=0;++retval=sctp_primitive_RECONF(net,asoc,chunk);+if(retval)+sctp_chunk_free(chunk);++returnretval;+}+/* Add a list of addresses as bind addresses to local endpoint or*association.*
@@ -3820,6 +3833,87 @@ static int sctp_setsockopt_enable_strreset(struct sock *sk,returnretval;}+staticintsctp_setsockopt_reset_streams(structsock*sk,+char__user*optval,+unsignedintoptlen)+{+structsctp_reset_streams*params;+structsctp_association*asoc;+structsctp_chunk*chunk=NULL;+__u16i,str_nums,*str_list;+intretval=-EINVAL;+boolout,in;++if(optlen<sizeof(structsctp_reset_streams))+return-EINVAL;++params=memdup_user(optval,optlen);+if(IS_ERR(params)){+retval=PTR_ERR(params);+gotoout;+}++asoc=sctp_id2assoc(sk,params->srs_assoc_id);+if(!asoc)+gotoout;++if(!asoc->peer.reconf_capable||+!(asoc->strreset_enable&SCTP_ENABLE_RESET_STREAM_REQ)){+retval=-ENOPROTOOPT;+gotoout;+}++if(asoc->strreset_outstanding){+retval=-EINPROGRESS;+gotoout;+}++out=params->srs_flags&SCTP_STREAM_RESET_OUTGOING;+in=params->srs_flags&SCTP_STREAM_RESET_INCOMING;+if(!out&&!in)+gotoout;++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]>=asoc->streamoutcnt)+gotoout;++if(in&&str_nums)+for(i=0;i<str_nums;i++)+if(str_list[i]>=asoc->streamincnt)+gotoout;++chunk=sctp_make_strreset_req(asoc,str_nums,str_list,out,in);+if(!chunk)+gotoout;++if(out){+if(str_nums)+for(i=0;i<str_nums;i++)+asoc->streamout[str_list[i]].state=+SCTP_STREAM_CLOSED;+else+for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[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:+kfree(params);+returnretval;+}+/* API 6.2 setsockopt(), getsockopt()**Applicationsusesetsockopt()andgetsockopt()tosetorretrieve
@@ -3992,6 +4086,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,caseSCTP_ENABLE_STREAM_RESET:retval=sctp_setsockopt_enable_strreset(sk,optval,optlen);break;+caseSCTP_RESET_STREAMS:+retval=sctp_setsockopt_reset_streams(sk,optval,optlen);+break;default:retval=-ENOPROTOOPT;break;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:22:53
This patch is to implement Sender-Side Procedures for the SSN/TSN
Reset Request Parameter descibed in section 5.1.4.
It is also to add sockopt SCTP_RESET_ASSOC in section 6.3.3 for
users.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/uapi/linux/sctp.h | 1 +
net/sctp/socket.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
@@ -3914,6 +3914,60 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,returnretval;}+staticintsctp_setsockopt_reset_assoc(structsock*sk,+char__user*optval,+unsignedintoptlen)+{+structsctp_association*asoc;+structsctp_chunk*chunk=NULL;+sctp_assoc_tassocid;+intretval=-EINVAL;+__u16i;++if(optlen!=sizeof(associd))+gotoout;++if(copy_from_user(&associd,optval,optlen)){+retval=-EFAULT;+gotoout;+}++asoc=sctp_id2assoc(sk,associd);+if(!asoc)+gotoout;++if(!asoc->peer.reconf_capable||+!(asoc->strreset_enable&SCTP_ENABLE_RESET_ASSOC_REQ)){+retval=-ENOPROTOOPT;+gotoout;+}++if(asoc->strreset_outstanding){+retval=-EINPROGRESS;+gotoout;+}++chunk=sctp_make_strreset_tsnreq(asoc);+if(!chunk)+gotoout;++for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].state=SCTP_STREAM_CLOSED;++asoc->strreset_outstanding=1;+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:+returnretval;+}+/* API 6.2 setsockopt(), getsockopt()**Applicationsusesetsockopt()andgetsockopt()tosetorretrieve
@@ -4089,6 +4143,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,caseSCTP_RESET_STREAMS:retval=sctp_setsockopt_reset_streams(sk,optval,optlen);break;+caseSCTP_RESET_ASSOC:+retval=sctp_setsockopt_reset_assoc(sk,optval,optlen);+break;default:retval=-ENOPROTOOPT;break;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:01
This patch is to implement Sender-Side Procedures for the Add
Outgoing and Incoming Streams Request Parameter described in
5.1.5-5.1.6.
It is also to add sockopt SCTP_ADD_STREAMS in section 6.3.4
for users.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/uapi/linux/sctp.h | 7 +++
net/sctp/socket.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+)
@@ -1028,4 +1029,10 @@ struct sctp_reset_streams {uint16_tsrs_stream_list[];/* list if srs_num_streams is not 0 */};+structsctp_add_streams{+sctp_assoc_tsas_assoc_id;+uint16_tsas_instrms;+uint16_tsas_outstrms;+};+#endif /* _UAPI_SCTP_H */
@@ -3968,6 +3968,117 @@ static int sctp_setsockopt_reset_assoc(struct sock *sk,returnretval;}+staticintsctp_setsockopt_add_streams(structsock*sk,+char__user*optval,+unsignedintoptlen)+{+structsctp_association*asoc;+structsctp_chunk*chunk=NULL;+structsctp_add_streamsparams;+intretval=-EINVAL;+__u16out,in;++if(optlen!=sizeof(params))+gotoout;++if(copy_from_user(¶ms,optval,optlen)){+retval=-EFAULT;+gotoout;+}++asoc=sctp_id2assoc(sk,params.sas_assoc_id);+if(!asoc)+gotoout;++if(!asoc->peer.reconf_capable||+!(asoc->strreset_enable&SCTP_ENABLE_CHANGE_ASSOC_REQ)){+retval=-ENOPROTOOPT;+gotoout;+}++if(asoc->strreset_outstanding){+retval=-EINPROGRESS;+gotoout;+}++out=params.sas_outstrms;+in=params.sas_instrms;++if(!out&&!in)+gotoout;++if(out){+__u16nums=asoc->streamoutcnt+out;++/* Check for overflow, can't use nums here */+if(asoc->streamoutcnt+out>SCTP_MAX_STREAM)+gotoout;++/* Use ksize to check if stream array really needs to realloc */+if(ksize(asoc->streamout)/sizeof(*asoc->streamout)<nums){+structsctp_stream_out*streamout;++streamout=kcalloc(nums,sizeof(*streamout),+GFP_KERNEL);+if(!streamout){+retval=-ENOMEM;+gotoout;+}++memcpy(streamout,asoc->streamout,+sizeof(*streamout)*asoc->streamoutcnt);++kfree(asoc->streamout);+asoc->streamout=streamout;+}++asoc->streamoutcnt=nums;+}++if(in){+__u16nums=asoc->streamincnt+in;++if(asoc->streamincnt+in>SCTP_MAX_STREAM)+gotoout;++if(ksize(asoc->streamin)/sizeof(*asoc->streamin)<nums){+structsctp_stream_in*streamin;++streamin=kcalloc(nums,sizeof(*streamin),+GFP_KERNEL);+if(!streamin){+retval=-ENOMEM;+gotoout;+}++memcpy(streamin,asoc->streamin,+sizeof(*streamin)*asoc->streamincnt);++kfree(asoc->streamin);+asoc->streamin=streamin;+}++asoc->streamincnt=nums;+}++chunk=sctp_make_strreset_addstrm(asoc,out,in);+if(!chunk)+gotoout;++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:+returnretval;+}+/* API 6.2 setsockopt(), getsockopt()**Applicationsusesetsockopt()andgetsockopt()tosetorretrieve
@@ -4146,6 +4257,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,caseSCTP_RESET_ASSOC:retval=sctp_setsockopt_reset_assoc(sk,optval,optlen);break;+caseSCTP_ADD_STREAMS:+retval=sctp_setsockopt_add_streams(sk,optval,optlen);+break;default:retval=-ENOPROTOOPT;break;
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:08
This patch is to add Stream Reset Event described in section 6.1.1.
It's added earlier here so that the codes for other sections could
invoked them.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/ulpevent.h | 4 ++++
include/uapi/linux/sctp.h | 36 ++++++++++++++++++++++++++----------
net/sctp/ulpevent.c | 30 ++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 10 deletions(-)
@@ -530,6 +543,7 @@ union sctp_notification {structsctp_pdapi_eventsn_pdapi_event;structsctp_authkey_eventsn_authkey_event;structsctp_sender_dry_eventsn_sender_dry_event;+structsctp_stream_reset_eventsn_strreset_event;};/* Section 5.3.1
@@ -557,6 +571,8 @@ enum sctp_sn_type {#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENTSCTP_SENDER_DRY_EVENT,#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT+SCTP_STREAM_RESET_EVENT,+#define SCTP_STREAM_RESET_EVENT SCTP_STREAM_RESET_EVENT};/* Notification error codes used to fill up the error fields in some
@@ -854,6 +854,36 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(returnevent;}+structsctp_ulpevent*sctp_ulpevent_make_stream_reset_event(+conststructsctp_association*asoc,__u16flags,__u16stream_num,+__u16*stream_list,gfp_tgfp)+{+structsctp_stream_reset_event*sreset;+structsctp_ulpevent*event;+structsk_buff*skb;++event=sctp_ulpevent_new(sizeof(structsctp_stream_reset_event)++2*stream_num,MSG_NOTIFICATION,gfp);+if(!event)+returnNULL;++skb=sctp_event2skb(event);+sreset=(structsctp_stream_reset_event*)skb_put(skb,+sizeof(structsctp_stream_reset_event)+2*stream_num);++sreset->strreset_type=SCTP_STREAM_RESET_EVENT;+sreset->strreset_flags=flags;+sreset->strreset_length=sizeof(structsctp_stream_reset_event);+sctp_ulpevent_set_owner(event,asoc);+sreset->strreset_assoc_id=sctp_assoc2id(asoc);++if(stream_num)+memcpy(sreset->strreset_stream_list,stream_list,+2*stream_num);++returnevent;+}+/* Return the notification type, assuming this is a notification*event.*/
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:16
This patch is to add Association Reset Event described in section 6.1.2.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/ulpevent.h | 4 ++++
include/uapi/linux/sctp.h | 15 +++++++++++++++
net/sctp/ulpevent.c | 28 ++++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
@@ -544,6 +556,7 @@ union sctp_notification {structsctp_authkey_eventsn_authkey_event;structsctp_sender_dry_eventsn_sender_dry_event;structsctp_stream_reset_eventsn_strreset_event;+structsctp_assoc_reset_eventsn_assocreset_event;};/* Section 5.3.1
@@ -573,6 +586,8 @@ enum sctp_sn_type {#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENTSCTP_STREAM_RESET_EVENT,#define SCTP_STREAM_RESET_EVENT SCTP_STREAM_RESET_EVENT+SCTP_ASSOC_RESET_EVENT,+#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT};/* Notification error codes used to fill up the error fields in some
@@ -884,6 +884,34 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(returnevent;}+structsctp_ulpevent*sctp_ulpevent_make_assoc_reset_event(+conststructsctp_association*asoc,__u16flags,__u32local_tsn,+__u32remote_tsn,gfp_tgfp)+{+structsctp_assoc_reset_event*areset;+structsctp_ulpevent*event;+structsk_buff*skb;++event=sctp_ulpevent_new(sizeof(structsctp_assoc_reset_event),+MSG_NOTIFICATION,gfp);+if(!event)+returnNULL;++skb=sctp_event2skb(event);+areset=(structsctp_assoc_reset_event*)+skb_put(skb,sizeof(structsctp_assoc_reset_event));++areset->assocreset_type=SCTP_ASSOC_RESET_EVENT;+areset->assocreset_flags=flags;+areset->assocreset_length=sizeof(structsctp_assoc_reset_event);+sctp_ulpevent_set_owner(event,asoc);+areset->assocreset_assoc_id=sctp_assoc2id(asoc);+areset->assocreset_local_tsn=local_tsn;+areset->assocreset_remote_tsn=remote_tsn;++returnevent;+}+/* Return the notification type, assuming this is a notification*event.*/
@@ -557,6 +569,7 @@ union sctp_notification {structsctp_sender_dry_eventsn_sender_dry_event;structsctp_stream_reset_eventsn_strreset_event;structsctp_assoc_reset_eventsn_assocreset_event;+structsctp_stream_change_eventsn_strchange_event;};/* Section 5.3.1
@@ -588,6 +601,8 @@ enum sctp_sn_type {#define SCTP_STREAM_RESET_EVENT SCTP_STREAM_RESET_EVENTSCTP_ASSOC_RESET_EVENT,#define SCTP_ASSOC_RESET_EVENT SCTP_ASSOC_RESET_EVENT+SCTP_STREAM_CHANGE_EVENT,+#define SCTP_STREAM_CHANGE_EVENT SCTP_STREAM_CHANGE_EVENT};/* Notification error codes used to fill up the error fields in some
@@ -912,6 +912,34 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(returnevent;}+structsctp_ulpevent*sctp_ulpevent_make_stream_change_event(+conststructsctp_association*asoc,__u16flags,+__u32strchange_instrms,__u32strchange_outstrms,gfp_tgfp)+{+structsctp_stream_change_event*schange;+structsctp_ulpevent*event;+structsk_buff*skb;++event=sctp_ulpevent_new(sizeof(structsctp_stream_change_event),+MSG_NOTIFICATION,gfp);+if(!event)+returnNULL;++skb=sctp_event2skb(event);+schange=(structsctp_stream_change_event*)+skb_put(skb,sizeof(structsctp_stream_change_event));++schange->strchange_type=SCTP_STREAM_CHANGE_EVENT;+schange->strchange_flags=flags;+schange->strchange_length=sizeof(structsctp_stream_change_event);+sctp_ulpevent_set_owner(event,asoc);+schange->strchange_assoc_id=sctp_assoc2id(asoc);+schange->strchange_instrms=strchange_instrms;+schange->strchange_outstrms=strchange_outstrms;++returnevent;+}+/* Return the notification type, assuming this is a notification*event.*/
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:32
This patch is to implement Receiver-Side Procedures for the Outgoing
SSN Reset Request Parameter described in section 5.2.2.
Note that some checks must be after request_seq check, as even those
checks fail, strreset_inseq still has to be increase by 1.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 6 +++
net/sctp/Makefile | 3 +-
net/sctp/stream.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 154 insertions(+), 1 deletion(-)
create mode 100644 net/sctp/stream.c
@@ -0,0 +1,146 @@+/* SCTP kernel implementation+*(C)CopyrightIBMCorp.2001,2004+*Copyright(c)1999-2000Cisco,Inc.+*Copyright(c)1999-2001Motorola,Inc.+*Copyright(c)2001IntelCorp.+*+*ThisfileispartoftheSCTPkernelimplementation+*+*Thesefunctionsmanipulatesctptsnmappingarray.+*+*ThisSCTPimplementationisfreesoftware;+*youcanredistributeitand/ormodifyitunderthetermsof+*theGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2,or(atyouroption)+*anylaterversion.+*+*ThisSCTPimplementationisdistributedinthehopethatit+*willbeuseful,butWITHOUTANYWARRANTY;withouteventheimplied+*************************+*warrantyofMERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.+*SeetheGNUGeneralPublicLicenseformoredetails.+*+*YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense+*alongwithGNUCC;seethefileCOPYING.Ifnot,see+*<http://www.gnu.org/licenses/>.+*+*Pleasesendanybugreportsorfixesyoumaketothe+*emailaddress(es):+*lksctpdevelopers<linux-sctp@vger.kernel.org>+*+*Writtenormodifiedby:+*XinLong<lucien.xin@gmail.com>+*/++#include<net/sctp/sctp.h>+#include<net/sctp/sm.h>++staticstructsctp_strreset_req*sctp_chunk_lookup_strreset_param(+structsctp_association*asoc,__u32resp_seq)+{+structsctp_chunk*chunk=asoc->strreset_chunk;+structsctp_reconf_chunk*hdr;+unionsctp_paramsparam;++if(resp_seq!=asoc->strreset_outseq||!chunk)+returnNULL;++hdr=(structsctp_reconf_chunk*)chunk->chunk_hdr;+sctp_walk_params(param,hdr,params){+structsctp_strreset_req*req=param.v;++if(ntohl(req->request_seq)==resp_seq)+returnreq;+}++returnNULL;+}++structsctp_chunk*sctp_process_strreset_outreq(+structsctp_association*asoc,+unionsctp_paramsparam,+structsctp_ulpevent**evp)+{+structsctp_strreset_outreq*outreq=param.v;+__u32result=SCTP_STRRESET_DENIED;+__u16i,nums,*str_p,flags=0;+__u32request_seq;++request_seq=ntohl(outreq->request_seq);++if(ntohl(outreq->send_reset_at_tsn)>+sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)){+result=SCTP_STRRESET_IN_PROGRESS;+gotoout;+}++if(request_seq>asoc->strreset_inseq){+result=SCTP_STRRESET_ERR_BAD_SEQNO;+gotoout;+}elseif(request_seq==asoc->strreset_inseq){+asoc->strreset_inseq++;+}++/* Check strreset_enable after inseq inc, as sender cannot tell+*thepeerdoesn'tenablestrresetafterreceivingresponsewith+*resultdenied,aswellastokeepconsistentwithbsd.+*/+if(!(asoc->strreset_enable&SCTP_ENABLE_RESET_STREAM_REQ))+gotoout;++if(asoc->strreset_chunk){+structsctp_strreset_req*inreq;+structsctp_transport*t;++inreq=sctp_chunk_lookup_strreset_param(+asoc,ntohl(outreq->response_seq));+if(!inreq||inreq->param_hdr.type!=+SCTP_PARAM_RESET_IN_REQUEST){+/* same process with outstanding isn't 0 */+result=SCTP_STRRESET_ERR_IN_PROGRESS;+gotoout;+}++asoc->strreset_outstanding--;+asoc->strreset_outseq++;++if(!asoc->strreset_outstanding){+t=asoc->strreset_chunk->transport;+if(del_timer(&t->reconf_timer))+sctp_transport_put(t);++sctp_chunk_put(asoc->strreset_chunk);+asoc->strreset_chunk=NULL;+}++flags=SCTP_STREAM_RESET_INCOMING_SSN;+}++nums=(ntohs(param.p->length)-sizeof(*outreq))/2;+if(nums){+str_p=outreq->list_of_streams;+for(i=0;i<nums;i++){+str_p[i]=ntohs(str_p[i]);+if(str_p[i]>=asoc->streamincnt){+result=SCTP_STRRESET_ERR_WRONG_SSN;+gotoout;+}+}++str_p=outreq->list_of_streams;+for(i=0;i<nums;i++,str_p++)+asoc->streamin[*str_p].ssn=0;+}else{+for(i=0;i<asoc->streamincnt;i++)+asoc->streamin[i].ssn=0;+}++result=SCTP_STRRESET_PERFORMED;++*evp=sctp_ulpevent_make_stream_reset_event(asoc,+flags|SCTP_STREAM_RESET_OUTGOING_SSN,nums,str_p,+GFP_ATOMIC);++out:+returnsctp_make_strreset_resp(asoc,result,request_seq);+}
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:40
This patch is to implement Receiver-Side Procedures for the Incoming
SSN Reset Request Parameter described in section 5.2.3.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 4 ++++
net/sctp/stream.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:48
This patch is to implement Receiver-Side Procedures for the SSN/TSN
Reset Request Parameter described in section 6.2.4.
The process is kinda complicate, it's wonth having comments from
section 6.2.4 in the codes.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 4 +++
net/sctp/stream.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+)
@@ -207,3 +207,79 @@ struct sctp_chunk *sctp_process_strreset_inreq(returnchunk;}++structsctp_chunk*sctp_process_strreset_tsnreq(+structsctp_association*asoc,+unionsctp_paramsparam,+structsctp_ulpevent**evp)+{+structsctp_strreset_tsnreq*tsnreq=param.v;+__u32request_seq,initial_tsn,max_tsn_seen;+__u32result=SCTP_STRRESET_DENIED;+__u16i;++request_seq=ntohl(tsnreq->request_seq);+if(request_seq>asoc->strreset_inseq){+result=SCTP_STRRESET_ERR_BAD_SEQNO;+gotoout;+}elseif(request_seq==asoc->strreset_inseq){+asoc->strreset_inseq++;+}++if(!(asoc->strreset_enable&SCTP_ENABLE_RESET_ASSOC_REQ))+gotoout;++if(asoc->strreset_outstanding){+result=SCTP_STRRESET_ERR_IN_PROGRESS;+gotoout;+}++/* G3: The same processing as though a SACK chunk with no gap report+*andacumulativeTSNACKoftheSender'sNextTSNminus1were+*receivedMUSTbeperformed.+*/+max_tsn_seen=sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);+sctp_ulpq_reasm_flushtsn(&asoc->ulpq,max_tsn_seen);+sctp_ulpq_abort_pd(&asoc->ulpq,GFP_ATOMIC);++/* G1: Compute an appropriate value for the Receiver's Next TSN -- the+*TSNthatthepeershouldusetosendthenextDATAchunk.The+*valueSHOULDbethesmallestTSNnotacknowledgedbythe+*receiveroftherequestplus2^31.+*/+initial_tsn=sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)+(1<<31);+sctp_tsnmap_init(&asoc->peer.tsn_map,SCTP_TSN_MAP_INITIAL,+initial_tsn,GFP_ATOMIC);++/* G4: The same processing as though a FWD-TSN chunk (as defined in+*[RFC3758])withallstreamsaffectedandanewcumulativeTSN+*ACKoftheReceiver'sNextTSNminus1werereceivedMUSTbe+*performed.+*/+sctp_outq_free(&asoc->outqueue);++/* G2: Compute an appropriate value for the local endpoint's next TSN,+*i.e.,thenextTSNassignedbythereceiveroftheSSN/TSNreset+*chunk.ThevalueSHOULDbethehighestTSNsentbythereceiver+*oftherequestplus1.+*/+asoc->ctsn_ack_point=asoc->next_tsn-1;+asoc->adv_peer_ack_point=asoc->ctsn_ack_point;++/* G5: The next expected and outgoing SSNs MUST be reset to 0 for all+*incomingandoutgoingstreams.+*/+for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].ssn=0;+for(i=0;i<asoc->streamincnt;i++)+asoc->streamin[i].ssn=0;++result=SCTP_STRRESET_PERFORMED;++*evp=sctp_ulpevent_make_assoc_reset_event(asoc,+0,initial_tsn,asoc->next_tsn,GFP_ATOMIC);++out:+returnsctp_make_strreset_tsnresp(asoc,result,request_seq,+asoc->next_tsn,initial_tsn);+}
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:23:56
This patch is to add Receiver-Side Procedures for the Add Outgoing
Streams Request Parameter described in section 5.2.5.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 4 ++++
net/sctp/stream.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:24:04
This patch is to implement Receiver-Side Procedures for the Add Incoming
Streams Request Parameter described in section 5.2.6.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 4 ++++
net/sctp/stream.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:24:12
This patch is to implement Receiver-Side Procedures for the
Re-configuration Response Parameter in section 5.2.7.
sctp_process_strreset_resp would process the response for any
kind of reconf request, and the stream reconf is applied only
when the response result is success.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 4 ++
net/sctp/stream.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 167 insertions(+)
@@ -398,3 +398,166 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(out:returnsctp_make_strreset_resp(asoc,result,request_seq);}++structsctp_chunk*sctp_process_strreset_resp(+structsctp_association*asoc,+unionsctp_paramsparam,+structsctp_ulpevent**evp)+{+structsctp_strreset_resp*resp=param.v;+structsctp_strreset_req*req;+structsctp_transport*t;+__u16i,nums,flags=0;+__u32result;++req=sctp_chunk_lookup_strreset_param(+asoc,ntohl(resp->response_seq));+if(!req)+returnNULL;++result=ntohl(resp->result);+if(result!=SCTP_STRRESET_PERFORMED){+/* if in progress, do nothing but retransmit */+if(result==SCTP_STRRESET_IN_PROGRESS)+returnNULL;+elseif(result==SCTP_STRRESET_DENIED)+flags=SCTP_STREAM_RESET_DENIED;+else+flags=SCTP_STREAM_RESET_FAILED;+}++if(req->param_hdr.type==SCTP_PARAM_RESET_OUT_REQUEST){+structsctp_strreset_outreq*outreq;+__u16*str_p=NULL;++outreq=(structsctp_strreset_outreq*)req;+nums=(ntohs(outreq->param_hdr.length)-sizeof(*outreq))/2;++if(nums){+str_p=outreq->list_of_streams;+for(i=0;i<nums;i++)+str_p[i]=ntohs(str_p[i]);+}++if(result==SCTP_STRRESET_PERFORMED){+if(nums){+str_p=outreq->list_of_streams;+for(i=0;i<nums;i++,str_p++)+asoc->streamout[*str_p].ssn=0;+}else{+for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].ssn=0;+}++flags=SCTP_STREAM_RESET_OUTGOING_SSN;+}++for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].state=SCTP_STREAM_OPEN;++*evp=sctp_ulpevent_make_stream_reset_event(asoc,flags,+nums,str_p,GFP_ATOMIC);+}elseif(req->param_hdr.type==SCTP_PARAM_RESET_IN_REQUEST){+structsctp_strreset_inreq*inreq;+__u16*str_p=NULL;++/* if the result is performed, it's impossible for inreq */+if(result==SCTP_STRRESET_PERFORMED)+returnNULL;++inreq=(structsctp_strreset_inreq*)req;+nums=(ntohs(inreq->param_hdr.length)-sizeof(*inreq))/2;++if(nums){+str_p=inreq->list_of_streams;+for(i=0;i<nums;i++)+str_p[i]=ntohs(str_p[i]);+}++str_p=inreq->list_of_streams;+*evp=sctp_ulpevent_make_stream_reset_event(asoc,flags,+nums,str_p,GFP_ATOMIC);+}elseif(req->param_hdr.type==SCTP_PARAM_RESET_TSN_REQUEST){+structsctp_strreset_resptsn*resptsn;+__u32stsn,rtsn;++/* check for resptsn, as sctp_verify_reconf didn't do it*/+if(ntohs(param.p->length)!=sizeof(*resptsn))+returnNULL;++resptsn=(structsctp_strreset_resptsn*)resp;+stsn=ntohl(resptsn->senders_next_tsn);+rtsn=ntohl(resptsn->receivers_next_tsn);++if(result==SCTP_STRRESET_PERFORMED){+__u32mtsn=sctp_tsnmap_get_max_tsn_seen(+&asoc->peer.tsn_map);++sctp_ulpq_reasm_flushtsn(&asoc->ulpq,mtsn);+sctp_ulpq_abort_pd(&asoc->ulpq,GFP_ATOMIC);++sctp_tsnmap_init(&asoc->peer.tsn_map,+SCTP_TSN_MAP_INITIAL,+stsn,GFP_ATOMIC);++sctp_outq_free(&asoc->outqueue);++asoc->next_tsn=rtsn;+asoc->ctsn_ack_point=asoc->next_tsn-1;+asoc->adv_peer_ack_point=asoc->ctsn_ack_point;++for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].ssn=0;+for(i=0;i<asoc->streamincnt;i++)+asoc->streamin[i].ssn=0;+}++for(i=0;i<asoc->streamoutcnt;i++)+asoc->streamout[i].state=SCTP_STREAM_OPEN;++*evp=sctp_ulpevent_make_assoc_reset_event(asoc,flags,+stsn,rtsn,GFP_ATOMIC);+}elseif(req->param_hdr.type==SCTP_PARAM_RESET_ADD_OUT_STREAMS){+structsctp_strreset_addstrm*addstrm;+__u16number;++addstrm=(structsctp_strreset_addstrm*)req;+nums=ntohs(addstrm->number_of_streams);+number=asoc->streamoutcnt-nums;++if(result==SCTP_STRRESET_PERFORMED)+for(i=number;i<asoc->streamoutcnt;i++)+asoc->streamout[i].state=SCTP_STREAM_OPEN;+else+asoc->streamoutcnt=number;++*evp=sctp_ulpevent_make_stream_change_event(asoc,flags,+0,nums,GFP_ATOMIC);+}elseif(req->param_hdr.type==SCTP_PARAM_RESET_ADD_IN_STREAMS){+structsctp_strreset_addstrm*addstrm;++addstrm=(structsctp_strreset_addstrm*)req;+nums=ntohs(addstrm->number_of_streams);++if(result!=SCTP_STRRESET_PERFORMED)+asoc->streamincnt=asoc->streamincnt-nums;++*evp=sctp_ulpevent_make_stream_change_event(asoc,flags,+nums,0,GFP_ATOMIC);+}++asoc->strreset_outstanding--;+asoc->strreset_outseq++;++/* remove everything for this reconf request */+if(!asoc->strreset_outstanding){+t=asoc->strreset_chunk->transport;+if(del_timer(&t->reconf_timer))+sctp_transport_put(t);++sctp_chunk_put(asoc->strreset_chunk);+asoc->strreset_chunk=NULL;+}++returnNULL;+}
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:24:20
This patch is to add a function to process the incoming reconf chunk,
in which it verifies the chunk, and traverses the param and process
it with the right function one by one.
sctp_sf_do_reconf would be the process function of reconf chunk event.
Note that to support multi-params in response chunk, it also adds a
function sctp_merge_reconf_chunk to merge two reconf chunk into one.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/sm.h | 8 +++++
net/sctp/sm_make_chunk.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
net/sctp/sm_statefuns.c | 68 +++++++++++++++++++++++++++++++++++
3 files changed, 170 insertions(+)
@@ -3834,6 +3834,74 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net,returnSCTP_DISPOSITION_DISCARD;}+/* RE-CONFIG Section 5.2 Upon reception of an RECONF Chunk. */+sctp_disposition_tsctp_sf_do_reconf(structnet*net,+conststructsctp_endpoint*ep,+conststructsctp_association*asoc,+constsctp_subtype_ttype,void*arg,+sctp_cmd_seq_t*commands)+{+structsctp_paramhdr*err_param=NULL;+structsctp_chunk*reply=NULL;+structsctp_chunk*last=NULL;+structsctp_chunk*chunk=arg;+structsctp_reconf_chunk*hdr;+unionsctp_paramsparam;++if(!sctp_vtag_verify(chunk,asoc)){+sctp_add_cmd_sf(commands,SCTP_CMD_REPORT_BAD_TAG,+SCTP_NULL());+returnsctp_sf_pdiscard(net,ep,asoc,type,arg,commands);+}++/* Make sure that the RECONF chunk has a valid length. */+if(!sctp_chunk_length_valid(chunk,sizeof(*hdr)))+returnsctp_sf_violation_chunklen(net,ep,asoc,type,arg,+commands);++if(!sctp_verify_reconf(asoc,chunk,&err_param))+returnsctp_sf_violation_paramlen(net,ep,asoc,type,arg,+(void*)err_param,commands);++hdr=(structsctp_reconf_chunk*)chunk->chunk_hdr;+sctp_walk_params(param,hdr,params){+structsctp_ulpevent*ev=NULL;++if(param.p->type==SCTP_PARAM_RESET_OUT_REQUEST)+reply=sctp_process_strreset_outreq(+(structsctp_association*)asoc,param,&ev);+elseif(param.p->type==SCTP_PARAM_RESET_IN_REQUEST)+reply=sctp_process_strreset_inreq(+(structsctp_association*)asoc,param,&ev);+elseif(param.p->type==SCTP_PARAM_RESET_TSN_REQUEST)+reply=sctp_process_strreset_tsnreq(+(structsctp_association*)asoc,param,&ev);+elseif(param.p->type==SCTP_PARAM_RESET_ADD_OUT_STREAMS)+reply=sctp_process_strreset_addstrm_out(+(structsctp_association*)asoc,param,&ev);+elseif(param.p->type==SCTP_PARAM_RESET_ADD_IN_STREAMS)+reply=sctp_process_strreset_addstrm_in(+(structsctp_association*)asoc,param,&ev);+elseif(param.p->type==SCTP_PARAM_RESET_RESPONSE)+reply=sctp_process_strreset_resp(+(structsctp_association*)asoc,param,&ev);++if(ev)+sctp_add_cmd_sf(commands,SCTP_CMD_EVENT_ULP,+SCTP_ULPEVENT(ev));++if(last)+reply=sctp_merge_reconf_chunk(+(structsctp_association*)asoc,last,reply);+last=reply;+}++if(reply)+sctp_add_cmd_sf(commands,SCTP_CMD_REPLY,SCTP_CHUNK(reply));++returnSCTP_DISPOSITION_CONSUME;+}+/**PR-SCTPSection3.6ReceiverSideImplementationofPR-SCTP*
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:24:28
This patch is to add reconf chunk event based on the sctp event
frame, after which, the reconf chunk process would be activated.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
include/net/sctp/constants.h | 3 +++
net/sctp/sm_statetable.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 11:32:24
On Sun, Jan 1, 2017 at 7:20 PM, Xin Long [off-list ref] wrote:
This patchset is to implement sctp stream reconf described in rfc6525.
Patch 1-3 add per stream information in sctp asoc.
Patch 4-8 make the chunk with different reconf params. (Section 3-4)
Patch 9-12 add reconf timer, primitive and enable option.
Patch 13-25 implement the procedures on both sender and receiver sides (Section 5)
add sockopts and event for users (Section 6)
Patch 26-27 add reconf event, activate the sctp stream reconf process.
Attachments are the scripts I used to do tests for this patchset.
including the scripts on bsd side when doing some interactivity
tests with bsd.
From: kbuild test robot <hidden> Date: 2017-01-01 12:15:32
Hi Xin,
[auto build test WARNING on net-next/master]
url: https://github.com/0day-ci/linux/commits/Xin-Long/sctp-implement-rfc6525-sctp-stream-reconf/20170101-192844
config: x86_64-randconfig-x015-201701 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
All warnings (new ones prefixed by >>):
net/sctp/stream.c: In function 'sctp_process_strreset_outreq':
net/sctp/stream.c:140:9: warning: 'str_p' may be used uninitialized in this function [-Wmaybe-uninitialized]
*evp = sctp_ulpevent_make_stream_reset_event(asoc,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GFP_ATOMIC);
~~~~~~~~~~~
net/sctp/stream.c: In function 'sctp_process_strreset_tsnreq':
quoted
net/sctp/stream.c:283:9: warning: 'initial_tsn' may be used uninitialized in this function [-Wmaybe-uninitialized]
return sctp_make_strreset_tsnresp(asoc, result, request_seq,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
asoc->next_tsn, initial_tsn);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/initial_tsn +283 net/sctp/stream.c
134 for (i = 0; i < asoc->streamincnt; i++)
135 asoc->streamin[i].ssn = 0;
136 }
137
138 result = SCTP_STRRESET_PERFORMED;
139
> 140 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
141 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
142 GFP_ATOMIC);
143
144 out:
145 return sctp_make_strreset_resp(asoc, result, request_seq);
146 }
147
148 struct sctp_chunk *sctp_process_strreset_inreq(
149 struct sctp_association *asoc,
150 union sctp_params param,
151 struct sctp_ulpevent **evp)
152 {
153 struct sctp_strreset_inreq *inreq = param.v;
154 __u32 result = SCTP_STRRESET_DENIED;
155 struct sctp_chunk *chunk = NULL;
156 __u16 i, nums, *str_p;
157 __u32 request_seq;
158
159 request_seq = ntohl(inreq->request_seq);
160 if (request_seq > asoc->strreset_inseq) {
161 result = SCTP_STRRESET_ERR_BAD_SEQNO;
162 goto out;
163 } else if (request_seq == asoc->strreset_inseq) {
164 asoc->strreset_inseq++;
165 }
166
167 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
168 goto out;
169
170 if (asoc->strreset_outstanding) {
171 result = SCTP_STRRESET_ERR_IN_PROGRESS;
172 goto out;
173 }
174
175 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
176 str_p = inreq->list_of_streams;
177 for (i = 0; i < nums; i++) {
178 str_p[i] = ntohs(str_p[i]);
179 if (str_p[i] >= asoc->streamoutcnt) {
180 result = SCTP_STRRESET_ERR_WRONG_SSN;
181 goto out;
182 }
183 }
184
185 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
186 if (!chunk)
187 goto out;
188
189 if (nums)
190 for (i = 0; i < nums; i++)
191 asoc->streamout[str_p[i]].state =
192 SCTP_STREAM_CLOSED;
193 else
194 for (i = 0; i < asoc->streamoutcnt; i++)
195 asoc->streamout[i].state = SCTP_STREAM_CLOSED;
196
197 asoc->strreset_chunk = chunk;
198 asoc->strreset_outstanding = 1;
199 sctp_chunk_hold(asoc->strreset_chunk);
200
201 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
202 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
203
204 out:
205 if (!chunk)
206 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
207
208 return chunk;
209 }
210
211 struct sctp_chunk *sctp_process_strreset_tsnreq(
212 struct sctp_association *asoc,
213 union sctp_params param,
214 struct sctp_ulpevent **evp)
215 {
216 struct sctp_strreset_tsnreq *tsnreq = param.v;
217 __u32 request_seq, initial_tsn, max_tsn_seen;
218 __u32 result = SCTP_STRRESET_DENIED;
219 __u16 i;
220
221 request_seq = ntohl(tsnreq->request_seq);
222 if (request_seq > asoc->strreset_inseq) {
223 result = SCTP_STRRESET_ERR_BAD_SEQNO;
224 goto out;
225 } else if (request_seq == asoc->strreset_inseq) {
226 asoc->strreset_inseq++;
227 }
228
229 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
230 goto out;
231
232 if (asoc->strreset_outstanding) {
233 result = SCTP_STRRESET_ERR_IN_PROGRESS;
234 goto out;
235 }
236
237 /* G3: The same processing as though a SACK chunk with no gap report
238 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
239 * received MUST be performed.
240 */
241 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
242 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
243 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
244
245 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
246 * TSN that the peer should use to send the next DATA chunk. The
247 * value SHOULD be the smallest TSN not acknowledged by the
248 * receiver of the request plus 2^31.
249 */
250 initial_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
251 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
252 initial_tsn, GFP_ATOMIC);
253
254 /* G4: The same processing as though a FWD-TSN chunk (as defined in
255 * [RFC3758]) with all streams affected and a new cumulative TSN
256 * ACK of the Receiver's Next TSN minus 1 were received MUST be
257 * performed.
258 */
259 sctp_outq_free(&asoc->outqueue);
260
261 /* G2: Compute an appropriate value for the local endpoint's next TSN,
262 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
263 * chunk. The value SHOULD be the highest TSN sent by the receiver
264 * of the request plus 1.
265 */
266 asoc->ctsn_ack_point = asoc->next_tsn - 1;
267 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
268
269 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
270 * incoming and outgoing streams.
271 */
272 for (i = 0; i < asoc->streamoutcnt; i++)
273 asoc->streamout[i].ssn = 0;
274 for (i = 0; i < asoc->streamincnt; i++)
275 asoc->streamin[i].ssn = 0;
276
277 result = SCTP_STRRESET_PERFORMED;
278
279 *evp = sctp_ulpevent_make_assoc_reset_event(asoc,
280 0, initial_tsn, asoc->next_tsn, GFP_ATOMIC);
281
282 out:
> 283 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
284 asoc->next_tsn, initial_tsn);
285 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
This warning is actually safe, as only when nums is NULL, str_p is
uninitialized, and in sctp_ulpevent_make_stream_reset_event(), if nums
is null, str_p wouldn't be really used.
vim +/str_p +140 net/sctp/stream.c
124 if (str_p[i] >= asoc->streamincnt) {
125 result = SCTP_STRRESET_ERR_WRONG_SSN;
126 goto out;
127 }
128 }
129
130 str_p = outreq->list_of_streams;
131 for (i = 0; i < nums; i++, str_p++)
132 asoc->streamin[*str_p].ssn = 0;
133 } else {
134 for (i = 0; i < asoc->streamincnt; i++)
135 asoc->streamin[i].ssn = 0;
136 }
137
138 result = SCTP_STRRESET_PERFORMED;
139
> 140 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
141 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
142 GFP_ATOMIC);
143
144 out:
145 return sctp_make_strreset_resp(asoc, result, request_seq);
146 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
From: Xin Long <lucien.xin@gmail.com> Date: 2017-01-01 13:26:49
On Sun, Jan 1, 2017 at 8:14 PM, kbuild test robot [off-list ref] wrote:
Hi Xin,
[auto build test WARNING on net-next/master]
url: https://github.com/0day-ci/linux/commits/Xin-Long/sctp-implement-rfc6525-sctp-stream-reconf/20170101-192844
config: x86_64-randconfig-x015-201701 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings
All warnings (new ones prefixed by >>):
net/sctp/stream.c: In function 'sctp_process_strreset_outreq':
net/sctp/stream.c:140:9: warning: 'str_p' may be used uninitialized in this function [-Wmaybe-uninitialized]
*evp = sctp_ulpevent_make_stream_reset_event(asoc,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GFP_ATOMIC);
~~~~~~~~~~~
net/sctp/stream.c: In function 'sctp_process_strreset_tsnreq':
quoted
quoted
net/sctp/stream.c:283:9: warning: 'initial_tsn' may be used uninitialized in this function [-Wmaybe-uninitialized]
As only when the result is not performed, initial_tsn variables is
uninitialized, peer side would ignore this value, so here is also
safe.
vim +/initial_tsn +283 net/sctp/stream.c
134 for (i = 0; i < asoc->streamincnt; i++)
135 asoc->streamin[i].ssn = 0;
136 }
137
138 result = SCTP_STRRESET_PERFORMED;
139
> 140 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
141 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
142 GFP_ATOMIC);
143
144 out:
145 return sctp_make_strreset_resp(asoc, result, request_seq);
146 }
147
148 struct sctp_chunk *sctp_process_strreset_inreq(
149 struct sctp_association *asoc,
150 union sctp_params param,
151 struct sctp_ulpevent **evp)
152 {
153 struct sctp_strreset_inreq *inreq = param.v;
154 __u32 result = SCTP_STRRESET_DENIED;
155 struct sctp_chunk *chunk = NULL;
156 __u16 i, nums, *str_p;
157 __u32 request_seq;
158
159 request_seq = ntohl(inreq->request_seq);
160 if (request_seq > asoc->strreset_inseq) {
161 result = SCTP_STRRESET_ERR_BAD_SEQNO;
162 goto out;
163 } else if (request_seq == asoc->strreset_inseq) {
164 asoc->strreset_inseq++;
165 }
166
167 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
168 goto out;
169
170 if (asoc->strreset_outstanding) {
171 result = SCTP_STRRESET_ERR_IN_PROGRESS;
172 goto out;
173 }
174
175 nums = (ntohs(param.p->length) - sizeof(*inreq)) / 2;
176 str_p = inreq->list_of_streams;
177 for (i = 0; i < nums; i++) {
178 str_p[i] = ntohs(str_p[i]);
179 if (str_p[i] >= asoc->streamoutcnt) {
180 result = SCTP_STRRESET_ERR_WRONG_SSN;
181 goto out;
182 }
183 }
184
185 chunk = sctp_make_strreset_req(asoc, nums, str_p, 1, 0);
186 if (!chunk)
187 goto out;
188
189 if (nums)
190 for (i = 0; i < nums; i++)
191 asoc->streamout[str_p[i]].state =
192 SCTP_STREAM_CLOSED;
193 else
194 for (i = 0; i < asoc->streamoutcnt; i++)
195 asoc->streamout[i].state = SCTP_STREAM_CLOSED;
196
197 asoc->strreset_chunk = chunk;
198 asoc->strreset_outstanding = 1;
199 sctp_chunk_hold(asoc->strreset_chunk);
200
201 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
202 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
203
204 out:
205 if (!chunk)
206 chunk = sctp_make_strreset_resp(asoc, result, request_seq);
207
208 return chunk;
209 }
210
211 struct sctp_chunk *sctp_process_strreset_tsnreq(
212 struct sctp_association *asoc,
213 union sctp_params param,
214 struct sctp_ulpevent **evp)
215 {
216 struct sctp_strreset_tsnreq *tsnreq = param.v;
217 __u32 request_seq, initial_tsn, max_tsn_seen;
218 __u32 result = SCTP_STRRESET_DENIED;
219 __u16 i;
220
221 request_seq = ntohl(tsnreq->request_seq);
222 if (request_seq > asoc->strreset_inseq) {
223 result = SCTP_STRRESET_ERR_BAD_SEQNO;
224 goto out;
225 } else if (request_seq == asoc->strreset_inseq) {
226 asoc->strreset_inseq++;
227 }
228
229 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
230 goto out;
231
232 if (asoc->strreset_outstanding) {
233 result = SCTP_STRRESET_ERR_IN_PROGRESS;
234 goto out;
235 }
236
237 /* G3: The same processing as though a SACK chunk with no gap report
238 * and a cumulative TSN ACK of the Sender's Next TSN minus 1 were
239 * received MUST be performed.
240 */
241 max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
242 sctp_ulpq_reasm_flushtsn(&asoc->ulpq, max_tsn_seen);
243 sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
244
245 /* G1: Compute an appropriate value for the Receiver's Next TSN -- the
246 * TSN that the peer should use to send the next DATA chunk. The
247 * value SHOULD be the smallest TSN not acknowledged by the
248 * receiver of the request plus 2^31.
249 */
250 initial_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1 << 31);
251 sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
252 initial_tsn, GFP_ATOMIC);
253
254 /* G4: The same processing as though a FWD-TSN chunk (as defined in
255 * [RFC3758]) with all streams affected and a new cumulative TSN
256 * ACK of the Receiver's Next TSN minus 1 were received MUST be
257 * performed.
258 */
259 sctp_outq_free(&asoc->outqueue);
260
261 /* G2: Compute an appropriate value for the local endpoint's next TSN,
262 * i.e., the next TSN assigned by the receiver of the SSN/TSN reset
263 * chunk. The value SHOULD be the highest TSN sent by the receiver
264 * of the request plus 1.
265 */
266 asoc->ctsn_ack_point = asoc->next_tsn - 1;
267 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
268
269 /* G5: The next expected and outgoing SSNs MUST be reset to 0 for all
270 * incoming and outgoing streams.
271 */
272 for (i = 0; i < asoc->streamoutcnt; i++)
273 asoc->streamout[i].ssn = 0;
274 for (i = 0; i < asoc->streamincnt; i++)
275 asoc->streamin[i].ssn = 0;
276
277 result = SCTP_STRRESET_PERFORMED;
278
279 *evp = sctp_ulpevent_make_assoc_reset_event(asoc,
280 0, initial_tsn, asoc->next_tsn, GFP_ATOMIC);
281
282 out:
> 283 return sctp_make_strreset_tsnresp(asoc, result, request_seq,
284 asoc->next_tsn, initial_tsn);
285 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation