diff options
-rw-r--r-- | include/net/sctp/sctp.h | 7 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 6 | ||||
-rw-r--r-- | net/sctp/associola.c | 4 | ||||
-rw-r--r-- | net/sctp/input.c | 8 | ||||
-rw-r--r-- | net/sctp/socket.c | 3 |
5 files changed, 27 insertions, 1 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index dda72bf5b9b4..16baef4dab7e 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -503,6 +503,13 @@ static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu) return frag; } +static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc) +{ + + sctp_assoc_sync_pmtu(asoc); + asoc->pmtu_pending = 0; +} + /* Walk through a list of TLV parameters. Don't trust the * individual parameter lengths and instead depend on * the chunk length to indicate when to stop. Make sure diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index dc0e70cb0f8b..ee4559b11302 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -912,6 +912,9 @@ struct sctp_transport { */ __u16 pathmaxrxt; + /* is the Path MTU update pending on this tranport */ + __u8 pmtu_pending; + /* PMTU : The current known path MTU. */ __u32 pathmtu; @@ -1566,6 +1569,9 @@ struct sctp_association { */ __u16 pathmaxrxt; + /* Flag that path mtu update is pending */ + __u8 pmtu_pending; + /* Association : The smallest PMTU discovered for all of the * PMTU : peer's transport addresses. */ diff --git a/net/sctp/associola.c b/net/sctp/associola.c index df94e3cdfba3..498edb0cd4e5 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1231,6 +1231,10 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) /* Get the lowest pmtu of all the transports. */ list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, struct sctp_transport, transports); + if (t->pmtu_pending && t->dst) { + sctp_transport_update_pmtu(t, dst_mtu(t->dst)); + t->pmtu_pending = 0; + } if (!pmtu || (t->pathmtu < pmtu)) pmtu = t->pathmtu; } diff --git a/net/sctp/input.c b/net/sctp/input.c index 45d6a644cf06..d57ff7f3c576 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -367,9 +367,15 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb) void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t, __u32 pmtu) { - if (sock_owned_by_user(sk) || !t || (t->pathmtu == pmtu)) + if (!t || (t->pathmtu == pmtu)) return; + if (sock_owned_by_user(sk)) { + asoc->pmtu_pending = 1; + t->pmtu_pending = 1; + return; + } + if (t->param_flags & SPP_PMTUD_ENABLE) { /* Update transports view of the MTU */ sctp_transport_update_pmtu(t, pmtu); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 45510c46c223..6edaaa009d62 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1662,6 +1662,9 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_free; } + if (asoc->pmtu_pending) + sctp_assoc_pending_pmtu(asoc); + /* If fragmentation is disabled and the message length exceeds the * association fragmentation point, return EMSGSIZE. The I-D * does not specify what this error is, but this looks like |