Commit 81663bee authored by David S. Miller's avatar David S. Miller

Merge branch 'sctp-rx-side-stream-reconf-asoc-reset-and-add-streams-and-response'

Xin Long says:

====================
sctp: add receiver-side procedures for stream reconf asoc reset and add streams and response

Patch 2/7, 4/7, 5/7, 6/7 are to implement the process of asoc reset request,
add streams requests and all kinds of responses.

Patch 1/7 and 3/7 are ahead of 2/7 and 4/7 to add two event notification
for asoc reset and add streams.

Patch 7/7 is the last patch for implementing rfc6525 sctp stream reconf
to add sysctl and sockopt interface for users to enable sctp stream reconf.

After this patchset, sctp stream reconf will be able to work as rfc6525.

v1->v2:
  - put these into a smaller group.
  - rename the titles of the commits and improve some changelogs.
  - improve sctp_chunk_lookup_strreset_param and reuse it in patch 4/7.
  - process addstrm outreq as the ack of in addstrm inreq if strreset_chunk
    is not NULL in patch 4/7.
  - remove the stream alloc when sending addstrm inreq, and the process in
    peer will response it by sending a addstrm out request back in patch 5/7.
  - adjust the process of addstrm in resp to fit in the codes that only alloc
    streams through addstrm outreq in patch 6/7.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b3ca9af0 c0d8bab6
