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 | |
| 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>
| -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 | } |
