aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-02-13 03:33:44 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-16 03:03:11 -0500
commit914e1c8b6980c516667375d3e55f0b6e674c8c58 (patch)
treed61194143a112ace85f6e6dfc22bc01d7173f62e /net/sctp
parentfaee47cdbfe8d74a1573c2f81ea6dbb08d735be6 (diff)
sctp: Inherit all socket options from parent correctly.
During peeloff/accept() sctp needs to save the parent socket state into the new socket so that any options set on the parent are inherited by the child socket. This was found when the parent/listener socket issues SO_BINDTODEVICE, but the data was misrouted after a route cache flush. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/ipv6.c33
-rw-r--r--net/sctp/protocol.c29
-rw-r--r--net/sctp/socket.c55
3 files changed, 51 insertions, 66 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 786227566696..a63de3f7f185 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -627,9 +627,7 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
627static struct sock *sctp_v6_create_accept_sk(struct sock *sk, 627static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
628 struct sctp_association *asoc) 628 struct sctp_association *asoc)
629{ 629{
630 struct inet_sock *inet = inet_sk(sk);
631 struct sock *newsk; 630 struct sock *newsk;
632 struct inet_sock *newinet;
633 struct ipv6_pinfo *newnp, *np = inet6_sk(sk); 631 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
634 struct sctp6_sock *newsctp6sk; 632 struct sctp6_sock *newsctp6sk;
635 633
@@ -639,17 +637,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
639 637
640 sock_init_data(NULL, newsk); 638 sock_init_data(NULL, newsk);
641 639
642 newsk->sk_type = SOCK_STREAM; 640 sctp_copy_sock(newsk, sk, asoc);
643
644 newsk->sk_prot = sk->sk_prot;
645 newsk->sk_no_check = sk->sk_no_check;
646 newsk->sk_reuse = sk->sk_reuse;
647
648 newsk->sk_destruct = inet_sock_destruct;
649 newsk->sk_family = PF_INET6;
650 newsk->sk_protocol = IPPROTO_SCTP;
651 newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
652 newsk->sk_shutdown = sk->sk_shutdown;
653 sock_reset_flag(sk, SOCK_ZAPPED); 641 sock_reset_flag(sk, SOCK_ZAPPED);
654 642
655 newsctp6sk = (struct sctp6_sock *)newsk; 643 newsctp6sk = (struct sctp6_sock *)newsk;
@@ -657,7 +645,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
657 645
658 sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped; 646 sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped;
659 647
660 newinet = inet_sk(newsk);
661 newnp = inet6_sk(newsk); 648 newnp = inet6_sk(newsk);
662 649
663 memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 650 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
@@ -665,26 +652,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
665 /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() 652 /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
666 * and getpeername(). 653 * and getpeername().
667 */ 654 */
668 newinet->sport = inet->sport;
669 newnp->saddr = np->saddr;
670 newnp->rcv_saddr = np->rcv_saddr;
671 newinet->dport = htons(asoc->peer.port);
672 sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk); 655 sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
673 656
674 /* Init the ipv4 part of the socket since we can have sockets
675 * using v6 API for ipv4.
676 */
677 newinet->uc_ttl = -1;
678 newinet->mc_loop = 1;
679 newinet->mc_ttl = 1;
680 newinet->mc_index = 0;
681 newinet->mc_list = NULL;
682
683 if (ipv4_config.no_pmtu_disc)
684 newinet->pmtudisc = IP_PMTUDISC_DONT;
685 else
686 newinet->pmtudisc = IP_PMTUDISC_WANT;
687
688 sk_refcnt_debug_inc(newsk); 657 sk_refcnt_debug_inc(newsk);
689 658
690 if (newsk->sk_prot->init(newsk)) { 659 if (newsk->sk_prot->init(newsk)) {
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index cc0b592698f9..c1e316ee7155 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -589,46 +589,21 @@ static int sctp_v4_is_ce(const struct sk_buff *skb)
589static struct sock *sctp_v4_create_accept_sk(struct sock *sk, 589static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
590 struct sctp_association *asoc) 590 struct sctp_association *asoc)
591{ 591{
592 struct inet_sock *inet = inet_sk(sk);
593 struct inet_sock *newinet;
594 struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL, 592 struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL,
595 sk->sk_prot); 593 sk->sk_prot);
594 struct inet_sock *newinet;
596 595
597 if (!newsk) 596 if (!newsk)
598 goto out; 597 goto out;
599 598
600 sock_init_data(NULL, newsk); 599 sock_init_data(NULL, newsk);
601 600
602 newsk->sk_type = SOCK_STREAM; 601 sctp_copy_sock(newsk, sk, asoc);
603
604 newsk->sk_no_check = sk->sk_no_check;
605 newsk->sk_reuse = sk->sk_reuse;
606 newsk->sk_shutdown = sk->sk_shutdown;
607
608 newsk->sk_destruct = inet_sock_destruct;
609 newsk->sk_family = PF_INET;
610 newsk->sk_protocol = IPPROTO_SCTP;
611 newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
612 sock_reset_flag(newsk, SOCK_ZAPPED); 602 sock_reset_flag(newsk, SOCK_ZAPPED);
613 603
614 newinet = inet_sk(newsk); 604 newinet = inet_sk(newsk);
615 605
616 /* Initialize sk's sport, dport, rcv_saddr and daddr for
617 * getsockname() and getpeername()
618 */
619 newinet->sport = inet->sport;
620 newinet->saddr = inet->saddr;
621 newinet->rcv_saddr = inet->rcv_saddr;
622 newinet->dport = htons(asoc->peer.port);
623 newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; 606 newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
624 newinet->pmtudisc = inet->pmtudisc;
625 newinet->id = asoc->next_tsn ^ jiffies;
626
627 newinet->uc_ttl = -1;
628 newinet->mc_loop = 1;
629 newinet->mc_ttl = 1;
630 newinet->mc_index = 0;
631 newinet->mc_list = NULL;
632 607
633 sk_refcnt_debug_inc(newsk); 608 sk_refcnt_debug_inc(newsk);
634 609
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index ff0a8f88de04..dea864f5de54 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3939,7 +3939,6 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
3939{ 3939{
3940 struct sock *sk = asoc->base.sk; 3940 struct sock *sk = asoc->base.sk;
3941 struct socket *sock; 3941 struct socket *sock;
3942 struct inet_sock *inetsk;
3943 struct sctp_af *af; 3942 struct sctp_af *af;
3944 int err = 0; 3943 int err = 0;
3945 3944
@@ -3954,18 +3953,18 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
3954 if (err < 0) 3953 if (err < 0)
3955 return err; 3954 return err;
3956 3955
3957 /* Populate the fields of the newsk from the oldsk and migrate the 3956 sctp_copy_sock(sock->sk, sk, asoc);
3958 * asoc to the newsk.
3959 */
3960 sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
3961 3957
3962 /* Make peeled-off sockets more like 1-1 accepted sockets. 3958 /* Make peeled-off sockets more like 1-1 accepted sockets.
3963 * Set the daddr and initialize id to something more random 3959 * Set the daddr and initialize id to something more random
3964 */ 3960 */
3965 af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family); 3961 af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family);
3966 af->to_sk_daddr(&asoc->peer.primary_addr, sk); 3962 af->to_sk_daddr(&asoc->peer.primary_addr, sk);
3967 inetsk = inet_sk(sock->sk); 3963
3968 inetsk->id = asoc->next_tsn ^ jiffies; 3964 /* Populate the fields of the newsk from the oldsk and migrate the
3965 * asoc to the newsk.
3966 */
3967 sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
3969 3968
3970 *sockp = sock; 3969 *sockp = sock;
3971 3970
@@ -6700,6 +6699,48 @@ done:
6700 sctp_skb_set_owner_r(skb, sk); 6699 sctp_skb_set_owner_r(skb, sk);
6701} 6700}
6702 6701
6702void sctp_copy_sock(struct sock *newsk, struct sock *sk,
6703 struct sctp_association *asoc)
6704{
6705 struct inet_sock *inet = inet_sk(sk);
6706 struct inet_sock *newinet = inet_sk(newsk);
6707
6708 newsk->sk_type = sk->sk_type;
6709 newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
6710 newsk->sk_flags = sk->sk_flags;
6711 newsk->sk_no_check = sk->sk_no_check;
6712 newsk->sk_reuse = sk->sk_reuse;
6713
6714 newsk->sk_shutdown = sk->sk_shutdown;
6715 newsk->sk_destruct = inet_sock_destruct;
6716 newsk->sk_family = sk->sk_family;
6717 newsk->sk_protocol = IPPROTO_SCTP;
6718 newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
6719 newsk->sk_sndbuf = sk->sk_sndbuf;
6720 newsk->sk_rcvbuf = sk->sk_rcvbuf;
6721 newsk->sk_lingertime = sk->sk_lingertime;
6722 newsk->sk_rcvtimeo = sk->sk_rcvtimeo;
6723 newsk->sk_sndtimeo = sk->sk_sndtimeo;
6724
6725 newinet = inet_sk(newsk);
6726
6727 /* Initialize sk's sport, dport, rcv_saddr and daddr for
6728 * getsockname() and getpeername()
6729 */
6730 newinet->sport = inet->sport;
6731 newinet->saddr = inet->saddr;
6732 newinet->rcv_saddr = inet->rcv_saddr;
6733 newinet->dport = htons(asoc->peer.port);
6734 newinet->pmtudisc = inet->pmtudisc;
6735 newinet->id = asoc->next_tsn ^ jiffies;
6736
6737 newinet->uc_ttl = inet->uc_ttl;
6738 newinet->mc_loop = 1;
6739 newinet->mc_ttl = 1;
6740 newinet->mc_index = 0;
6741 newinet->mc_list = NULL;
6742}
6743
6703/* Populate the fields of the newsk from the oldsk and migrate the assoc 6744/* Populate the fields of the newsk from the oldsk and migrate the assoc
6704 * and its messages to the newsk. 6745 * and its messages to the newsk.
6705 */ 6746 */