diff options
| author | Geir Ola Vaagland <geirola@gmail.com> | 2014-07-12 14:30:39 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-07-16 17:40:04 -0400 |
| commit | 6b3fd5f3a2bbc8464a8e0bf134a183b8fa026439 (patch) | |
| tree | 0c8fbc13226cbaa0e21401b0d1d438c6764d45f2 | |
| parent | 2347c80ff127b94ddaa675e2b78ab4cef46dc905 (diff) | |
net: sctp: implement rfc6458, 8.1.31. SCTP_DEFAULT_SNDINFO support
This patch implements section 8.1.31. of RFC6458, which adds support
for setting/retrieving SCTP_DEFAULT_SNDINFO:
Applications that wish to use the sendto() system call may wish
to specify a default set of parameters that would normally be
supplied through the inclusion of ancillary data. This socket
option allows such an application to set the default sctp_sndinfo
structure. The application that wishes to use this socket option
simply passes the sctp_sndinfo structure (defined in Section 5.3.4)
to this call. The input parameters accepted by this call include
snd_sid, snd_flags, snd_ppid, and snd_context. The snd_flags
parameter is composed of a bitwise OR of SCTP_UNORDERED, SCTP_EOF,
and SCTP_SENDALL. The snd_assoc_id field specifies the association
to which to apply the parameters. For a one-to-many style socket,
any of the predefined constants are also allowed in this field.
The field is ignored for one-to-one style sockets.
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>
| -rw-r--r-- | include/uapi/linux/sctp.h | 1 | ||||
| -rw-r--r-- | net/sctp/socket.c | 107 |
2 files changed, 99 insertions, 9 deletions
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index 222f82ffeca4..ce70fe6b45df 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h | |||
| @@ -97,6 +97,7 @@ typedef __s32 sctp_assoc_t; | |||
| 97 | #define SCTP_PEER_ADDR_THLDS 31 | 97 | #define SCTP_PEER_ADDR_THLDS 31 |
| 98 | #define SCTP_RECVRCVINFO 32 | 98 | #define SCTP_RECVRCVINFO 32 |
| 99 | #define SCTP_RECVNXTINFO 33 | 99 | #define SCTP_RECVNXTINFO 33 |
| 100 | #define SCTP_DEFAULT_SNDINFO 34 | ||
| 100 | 101 | ||
| 101 | /* Internal Socket Options. Some of the sctp library functions are | 102 | /* Internal Socket Options. Some of the sctp library functions are |
| 102 | * implemented using these socket options. | 103 | * implemented using these socket options. |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9bca87ee5152..d95a50c013c9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -2770,19 +2770,22 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, | |||
| 2770 | char __user *optval, | 2770 | char __user *optval, |
| 2771 | unsigned int optlen) | 2771 | unsigned int optlen) |
| 2772 | { | 2772 | { |
| 2773 | struct sctp_sndrcvinfo info; | ||
| 2774 | struct sctp_association *asoc; | ||
| 2775 | struct sctp_sock *sp = sctp_sk(sk); | 2773 | struct sctp_sock *sp = sctp_sk(sk); |
| 2774 | struct sctp_association *asoc; | ||
| 2775 | struct sctp_sndrcvinfo info; | ||
| 2776 | 2776 | ||
| 2777 | if (optlen != sizeof(struct sctp_sndrcvinfo)) | 2777 | if (optlen != sizeof(info)) |
| 2778 | return -EINVAL; | 2778 | return -EINVAL; |
| 2779 | if (copy_from_user(&info, optval, optlen)) | 2779 | if (copy_from_user(&info, optval, optlen)) |
| 2780 | return -EFAULT; | 2780 | return -EFAULT; |
| 2781 | if (info.sinfo_flags & | ||
| 2782 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
| 2783 | SCTP_ABORT | SCTP_EOF)) | ||
| 2784 | return -EINVAL; | ||
| 2781 | 2785 | ||
| 2782 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); | 2786 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); |
| 2783 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) | 2787 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) |
| 2784 | return -EINVAL; | 2788 | return -EINVAL; |
| 2785 | |||
| 2786 | if (asoc) { | 2789 | if (asoc) { |
| 2787 | asoc->default_stream = info.sinfo_stream; | 2790 | asoc->default_stream = info.sinfo_stream; |
| 2788 | asoc->default_flags = info.sinfo_flags; | 2791 | asoc->default_flags = info.sinfo_flags; |
| @@ -2800,6 +2803,44 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, | |||
| 2800 | return 0; | 2803 | return 0; |
| 2801 | } | 2804 | } |
| 2802 | 2805 | ||
| 2806 | /* RFC6458, Section 8.1.31. Set/get Default Send Parameters | ||
| 2807 | * (SCTP_DEFAULT_SNDINFO) | ||
| 2808 | */ | ||
| 2809 | static int sctp_setsockopt_default_sndinfo(struct sock *sk, | ||
| 2810 | char __user *optval, | ||
| 2811 | unsigned int optlen) | ||
| 2812 | { | ||
| 2813 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 2814 | struct sctp_association *asoc; | ||
| 2815 | struct sctp_sndinfo info; | ||
| 2816 | |||
| 2817 | if (optlen != sizeof(info)) | ||
| 2818 | return -EINVAL; | ||
| 2819 | if (copy_from_user(&info, optval, optlen)) | ||
| 2820 | return -EFAULT; | ||
| 2821 | if (info.snd_flags & | ||
| 2822 | ~(SCTP_UNORDERED | SCTP_ADDR_OVER | | ||
| 2823 | SCTP_ABORT | SCTP_EOF)) | ||
| 2824 | return -EINVAL; | ||
| 2825 | |||
| 2826 | asoc = sctp_id2assoc(sk, info.snd_assoc_id); | ||
| 2827 | if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) | ||
| 2828 | return -EINVAL; | ||
| 2829 | if (asoc) { | ||
| 2830 | asoc->default_stream = info.snd_sid; | ||
| 2831 | asoc->default_flags = info.snd_flags; | ||
| 2832 | asoc->default_ppid = info.snd_ppid; | ||
| 2833 | asoc->default_context = info.snd_context; | ||
| 2834 | } else { | ||
| 2835 | sp->default_stream = info.snd_sid; | ||
| 2836 | sp->default_flags = info.snd_flags; | ||
| 2837 | sp->default_ppid = info.snd_ppid; | ||
| 2838 | sp->default_context = info.snd_context; | ||
| 2839 | } | ||
| 2840 | |||
| 2841 | return 0; | ||
| 2842 | } | ||
| 2843 | |||
| 2803 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) | 2844 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) |
| 2804 | * | 2845 | * |
| 2805 | * Requests that the local SCTP stack use the enclosed peer address as | 2846 | * Requests that the local SCTP stack use the enclosed peer address as |
| @@ -3725,6 +3766,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
| 3725 | retval = sctp_setsockopt_default_send_param(sk, optval, | 3766 | retval = sctp_setsockopt_default_send_param(sk, optval, |
| 3726 | optlen); | 3767 | optlen); |
| 3727 | break; | 3768 | break; |
| 3769 | case SCTP_DEFAULT_SNDINFO: | ||
| 3770 | retval = sctp_setsockopt_default_sndinfo(sk, optval, optlen); | ||
| 3771 | break; | ||
| 3728 | case SCTP_PRIMARY_ADDR: | 3772 | case SCTP_PRIMARY_ADDR: |
| 3729 | retval = sctp_setsockopt_primary_addr(sk, optval, optlen); | 3773 | retval = sctp_setsockopt_primary_addr(sk, optval, optlen); |
| 3730 | break; | 3774 | break; |
| @@ -5027,14 +5071,14 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 5027 | int len, char __user *optval, | 5071 | int len, char __user *optval, |
| 5028 | int __user *optlen) | 5072 | int __user *optlen) |
| 5029 | { | 5073 | { |
| 5030 | struct sctp_sndrcvinfo info; | ||
| 5031 | struct sctp_association *asoc; | ||
| 5032 | struct sctp_sock *sp = sctp_sk(sk); | 5074 | struct sctp_sock *sp = sctp_sk(sk); |
| 5075 | struct sctp_association *asoc; | ||
| 5076 | struct sctp_sndrcvinfo info; | ||
| 5033 | 5077 | ||
| 5034 | if (len < sizeof(struct sctp_sndrcvinfo)) | 5078 | if (len < sizeof(info)) |
| 5035 | return -EINVAL; | 5079 | return -EINVAL; |
| 5036 | 5080 | ||
| 5037 | len = sizeof(struct sctp_sndrcvinfo); | 5081 | len = sizeof(info); |
| 5038 | 5082 | ||
| 5039 | if (copy_from_user(&info, optval, len)) | 5083 | if (copy_from_user(&info, optval, len)) |
| 5040 | return -EFAULT; | 5084 | return -EFAULT; |
| @@ -5042,7 +5086,6 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 5042 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); | 5086 | asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); |
| 5043 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) | 5087 | if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) |
| 5044 | return -EINVAL; | 5088 | return -EINVAL; |
| 5045 | |||
| 5046 | if (asoc) { | 5089 | if (asoc) { |
| 5047 | info.sinfo_stream = asoc->default_stream; | 5090 | info.sinfo_stream = asoc->default_stream; |
| 5048 | info.sinfo_flags = asoc->default_flags; | 5091 | info.sinfo_flags = asoc->default_flags; |
| @@ -5065,6 +5108,48 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, | |||
| 5065 | return 0; | 5108 | return 0; |
| 5066 | } | 5109 | } |
| 5067 | 5110 | ||
| 5111 | /* RFC6458, Section 8.1.31. Set/get Default Send Parameters | ||
| 5112 | * (SCTP_DEFAULT_SNDINFO) | ||
| 5113 | */ | ||
| 5114 | static int sctp_getsockopt_default_sndinfo(struct sock *sk, int len, | ||
| 5115 | char __user *optval, | ||
| 5116 | int __user *optlen) | ||
| 5117 | { | ||
| 5118 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 5119 | struct sctp_association *asoc; | ||
| 5120 | struct sctp_sndinfo info; | ||
| 5121 | |||
| 5122 | if (len < sizeof(info)) | ||
| 5123 | return -EINVAL; | ||
| 5124 | |||
| 5125 | len = sizeof(info); | ||
| 5126 | |||
| 5127 | if (copy_from_user(&info, optval, len)) | ||
| 5128 | return -EFAULT; | ||
| 5129 | |||
| 5130 | asoc = sctp_id2assoc(sk, info.snd_assoc_id); | ||
| 5131 | if (!asoc && info.snd_assoc_id && sctp_style(sk, UDP)) | ||
| 5132 | return -EINVAL; | ||
| 5133 | if (asoc) { | ||
| 5134 | info.snd_sid = asoc->default_stream; | ||
| 5135 | info.snd_flags = asoc->default_flags; | ||
| 5136 | info.snd_ppid = asoc->default_ppid; | ||
| 5137 | info.snd_context = asoc->default_context; | ||
| 5138 | } else { | ||
| 5139 | info.snd_sid = sp->default_stream; | ||
| 5140 | info.snd_flags = sp->default_flags; | ||
| 5141 | info.snd_ppid = sp->default_ppid; | ||
| 5142 | info.snd_context = sp->default_context; | ||
| 5143 | } | ||
| 5144 | |||
| 5145 | if (put_user(len, optlen)) | ||
| 5146 | return -EFAULT; | ||
| 5147 | if (copy_to_user(optval, &info, len)) | ||
| 5148 | return -EFAULT; | ||
| 5149 | |||
| 5150 | return 0; | ||
| 5151 | } | ||
| 5152 | |||
| 5068 | /* | 5153 | /* |
| 5069 | * | 5154 | * |
| 5070 | * 7.1.5 SCTP_NODELAY | 5155 | * 7.1.5 SCTP_NODELAY |
| @@ -5924,6 +6009,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 5924 | retval = sctp_getsockopt_default_send_param(sk, len, | ||
