aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:56 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:56 -0400
commit3e62abf92f34d75fe22352d8d102e3cd2755804d (patch)
treee8e175b95bdf137565a301e382d6f7c22e4a417e /net
parentbec9640bb0d451813b1bb1f2cc13a5bfb17c3e48 (diff)
sctp: Fix data segmentation with small frag_size
Since an application may specify the maximum SCTP fragment size that all data should be fragmented to, we need to fix how we do segmentation. Right now, if a user specifies a small fragment size, the segment size can go negative in the presence of AUTH or COOKIE_ECHO bundling. What we need to do is track the largest possbile DATA chunk that can fit into the mtu. Then if the fragment size specified is bigger then this maximum length, we'll shrink it down. Otherwise, we just use the smaller segment size without changing it further. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/chunk.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef90950c..9292294dbc12 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -158,6 +158,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
158{ 158{
159 int max, whole, i, offset, over, err; 159 int max, whole, i, offset, over, err;
160 int len, first_len; 160 int len, first_len;
161 int max_data;
161 struct sctp_chunk *chunk; 162 struct sctp_chunk *chunk;
162 struct sctp_datamsg *msg; 163 struct sctp_datamsg *msg;
163 struct list_head *pos, *temp; 164 struct list_head *pos, *temp;
@@ -179,8 +180,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
179 __func__, msg, msg->expires_at, jiffies); 180 __func__, msg, msg->expires_at, jiffies);
180 } 181 }
181 182
182 max = asoc->frag_point; 183 /* This is the biggest possible DATA chunk that can fit into
184 * the packet
185 */
186 max_data = asoc->pathmtu -
187 sctp_sk(asoc->base.sk)->pf->af->net_header_len -
188 sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk);
183 189
190 max = asoc->frag_point;
184 /* If the the peer requested that we authenticate DATA chunks 191 /* If the the peer requested that we authenticate DATA chunks
185 * we need to accound for bundling of the AUTH chunks along with 192 * we need to accound for bundling of the AUTH chunks along with
186 * DATA. 193 * DATA.
@@ -189,23 +196,30 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
189 struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); 196 struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
190 197
191 if (hmac_desc) 198 if (hmac_desc)
192 max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) + 199 max_data -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
193 hmac_desc->hmac_len); 200 hmac_desc->hmac_len);
194 } 201 }
195 202
203 /* Now, check if we need to reduce our max */
204 if (max > max_data)
205 max = max_data;
206
196 whole = 0; 207 whole = 0;
197 first_len = max; 208 first_len = max;
198 209
199 /* Encourage Cookie-ECHO bundling. */ 210 /* Encourage Cookie-ECHO bundling. */
200 if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { 211 if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
201 whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); 212 max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;
202 213
203 /* Account for the DATA to be bundled with the COOKIE-ECHO. */ 214 /* This is the biggesr first_len we can have */
204 if (whole) { 215 if (first_len > max_data)
205 first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; 216 first_len = max_data;
206 msg_len -= first_len; 217 }
207 whole = 1; 218
208 } 219 /* Account for a different sized first fragment */
220 if (msg_len >= first_len) {
221 msg_len -= first_len;
222 whole = 1;
209 } 223 }
210 224
211 /* How many full sized? How many bytes leftover? */ 225 /* How many full sized? How many bytes leftover? */