Skip to content

Commit 2cbf5b4

Browse files
committed
Merge branch 'sctp-sender-stream-reconf-reset-add-streams'
Xin Long says: ==================== sctp: add sender-side procedures for stream reconf asoc reset and add streams Patch 4/6 is to implement sender-side procedures for the SSN/TSN Reset Request Parameter described in rfc6525 section 5.1.4, patch 3/6 is ahead of it to define a function to make the request chunk for it. Patch 6/6 is to implement sender-side procedures for the Add Incoming and Outgoing Streams Request Parameter Request Parameter described in rfc6525 section 5.1.5 and 5.1.6, patch 5/6 is ahead of it to define a function to make the request chunk for it. Patch 2/6 is a fix to recover streams states when it fails to send request and Patch 1/6 is to drop some unncessary __packed from some old structures. 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. - move some codes into stream.c from socket.c. v3->v4: - add one more patch to fix a send reset stream request issue. - doing actual work only when request is sent successfully. - reduce some indents in sctp_send_add_streams. v4->v5: - close streams before sending request and recover them when sending fails in patch 1/5 and patch 3/5 v5->v6: - add patch 1/6 to drop some unncessary __packed from some old structures. - remove __packed from some new structures in patch 3/6 and 5/6. - define unsigned int outcnt and incnt to make codes smaller in patch 6/6. - use krealloc instead of kcalloc and remove ksize check in patch 6/6, as ksize check is acutally used in krealloc already. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents caa2858 + 242bd2d commit 2cbf5b4

File tree

7 files changed

+297
-4
lines changed

7 files changed

+297
-4
lines changed

include/linux/sctp.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -721,20 +721,32 @@ struct sctp_infox {
721721
struct sctp_reconf_chunk {
722722
sctp_chunkhdr_t chunk_hdr;
723723
__u8 params[0];
724-
} __packed;
724+
};
725725

726726
struct sctp_strreset_outreq {
727727
sctp_paramhdr_t param_hdr;
728728
__u32 request_seq;
729729
__u32 response_seq;
730730
__u32 send_reset_at_tsn;
731731
__u16 list_of_streams[0];
732-
} __packed;
732+
};
733733

734734
struct sctp_strreset_inreq {
735735
sctp_paramhdr_t param_hdr;
736736
__u32 request_seq;
737737
__u16 list_of_streams[0];
738-
} __packed;
738+
};
739+
740+
struct sctp_strreset_tsnreq {
741+
sctp_paramhdr_t param_hdr;
742+
__u32 request_seq;
743+
};
744+
745+
struct sctp_strreset_addstrm {
746+
sctp_paramhdr_t param_hdr;
747+
__u32 request_seq;
748+
__u16 number_of_streams;
749+
__u16 reserved;
750+
};
739751

740752
#endif /* __LINUX_SCTP_H__ */

include/net/sctp/sctp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ int sctp_offload_init(void);
198198
*/
199199
int sctp_send_reset_streams(struct sctp_association *asoc,
200200
struct sctp_reset_streams *params);
201+
int sctp_send_reset_assoc(struct sctp_association *asoc);
202+
int sctp_send_add_streams(struct sctp_association *asoc,
203+
struct sctp_add_streams *params);
201204

202205
/*
203206
* Module global variables

include/net/sctp/sm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ struct sctp_chunk *sctp_make_strreset_req(
265265
const struct sctp_association *asoc,
266266
__u16 stream_num, __u16 *stream_list,
267267
bool out, bool in);
268+
struct sctp_chunk *sctp_make_strreset_tsnreq(
269+
const struct sctp_association *asoc);
270+
struct sctp_chunk *sctp_make_strreset_addstrm(
271+
const struct sctp_association *asoc,
272+
__u16 out, __u16 in);
268273
void sctp_chunk_assign_tsn(struct sctp_chunk *);
269274
void sctp_chunk_assign_ssn(struct sctp_chunk *);
270275

include/uapi/linux/sctp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ typedef __s32 sctp_assoc_t;
117117
#define SCTP_PR_ASSOC_STATUS 115
118118
#define SCTP_ENABLE_STREAM_RESET 118
119119
#define SCTP_RESET_STREAMS 119
120+
#define SCTP_RESET_ASSOC 120
121+
#define SCTP_ADD_STREAMS 121
120122

121123
/* PR-SCTP policies */
122124
#define SCTP_PR_SCTP_NONE 0x0000
@@ -1026,4 +1028,10 @@ struct sctp_reset_streams {
10261028
uint16_t srs_stream_list[]; /* list if srs_num_streams is not 0 */
10271029
};
10281030

