diff options
author | Wei Yongjun <yjwei@cn.fujitsu.com> | 2008-12-25 19:54:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-25 19:54:58 -0500 |
commit | e89c2095815d82eaa9fb85eff42f8b65b67a59cf (patch) | |
tree | a6ee89692051c0fa1328b8b79c3b9d7b44dbeab5 /net/sctp/socket.c | |
parent | 161c8d2f50109b44b664eaf23831ea1587979a61 (diff) |
sctp: Bring SCTP_MAXSEG socket option into ietf API extension compliance
Brings maxseg socket option set/get into line with the latest ietf socket
extensions API draft, while maintaining backwards compatibility.
Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 130 |
1 files changed, 107 insertions, 23 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a2de585888d0..0738843876a1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2778,32 +2778,77 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op | |||
2778 | } | 2778 | } |
2779 | 2779 | ||
2780 | /* | 2780 | /* |
2781 | * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) | 2781 | * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) |
2782 | * | 2782 | * This option will get or set the maximum size to put in any outgoing |
2783 | * This socket option specifies the maximum size to put in any outgoing | 2783 | * SCTP DATA chunk. If a message is larger than this size it will be |
2784 | * SCTP chunk. If a message is larger than this size it will be | ||
2785 | * fragmented by SCTP into the specified size. Note that the underlying | 2784 | * fragmented by SCTP into the specified size. Note that the underlying |
2786 | * SCTP implementation may fragment into smaller sized chunks when the | 2785 | * SCTP implementation may fragment into smaller sized chunks when the |
2787 | * PMTU of the underlying association is smaller than the value set by | 2786 | * PMTU of the underlying association is smaller than the value set by |
2788 | * the user. | 2787 | * the user. The default value for this option is '0' which indicates |
2788 | * the user is NOT limiting fragmentation and only the PMTU will effect | ||
2789 | * SCTP's choice of DATA chunk size. Note also that values set larger | ||
2790 | * than the maximum size of an IP datagram will effectively let SCTP | ||
2791 | * control fragmentation (i.e. the same as setting this option to 0). | ||
2792 | * | ||
2793 | * The following structure is used to access and modify this parameter: | ||
2794 | * | ||
2795 | * struct sctp_assoc_value { | ||
2796 | * sctp_assoc_t assoc_id; | ||
2797 | * uint32_t assoc_value; | ||
2798 | * }; | ||
2799 | * | ||
2800 | * assoc_id: This parameter is ignored for one-to-one style sockets. | ||
2801 | * For one-to-many style sockets this parameter indicates which | ||
2802 | * association the user is performing an action upon. Note that if | ||
2803 | * this field's value is zero then the endpoints default value is | ||
2804 | * changed (effecting future associations only). | ||
2805 | * assoc_value: This parameter specifies the maximum size in bytes. | ||
2789 | */ | 2806 | */ |
2790 | static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) | 2807 | static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) |
2791 | { | 2808 | { |
2809 | struct sctp_assoc_value params; | ||
2792 | struct sctp_association *asoc; | 2810 | struct sctp_association *asoc; |
2793 | struct sctp_sock *sp = sctp_sk(sk); | 2811 | struct sctp_sock *sp = sctp_sk(sk); |
2794 | int val; | 2812 | int val; |
2795 | 2813 | ||
2796 | if (optlen < sizeof(int)) | 2814 | if (optlen == sizeof(int)) { |
2815 | printk(KERN_WARNING | ||
2816 | "SCTP: Use of int in maxseg socket option deprecated\n"); | ||
2817 | printk(KERN_WARNING | ||
2818 | "SCTP: Use struct sctp_assoc_value instead\n"); | ||
2819 | if (copy_from_user(&val, optval, optlen)) | ||
2820 | return -EFAULT; | ||
2821 | params.assoc_id = 0; | ||
2822 | } else if (optlen == sizeof(struct sctp_assoc_value)) { | ||
2823 | if (copy_from_user(¶ms, optval, optlen)) | ||
2824 | return -EFAULT; | ||
2825 | val = params.assoc_value; | ||
2826 | } else | ||
2797 | return -EINVAL; | 2827 | return -EINVAL; |
2798 | if (get_user(val, (int __user *)optval)) | 2828 | |
2799 | return -EFAULT; | ||
2800 | if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) | 2829 | if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) |
2801 | return -EINVAL; | 2830 | return -EINVAL; |
2802 | sp->user_frag = val; | ||
2803 | 2831 | ||
2804 | /* Update the frag_point of the existing associations. */ | 2832 | asoc = sctp_id2assoc(sk, params.assoc_id); |
2805 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | 2833 | if (!asoc && params.assoc_id && sctp_style(sk, UDP)) |
2806 | asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); | 2834 | return -EINVAL; |
2835 | |||
2836 | if (asoc) { | ||
2837 | if (val == 0) { | ||
2838 | val = asoc->pathmtu; | ||
2839 | val -= sp->pf->af->net_header_len; | ||
2840 | val -= sizeof(struct sctphdr) + | ||
2841 | sizeof(struct sctp_data_chunk); | ||
2842 | } | ||
2843 | |||
2844 | asoc->frag_point = val; | ||
2845 | } else { | ||
2846 | sp->user_frag = val; | ||
2847 | |||
2848 | /* Update the frag_point of the existing associations. */ | ||
2849 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | ||
2850 | asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); | ||
2851 | } | ||
2807 | } | 2852 | } |
2808 | 2853 | ||
2809 | return 0; | 2854 | return 0; |
@@ -5100,30 +5145,69 @@ static int sctp_getsockopt_context(struct sock *sk, int len, | |||
5100 | } | 5145 | } |
5101 | 5146 | ||
5102 | /* | 5147 | /* |
5103 | * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) | 5148 | * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) |
5104 | * | 5149 | * This option will get or set the maximum size to put in any outgoing |
5105 | * This socket option specifies the maximum size to put in any outgoing | 5150 | * SCTP DATA chunk. If a message is larger than this size it will be |
5106 | * SCTP chunk. If a message is larger than this size it will be | ||
5107 | * fragmented by SCTP into the specified size. Note that the underlying | 5151 | * fragmented by SCTP into the specified size. Note that the underlying |
5108 | * SCTP implementation may fragment into smaller sized chunks when the | 5152 | * SCTP implementation may fragment into smaller sized chunks when the |
5109 | * PMTU of the underlying association is smaller than the value set by | 5153 | * PMTU of the underlying association is smaller than the value set by |
5110 | * the user. | 5154 | * the user. The default value for this option is '0' which indicates |
5155 | * the user is NOT limiting fragmentation and only the PMTU will effect | ||
5156 | * SCTP's choice of DATA chunk size. Note also that values set larger | ||
5157 | * than the maximum size of an IP datagram will effectively let SCTP | ||
5158 | * control fragmentation (i.e. the same as setting this option to 0). | ||
5159 | * | ||
5160 | * The following structure is used to access and modify this parameter: | ||
5161 | * | ||
5162 | * struct sctp_assoc_value { | ||
5163 | * sctp_assoc_t assoc_id; | ||
5164 | * uint32_t assoc_value; | ||
5165 | * }; | ||
5166 | * | ||
5167 | * assoc_id: This parameter is ignored for one-to-one style sockets. | ||
5168 | * For one-to-many style sockets this parameter indicates which | ||
5169 | * association the user is performing an action upon. Note that if | ||
5170 | * this field's value is zero then the endpoints default value is | ||
5171 | * changed (effecting future associations only). | ||
5172 | * assoc_value: This parameter specifies the maximum size in bytes. | ||
5111 | */ | 5173 | */ |
5112 | static int sctp_getsockopt_maxseg(struct sock *sk, int len, | 5174 | static int sctp_getsockopt_maxseg(struct sock *sk, int len, |
5113 | char __user *optval, int __user *optlen) | 5175 | char __user *optval, int __user *optlen) |
5114 | { | 5176 | { |
5115 | int val; | 5177 | struct sctp_assoc_value params; |
5178 | struct sctp_association *asoc; | ||
5116 | 5179 | ||
5117 | if (len < sizeof(int)) | 5180 | if (len == sizeof(int)) { |
5181 | printk(KERN_WARNING | ||
5182 | "SCTP: Use of int in maxseg socket option deprecated\n"); | ||
5183 | printk(KERN_WARNING | ||
5184 | "SCTP: Use struct sctp_assoc_value instead\n"); | ||
5185 | params.assoc_id = 0; | ||
5186 | } else if (len >= sizeof(struct sctp_assoc_value)) { | ||
5187 | len = sizeof(struct sctp_assoc_value); | ||
5188 | if (copy_from_user(¶ms, optval, sizeof(params))) | ||
5189 | return -EFAULT; | ||
5190 | } else | ||
5118 | return -EINVAL; | 5191 | return -EINVAL; |
5119 | 5192 | ||
5120 | len = sizeof(int); | 5193 | asoc = sctp_id2assoc(sk, params.assoc_id); |
5194 | if (!asoc && params.assoc_id && sctp_style(sk, UDP)) | ||
5195 | return -EINVAL; | ||
5196 | |||
5197 | if (asoc) | ||
5198 | params.assoc_value = asoc->frag_point; | ||
5199 | else | ||
5200 | params.assoc_value = sctp_sk(sk)->user_frag; | ||
5121 | 5201 | ||
5122 | val = sctp_sk(sk)->user_frag; | ||
5123 | if (put_user(len, optlen)) | 5202 | if (put_user(len, optlen)) |
5124 | return -EFAULT; | 5203 | return -EFAULT; |
5125 | if (copy_to_user(optval, &val, len)) | 5204 | if (len == sizeof(int)) { |
5126 | return -EFAULT; | 5205 | if (copy_to_user(optval, ¶ms.assoc_value, len)) |
5206 | return -EFAULT; | ||
5207 | } else { | ||
5208 | if (copy_to_user(optval, ¶ms, len)) | ||
5209 | return -EFAULT; | ||
5210 | } | ||
5127 | 5211 | ||
5128 | return 0; | 5212 | return 0; |
5129 | } | 5213 | } |