diff options
author | Geir Ola Vaagland <geirola@gmail.com> | 2014-07-12 14:30:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-16 17:40:03 -0400 |
commit | 63b949382c5f263746b1c177f6ff84de2201ae9d (patch) | |
tree | 5e946189fa98de8699606a6f6ec8165ee8e0ed1e /net/sctp | |
parent | 1a98c69af1ecd97bfd1f4e4539924a9192434e36 (diff) |
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: Geir Ola Vaagland <geirola@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/socket.c | 77 |
1 files changed, 57 insertions, 20 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 429899689408..d61729e99856 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1602,12 +1602,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1602 | struct sctp_initmsg *sinit; | 1602 | struct sctp_initmsg *sinit; |
1603 | sctp_assoc_t associd = 0; | 1603 | sctp_assoc_t associd = 0; |
1604 | sctp_cmsgs_t cmsgs = { NULL }; | 1604 | sctp_cmsgs_t cmsgs = { NULL }; |
1605 | int err; | ||
1606 | sctp_scope_t scope; | 1605 | sctp_scope_t scope; |
1607 | long timeo; | 1606 | bool fill_sinfo_ttl = false; |
1608 | __u16 sinfo_flags = 0; | ||
1609 | struct sctp_datamsg *datamsg; | 1607 | struct sctp_datamsg *datamsg; |
1610 | int msg_flags = msg->msg_flags; | 1608 | int msg_flags = msg->msg_flags; |
1609 | __u16 sinfo_flags = 0; | ||
1610 | long timeo; | ||
1611 | int err; | ||
1611 | 1612 | ||
1612 | err = 0; | 1613 | err = 0; |
1613 | sp = sctp_sk(sk); | 1614 | sp = sctp_sk(sk); |
@@ -1648,10 +1649,21 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1648 | msg_name = msg->msg_name; | 1649 | msg_name = msg->msg_name; |
1649 | } | 1650 | } |
1650 | 1651 | ||
1651 | sinfo = cmsgs.info; | ||
1652 | sinit = cmsgs.init; | 1652 | sinit = cmsgs.init; |
1653 | if (cmsgs.sinfo != NULL) { | ||
1654 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | ||
1655 | default_sinfo.sinfo_stream = cmsgs.sinfo->snd_sid; | ||
1656 | default_sinfo.sinfo_flags = cmsgs.sinfo->snd_flags; | ||
1657 | default_sinfo.sinfo_ppid = cmsgs.sinfo->snd_ppid; | ||
1658 | default_sinfo.sinfo_context = cmsgs.sinfo->snd_context; | ||
1659 | default_sinfo.sinfo_assoc_id = cmsgs.sinfo->snd_assoc_id; | ||
1653 | 1660 | ||
1654 | /* Did the user specify SNDRCVINFO? */ | 1661 | sinfo = &default_sinfo; |
1662 | fill_sinfo_ttl = true; | ||
1663 | } else { | ||
1664 | sinfo = cmsgs.srinfo; | ||
1665 | } | ||
1666 | /* Did the user specify SNDINFO/SNDRCVINFO? */ | ||
1655 | if (sinfo) { | 1667 | if (sinfo) { |
1656 | sinfo_flags = sinfo->sinfo_flags; | 1668 | sinfo_flags = sinfo->sinfo_flags; |
1657 | associd = sinfo->sinfo_assoc_id; | 1669 | associd = sinfo->sinfo_assoc_id; |
@@ -1858,8 +1870,8 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1858 | pr_debug("%s: we have a valid association\n", __func__); | 1870 | pr_debug("%s: we have a valid association\n", __func__); |
1859 | 1871 | ||
1860 | if (!sinfo) { | 1872 | if (!sinfo) { |
1861 | /* If the user didn't specify SNDRCVINFO, make up one with | 1873 | /* If the user didn't specify SNDINFO/SNDRCVINFO, make up |
1862 | * some defaults. | 1874 | * one with some defaults. |
1863 | */ | 1875 | */ |
1864 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | 1876 | memset(&default_sinfo, 0, sizeof(default_sinfo)); |
1865 | default_sinfo.sinfo_stream = asoc->default_stream; | 1877 | default_sinfo.sinfo_stream = asoc->default_stream; |
@@ -1868,7 +1880,13 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1868 | default_sinfo.sinfo_context = asoc->default_context; | 1880 | default_sinfo.sinfo_context = asoc->default_context; |
1869 | default_sinfo.sinfo_timetolive = asoc->default_timetolive; | 1881 | default_sinfo.sinfo_timetolive = asoc->default_timetolive; |
1870 | default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); | 1882 | default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); |
1883 | |||
1871 | sinfo = &default_sinfo; | 1884 | sinfo = &default_sinfo; |
1885 | } else if (fill_sinfo_ttl) { | ||
1886 | /* In case SNDINFO was specified, we still need to fill | ||
1887 | * it with a default ttl from the assoc here. | ||
1888 | */ | ||
1889 | sinfo->sinfo_timetolive = asoc->default_timetolive; | ||
1872 | } | 1890 | } |
1873 | 1891 | ||
1874 | /* API 7.1.7, the sndbuf size per association bounds the | 1892 | /* 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 | struct cmsghdr *cmsg; | 6408 | struct cmsghdr *cmsg; |
6391 | struct msghdr *my_msg = (struct msghdr *)msg; | 6409 | struct msghdr *my_msg = (struct msghdr *)msg; |
6392 | 6410 | ||
6393 | for (cmsg = CMSG_FIRSTHDR(msg); | 6411 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; |
6394 | cmsg != NULL; | ||
6395 | cmsg = CMSG_NXTHDR(my_msg, cmsg)) { | 6412 | cmsg = CMSG_NXTHDR(my_msg, cmsg)) { |
6396 | if (!CMSG_OK(my_msg, cmsg)) | 6413 | if (!CMSG_OK(my_msg, cmsg)) |
6397 | return -EINVAL; | 6414 | return -EINVAL; |
@@ -6404,7 +6421,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
6404 | switch (cmsg->cmsg_type) { | 6421 | switch (cmsg->cmsg_type) { |
6405 | case SCTP_INIT: | 6422 | case SCTP_INIT: |
6406 | /* SCTP Socket API Extension | 6423 | /* SCTP Socket API Extension |
6407 | * 5.2.1 SCTP Initiation Structure (SCTP_INIT) | 6424 | * 5.3.1 SCTP Initiation Structure (SCTP_INIT) |
6408 | * | 6425 | * |
6409 | * This cmsghdr structure provides information for | 6426 | * This cmsghdr structure provides information for |
6410 | * initializing new SCTP associations with sendmsg(). | 6427 | * initializing new SCTP associations with sendmsg(). |
@@ -6416,15 +6433,15 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
6416 | * ------------ ------------ ---------------------- | 6433 | * ------------ ------------ ---------------------- |
6417 | * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg | 6434 | * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg |
6418 | */ | 6435 | */ |
6419 | if (cmsg->cmsg_len != | 6436 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_initmsg))) |
6420 | CMSG_LEN(sizeof(struct sctp_initmsg))) | ||
6421 | return -EINVAL; | 6437 | return -EINVAL; |
6422 | cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); | 6438 | |
6439 | cmsgs->init = CMSG_DATA(cmsg); | ||
6423 | break; | 6440 | break; |
6424 | 6441 | ||
6425 | case SCTP_SNDRCV: | 6442 | case SCTP_SNDRCV: |
6426 | /* SCTP Socket API Extension | 6443 | /* SCTP Socket API Extension |
6427 | * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) | 6444 | * 5.3.2 SCTP Header Information Structure(SCTP_SNDRCV) |
6428 | * | 6445 | * |
6429 | * This cmsghdr structure specifies SCTP options for | 6446 | * This cmsghdr structure specifies SCTP options for |
6430 | * sendmsg() and describes SCTP header information | 6447 | * sendmsg() and describes SCTP header information |
@@ -6434,24 +6451,44 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) | |||
6434 | * ------------ ------------ ---------------------- | 6451 | * ------------ ------------ ---------------------- |
6435 | * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo | 6452 | * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo |
6436 | */ | 6453 | */ |
6437 | if (cmsg->cmsg_len != | 6454 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) |
6438 | CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) | ||
6439 | return -EINVAL; | 6455 | return -EINVAL; |
6440 | 6456 | ||
6441 | cmsgs->info = | 6457 | cmsgs->srinfo = CMSG_DATA(cmsg); |
6442 | (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); | ||
6443 | 6458 | ||
6444 | /* Minimally, validate the sinfo_flags. */ | 6459 | if (cmsgs->srinfo->sinfo_flags & |
6445 | if (cmsgs->info->sinfo_flags & | ||
6446 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | 6460 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | |
6447 | SCTP_ABORT | SCTP_EOF)) | 6461 | SCTP_ABORT | SCTP_EOF)) |
6448 | return -EINVAL; | 6462 | return -EINVAL; |
6449 | break; | 6463 | break; |
6450 | 6464 | ||
6465 | case SCTP_SNDINFO: | ||
6466 | /* SCTP Socket API Extension | ||
6467 | * 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) | ||
6468 | * | ||
6469 | * This cmsghdr structure specifies SCTP options for | ||
6470 | * sendmsg(). This structure and SCTP_RCVINFO replaces | ||
6471 | * SCTP_SNDRCV which has been deprecated. | ||
6472 | * | ||
6473 | * cmsg_level cmsg_type cmsg_data[] | ||
6474 | * ------------ ------------ --------------------- | ||
6475 | * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo | ||
6476 | */ | ||
6477 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_sndinfo))) | ||
6478 | return -EINVAL; | ||
6479 | |||
6480 | cmsgs->sinfo = CMSG_DATA(cmsg); | ||
6481 | |||
6482 | if (cmsgs->sinfo->snd_flags & | ||
6483 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
6484 | SCTP_ABORT | SCTP_EOF)) | ||
6485 | return -EINVAL; | ||
6486 | break; | ||
6451 | default: | 6487 | default: |
6452 | return -EINVAL; | 6488 | return -EINVAL; |
6453 | } | 6489 | } |
6454 | } | 6490 | } |
6491 | |||
6455 | return 0; | 6492 | return 0; |
6456 | } | 6493 | } |
6457 | 6494 | ||