1031+
struct sctp_add_streams {
1032+
sctp_assoc_t sas_assoc_id;
1033+
uint16_t sas_instrms;
1034+
uint16_t sas_outstrms;
1035+
};
1036+
10291037
#endif /* _UAPI_SCTP_H */

net/sctp/sm_make_chunk.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,3 +3658,78 @@ struct sctp_chunk *sctp_make_strreset_req(
36583658

36593659
return retval;
36603660
}
3661+
3662+
/* RE-CONFIG 4.3 (SSN/TSN RESET ALL)
3663+
* 0 1 2 3
3664+
* 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
3665+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3666+
* | Parameter Type = 15 | Parameter Length = 8 |
3667+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3668+
* | Re-configuration Request Sequence Number |
3669+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3670+
*/
3671+
struct sctp_chunk *sctp_make_strreset_tsnreq(
3672+
const struct sctp_association *asoc)
3673+
{
3674+
struct sctp_strreset_tsnreq tsnreq;
3675+
__u16 length = sizeof(tsnreq);
3676+
struct sctp_chunk *retval;
3677+
3678+
retval = sctp_make_reconf(asoc, length);
3679+
if (!retval)
3680+
return NULL;
3681+
3682+
tsnreq.param_hdr.type = SCTP_PARAM_RESET_TSN_REQUEST;
3683+
tsnreq.param_hdr.length = htons(length);
3684+
tsnreq.request_seq = htonl(asoc->strreset_outseq);
3685+
3686+
sctp_addto_chunk(retval, sizeof(tsnreq), &tsnreq);
3687+
3688+
return retval;
3689+
}
3690+
3691+
/* RE-CONFIG 4.5/4.6 (ADD STREAM)
3692+
* 0 1 2 3
3693+
* 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
3694+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3695+
* | Parameter Type = 17 | Parameter Length = 12 |
3696+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3697+
* | Re-configuration Request Sequence Number |
3698+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3699+
* | Number of new streams | Reserved |
3700+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3701+
*/
3702+
struct sctp_chunk *sctp_make_strreset_addstrm(
3703+
const struct sctp_association *asoc,
3704+
__u16 out, __u16 in)
3705+
{
3706+
struct sctp_strreset_addstrm addstrm;
3707+
__u16 size = sizeof(addstrm);
3708+
struct sctp_chunk *retval;
3709+
3710+
retval = sctp_make_reconf(asoc, (!!out + !!in) * size);
3711+
if (!retval)
3712+
return NULL;
3713+
3714+
if (out) {
3715+
addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_OUT_STREAMS;
3716+
addstrm.param_hdr.length = htons(size);
3717+
addstrm.number_of_streams = htons(out);
3718+
addstrm.request_seq = htonl(asoc->strreset_outseq);
3719+
addstrm.reserved = 0;
3720+
3721+
sctp_addto_chunk(retval, size, &addstrm);
3722+
}
3723+
3724+
if (in) {
3725+
addstrm.param_hdr.type = SCTP_PARAM_RESET_ADD_IN_STREAMS;
3726+
addstrm.param_hdr.length = htons(size);
3727+
addstrm.number_of_streams = htons(in);
3728+
addstrm.request_seq = htonl(asoc->strreset_outseq + !!out);
3729+
addstrm.reserved = 0;
3730+
3731+
sctp_addto_chunk(retval, size, &addstrm);
3732+
}
3733+
3734+
return retval;
3735+
}

