diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:00 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2009-09-04 18:21:00 -0400 |
commit | f68b2e05f326971cd76c65aa91a1a41771dd7485 (patch) | |
tree | 2940d83f3787570cc030791378ee23b89b941662 | |
parent | cb95ea32a457871f72752164de8d94fa20f4703c (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.h | 7 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 1 | ||||
-rw-r--r-- | net/sctp/associola.c | 6 | ||||
-rw-r--r-- | net/sctp/socket.c | 11 |
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. */ |
489 | static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu) | 489 | static 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; |