Commit ed410ecf authored by David S. Miller's avatar David S. Miller

Merge branch 'sctp-next'

Daniel Borkmann says:

====================
SCTP updates

This set improves the SCTP socket API to be more in line with RFC6458,
Geir and myself have finalized it eventually. While at it, the first
patch also fixes two possible information leaks that should go to net
tree as well (therefore the change is already here in net-next via a
merge of the 'net' tree -DaveM). For more details, I refer you to the
patches themselves.

Thanks a lot.

v1 -> v2:
 - Added 6th patch to deprecate SCTP_SNDRCV, rest unchanged
====================

CC: Jay Vosburgh <j.vosburgh@gmail.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: default avatarVeaceslav Falico <vfalico@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a98c69a bbbea41d
...@@ -109,6 +109,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, ...@@ -109,6 +109,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
struct sctp_association *asoc); struct sctp_association *asoc);
extern struct percpu_counter sctp_sockets_allocated; extern struct percpu_counter sctp_sockets_allocated;
int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *); int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
/* /*
* sctp/primitive.c * sctp/primitive.c
......
...@@ -207,7 +207,9 @@ struct sctp_sock { ...@@ -207,7 +207,9 @@ struct sctp_sock {
struct sctp_paddrparams paddrparam; struct sctp_paddrparams paddrparam;
struct sctp_event_subscribe subscribe; struct sctp_event_subscribe subscribe;
struct sctp_assocparams assocparams; struct sctp_assocparams assocparams;
int user_frag; int user_frag;
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
__u8 disable_fragments; __u8 disable_fragments;
...@@ -215,6 +217,8 @@ struct sctp_sock { ...@@ -215,6 +217,8 @@ struct sctp_sock {
__u8 frag_interleave; __u8 frag_interleave;
__u32 adaptation_ind; __u32 adaptation_ind;
__u32 pd_point; __u32 pd_point;
__u8 recvrcvinfo;
__u8 recvnxtinfo;
atomic_t pd_mode; atomic_t pd_mode;
/* Receive to here while partial delivery is in effect. */ /* Receive to here while partial delivery is in effect. */
...@@ -1919,7 +1923,8 @@ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); ...@@ -1919,7 +1923,8 @@ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
/* A convenience structure to parse out SCTP specific CMSGs. */ /* A convenience structure to parse out SCTP specific CMSGs. */
typedef struct sctp_cmsgs { typedef struct sctp_cmsgs {
struct sctp_initmsg *init; struct sctp_initmsg *init;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *srinfo;
struct sctp_sndinfo *sinfo;
} sctp_cmsgs_t; } sctp_cmsgs_t;
/* Structure for tracking memory objects */ /* Structure for tracking memory objects */
......
...@@ -130,6 +130,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( ...@@ -130,6 +130,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
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,
struct msghdr *);
void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
struct msghdr *, struct sock *sk);
__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event);
/* Is this event type enabled? */ /* Is this event type enabled? */
...@@ -155,10 +160,3 @@ static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event, ...@@ -155,10 +160,3 @@ static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event,
} }
#endif /* __sctp_ulpevent_h__ */ #endif /* __sctp_ulpevent_h__ */
...@@ -95,6 +95,9 @@ typedef __s32 sctp_assoc_t; ...@@ -95,6 +95,9 @@ typedef __s32 sctp_assoc_t;
#define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ #define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */
#define SCTP_AUTO_ASCONF 30 #define SCTP_AUTO_ASCONF 30
#define SCTP_PEER_ADDR_THLDS 31 #define SCTP_PEER_ADDR_THLDS 31
#define SCTP_RECVRCVINFO 32
#define SCTP_RECVNXTINFO 33
#define SCTP_DEFAULT_SNDINFO 34
/* Internal Socket Options. Some of the sctp library functions are /* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options. * implemented using these socket options.
...@@ -110,8 +113,14 @@ typedef __s32 sctp_assoc_t; ...@@ -110,8 +113,14 @@ typedef __s32 sctp_assoc_t;
#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */
#define SCTP_GET_ASSOC_STATS 112 /* Read only */ #define SCTP_GET_ASSOC_STATS 112 /* Read only */
/* /* These are bit fields for msghdr->msg_flags. See section 5.1. */
* 5.2.1 SCTP Initiation Structure (SCTP_INIT) /* On user space Linux, these live in <bits/socket.h> as an enum. */
enum sctp_msg_flags {
MSG_NOTIFICATION = 0x8000,
#define MSG_NOTIFICATION MSG_NOTIFICATION
};
/* 5.3.1 SCTP Initiation Structure (SCTP_INIT)
* *
* This cmsghdr structure provides information for initializing new * This cmsghdr structure provides information for initializing new
* SCTP associations with sendmsg(). The SCTP_INITMSG socket option * SCTP associations with sendmsg(). The SCTP_INITMSG socket option
...@@ -121,7 +130,6 @@ typedef __s32 sctp_assoc_t; ...@@ -121,7 +130,6 @@ typedef __s32 sctp_assoc_t;
* cmsg_level cmsg_type cmsg_data[] * cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ ---------------------- * ------------ ------------ ----------------------
* IPPROTO_SCTP SCTP_INIT struct sctp_initmsg * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg
*
*/ */
struct sctp_initmsg { struct sctp_initmsg {
__u16 sinit_num_ostreams; __u16 sinit_num_ostreams;
...@@ -130,8 +138,7 @@ struct sctp_initmsg { ...@@ -130,8 +138,7 @@ struct sctp_initmsg {
__u16 sinit_max_init_timeo; __u16 sinit_max_init_timeo;
}; };
/* /* 5.3.2 SCTP Header Information Structure (SCTP_SNDRCV)
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
* *
* This cmsghdr structure specifies SCTP options for sendmsg() and * This cmsghdr structure specifies SCTP options for sendmsg() and
* describes SCTP header information about a received message through * describes SCTP header information about a received message through
...@@ -140,7 +147,6 @@ struct sctp_initmsg { ...@@ -140,7 +147,6 @@ struct sctp_initmsg {
* cmsg_level cmsg_type cmsg_data[] * cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ ---------------------- * ------------ ------------ ----------------------
* IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo
*
*/ */
struct sctp_sndrcvinfo { struct sctp_sndrcvinfo {
__u16 sinfo_stream; __u16 sinfo_stream;
...@@ -154,19 +160,74 @@ struct sctp_sndrcvinfo { ...@@ -154,19 +160,74 @@ struct sctp_sndrcvinfo {
sctp_assoc_t sinfo_assoc_id; sctp_assoc_t sinfo_assoc_id;
}; };
/* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO)
*
* This cmsghdr structure specifies SCTP options for sendmsg().
*
* cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ -------------------
* IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo
*/
struct sctp_sndinfo {
__u16 snd_sid;
__u16 snd_flags;
__u32 snd_ppid;
__u32 snd_context;
sctp_assoc_t snd_assoc_id;
};
/* 5.3.5 SCTP Receive Information Structure (SCTP_RCVINFO)
*
* This cmsghdr structure describes SCTP receive information
* about a received message through recvmsg().
*
* cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ -------------------
* IPPROTO_SCTP SCTP_RCVINFO struct sctp_rcvinfo
*/
struct sctp_rcvinfo {
__u16 rcv_sid;
__u16 rcv_ssn;
__u16 rcv_flags;
__u32 rcv_ppid;
__u32 rcv_tsn;
__u32 rcv_cumtsn;
__u32 rcv_context;
sctp_assoc_t rcv_assoc_id;
};
/* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO)
*
* This cmsghdr structure describes SCTP receive information
* of the next message that will be delivered through recvmsg()
* if this information is already available when delivering
* the current message.
*
* cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ -------------------
* IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo
*/
struct sctp_nxtinfo {
__u16 nxt_sid;
__u16 nxt_flags;
__u32 nxt_ppid;
__u32 nxt_length;
sctp_assoc_t nxt_assoc_id;
};
/* /*
* sinfo_flags: 16 bits (unsigned integer) * sinfo_flags: 16 bits (unsigned integer)
* *
* This field may contain any of the following flags and is composed of * This field may contain any of the following flags and is composed of
* a bitwise OR of these values. * a bitwise OR of these values.
*/ */
enum sctp_sinfo_flags { enum sctp_sinfo_flags {
SCTP_UNORDERED = 1, /* Send/receive message unordered. */ SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */
SCTP_ADDR_OVER = 2, /* Override the primary destination. */ SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */
SCTP_ABORT=4, /* Send an ABORT message to the peer. */ SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */
SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */
SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */
SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
}; };
typedef union { typedef union {
...@@ -181,6 +242,12 @@ typedef enum sctp_cmsg_type { ...@@ -181,6 +242,12 @@ typedef enum sctp_cmsg_type {
#define SCTP_INIT SCTP_INIT #define SCTP_INIT SCTP_INIT
SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */
#define SCTP_SNDRCV SCTP_SNDRCV #define SCTP_SNDRCV SCTP_SNDRCV
SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */
#define SCTP_SNDINFO SCTP_SNDINFO
SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */
#define SCTP_RCVINFO SCTP_RCVINFO
SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */
#define SCTP_NXTINFO SCTP_NXTINFO
} sctp_cmsg_t; } sctp_cmsg_t;
/* /*
...@@ -808,13 +875,6 @@ struct sctp_assoc_stats { ...@@ -808,13 +875,6 @@ struct sctp_assoc_stats {
__u64 sas_ictrlchunks; /* Control chunks received */ __u64 sas_ictrlchunks; /* Control chunks received */
}; };
/* These are bit fields for msghdr->msg_flags. See section 5.1. */
/* On user space Linux, these live in <bits/socket.h> as an enum. */
enum sctp_msg_flags {
MSG_NOTIFICATION = 0x8000,
#define MSG_NOTIFICATION MSG_NOTIFICATION
};
/* /*
* 8.1 sctp_bindx() * 8.1 sctp_bindx()
* *
......
...@@ -1602,12 +1602,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1602,12 +1602,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct sctp_initmsg *sinit; struct sctp_initmsg *sinit;
sctp_assoc_t associd = 0; sctp_assoc_t associd = 0;
sctp_cmsgs_t cmsgs = { NULL }; sctp_cmsgs_t cmsgs = { NULL };
int err;
sctp_scope_t scope; sctp_scope_t scope;
long timeo; bool fill_sinfo_ttl = false;
__u16 sinfo_flags = 0;
struct sctp_datamsg *datamsg; struct sctp_datamsg *datamsg;
int msg_flags = msg->msg_flags; int msg_flags = msg->msg_flags;
__u16 sinfo_flags = 0;
long timeo;
int err;
err = 0; err = 0;
sp = sctp_sk(sk); sp = sctp_sk(sk);
...@@ -1648,10 +1649,21 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1648,10 +1649,21 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
msg_name = msg->msg_name; msg_name = msg->msg_name;
} }
sinfo = cmsgs.info;
sinit = cmsgs.init; sinit = cmsgs.init;
if (cmsgs.sinfo != NULL) {
memset(&default_sinfo, 0, sizeof(default_sinfo));
default_sinfo.sinfo_stream = cmsgs.sinfo->snd_sid;
default_sinfo.sinfo_flags = cmsgs.sinfo->snd_flags;
default_sinfo.sinfo_ppid = cmsgs.sinfo->snd_ppid;
default_sinfo.sinfo_context = cmsgs.sinfo->snd_context;
default_sinfo.sinfo_assoc_id = cmsgs.sinfo->snd_assoc_id;
/* Did the user specify SNDRCVINFO? */ sinfo = &default_sinfo;
fill_sinfo_ttl = true;
} else {
sinfo = cmsgs.srinfo;
}
/* Did the user specify SNDINFO/SNDRCVINFO? */
if (sinfo) { if (sinfo) {
sinfo_flags = sinfo->sinfo_flags; sinfo_flags = sinfo->sinfo_flags;
associd = sinfo->sinfo_assoc_id; associd = sinfo->sinfo_assoc_id;
...@@ -1858,8 +1870,8 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1858,8 +1870,8 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
pr_debug("%s: we have a valid association\n", __func__); pr_debug("%s: we have a valid association\n", __func__);
if (!sinfo) { if (!sinfo) {
/* If the user didn't specify SNDRCVINFO, make up one with /* If the user didn't specify SNDINFO/SNDRCVINFO, make up
* some defaults. * one with some defaults.
*/ */
memset(&default_sinfo, 0, sizeof(default_sinfo)); memset(&default_sinfo, 0, sizeof(default_sinfo));
default_sinfo.sinfo_stream = asoc->default_stream; default_sinfo.sinfo_stream = asoc->default_stream;
...@@ -1868,7 +1880,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1868,7 +1880,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
default_sinfo.sinfo_context = asoc->default_context; default_sinfo.sinfo_context = asoc->default_context;
default_sinfo.sinfo_timetolive = asoc->default_timetolive; default_sinfo.sinfo_timetolive = asoc->default_timetolive;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo; sinfo = &default_sinfo;
} else if (fill_sinfo_ttl) {
/* In case SNDINFO was specified, we still need to fill
* it with a default ttl from the assoc here.
*/
sinfo->sinfo_timetolive = asoc->default_timetolive;
} }
/* API 7.1.7, the sndbuf size per association bounds the /* API 7.1.7, the sndbuf size per association bounds the
...@@ -2042,8 +2060,6 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) ...@@ -2042,8 +2060,6 @@ static int sctp_skb_pull(struct sk_buff *skb, int len)
* flags - flags sent or received with the user message, see Section * flags - flags sent or received with the user message, see Section
* 5 for complete description of the flags. * 5 for complete description of the flags.
*/ */
static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len, int noblock, struct msghdr *msg, size_t len, int noblock,
int flags, int *addr_len) int flags, int *addr_len)
...@@ -2094,9 +2110,16 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -2094,9 +2110,16 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
sp->pf->skb_msgname(skb, msg->msg_name, addr_len); sp->pf->skb_msgname(skb, msg->msg_name, addr_len);
} }
/* Check if we allow SCTP_NXTINFO. */
if (sp->recvnxtinfo)
sctp_ulpevent_read_nxtinfo(event, msg, sk);
/* Check if we allow SCTP_RCVINFO. */
if (sp->recvrcvinfo)
sctp_ulpevent_read_rcvinfo(event, msg);
/* Check if we allow SCTP_SNDRCVINFO. */ /* Check if we allow SCTP_SNDRCVINFO. */
if (sp->subscribe.sctp_data_io_event) if (sp->subscribe.sctp_data_io_event)
sctp_ulpevent_read_sndrcvinfo(event, msg); sctp_ulpevent_read_sndrcvinfo(event, msg);
#if 0 #if 0
/* FIXME: we should be calling IP/IPv6 layers. */ /* FIXME: we should be calling IP/IPv6 layers. */
if (sk->sk_protinfo.af_inet.cmsg_flags) if (sk->sk_protinfo.af_inet.cmsg_flags)
...@@ -2182,8 +2205,13 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, ...@@ -2182,8 +2205,13 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
return -EFAULT; return -EFAULT;
/* if (sctp_sk(sk)->subscribe.sctp_data_io_event)
* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, pr_warn_ratelimited(DEPRECATED "%s (pid %d) "
"Requested SCTP_SNDRCVINFO event.\n"
"Use SCTP_RCVINFO through SCTP_RECVRCVINFO option instead.\n",
current->comm, task_pid_nr(current));
/* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
* if there is no data to be sent or retransmit, the stack will * if there is no data to be sent or retransmit, the stack will
* immediately send up this notification. * immediately send up this notification.
*/ */
...@@ -2747,19 +2775,22 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -2747,19 +2775,22 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
char __user *optval, char __user *optval,
unsigned int optlen) unsigned int optlen)
{ {
struct sctp_sndrcvinfo info;
struct sctp_association *asoc;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
struct sctp_sndrcvinfo info;
if (optlen != sizeof(struct sctp_sndrcvinfo)) if (optlen != sizeof(info))
return -EINVAL; return -EINVAL;
if (copy_from_user(&info, optval, optlen)) if (copy_from_user(&info, optval, optlen))
return -EFAULT; return -EFAULT;
if (info.sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
asoc->default_stream = info.sinfo_stream; asoc->default_stream = info.sinfo_stream;
asoc->default_flags = info.sinfo_flags; asoc->default_flags = info.sinfo_flags;
...@@ -2777,6 +2808,44 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -2777,6 +2808,44 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
return 0; return 0;
} }
/* RFC6458, Section 8.1.31. Set/get Default Send Parameters
* (SCTP_DEFAULT_SNDINFO)
*/
static int sctp_setsockopt_default_sndinfo(struct sock *sk,
char __user *optval,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
struct sctp_sndinfo info;
if (optlen != sizeof(info))
return -EINVAL;
if (copy_from_user(&info, optval, optlen))
return -EFAULT;
if (info.snd_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
asoc = sctp_id2assoc(sk, info.snd_assoc_id);
if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
asoc->default_stream = info.snd_sid;
asoc->default_flags = info.snd_flags;
asoc->default_ppid = info.snd_ppid;
asoc->default_context = info.snd_context;
} else {
sp->default_stream = info.snd_sid;
sp->default_flags = info.snd_flags;
sp->default_ppid = info.snd_ppid;
sp->default_context = info.snd_context;
}
return 0;
}
/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
* *
* Requests that the local SCTP stack use the enclosed peer address as * Requests that the local SCTP stack use the enclosed peer address as
...@@ -3523,7 +3592,6 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, ...@@ -3523,7 +3592,6 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
return 0; return 0;
} }
/* /*
* SCTP_PEER_ADDR_THLDS * SCTP_PEER_ADDR_THLDS
* *
...@@ -3574,6 +3642,38 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk, ...@@ -3574,6 +3642,38 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk,
return 0; return 0;
} }
static int sctp_setsockopt_recvrcvinfo(struct sock *sk,
char __user *optval,
unsigned int optlen)
{
int val;
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *) optval))
return -EFAULT;
sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1;
return 0;
}
static int sctp_setsockopt_recvnxtinfo(struct sock *sk,
char __user *optval,
unsigned int optlen)
{
int val;
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *) optval))
return -EFAULT;
sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1;
return 0;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -3671,6 +3771,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -3671,6 +3771,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_default_send_param(sk, optval, retval = sctp_setsockopt_default_send_param(sk, optval,
optlen); optlen);
break; break;
case SCTP_DEFAULT_SNDINFO:
retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen);
break;
case SCTP_PRIMARY_ADDR: case SCTP_PRIMARY_ADDR:
retval = sctp_setsockopt_primary_addr(sk, optval, optlen); retval = sctp_setsockopt_primary_addr(sk, optval, optlen);
break; break;
...@@ -3725,6 +3828,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -3725,6 +3828,12 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_PEER_ADDR_THLDS: case SCTP_PEER_ADDR_THLDS:
retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen);
break; break;
case SCTP_RECVRCVINFO:
retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen);
break;
case SCTP_RECVNXTINFO:
retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -3971,6 +4080,9 @@ static int sctp_init_sock(struct sock *sk) ...@@ -3971,6 +4080,9 @@ static int sctp_init_sock(struct sock *sk)
/* Enable Nagle algorithm by default. */ /* Enable Nagle algorithm by default. */
sp->nodelay = 0; sp->nodelay = 0;
sp->recvrcvinfo = 0;
sp->recvnxtinfo = 0;
/* Enable by default. */ /* Enable by default. */
sp->v4mapped = 1; sp->v4mapped = 1;
...@@ -4964,14 +5076,14 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -4964,14 +5076,14 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
int len, char __user *optval, int len, char __user *optval,
int __user *optlen) int __user *optlen)
{ {
struct sctp_sndrcvinfo info;
struct sctp_association *asoc;
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
struct sctp_sndrcvinfo info;
if (len < sizeof(struct sctp_sndrcvinfo)) if (len < sizeof(info))
return -EINVAL; return -EINVAL;
len = sizeof(struct sctp_sndrcvinfo); len = sizeof(info);
if (copy_from_user(&info, optval, len)) if (copy_from_user(&info, optval, len))
return -EFAULT; return -EFAULT;
...@@ -4979,7 +5091,6 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -4979,7 +5091,6 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (asoc) { if (asoc) {
info.sinfo_stream = asoc->default_stream; info.sinfo_stream = asoc->default_stream;
info.sinfo_flags = asoc->default_flags; info.sinfo_flags = asoc->default_flags;
...@@ -5002,6 +5113,48 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -5002,6 +5113,48 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
return 0; return 0;
} }
/* RFC6458, Section 8.1.31. Set/get Default Send Parameters
* (SCTP_DEFAULT_SNDINFO)
*/
static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
struct sctp_sndinfo info;
if (len < sizeof(info))
return -EINVAL;
len = sizeof(info);
if (copy_from_user(&info, optval, len))
return -EFAULT;
asoc = sctp_id2assoc(sk, info.snd_assoc_id);
if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
info.snd_sid = asoc->default_stream;
info.snd_flags = asoc->default_flags;
info.snd_ppid = asoc->default_ppid;
info.snd_context = asoc->default_context;
} else {
info.snd_sid = sp->default_stream;
info.snd_flags = sp->default_flags;
info.snd_ppid = sp->default_ppid;
info.snd_context = sp->default_context;
}
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &info, len))
return -EFAULT;
return 0;
}
/* /*
* *
* 7.1.5 SCTP_NODELAY * 7.1.5 SCTP_NODELAY
...@@ -5752,6 +5905,46 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, ...@@ -5752,6 +5905,46 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len,
return 0; return 0;
} }
static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
int val = 0;
if (len < sizeof(int))
return -EINVAL;
len = sizeof(int);
if (sctp_sk(sk)->recvrcvinfo)
val = 1;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
int val = 0;
if (len < sizeof(int))
return -EINVAL;
len = sizeof(int);
if (sctp_sk(sk)->recvnxtinfo)
val = 1;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
static int sctp_getsockopt(struct sock *sk, int level, int optname, static int sctp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
...@@ -5821,6 +6014,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -5821,6 +6014,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_default_send_param(sk, len, retval = sctp_getsockopt_default_send_param(sk, len,
optval, optlen); optval, optlen);
break; break;
case SCTP_DEFAULT_SNDINFO:
retval = sctp_getsockopt_default_sndinfo(sk, len,
optval, optlen);
break;
case SCTP_PRIMARY_ADDR: case SCTP_PRIMARY_ADDR:
retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen);
break; break;
...@@ -5895,6 +6092,12 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -5895,6 +6092,12 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_GET_ASSOC_STATS: case SCTP_GET_ASSOC_STATS:
retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen);
break; break;
case SCTP_RECVRCVINFO:
retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen);
break;
case SCTP_RECVNXTINFO:
retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -6390,8 +6593,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6390,8 +6593,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
struct msghdr *my_msg = (struct msghdr *)msg; struct msghdr *my_msg = (struct msghdr *)msg;
for (cmsg = CMSG_FIRSTHDR(msg); for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
cmsg != NULL;
cmsg = CMSG_NXTHDR(my_msg, cmsg)) { cmsg = CMSG_NXTHDR(my_msg, cmsg)) {
if (!CMSG_OK(my_msg, cmsg)) if (!CMSG_OK(my_msg, cmsg))
return -EINVAL; return -EINVAL;
...@@ -6404,7 +6606,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6404,7 +6606,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
switch (cmsg->cmsg_type) { switch (cmsg->cmsg_type) {
case SCTP_INIT: case SCTP_INIT:
/* SCTP Socket API Extension /* SCTP Socket API Extension
* 5.2.1 SCTP Initiation Structure (SCTP_INIT) * 5.3.1 SCTP Initiation Structure (SCTP_INIT)
* *
* This cmsghdr structure provides information for * This cmsghdr structure provides information for
* initializing new SCTP associations with sendmsg(). * initializing new SCTP associations with sendmsg().
...@@ -6416,15 +6618,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6416,15 +6618,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
* ------------ ------------ ---------------------- * ------------ ------------ ----------------------
* IPPROTO_SCTP SCTP_INIT struct sctp_initmsg * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg
*/ */
if (cmsg->cmsg_len != if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg)))
CMSG_LEN(sizeof(struct sctp_initmsg)))
return -EINVAL; return -EINVAL;
cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg);
cmsgs->init = CMSG_DATA(cmsg);
break; break;
case SCTP_SNDRCV: case SCTP_SNDRCV:
/* SCTP Socket API Extension /* SCTP Socket API Extension
* 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV)
* *
* This cmsghdr structure specifies SCTP options for * This cmsghdr structure specifies SCTP options for
* sendmsg() and describes SCTP header information * sendmsg() and describes SCTP header information
...@@ -6434,24 +6636,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6434,24 +6636,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)
* ------------ ------------ ---------------------- * ------------ ------------ ----------------------
* IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo
*/ */
if (cmsg->cmsg_len != if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
return -EINVAL; return -EINVAL;
cmsgs->info = cmsgs->srinfo = CMSG_DATA(cmsg);
(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
/* Minimally, validate the sinfo_flags. */ if (cmsgs->srinfo->sinfo_flags &
if (cmsgs->info->sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER | ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF)) SCTP_ABORT | SCTP_EOF))
return -EINVAL; return -EINVAL;
break; break;
case SCTP_SNDINFO:
/* SCTP Socket API Extension
* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO)
*
* This cmsghdr structure specifies SCTP options for
* sendmsg(). This structure and SCTP_RCVINFO replaces
* SCTP_SNDRCV which has been deprecated.
*
* cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ ---------------------
* IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo
*/
if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo)))
return -EINVAL;
cmsgs->sinfo = CMSG_DATA(cmsg);
if (cmsgs->sinfo->snd_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
} }
return 0; return 0;
} }
...@@ -6518,7 +6740,7 @@ static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p) ...@@ -6518,7 +6740,7 @@ static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p)
* Note: This is pretty much the same routine as in core/datagram.c * Note: This is pretty much the same routine as in core/datagram.c
* with a few changes to make lksctp work. * with a few changes to make lksctp work.
*/ */
static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
int noblock, int *err) int noblock, int *err)
{ {
int error; int error;
......
...@@ -886,6 +886,69 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, ...@@ -886,6 +886,69 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
sizeof(sinfo), &sinfo); sizeof(sinfo), &sinfo);
} }
/* RFC6458, Section 5.3.5 SCTP Receive Information Structure
* (SCTP_SNDRCV)
*/
void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event,
struct msghdr *msghdr)
{
struct sctp_rcvinfo rinfo;
if (sctp_ulpevent_is_notification(event))
return;
memset(&rinfo, 0, sizeof(struct sctp_rcvinfo));
rinfo.rcv_sid = event->stream;
rinfo.rcv_ssn = event->ssn;
rinfo.rcv_ppid = event->ppid;
rinfo.rcv_flags = event->flags;
rinfo.rcv_tsn = event->tsn;
rinfo.rcv_cumtsn = event->cumtsn;
rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc);
rinfo.rcv_context = event->asoc->default_rcv_context;
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO,
sizeof(rinfo), &rinfo);
}
/* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure
* (SCTP_NXTINFO)
*/
static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
struct msghdr *msghdr,
const struct sk_buff *skb)
{
struct sctp_nxtinfo nxtinfo;
memset(&nxtinfo, 0, sizeof(nxtinfo));
nxtinfo.nxt_sid = event->stream;
nxtinfo.nxt_ppid = event->ppid;
nxtinfo.nxt_flags = event->flags;
if (sctp_ulpevent_is_notification(event))
nxtinfo.nxt_flags |= SCTP_NOTIFICATION;
nxtinfo.nxt_length = skb->len;
nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc);
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO,
sizeof(nxtinfo), &nxtinfo);
}
void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
struct msghdr *msghdr,
struct sock *sk)
{
struct sk_buff *skb;
int err;
skb = sctp_skb_recv_datagram(sk, MSG_PEEK, 1, &err);
if (skb != NULL) {
__sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb),
msghdr, skb);
/* Just release refcount here. */
kfree_skb(skb);
}
}
/* Do accounting for bytes received and hold a reference to the association /* Do accounting for bytes received and hold a reference to the association
* for each skb. * for each skb.
*/ */
......
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