net/sctp/socket.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,58 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
38183818
return retval;
38193819
}
38203820

3821+
static int sctp_setsockopt_reset_assoc(struct sock *sk,
3822+
char __user *optval,
3823+
unsigned int optlen)
3824+
{
3825+
struct sctp_association *asoc;
3826+
sctp_assoc_t associd;
3827+
int retval = -EINVAL;
3828+
3829+
if (optlen != sizeof(associd))
3830+
goto out;
3831+
3832+
if (copy_from_user(&associd, optval, optlen)) {
3833+
retval = -EFAULT;
3834+
goto out;
3835+
}
3836+
3837+
asoc = sctp_id2assoc(sk, associd);
3838+
if (!asoc)
3839+
goto out;
3840+
3841+
retval = sctp_send_reset_assoc(asoc);
3842+
3843+
out:
3844+
return retval;
3845+
}
3846+
3847+
static int sctp_setsockopt_add_streams(struct sock *sk,
3848+
char __user *optval,
3849+
unsigned int optlen)
3850+
{
3851+
struct sctp_association *asoc;
3852+
struct sctp_add_streams params;
3853+
int retval = -EINVAL;
3854+
3855+
if (optlen != sizeof(params))
3856+
goto out;
3857+
3858+
if (copy_from_user(&params, optval, optlen)) {
3859+
retval = -EFAULT;
3860+
goto out;
3861+
}
3862+
3863+
asoc = sctp_id2assoc(sk, params.sas_assoc_id);
3864+
if (!asoc)
3865+
goto out;
3866+
3867+
retval = sctp_send_add_streams(asoc, &params);
3868+
3869+
out:
3870+
return retval;
3871+
}
3872+
38213873
/* API 6.2 setsockopt(), getsockopt()
38223874
*
38233875
* Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3990,6 +4042,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
39904042
case SCTP_RESET_STREAMS:
39914043
retval = sctp_setsockopt_reset_streams(sk, optval, optlen);
39924044
break;
4045+
case SCTP_RESET_ASSOC:
4046+
retval = sctp_setsockopt_reset_assoc(sk, optval, optlen);
4047+
break;
4048+
case SCTP_ADD_STREAMS:
4049+
retval = sctp_setsockopt_add_streams(sk, optval, optlen);
4050+
break;
39934051
default:
39944052
retval = -ENOPROTOOPT;
39954053
break;

net/sctp/stream.c

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,10 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
136136
goto out;
137137

138138
chunk = sctp_make_strreset_req(asoc, str_nums, str_list, out, in);
139-
if (!chunk)
139+
if (!chunk) {
140+
retval = -ENOMEM;
140141
goto out;
142+
}
141143

142144
if (out) {
143145
if (str_nums)
@@ -149,16 +151,146 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
149151
stream->out[i].state = SCTP_STREAM_CLOSED;
150152
}
151153

154+
asoc->strreset_chunk = chunk;
155+
sctp_chunk_hold(asoc->strreset_chunk);
156+
157+
retval = sctp_send_reconf(asoc, chunk);
158+
if (retval) {
159+
sctp_chunk_put(asoc->strreset_chunk);
160+
asoc->strreset_chunk = NULL;
161+
if (!out)
162+
goto out;
163+
164+
if (str_nums)
165+
for (i = 0; i < str_nums; i++)
166+
stream->out[str_list[i]].state =
167+
SCTP_STREAM_OPEN;
168+
else
169+
for (i = 0; i < stream->outcnt; i++)
170+
stream->out[i].state = SCTP_STREAM_OPEN;
171+
172+
goto out;
173+
}
174+
152175
asoc->strreset_outstanding = out + in;
176+
177+
out:
178+
return retval;
179+
}
180+
181+
int sctp_send_reset_assoc(struct sctp_association *asoc)
182+
{
183+
struct sctp_chunk *chunk = NULL;
184+
int retval;
185+
__u16 i;
186+
187+
if (!asoc->peer.reconf_capable ||
188+
!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ))
189+
return -ENOPROTOOPT;
190+
191+
if (asoc->strreset_outstanding)
192+
return -EINPROGRESS;
193+
194+
chunk = sctp_make_strreset_tsnreq(asoc);
195+
if (!chunk)
196+
return -ENOMEM;
197+
198+
/* Block further xmit of data until this request is completed */
199+
for (i = 0; i < asoc->stream->outcnt; i++)
200+
asoc->stream->out[i].state = SCTP_STREAM_CLOSED;
201+
153202
asoc->strreset_chunk = chunk;
154203
sctp_chunk_hold(asoc->strreset_chunk);
155204

