Commit 559f0a28 authored by David S. Miller's avatar David S. Miller

Merge master.kernel.org:/pub/scm/linux/kernel/git/vxy/lksctp-dev

parents 74235a25 06ad3919
...@@ -503,6 +503,13 @@ static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu) ...@@ -503,6 +503,13 @@ static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu)
return frag; 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 /* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on * individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure * the chunk length to indicate when to stop. Make sure
......
...@@ -912,6 +912,9 @@ struct sctp_transport { ...@@ -912,6 +912,9 @@ struct sctp_transport {
*/ */
__u16 pathmaxrxt; __u16 pathmaxrxt;
/* is the Path MTU update pending on this tranport */
__u8 pmtu_pending;
/* PMTU : The current known path MTU. */ /* PMTU : The current known path MTU. */
__u32 pathmtu; __u32 pathmtu;
...@@ -1006,6 +1009,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); ...@@ -1006,6 +1009,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32);
void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t);
unsigned long sctp_transport_timeout(struct sctp_transport *); unsigned long sctp_transport_timeout(struct sctp_transport *);
void sctp_transport_reset(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 /* This is the structure we use to queue packets as they come into
...@@ -1565,6 +1569,9 @@ struct sctp_association { ...@@ -1565,6 +1569,9 @@ struct sctp_association {
*/ */
__u16 pathmaxrxt; __u16 pathmaxrxt;
/* Flag that path mtu update is pending */
__u8 pmtu_pending;
/* Association : The smallest PMTU discovered for all of the /* Association : The smallest PMTU discovered for all of the
* PMTU : peer's transport addresses. * PMTU : peer's transport addresses.
*/ */
......
...@@ -1231,6 +1231,10 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) ...@@ -1231,6 +1231,10 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
/* Get the lowest pmtu of all the transports. */ /* Get the lowest pmtu of all the transports. */
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport, transports); 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)) if (!pmtu || (t->pathmtu < pmtu))
pmtu = t->pathmtu; pmtu = t->pathmtu;
} }
......
...@@ -367,25 +367,19 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb) ...@@ -367,25 +367,19 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
struct sctp_transport *t, __u32 pmtu) struct sctp_transport *t, __u32 pmtu)
{ {
if (sock_owned_by_user(sk) || !t || (t->pathmtu == pmtu)) if (!t || (t->pathmtu == pmtu))
return; return;
if (t->param_flags & SPP_PMTUD_ENABLE) { if (sock_owned_by_user(sk)) {
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { asoc->pmtu_pending = 1;
printk(KERN_WARNING "%s: Reported pmtu %d too low, " t->pmtu_pending = 1;
"using default minimum of %d\n", return;
__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;
} }
if (t->param_flags & SPP_PMTUD_ENABLE) {
/* Update transports view of the MTU */
sctp_transport_update_pmtu(t, pmtu);
/* Update association pmtu. */ /* Update association pmtu. */
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
} }
......
...@@ -333,13 +333,20 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) ...@@ -333,13 +333,20 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
if (!sp->pf->bind_verify(sp, addr)) if (!sp->pf->bind_verify(sp, addr))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
/* We must either be unbound, or bind to the same port. */ /* We must either be unbound, or bind to the same port.
if (bp->port && (snum != bp->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:" SCTP_DEBUG_PRINTK("sctp_do_bind:"
" New port %d does not match existing port " " New port %d does not match existing port "
"%d.\n", snum, bp->port); "%d.\n", snum, bp->port);
return -EINVAL; return -EINVAL;
} }
}
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
...@@ -1655,6 +1662,9 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1655,6 +1662,9 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_free; goto out_free;
} }
if (asoc->pmtu_pending)
sctp_assoc_pending_pmtu(asoc);
/* If fragmentation is disabled and the message length exceeds the /* If fragmentation is disabled and the message length exceeds the
* association fragmentation point, return EMSGSIZE. The I-D * association fragmentation point, return EMSGSIZE. The I-D
* does not specify what this error is, but this looks like * does not specify what this error is, but this looks like
...@@ -3550,6 +3560,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, ...@@ -3550,6 +3560,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct socket *sock; struct socket *sock;
struct inet_sock *inetsk; struct inet_sock *inetsk;
struct sctp_af *af;
int err = 0; int err = 0;
/* An association cannot be branched off from an already peeled-off /* An association cannot be branched off from an already peeled-off
...@@ -3571,8 +3582,9 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, ...@@ -3571,8 +3582,9 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
/* Make peeled-off sockets more like 1-1 accepted sockets. /* Make peeled-off sockets more like 1-1 accepted sockets.
* Set the daddr and initialize id to something more random * 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 = inet_sk(sock->sk);
inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
inetsk->id = asoc->next_tsn ^ jiffies; inetsk->id = asoc->next_tsn ^ jiffies;
*sockp = sock; *sockp = sock;
...@@ -4343,11 +4355,12 @@ copy_getaddrs: ...@@ -4343,11 +4355,12 @@ copy_getaddrs:
err = -EFAULT; err = -EFAULT;
goto error; goto error;
} }
if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) {
return -EFAULT; err = -EFAULT;
goto error;
}
if (put_user(bytes_copied, optlen)) if (put_user(bytes_copied, optlen))
return -EFAULT; err = -EFAULT;
error: error:
kfree(addrs); kfree(addrs);
return err; return err;
......
...@@ -241,6 +241,45 @@ void sctp_transport_pmtu(struct sctp_transport *transport) ...@@ -241,6 +241,45 @@ void sctp_transport_pmtu(struct sctp_transport *transport)
transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; 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;
} 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 /* Caches the dst entry and source address for a transport's destination
* address. * address.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment