aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:21:00 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:21:00 -0400
commitf68b2e05f326971cd76c65aa91a1a41771dd7485 (patch)
tree2940d83f3787570cc030791378ee23b89b941662
parentcb95ea32a457871f72752164de8d94fa20f4703c (diff)
sctp: Fix SCTP_MAXSEG socket option to comply to spec.
We had a bug that we never stored the user-defined value for MAXSEG when setting the value on an association. Thus future PMTU events ended up re-writing the frag point and increasing it past user limit. Additionally, when setting the option on the socket/endpoint, we effect all current associations, which is against spec. Now, we store the user 'maxseg' value along with the computed 'frag_point'. We inherit 'maxseg' from the socket at association creation and use it as an upper limit for 'frag_point' when its set. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
-rw-r--r--include/net/sctp/sctp.h7
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--net/sctp/associola.c6
-rw-r--r--net/sctp/socket.c11
4 files changed, 11 insertions, 14 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index d16a304cbed4..8a6d5297de16 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -486,15 +486,16 @@ static inline __s32 sctp_jitter(__u32 rto)
486} 486}
487 487
488/* Break down data chunks at this point. */ 488/* Break down data chunks at this point. */
489static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu) 489static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
490{ 490{
491 struct sctp_sock *sp = sctp_sk(asoc->base.sk);
491 int frag = pmtu; 492 int frag = pmtu;
492 493
493 frag -= sp->pf->af->net_header_len; 494 frag -= sp->pf->af->net_header_len;
494 frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk); 495 frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk);
495 496
496 if (sp->user_frag) 497 if (asoc->user_frag)
497 frag = min_t(int, frag, sp->user_frag); 498 frag = min_t(int, frag, asoc->user_frag);
498 499
499 frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN); 500 frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN);
500 501
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index df4c6321996d..b10612810f56 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1763,6 +1763,7 @@ struct sctp_association {
1763 1763
1764 /* The message size at which SCTP fragmentation will occur. */ 1764 /* The message size at which SCTP fragmentation will occur. */
1765 __u32 frag_point; 1765 __u32 frag_point;
1766 __u32 user_frag;
1766 1767
1767 /* Counter used to count INIT errors. */ 1768 /* Counter used to count INIT errors. */
1768 int init_err_counter; 1769 int init_err_counter;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 39c3821b7d3d..1f05b942564e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -112,6 +112,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
112 asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) 112 asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000)
113 * 1000; 113 * 1000;
114 asoc->frag_point = 0; 114 asoc->frag_point = 0;
115 asoc->user_frag = sp->user_frag;
115 116
116 /* Set the association max_retrans and RTO values from the 117 /* Set the association max_retrans and RTO values from the
117 * socket values. 118 * socket values.
@@ -674,7 +675,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
674 "%d\n", asoc, asoc->pathmtu); 675 "%d\n", asoc, asoc->pathmtu);
675 peer->pmtu_pending = 0; 676 peer->pmtu_pending = 0;
676 677
677 asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); 678 asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
678 679
679 /* The asoc->peer.port might not be meaningful yet, but 680 /* The asoc->peer.port might not be meaningful yet, but
680 * initialize the packet structure anyway. 681 * initialize the packet structure anyway.
@@ -1330,9 +1331,8 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
1330 } 1331 }
1331 1332
1332 if (pmtu) { 1333 if (pmtu) {
1333 struct sctp_sock *sp = sctp_sk(asoc->base.sk);
1334 asoc->pathmtu = pmtu; 1334 asoc->pathmtu = pmtu;
1335 asoc->frag_point = sctp_frag_point(sp, pmtu); 1335 asoc->frag_point = sctp_frag_point(asoc, pmtu);
1336 } 1336 }
1337 1337
1338 SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", 1338 SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 95a5623d79a0..89af37a6c871 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2243,7 +2243,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
2243 sctp_assoc_sync_pmtu(asoc); 2243 sctp_assoc_sync_pmtu(asoc);
2244 } else if (asoc) { 2244 } else if (asoc) {
2245 asoc->pathmtu = params->spp_pathmtu; 2245 asoc->pathmtu = params->spp_pathmtu;
2246 sctp_frag_point(sp, params->spp_pathmtu); 2246 sctp_frag_point(asoc, params->spp_pathmtu);
2247 } else { 2247 } else {
2248 sp->pathmtu = params->spp_pathmtu; 2248 sp->pathmtu = params->spp_pathmtu;
2249 } 2249 }
@@ -2880,15 +2880,10 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl
2880 val -= sizeof(struct sctphdr) + 2880 val -= sizeof(struct sctphdr) +
2881 sizeof(struct sctp_data_chunk); 2881 sizeof(struct sctp_data_chunk);
2882 } 2882 }
2883 2883 asoc->user_frag = val;
2884 asoc->frag_point = val; 2884 asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
2885 } else { 2885 } else {
2886 sp->user_frag = val; 2886 sp->user_frag = val;
2887
2888 /* Update the frag_point of the existing associations. */
2889 list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
2890 asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
2891 }
2892 } 2887 }
2893 2888
2894 return 0; 2889 return 0;