156205
retval = sctp_send_reconf(asoc, chunk);
157206
if (retval) {
158207
sctp_chunk_put(asoc->strreset_chunk);
159208
asoc->strreset_chunk = NULL;
209+
210+
for (i = 0; i < asoc->stream->outcnt; i++)
211+
asoc->stream->out[i].state = SCTP_STREAM_OPEN;
212+
213+
return retval;
160214
}
161215

216+
asoc->strreset_outstanding = 1;
217+
218+
return 0;
219+
}
220+
221+
int sctp_send_add_streams(struct sctp_association *asoc,
222+
struct sctp_add_streams *params)
223+
{
224+
struct sctp_stream *stream = asoc->stream;
225+
struct sctp_chunk *chunk = NULL;
226+
int retval = -ENOMEM;
227+
__u32 outcnt, incnt;
228+
__u16 out, in;
229+
230+
if (!asoc->peer.reconf_capable ||
231+
!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) {
232+
retval = -ENOPROTOOPT;
233+
goto out;
234+
}
235+
236+
if (asoc->strreset_outstanding) {
237+
retval = -EINPROGRESS;
238+
goto out;
239+
}
240+
241+
out = params->sas_outstrms;
242+
in = params->sas_instrms;
243+
outcnt = stream->outcnt + out;
244+
incnt = stream->incnt + in;
245+
if (outcnt > SCTP_MAX_STREAM || incnt > SCTP_MAX_STREAM ||
246+
(!out && !in)) {
247+
retval = -EINVAL;
248+
goto out;
249+
}
250+
251+
if (out) {
252+
struct sctp_stream_out *streamout;
253+
254+
streamout = krealloc(stream->out, outcnt * sizeof(*streamout),
255+
GFP_KERNEL);
256+
if (!streamout)
257+
goto out;
258+
259+
memset(streamout + stream->outcnt, 0, out * sizeof(*streamout));
260+
stream->out = streamout;
261+
}
262+
263+
if (in) {
264+
struct sctp_stream_in *streamin;
265+
266+
streamin = krealloc(stream->in, incnt * sizeof(*streamin),
267+
GFP_KERNEL);
268+
if (!streamin)
269+
goto out;
270+
271+
memset(streamin + stream->incnt, 0, in * sizeof(*streamin));
272+
stream->in = streamin;
273+
}
274+
275+
chunk = sctp_make_strreset_addstrm(asoc, out, in);
276+
if (!chunk)
277+
goto out;
278+
279+
asoc->strreset_chunk = chunk;
280+
sctp_chunk_hold(asoc->strreset_chunk);
281+
282+
retval = sctp_send_reconf(asoc, chunk);
283+
if (retval) {
284+
sctp_chunk_put(asoc->strreset_chunk);
285+
asoc->strreset_chunk = NULL;
286+
goto out;
287+
}
288+
289+
stream->incnt = incnt;
290+
stream->outcnt = outcnt;
291+
292+
asoc->strreset_outstanding = !!out + !!in;
293+
162294
out:
163295
return retval;
164296
}

0 commit comments

Comments
 (0)