Commit 63b94938 authored by Geir Ola Vaagland's avatar Geir Ola Vaagland Committed by David S. Miller

net: sctp: implement rfc6458, 5.3.4. SCTP_SNDINFO cmsg support

This patch implements section 5.3.4. of RFC6458, that is, support
for 'SCTP Send Information Structure' (SCTP_SNDINFO) which can be
placed into ancillary data cmsghdr structure for sendmsg() calls.

The sctp_sndinfo structure is defined as per RFC as below ...

  struct sctp_sndinfo {
    uint16_t snd_sid;
    uint16_t snd_flags;
    uint32_t snd_ppid;
    uint32_t snd_context;
    sctp_assoc_t snd_assoc_id;
  };

... and supplied under cmsg_level IPPROTO_SCTP, cmsg_type
SCTP_SNDINFO, while cmsg_data[] contains struct sctp_sndinfo.
An sctp_sndinfo item always corresponds to the data in msg_iov.

Joint work with Daniel Borkmann.
Signed-off-by: default avatarGeir Ola Vaagland <geirola@gmail.com>
Signed-off-by: default avatarDaniel Borkmann <dborkman@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a98c69a
...@@ -1919,7 +1919,8 @@ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); ...@@ -1919,7 +1919,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 */
......
...@@ -154,6 +154,22 @@ struct sctp_sndrcvinfo { ...@@ -154,6 +154,22 @@ 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;
};
/* /*
* sinfo_flags: 16 bits (unsigned integer) * sinfo_flags: 16 bits (unsigned integer)
* *
...@@ -181,6 +197,8 @@ typedef enum sctp_cmsg_type { ...@@ -181,6 +197,8 @@ 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_cmsg_t; } sctp_cmsg_t;
/* /*
......
...@@ -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
...@@ -6390,8 +6408,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6390,8 +6408,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 +6421,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6404,7 +6421,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 +6433,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6416,15 +6433,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 +6451,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) ...@@ -6434,24 +6451,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;
} }
......
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