From d570ee490fb18220262cfe41284d7aede797ed4f Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 15 May 2007 16:32:39 -0400 Subject: [SCTP]: Correctly set daddr for IPv6 sockets during peeloff During peeloff of AF_INET6 socket, the inet6_sk(sk)->daddr wasn't set correctly since the code was assuming IPv4 only. Now we use a correct call to set the destination address. Signed-off-by: Vlad Yasevich Acked-by: Sridhar Samudrala --- net/sctp/socket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 4dcdabf5647..d370c945a75 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3550,6 +3550,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, struct sock *sk = asoc->base.sk; struct socket *sock; struct inet_sock *inetsk; + struct sctp_af *af; int err = 0; /* An association cannot be branched off from an already peeled-off @@ -3571,8 +3572,9 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, /* Make peeled-off sockets more like 1-1 accepted sockets. * Set the daddr and initialize id to something more random */ + af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family); + af->to_sk_daddr(&asoc->peer.primary_addr, sk); inetsk = inet_sk(sock->sk); - inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; inetsk->id = asoc->next_tsn ^ jiffies; *sockp = sock; -- cgit v1.2.3 From 8b35805693e1915829355723537f99f1b8bc9cc0 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 15 May 2007 17:14:58 -0400 Subject: [SCTP]: Allow unspecified port in sctp_bindx() Allow sctp_bindx() to accept multiple address with unspecified port. In this case, all addresses inherit the first bound port. We still catch full mis-matches. Signed-off-by: Vlad Yasevich Acked-by: Sridhar Samudrala --- net/sctp/socket.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d370c945a75..a5b6e559451 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -333,12 +333,19 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) if (!sp->pf->bind_verify(sp, addr)) return -EADDRNOTAVAIL; - /* We must either be unbound, or bind to the same port. */ - if (bp->port && (snum != bp->port)) { - SCTP_DEBUG_PRINTK("sctp_do_bind:" + /* We must either be unbound, or bind to the same port. + * It's OK to allow 0 ports if we are already bound. + * We'll just inhert an already bound port in this case + */ + if (bp->port) { + if (!snum) + snum = bp->port; + else if (snum != bp->port) { + SCTP_DEBUG_PRINTK("sctp_do_bind:" " New port %d does not match existing port " "%d.\n", snum, bp->port); - return -EINVAL; + return -EINVAL; + } } if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) -- cgit v1.2.3 From fe979ac169970b3d12facd6565766735862395c5 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 23 May 2007 11:11:37 -0400 Subject: [SCTP] Fix leak in sctp_getsockopt_local_addrs when copy_to_user fails If the copy_to_user or copy_user calls fail in sctp_getsockopt_local_addrs(), the function should free locally allocated storage before returning error. Spotted by Coverity. Signed-off-by: Vlad Yasevich Acked-by: Sridhar Samudrala --- net/sctp/socket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a5b6e559451..45510c46c22 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4352,11 +4352,12 @@ copy_getaddrs: err = -EFAULT; goto error; } - if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) - return -EFAULT; + if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) { + err = -EFAULT; + goto error; + } if (put_user(bytes_copied, optlen)) - return -EFAULT; - + err = -EFAULT; error: kfree(addrs); return err; -- cgit v1.2.3 From c910b47e1811b3f8b184108c48de3d7af3e2999b Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 7 Jun 2007 13:47:03 -0400 Subject: [SCTP] Update pmtu handling to be similar to tcp Introduce new function sctp_transport_update_pmtu that updates the transports and destination caches view of the path mtu. Signed-off-by: Vlad Yasevich Acked-by: Sridhar Samudrala --- include/net/sctp/structs.h | 1 + net/sctp/input.c | 16 ++-------------- net/sctp/transport.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5e81984b847..dc0e70cb0f8 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1006,6 +1006,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); unsigned long sctp_transport_timeout(struct sctp_transport *); void sctp_transport_reset(struct sctp_transport *); +void sctp_transport_update_pmtu(struct sctp_transport *, u32); /* This is the structure we use to queue packets as they come into diff --git a/net/sctp/input.c b/net/sctp/input.c index 885109fb3dd..45d6a644cf0 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -371,20 +371,8 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, return; if (t->param_flags & SPP_PMTUD_ENABLE) { - if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { - printk(KERN_WARNING "%s: Reported pmtu %d too low, " - "using default minimum of %d\n", - __FUNCTION__, pmtu, - SCTP_DEFAULT_MINSEGMENT); - /* Use default minimum segment size and disable - * pmtu discovery on this transport. - */ - t->pathmtu = SCTP_DEFAULT_MINSEGMENT; - t->param_flags = (t->param_flags & ~SPP_PMTUD) | - SPP_PMTUD_DISABLE; - } else { - t->pathmtu = pmtu; - } + /* Update transports view of the MTU */ + sctp_transport_update_pmtu(t, pmtu); /* Update association pmtu. */ sctp_assoc_sync_pmtu(asoc); diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 961df275d5b..e14c271cf28 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -241,6 +241,47 @@ void sctp_transport_pmtu(struct sctp_transport *transport) transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } +/* this is a complete rip-off from __sk_dst_check + * the cookie is always 0 since this is how it's used in the + * pmtu code + */ +static struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t) +{ + struct dst_entry *dst = t->dst; + + if (dst && dst->obsolete && dst->ops->check(dst, 0) == NULL) { + dst_release(t->dst); + t->dst = NULL; + return NULL; + } + + return dst; +} + +void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) +{ + struct dst_entry *dst; + + if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { + printk(KERN_WARNING "%s: Reported pmtu %d too low, " + "using default minimum of %d\n", + __FUNCTION__, pmtu, + SCTP_DEFAULT_MINSEGMENT); + /* Use default minimum segment size and disable + * pmtu discovery on this transport. + */ + t->pathmtu = SCTP_DEFAULT_MINSEGMENT; + t->param_flags = (t->param_flags & ~SPP_PMTUD) | + SPP_PMTUD_DISABLE; + } else { + t->pathmtu = pmtu; + } + + dst = sctp_transport_dst_check(t); + if (dst) + dst->ops->update_pmtu(dst, pmtu); +} + /* Caches the dst entry and source address for a transport's destination * address. */ -- cgit v1.2.3 From 8a4794914f9cf2681235ec2311e189fe307c28c7 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Thu, 7 Jun 2007 14:21:05 -0400 Subject: [SCTP] Flag a pmtu change request Currently, if the socket is owned by the user, we drop the ICMP message. As a result SCTP forgets that path MTU changed and never adjusting it's estimate. This causes all subsequent packets to be fragmented. With this patch, we'll flag the association that it needs to udpate it's estimate based on the already updated routing information. Signed-off-by: Vlad Yasevich Acked-by: Sridhar Samudrala --- include/net/sctp/sctp.h | 7 +++++++ include/net/sctp/structs.h | 6 ++++++ net/sctp/associola.c | 4 ++++ net/sctp/input.c | 8 +++++++- net/sctp/socket.c | 3 +++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index dda72bf5b9b..16baef4dab7 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 dc0e70cb0f8..ee4559b1130 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 df94e3cdfba..498edb0cd4e 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 45d6a644cf0..d57ff7f3c57 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 45510c46c22..6edaaa009d6 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 -- cgit v1.2.3 From 06ad391919b2078ec2e012f0593014b88e7a6c4e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 12 Jun 2007 15:26:22 -0400 Subject: [SCTP] Don't disable PMTU discovery when mtu is small Right now, when we receive a mtu estimate smaller then minim threshold in the ICMP message, we disable the path mtu discovery on the transport. This leads to the never increasing sctp fragmentation point even when the real path mtu has increased. Signed-off-by: Vlad Yasevich --- net/sctp/transport.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index e14c271cf28..5f467c914f8 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -271,8 +271,6 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) * pmtu discovery on this transport. */ t->pathmtu = SCTP_DEFAULT_MINSEGMENT; - t->param_flags = (t->param_flags & ~SPP_PMTUD) | - SPP_PMTUD_DISABLE; } else { t->pathmtu = pmtu; } -- cgit v1.2.3