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 /net/sctp | |
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>
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/socket.c | 107 |
1 files changed, 98 insertions, 9 deletions
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, | 6009 | retval = sctp_getsockopt_default_send_param(sk, len, |
5925 | optval, optlen); | 6010 | optval, optlen); |
5926 | break; | 6011 | break; |
6012 | case SCTP_DEFAULT_SNDINFO: | ||
6013 | retval = sctp_getsockopt_default_sndinfo(sk, len, | ||
6014 | optval, optlen); | ||
6015 | break; | ||
5927 | case SCTP_PRIMARY_ADDR: | 6016 | case SCTP_PRIMARY_ADDR: |
5928 | retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); | 6017 | retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); |
5929 | break; | 6018 | break; |