diff options
author | Geir Ola Vaagland <geirola@gmail.com> | 2014-07-12 14:30:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-16 17:40:03 -0400 |
commit | 0d3a421d284812d07970b4ccee74d4fa38737e4d (patch) | |
tree | c9d97227606c9682671e8d9e7d2ebfc727416c31 /net/sctp | |
parent | 63b949382c5f263746b1c177f6ff84de2201ae9d (diff) |
net: sctp: implement rfc6458, 5.3.5. SCTP_RCVINFO cmsg support
This patch implements section 5.3.5. of RFC6458, that is, support
for 'SCTP Receive Information Structure' (SCTP_RCVINFO) which is
placed into ancillary data cmsghdr structure for each recvmsg()
call.
This option can be enabled/disabled via setsockopt(2) on SOL_SCTP
level by setting an int value with 1/0 for SCTP_RECVRCVINFO in user
space applications as per RFC6458, section 8.1.29.
The sctp_rcvinfo structure is defined as per RFC as below ...
struct sctp_rcvinfo {
uint16_t rcv_sid;
uint16_t rcv_ssn;
uint16_t rcv_flags;
<-- 2 bytes hole -->
uint32_t rcv_ppid;
uint32_t rcv_tsn;
uint32_t rcv_cumtsn;
uint32_t rcv_context;
sctp_assoc_t rcv_assoc_id;
};
... and provided under cmsg_level IPPROTO_SCTP, cmsg_type
SCTP_RCVINFO, while cmsg_data[] contains struct sctp_rcvinfo.
An sctp_rcvinfo 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 | 49 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 25 |
2 files changed, 73 insertions, 1 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d61729e99856..9c193887c5cd 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2112,9 +2112,13 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
2112 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); | 2112 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); |
2113 | } | 2113 | } |
2114 | 2114 | ||
2115 | /* Check if we allow SCTP_RCVINFO. */ | ||
2116 | if (sp->recvrcvinfo) | ||
2117 | sctp_ulpevent_read_rcvinfo(event, msg); | ||
2115 | /* Check if we allow SCTP_SNDRCVINFO. */ | 2118 | /* Check if we allow SCTP_SNDRCVINFO. */ |
2116 | if (sp->subscribe.sctp_data_io_event) | 2119 | if (sp->subscribe.sctp_data_io_event) |
2117 | sctp_ulpevent_read_sndrcvinfo(event, msg); | 2120 | sctp_ulpevent_read_sndrcvinfo(event, msg); |
2121 | |||
2118 | #if 0 | 2122 | #if 0 |
2119 | /* FIXME: we should be calling IP/IPv6 layers. */ | 2123 | /* FIXME: we should be calling IP/IPv6 layers. */ |
2120 | if (sk->sk_protinfo.af_inet.cmsg_flags) | 2124 | if (sk->sk_protinfo.af_inet.cmsg_flags) |
@@ -3541,7 +3545,6 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, | |||
3541 | return 0; | 3545 | return 0; |
3542 | } | 3546 | } |
3543 | 3547 | ||
3544 | |||
3545 | /* | 3548 | /* |
3546 | * SCTP_PEER_ADDR_THLDS | 3549 | * SCTP_PEER_ADDR_THLDS |
3547 | * | 3550 | * |
@@ -3592,6 +3595,22 @@ static int sctp_setsockopt_paddr_thresholds(struct sock *sk, | |||
3592 | return 0; | 3595 | return 0; |
3593 | } | 3596 | } |
3594 | 3597 | ||
3598 | static int sctp_setsockopt_recvrcvinfo(struct sock *sk, | ||
3599 | char __user *optval, | ||
3600 | unsigned int optlen) | ||
3601 | { | ||
3602 | int val; | ||
3603 | |||
3604 | if (optlen < sizeof(int)) | ||
3605 | return -EINVAL; | ||
3606 | if (get_user(val, (int __user *) optval)) | ||
3607 | return -EFAULT; | ||
3608 | |||
3609 | sctp_sk(sk)->recvrcvinfo = (val == 0) ? 0 : 1; | ||
3610 | |||
3611 | return 0; | ||
3612 | } | ||
3613 | |||
3595 | /* API 6.2 setsockopt(), getsockopt() | 3614 | /* API 6.2 setsockopt(), getsockopt() |
3596 | * | 3615 | * |
3597 | * Applications use setsockopt() and getsockopt() to set or retrieve | 3616 | * Applications use setsockopt() and getsockopt() to set or retrieve |
@@ -3743,6 +3762,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3743 | case SCTP_PEER_ADDR_THLDS: | 3762 | case SCTP_PEER_ADDR_THLDS: |
3744 | retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); | 3763 | retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); |
3745 | break; | 3764 | break; |
3765 | case SCTP_RECVRCVINFO: | ||
3766 | retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); | ||
3767 | break; | ||
3746 | default: | 3768 | default: |
3747 | retval = -ENOPROTOOPT; | 3769 | retval = -ENOPROTOOPT; |
3748 | break; | 3770 | break; |
@@ -3989,6 +4011,8 @@ static int sctp_init_sock(struct sock *sk) | |||
3989 | /* Enable Nagle algorithm by default. */ | 4011 | /* Enable Nagle algorithm by default. */ |
3990 | sp->nodelay = 0; | 4012 | sp->nodelay = 0; |
3991 | 4013 | ||
4014 | sp->recvrcvinfo = 0; | ||
4015 | |||
3992 | /* Enable by default. */ | 4016 | /* Enable by default. */ |
3993 | sp->v4mapped = 1; | 4017 | sp->v4mapped = 1; |
3994 | 4018 | ||
@@ -5770,6 +5794,26 @@ static int sctp_getsockopt_assoc_stats(struct sock *sk, int len, | |||
5770 | return 0; | 5794 | return 0; |
5771 | } | 5795 | } |
5772 | 5796 | ||
5797 | static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, | ||
5798 | char __user *optval, | ||
5799 | int __user *optlen) | ||
5800 | { | ||
5801 | int val = 0; | ||
5802 | |||
5803 | if (len < sizeof(int)) | ||
5804 | return -EINVAL; | ||
5805 | |||
5806 | len = sizeof(int); | ||
5807 | if (sctp_sk(sk)->recvrcvinfo) | ||
5808 | val = 1; | ||
5809 | if (put_user(len, optlen)) | ||
5810 | return -EFAULT; | ||
5811 | if (copy_to_user(optval, &val, len)) | ||
5812 | return -EFAULT; | ||
5813 | |||
5814 | return 0; | ||
5815 | } | ||
5816 | |||
5773 | static int sctp_getsockopt(struct sock *sk, int level, int optname, | 5817 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
5774 | char __user *optval, int __user *optlen) | 5818 | char __user *optval, int __user *optlen) |
5775 | { | 5819 | { |
@@ -5913,6 +5957,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5913 | case SCTP_GET_ASSOC_STATS: | 5957 | case SCTP_GET_ASSOC_STATS: |
5914 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); | 5958 | retval = sctp_getsockopt_assoc_stats(sk, len, optval, optlen); |
5915 | break; | 5959 | break; |
5960 | case SCTP_RECVRCVINFO: | ||
5961 | retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); | ||
5962 | break; | ||
5916 | default: | 5963 | default: |
5917 | retval = -ENOPROTOOPT; | 5964 | retval = -ENOPROTOOPT; |
5918 | break; | 5965 | break; |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index b6842fdb53d4..b31f365f18ab 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -886,6 +886,31 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, | |||
886 | sizeof(sinfo), &sinfo); | 886 | sizeof(sinfo), &sinfo); |
887 | } | 887 | } |
888 | 888 | ||
889 | /* RFC6458, Section 5.3.5 SCTP Receive Information Structure | ||
890 | * (SCTP_SNDRCV) | ||
891 | */ | ||
892 | void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, | ||
893 | struct msghdr *msghdr) | ||
894 | { | ||
895 | struct sctp_rcvinfo rinfo; | ||
896 | |||
897 | if (sctp_ulpevent_is_notification(event)) | ||
898 | return; | ||
899 | |||
900 | memset(&rinfo, 0, sizeof(struct sctp_rcvinfo)); | ||
901 | rinfo.rcv_sid = event->stream; | ||
902 | rinfo.rcv_ssn = event->ssn; | ||
903 | rinfo.rcv_ppid = event->ppid; | ||
904 | rinfo.rcv_flags = event->flags; | ||
905 | rinfo.rcv_tsn = event->tsn; | ||
906 | rinfo.rcv_cumtsn = event->cumtsn; | ||
907 | rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc); | ||
908 | rinfo.rcv_context = event->asoc->default_rcv_context; | ||
909 | |||
910 | put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO, | ||
911 | sizeof(rinfo), &rinfo); | ||
912 | } | ||
913 | |||
889 | /* Do accounting for bytes received and hold a reference to the association | 914 | /* Do accounting for bytes received and hold a reference to the association |
890 | * for each skb. | 915 | * for each skb. |
891 | */ | 916 | */ |