...@@ -293,6 +293,22 @@ struct sctp_chunk *sctp_process_strreset_inreq( ...@@ -293,6 +293,22 @@ struct sctp_chunk *sctp_process_strreset_inreq(
struct sctp_association *asoc, struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
struct sctp_ulpevent **evp); struct sctp_ulpevent **evp);
struct sctp_chunk *sctp_process_strreset_tsnreq(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp);
struct sctp_chunk *sctp_process_strreset_addstrm_out(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp);
struct sctp_chunk *sctp_process_strreset_addstrm_in(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp);
struct sctp_chunk *sctp_process_strreset_resp(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp);
/* Prototypes for statetable processing. */ /* Prototypes for statetable processing. */
......
...@@ -132,6 +132,14 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( ...@@ -132,6 +132,14 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(
const struct sctp_association *asoc, __u16 flags, const struct sctp_association *asoc, __u16 flags,
__u16 stream_num, __u16 *stream_list, gfp_t gfp); __u16 stream_num, __u16 *stream_list, gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(
const struct sctp_association *asoc, __u16 flags,
__u32 local_tsn, __u32 remote_tsn, gfp_t gfp);
struct sctp_ulpevent *sctp_ulpevent_make_stream_change_event(
const struct sctp_association *asoc, __u16 flags,
__u32 strchange_instrms, __u32 strchange_outstrms, gfp_t gfp);
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
struct msghdr *); struct msghdr *);
void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event,
......
...@@ -115,6 +115,7 @@ typedef __s32 sctp_assoc_t; ...@@ -115,6 +115,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_PR_SUPPORTED 113 #define SCTP_PR_SUPPORTED 113
#define SCTP_DEFAULT_PRINFO 114 #define SCTP_DEFAULT_PRINFO 114
#define SCTP_PR_ASSOC_STATUS 115 #define SCTP_PR_ASSOC_STATUS 115
#define SCTP_RECONFIG_SUPPORTED 117
#define SCTP_ENABLE_STREAM_RESET 118 #define SCTP_ENABLE_STREAM_RESET 118
#define SCTP_RESET_STREAMS 119 #define SCTP_RESET_STREAMS 119
#define SCTP_RESET_ASSOC 120 #define SCTP_RESET_ASSOC 120
...@@ -502,6 +503,28 @@ struct sctp_stream_reset_event { ...@@ -502,6 +503,28 @@ struct sctp_stream_reset_event {
__u16 strreset_stream_list[]; __u16 strreset_stream_list[];
}; };
#define SCTP_ASSOC_RESET_DENIED 0x0004
#define SCTP_ASSOC_RESET_FAILED 0x0008
struct sctp_assoc_reset_event {
__u16 assocreset_type;
__u16 assocreset_flags;
__u32 assocreset_length;
sctp_assoc_t assocreset_assoc_id;
__u32 assocreset_local_tsn;
__u32 assocreset_remote_tsn;
};
#define SCTP_ASSOC_CHANGE_DENIED 0x0004
#define SCTP_ASSOC_CHANGE_FAILED 0x0008
struct sctp_stream_change_event {
__u16 strchange_type;
__u16 strchange_flags;
__u32 strchange_length;
sctp_assoc_t strchange_assoc_id;
__u16 strchange_instrms;
__u16 strchange_outstrms;
};
/* /*
* Described in Section 7.3 * Described in Section 7.3
* Ancillary Data and Notification Interest Options * Ancillary Data and Notification Interest Options
...@@ -518,6 +541,8 @@ struct sctp_event_subscribe { ...@@ -518,6 +541,8 @@ struct sctp_event_subscribe {
__u8 sctp_authentication_event; __u8 sctp_authentication_event;
__u8 sctp_sender_dry_event; __u8 sctp_sender_dry_event;
__u8 sctp_stream_reset_event; __u8 sctp_stream_reset_event;
__u8 sctp_assoc_reset_event;
__u8 sctp_stream_change_event;
}; };
/* /*
...@@ -543,6 +568,8 @@ union sctp_notification { ...@@ -543,6 +568,8 @@ union sctp_notification {
struct sctp_authkey_event sn_authkey_event; struct sctp_authkey_event sn_authkey_event;
struct sctp_sender_dry_event sn_sender_dry_event; struct sctp_sender_dry_event sn_sender_dry_event;
struct sctp_stream_reset_event sn_strreset_event; struct sctp_stream_reset_event sn_strreset_event;
struct sctp_assoc_reset_event sn_assocreset_event;
struct sctp_stream_change_event sn_strchange_event;
}; };
/* Section 5.3.1 /* Section 5.3.1
...@@ -572,6 +599,10 @@ enum sctp_sn_type { ...@@ -572,6 +599,10 @@ enum sctp_sn_type {
#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT #define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT
SCTP_STREAM_RESET_EVENT, SCTP_STREAM_RESET_EVENT,
#define SCTP_STREAM_RESET_EVENT SCTP_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
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 /* Notification error codes used to fill up the error fields in some
......
...@@ -3872,9 +3872,18 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net, ...@@ -3872,9 +3872,18 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net,
else if (param.p->type == SCTP_PARAM_RESET_IN_REQUEST) else if (param.p->type == SCTP_PARAM_RESET_IN_REQUEST)
reply = sctp_process_strreset_inreq( reply = sctp_process_strreset_inreq(
(struct sctp_association *)asoc, param, &ev); (struct sctp_association *)asoc, param, &ev);
/* More handles for other types will be added here, by now it else if (param.p->type == SCTP_PARAM_RESET_TSN_REQUEST)
* just ignores other types. reply = sctp_process_strreset_tsnreq(
*/ (struct sctp_association *)asoc, param, &ev);
else if (param.p->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS)
reply = sctp_process_strreset_addstrm_out(
(struct sctp_association *)asoc, param, &ev);
else if (param.p->type == SCTP_PARAM_RESET_ADD_IN_STREAMS)
reply = sctp_process_strreset_addstrm_in(
(struct sctp_association *)asoc, param, &ev);
else if (param.p->type == SCTP_PARAM_RESET_RESPONSE)
reply = sctp_process_strreset_resp(
(struct sctp_association *)asoc, param, &ev);
if (ev) if (ev)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
......
...@@ -3758,6 +3758,39 @@ static int sctp_setsockopt_default_prinfo(struct sock *sk, ...@@ -3758,6 +3758,39 @@ static int sctp_setsockopt_default_prinfo(struct sock *sk,
return retval; return retval;
} }
static int sctp_setsockopt_reconfig_supported(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(&params, optval, optlen)) {
retval = -EFAULT;
goto out;
}
asoc = sctp_id2assoc(sk, params.assoc_id);
if (asoc) {
asoc->reconf_enable = !!params.assoc_value;
} else if (!params.assoc_id) {
struct sctp_sock *sp = sctp_sk(sk);
sp->ep->reconf_enable = !!params.assoc_value;
} else {
goto out;
}
retval = 0;
out:
return retval;
}
static int sctp_setsockopt_enable_strreset(struct sock *sk, static int sctp_setsockopt_enable_strreset(struct sock *sk,
char __user *optval, char __user *optval,
unsigned int optlen) unsigned int optlen)
...@@ -4038,6 +4071,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -4038,6 +4071,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_DEFAULT_PRINFO: case SCTP_DEFAULT_PRINFO:
retval = sctp_setsockopt_default_prinfo(sk, optval, optlen); retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);
break; break;
case SCTP_RECONFIG_SUPPORTED:
retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen);
break;
case SCTP_ENABLE_STREAM_RESET: case SCTP_ENABLE_STREAM_RESET:
retval = sctp_setsockopt_enable_strreset(sk, optval, optlen); retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);
break; break;
...@@ -6540,6 +6576,47 @@ static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len, ...@@ -6540,6 +6576,47 @@ static int sctp_getsockopt_pr_assocstatus(struct sock *sk, int len,
return retval; return retval;
} }
static int sctp_getsockopt_reconfig_supported(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(&params, optval, len))
goto out;
asoc = sctp_id2assoc(sk, params.assoc_id);
if (asoc) {
params.assoc_value = asoc->reconf_enable;
} else if (!params.assoc_id) {
struct sctp_sock *sp = sctp_sk(sk);
params.assoc_value = sp->ep->reconf_enable;
} else {
retval = -EINVAL;
goto out;
}
if (put_user(len, optlen))
goto out;
if (copy_to_user(optval, &params, len))
goto out;
retval = 0;
out:
return retval;
}
static int sctp_getsockopt_enable_strreset(struct sock *sk, int len, static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,
char __user *optval, char __user *optval,
int __user *optlen) int __user *optlen)
...@@ -6748,6 +6825,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -6748,6 +6825,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_pr_assocstatus(sk, len, optval, retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,
optlen); optlen);
break; break;
case SCTP_RECONFIG_SUPPORTED:
retval = sctp_getsockopt_reconfig_supported(sk, len, optval,
optlen);
break;
case SCTP_ENABLE_STREAM_RESET: case SCTP_ENABLE_STREAM_RESET:
retval = sctp_getsockopt_enable_strreset(sk, len, optval, retval = sctp_getsockopt_enable_strreset(sk, len, optval,
optlen); optlen);
......
This diff is collapsed.
...@@ -274,6 +274,13 @@ static struct ctl_table sctp_net_table[] = { ...@@ -274,6 +274,13 @@ static struct ctl_table sctp_net_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = proc_dointvec,
}, },
{
.procname = "reconf_enable",
.data = &init_net.sctp.reconf_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{ {
.procname = "auth_enable", .procname = "auth_enable",
.data = &init_net.sctp.auth_enable, .data = &init_net.sctp.auth_enable,
......
...@@ -883,6 +883,62 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event( ...@@ -883,6 +883,62 @@ struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(
return event; return event;
} }
struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(
const struct sctp_association *asoc, __u16 flags, __u32 local_tsn,
__u32 remote_tsn, gfp_t gfp)
{
struct sctp_assoc_reset_event *areset;
struct sctp_ulpevent *event;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_reset_event),
MSG_NOTIFICATION, gfp);
if (!event)
return NULL;
skb = sctp_event2skb(event);
areset = (struct sctp_assoc_reset_event *)
skb_put(skb, sizeof(struct sctp_assoc_reset_event));
areset->assocreset_type = SCTP_ASSOC_RESET_EVENT;
areset->assocreset_flags = flags;
areset->assocreset_length = sizeof(struct sctp_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;
return event;
}
struct sctp_ulpevent *sctp_ulpevent_make_stream_change_event(
const struct sctp_association *asoc, __u16 flags,
__u32 strchange_instrms, __u32 strchange_outstrms, gfp_t gfp)
{
struct sctp_stream_change_event *schange;
struct sctp_ulpevent *event;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_stream_change_event),
MSG_NOTIFICATION, gfp);
if (!event)
return NULL;
skb = sctp_event2skb(event);
schange = (struct sctp_stream_change_event *)
skb_put(skb, sizeof(struct sctp_stream_change_event));
schange->strchange_type = SCTP_STREAM_CHANGE_EVENT;
schange->strchange_flags = flags;
schange->strchange_length = sizeof(struct sctp_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;
return event;
}
/* Return the notification type, assuming this is a notification /* Return the notification type, assuming this is a notification
* event. * event.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment