aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorGeir Ola Vaagland <geirola@gmail.com>2014-07-12 14:30:38 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-16 17:40:03 -0400
commit2347c80ff127b94ddaa675e2b78ab4cef46dc905 (patch)
tree5fe57c8b7814f629cb773bbea0c1a9f8eba035d0 /net/sctp
parent0d3a421d284812d07970b4ccee74d4fa38737e4d (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.c52
-rw-r--r--net/sctp/ulpevent.c38
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 */
2063static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
2064
2065static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, 2063static 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
3615static 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
5838static 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
5817static int sctp_getsockopt(struct sock *sk, int level, int optname, 5858static 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 */
6605static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 6649struct 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 */
917static 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
936void 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 */