Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Geir Ola Vaagland and committed by
David S. Miller
2347c80f 0d3a421d

+125 -23
+1
include/net/sctp/sctp.h
··· 109 109 struct sctp_association *asoc); 110 110 extern struct percpu_counter sctp_sockets_allocated; 111 111 int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *); 112 + struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); 112 113 113 114 /* 114 115 * sctp/primitive.c
+1
include/net/sctp/structs.h
··· 218 218 __u32 adaptation_ind; 219 219 __u32 pd_point; 220 220 __u8 recvrcvinfo; 221 + __u8 recvnxtinfo; 221 222 222 223 atomic_t pd_mode; 223 224 /* Receive to here while partial delivery is in effect. */
+2 -7
include/net/sctp/ulpevent.h
··· 132 132 struct msghdr *); 133 133 void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event, 134 134 struct msghdr *); 135 + void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event, 136 + struct msghdr *, struct sock *sk); 135 137 136 138 __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); 137 139 ··· 160 158 } 161 159 162 160 #endif /* __sctp_ulpevent_h__ */ 163 - 164 - 165 - 166 - 167 - 168 - 169 -
+35 -12
include/uapi/linux/sctp.h
··· 96 96 #define SCTP_AUTO_ASCONF 30 97 97 #define SCTP_PEER_ADDR_THLDS 31 98 98 #define SCTP_RECVRCVINFO 32 99 + #define SCTP_RECVNXTINFO 33 99 100 100 101 /* Internal Socket Options. Some of the sctp library functions are 101 102 * implemented using these socket options. ··· 111 110 #define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ 112 111 #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ 113 112 #define SCTP_GET_ASSOC_STATS 112 /* Read only */ 113 + 114 + /* These are bit fields for msghdr->msg_flags. See section 5.1. */ 115 + /* On user space Linux, these live in <bits/socket.h> as an enum. */ 116 + enum sctp_msg_flags { 117 + MSG_NOTIFICATION = 0x8000, 118 + #define MSG_NOTIFICATION MSG_NOTIFICATION 119 + }; 114 120 115 121 /* 5.3.1 SCTP Initiation Structure (SCTP_INIT) 116 122 * ··· 195 187 sctp_assoc_t rcv_assoc_id; 196 188 }; 197 189 190 + /* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO) 191 + * 192 + * This cmsghdr structure describes SCTP receive information 193 + * of the next message that will be delivered through recvmsg() 194 + * if this information is already available when delivering 195 + * the current message. 196 + * 197 + * cmsg_level cmsg_type cmsg_data[] 198 + * ------------ ------------ ------------------- 199 + * IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo 200 + */ 201 + struct sctp_nxtinfo { 202 + __u16 nxt_sid; 203 + __u16 nxt_flags; 204 + __u32 nxt_ppid; 205 + __u32 nxt_length; 206 + sctp_assoc_t nxt_assoc_id; 207 + }; 208 + 198 209 /* 199 210 * sinfo_flags: 16 bits (unsigned integer) 200 211 * ··· 221 194 * a bitwise OR of these values. 222 195 */ 223 196 enum sctp_sinfo_flags { 224 - SCTP_UNORDERED = 1, /* Send/receive message unordered. */ 225 - SCTP_ADDR_OVER = 2, /* Override the primary destination. */ 226 - SCTP_ABORT=4, /* Send an ABORT message to the peer. */ 227 - SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ 228 - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ 197 + SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */ 198 + SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */ 199 + SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */ 200 + SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */ 201 + SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */ 202 + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */ 229 203 }; 230 204 231 205 typedef union { ··· 245 217 #define SCTP_SNDINFO SCTP_SNDINFO 246 218 SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ 247 219 #define SCTP_RCVINFO SCTP_RCVINFO 220 + SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */ 221 + #define SCTP_NXTINFO SCTP_NXTINFO 248 222 } sctp_cmsg_t; 249 223 250 224 /* ··· 872 842 __u64 sas_iodchunks; /* Ordered data chunks received */ 873 843 __u64 sas_octrlchunks; /* Control chunks sent */ 874 844 __u64 sas_ictrlchunks; /* Control chunks received */ 875 - }; 876 - 877 - /* These are bit fields for msghdr->msg_flags. See section 5.1. */ 878 - /* On user space Linux, these live in <bits/socket.h> as an enum. */ 879 - enum sctp_msg_flags { 880 - MSG_NOTIFICATION = 0x8000, 881 - #define MSG_NOTIFICATION MSG_NOTIFICATION 882 845 }; 883 846 884 847 /*
+48 -4
net/sctp/socket.c
··· 2060 2060 * flags - flags sent or received with the user message, see Section 2061 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 2063 static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, 2066 2064 struct msghdr *msg, size_t len, int noblock, 2067 2065 int flags, int *addr_len) ··· 2110 2112 sp->pf->skb_msgname(skb, msg->msg_name, addr_len); 2111 2113 } 2112 2114 2115 + /* Check if we allow SCTP_NXTINFO. */ 2116 + if (sp->recvnxtinfo) 2117 + sctp_ulpevent_read_nxtinfo(event, msg, sk); 2113 2118 /* Check if we allow SCTP_RCVINFO. */ 2114 2119 if (sp->recvrcvinfo) 2115 2120 sctp_ulpevent_read_rcvinfo(event, msg); ··· 3612 3611 return 0; 3613 3612 } 3614 3613 3614 + static int sctp_setsockopt_recvnxtinfo(struct sock *sk, 3615 + char __user *optval, 3616 + unsigned int optlen) 3617 + { 3618 + int val; 3619 + 3620 + if (optlen < sizeof(int)) 3621 + return -EINVAL; 3622 + if (get_user(val, (int __user *) optval)) 3623 + return -EFAULT; 3624 + 3625 + sctp_sk(sk)->recvnxtinfo = (val == 0) ? 0 : 1; 3626 + 3627 + return 0; 3628 + } 3629 + 3615 3630 /* API 6.2 setsockopt(), getsockopt() 3616 3631 * 3617 3632 * Applications use setsockopt() and getsockopt() to set or retrieve ··· 3781 3764 break; 3782 3765 case SCTP_RECVRCVINFO: 3783 3766 retval = sctp_setsockopt_recvrcvinfo(sk, optval, optlen); 3767 + break; 3768 + case SCTP_RECVNXTINFO: 3769 + retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen); 3784 3770 break; 3785 3771 default: 3786 3772 retval = -ENOPROTOOPT; ··· 4032 4012 sp->nodelay = 0; 4033 4013 4034 4014 sp->recvrcvinfo = 0; 4015 + sp->recvnxtinfo = 0; 4035 4016 4036 4017 /* Enable by default. */ 4037 4018 sp->v4mapped = 1; ··· 5835 5814 return 0; 5836 5815 } 5837 5816 5817 + static int sctp_getsockopt_recvnxtinfo(struct sock *sk, int len, 5818 + char __user *optval, 5819 + int __user *optlen) 5820 + { 5821 + int val = 0; 5822 + 5823 + if (len < sizeof(int)) 5824 + return -EINVAL; 5825 + 5826 + len = sizeof(int); 5827 + if (sctp_sk(sk)->recvnxtinfo) 5828 + val = 1; 5829 + if (put_user(len, optlen)) 5830 + return -EFAULT; 5831 + if (copy_to_user(optval, &val, len)) 5832 + return -EFAULT; 5833 + 5834 + return 0; 5835 + } 5836 + 5838 5837 static int sctp_getsockopt(struct sock *sk, int level, int optname, 5839 5838 char __user *optval, int __user *optlen) 5840 5839 { ··· 6000 5959 break; 6001 5960 case SCTP_RECVRCVINFO: 6002 5961 retval = sctp_getsockopt_recvrcvinfo(sk, len, optval, optlen); 5962 + break; 5963 + case SCTP_RECVNXTINFO: 5964 + retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen); 6003 5965 break; 6004 5966 default: 6005 5967 retval = -ENOPROTOOPT; ··· 6646 6602 * Note: This is pretty much the same routine as in core/datagram.c 6647 6603 * with a few changes to make lksctp work. 6648 6604 */ 6649 - static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 6650 - int noblock, int *err) 6605 + struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, 6606 + int noblock, int *err) 6651 6607 { 6652 6608 int error; 6653 6609 struct sk_buff *skb;
+38
net/sctp/ulpevent.c
··· 911 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 952 /* Do accounting for bytes received and hold a reference to the association 915 953 * for each skb. 916 954 */