diff options
author | Geir Ola Vaagland <geirola@gmail.com> | 2014-07-12 14:30:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-16 17:40:03 -0400 |
commit | 2347c80ff127b94ddaa675e2b78ab4cef46dc905 (patch) | |
tree | 5fe57c8b7814f629cb773bbea0c1a9f8eba035d0 /net/sctp | |
parent | 0d3a421d284812d07970b4ccee74d4fa38737e4d (diff) |
net: sctp: implement rfc6458, 5.3.6. SCTP_NXTINFO cmsg support
This patch implements section 5.3.6. of RFC6458, that is, support
for 'SCTP Next Receive Information Structure' (SCTP_NXTINFO) which
is placed into ancillary data cmsghdr structure for each recvmsg()
call, if this information is already available when delivering the
current message.
This option can be enabled/disabled via setsockopt(2) on SOL_SCTP
level by setting an int value with 1/0 for SCTP_RECVNXTINFO in
user space applications as per RFC6458, section 8.1.30.
The sctp_nxtinfo structure is defined as per RFC as below ...
struct sctp_nxtinfo {
uint16_t nxt_sid;
uint16_t nxt_flags;
uint32_t nxt_ppid;
uint32_t nxt_length;
sctp_assoc_t nxt_assoc_id;
};
... and provided under cmsg_level IPPROTO_SCTP, cmsg_type
SCTP_NXTINFO, while cmsg_data[] contains struct sctp_nxtinfo.
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 | 52 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 38 |
2 files changed, 86 insertions, 4 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9c193887c5cd..9bca87ee5152 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2060,8 +2060,6 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) | |||
2060 | * flags - flags sent or received with the user message, see Section | 2060 | * flags - flags sent or received with the user message, see Section |
2061 | * 5 for complete description of the flags. | 2061 | * 5 for complete description of the flags. |
2062 | */ | 2062 | */ |
2063 | static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); | ||
2064 | |||
2065 | static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | 2063 | static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, |
2066 | struct msghdr *msg, size_t len, int noblock, | 2064 | struct msghdr *msg, size_t len, int noblock, |
2067 | int flags, int *addr_len) | 2065 | int flags, int *addr_len) |
@@ -2112,6 +2110,9 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
2112 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); | 2110 | sp->pf->skb_msgname(skb, msg->msg_name, addr_len); |
2113 | } | 2111 | } |
2114 | 2112 | ||
2113 | /* Check if we allow SCTP_NXTINFO. */ | ||
2114 | if (sp->recvnxtinfo) | ||
2115 | sctp_ulpevent_read_nxtinfo(event, msg, sk); | ||
2115 | /* Check if we allow SCTP_RCVINFO. */ | 2116 | /* Check if we allow SCTP_RCVINFO. */ |
2116 | if (sp->recvrcvinfo) | 2117 | if (sp->recvrcvinfo) |
2117 | sctp_ulpevent_read_rcvinfo(event, msg); | 2118 | sctp_ulpevent_read_rcvinfo(event, msg); |
@@ -3611,6 +3612,22 @@ static int sctp_setsockopt_recvrcvinfo(struct sock *sk, | |||
3611 | return 0; | 3612 | return 0; |
3612 | } | 3613 | } |
3613 | 3614 | ||
3615 | static int sctp_setsockopt_recvnxtinfo(struct sock *sk, | ||
3616 | char __user *optval, | ||
3617 | unsigned int optlen) | ||
3618 | { | ||
3619 | int val; | ||
3620 | |||
3621 | if (optlen < sizeof(int)) | ||
3622 | return -EINVAL; | ||
3623 | if (get_user(val, (int __user *) optval)) | ||
3624 | return -EFAULT; | ||
3625 | |||
3626 | sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; | ||
3627 | |||
3628 | return 0; | ||
3629 | } | ||
3630 | |||
3614 | /* API 6.2 setsockopt(), getsockopt() | 3631 | /* API 6.2 setsockopt(), getsockopt() |
3615 | * | 3632 | * |
3616 | * Applications use setsockopt() and getsockopt() to set or retrieve | 3633 | * Applications use setsockopt() and getsockopt() to set or retrieve |
@@ -3765,6 +3782,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3765 | case SCTP_RECVRCVINFO: | 3782 | case SCTP_RECVRCVINFO: |
3766 | retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); | 3783 | retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); |
3767 | break; | 3784 | break; |
3785 | case SCTP_RECVNXTINFO: | ||
3786 | retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); | ||
3787 | break; | ||
3768 | default: | 3788 | default: |
3769 | retval = -ENOPROTOOPT; | 3789 | retval = -ENOPROTOOPT; |
3770 | break; | 3790 | break; |
@@ -4012,6 +4032,7 @@ static int sctp_init_sock(struct sock *sk) | |||
4012 | sp->nodelay = 0; | 4032 | sp->nodelay = 0; |
4013 | 4033 | ||
4014 | sp->recvrcvinfo = 0; | 4034 | sp->recvrcvinfo = 0; |
4035 | sp->recvnxtinfo = 0; | ||
4015 | 4036 | ||
4016 | /* Enable by default. */ | 4037 | /* Enable by default. */ |
4017 | sp->v4mapped = 1; | 4038 | sp->v4mapped = 1; |
@@ -5814,6 +5835,26 @@ static int sctp_getsockopt_recvrcvinfo(struct sock *sk, int len, | |||
5814 | return 0; | 5835 | return 0; |
5815 | } | 5836 | } |
5816 | 5837 | ||
5838 | static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, | ||
5839 | char __user *optval, | ||
5840 | int __user *optlen) | ||
5841 | { | ||
5842 | int val = 0; | ||
5843 | |||
5844 | if (len < sizeof(int)) | ||
5845 | return -EINVAL; | ||
5846 | |||
5847 | len = sizeof(int); | ||
5848 | if (sctp_sk(sk)->recvnxtinfo) | ||
5849 | val = 1; | ||
5850 | if (put_user(len, optlen)) | ||
5851 | return -EFAULT; | ||
5852 | if (copy_to_user(optval, &val, len)) | ||
5853 | return -EFAULT; | ||
5854 | |||
5855 | return 0; | ||
5856 | } | ||
5857 | |||
5817 | static int sctp_getsockopt(struct sock *sk, int level, int optname, | 5858 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
5818 | char __user *optval, int __user *optlen) | 5859 | char __user *optval, int __user *optlen) |
5819 | { | 5860 | { |
@@ -5960,6 +6001,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5960 | case SCTP_RECVRCVINFO: | 6001 | case SCTP_RECVRCVINFO: |
5961 | retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); | 6002 | retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); |
5962 | break; | 6003 | break; |
6004 | case SCTP_RECVNXTINFO: | ||
6005 | retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); | ||
6006 | break; | ||
5963 | default: | 6007 | default: |
5964 | retval = -ENOPROTOOPT; | 6008 | retval = -ENOPROTOOPT; |
5965 | break; | 6009 | break; |
@@ -6602,8 +6646,8 @@ out: | |||
6602 | * Note: This is pretty much the same routine as in core/datagram.c | 6646 | * Note: This is pretty much the same routine as in core/datagram.c |
6603 | * with a few changes to make lksctp work. | 6647 | * with a few changes to make lksctp work. |
6604 | */ | 6648 | */ |
6605 | static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, | 6649 | struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, |
6606 | int noblock, int *err) | 6650 | int noblock, int *err) |
6607 | { | 6651 | { |
6608 | int error; | 6652 | int error; |
6609 | struct sk_buff *skb; | 6653 | struct sk_buff *skb; |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index b31f365f18ab..e049298ecfa0 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -911,6 +911,44 @@ void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, | |||
911 | sizeof(rinfo), &rinfo); | 911 | sizeof(rinfo), &rinfo); |
912 | } | 912 | } |
913 | 913 | ||
914 | /* RFC6458, Section 5.3.6. SCTP Next Receive Information Structure | ||
915 | * (SCTP_NXTINFO) | ||
916 | */ | ||
917 | static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, | ||
918 | struct msghdr *msghdr, | ||
919 | const struct sk_buff *skb) | ||
920 | { | ||
921 | struct sctp_nxtinfo nxtinfo; | ||
922 | |||
923 | memset(&nxtinfo, 0, sizeof(nxtinfo)); | ||
924 | nxtinfo.nxt_sid = event->stream; | ||
925 | nxtinfo.nxt_ppid = event->ppid; | ||
926 | nxtinfo.nxt_flags = event->flags; | ||
927 | if (sctp_ulpevent_is_notification(event)) | ||
928 | nxtinfo.nxt_flags |= SCTP_NOTIFICATION; | ||
929 | nxtinfo.nxt_length = skb->len; | ||
930 | nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc); | ||
931 | |||
932 | put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO, | ||
933 | sizeof(nxtinfo), &nxtinfo); | ||
934 | } | ||
935 | |||
936 | void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, | ||
937 | struct msghdr *msghdr, | ||
938 | struct sock *sk) | ||
939 | { | ||
940 | struct sk_buff *skb; | ||
941 | int err; | ||
942 | |||
943 | skb = sctp_skb_recv_datagram(sk, MSG_PEEK, 1, &err); | ||
944 | if (skb != NULL) { | ||
945 | __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb), | ||
946 | msghdr, skb); | ||
947 | /* Just release refcount here. */ | ||
948 | kfree_skb(skb); | ||
949 | } | ||
950 | } | ||
951 | |||
914 | /* Do accounting for bytes received and hold a reference to the association | 952 | /* Do accounting for bytes received and hold a reference to the association |
915 | * for each skb. | 953 | * for each skb. |
916 | */ | 954 | */ |