diff options
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 156 |
1 files changed, 82 insertions, 74 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1999592ba88c..0e4198ee2370 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -434,7 +434,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) | |||
434 | /* Initialize sk->sk_rcv_saddr from sctp_addr. */ | 434 | /* Initialize sk->sk_rcv_saddr from sctp_addr. */ |
435 | static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) | 435 | static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) |
436 | { | 436 | { |
437 | if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { | 437 | if (addr->sa.sa_family == AF_INET) { |
438 | sk->sk_v6_rcv_saddr.s6_addr32[0] = 0; | 438 | sk->sk_v6_rcv_saddr.s6_addr32[0] = 0; |
439 | sk->sk_v6_rcv_saddr.s6_addr32[1] = 0; | 439 | sk->sk_v6_rcv_saddr.s6_addr32[1] = 0; |
440 | sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); | 440 | sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); |
@@ -448,7 +448,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) | |||
448 | /* Initialize sk->sk_daddr from sctp_addr. */ | 448 | /* Initialize sk->sk_daddr from sctp_addr. */ |
449 | static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) | 449 | static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) |
450 | { | 450 | { |
451 | if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { | 451 | if (addr->sa.sa_family == AF_INET) { |
452 | sk->sk_v6_daddr.s6_addr32[0] = 0; | 452 | sk->sk_v6_daddr.s6_addr32[0] = 0; |
453 | sk->sk_v6_daddr.s6_addr32[1] = 0; | 453 | sk->sk_v6_daddr.s6_addr32[1] = 0; |
454 | sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff); | 454 | sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff); |
@@ -556,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) | |||
556 | if (IPV6_ADDR_ANY == type) | 556 | if (IPV6_ADDR_ANY == type) |
557 | return 1; | 557 | return 1; |
558 | if (type == IPV6_ADDR_MAPPED) { | 558 | if (type == IPV6_ADDR_MAPPED) { |
559 | if (sp && !sp->v4mapped) | ||
560 | return 0; | ||
561 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) | 559 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) |
562 | return 0; | 560 | return 0; |
563 | sctp_v6_map_v4(addr); | 561 | sctp_v6_map_v4(addr); |
@@ -587,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, | |||
587 | /* Note: This routine is used in input, so v4-mapped-v6 | 585 | /* Note: This routine is used in input, so v4-mapped-v6 |
588 | * are disallowed here when there is no sctp_sock. | 586 | * are disallowed here when there is no sctp_sock. |
589 | */ | 587 | */ |
590 | if (!sp || !sp->v4mapped) | ||
591 | return 0; | ||
592 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) | 588 | if (sp && ipv6_only_sock(sctp_opt2sk(sp))) |
593 | return 0; | 589 | return 0; |
594 | sctp_v6_map_v4(addr); | 590 | sctp_v6_map_v4(addr); |
@@ -675,11 +671,23 @@ out: | |||
675 | return newsk; | 671 | return newsk; |
676 | } | 672 | } |
677 | 673 | ||
678 | /* Map v4 address to mapped v6 address */ | 674 | /* Format a sockaddr for return to user space. This makes sure the return is |
679 | static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) | 675 | * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option. |
676 | */ | ||
677 | static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) | ||
680 | { | 678 | { |
681 | if (sp->v4mapped && AF_INET == addr->sa.sa_family) | 679 | if (sp->v4mapped) { |
682 | sctp_v4_map_v6(addr); | 680 | if (addr->sa.sa_family == AF_INET) |
681 | sctp_v4_map_v6(addr); | ||
682 | } else { | ||
683 | if (addr->sa.sa_family == AF_INET6 && | ||
684 | ipv6_addr_v4mapped(&addr->v6.sin6_addr)) | ||
685 | sctp_v6_map_v4(addr); | ||
686 | } | ||
687 | |||
688 | if (addr->sa.sa_family == AF_INET) | ||
689 | return sizeof(struct sockaddr_in); | ||
690 | return sizeof(struct sockaddr_in6); | ||
683 | } | 691 | } |
684 | 692 | ||
685 | /* Where did this skb come from? */ | 693 | /* Where did this skb come from? */ |
@@ -706,82 +714,68 @@ static void sctp_v6_ecn_capable(struct sock *sk) | |||
706 | inet6_sk(sk)->tclass |= INET_ECN_ECT_0; | 714 | inet6_sk(sk)->tclass |= INET_ECN_ECT_0; |
707 | } | 715 | } |
708 | 716 | ||
709 | /* Initialize a PF_INET6 socket msg_name. */ | ||
710 | static void sctp_inet6_msgname(char *msgname, int *addr_len) | ||
711 | { | ||
712 | struct sockaddr_in6 *sin6; | ||
713 | |||
714 | sin6 = (struct sockaddr_in6 *)msgname; | ||
715 | sin6->sin6_family = AF_INET6; | ||
716 | sin6->sin6_flowinfo = 0; | ||
717 | sin6->sin6_scope_id = 0; /*FIXME */ | ||
718 | *addr_len = sizeof(struct sockaddr_in6); | ||
719 | } | ||
720 | |||
721 | /* Initialize a PF_INET msgname from a ulpevent. */ | 717 | /* Initialize a PF_INET msgname from a ulpevent. */ |
722 | static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, | 718 | static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, |
723 | char *msgname, int *addrlen) | 719 | char *msgname, int *addrlen) |
724 | { | 720 | { |
725 | struct sockaddr_in6 *sin6, *sin6from; | 721 | union sctp_addr *addr; |
726 | 722 | struct sctp_association *asoc; | |
727 | if (msgname) { | 723 | union sctp_addr *paddr; |
728 | union sctp_addr *addr; | ||
729 | struct sctp_association *asoc; | ||
730 | |||
731 | asoc = event->asoc; | ||
732 | sctp_inet6_msgname(msgname, addrlen); | ||
733 | sin6 = (struct sockaddr_in6 *)msgname; | ||
734 | sin6->sin6_port = htons(asoc->peer.port); | ||
735 | addr = &asoc->peer.primary_addr; | ||
736 | 724 | ||
737 | /* Note: If we go to a common v6 format, this code | 725 | if (!msgname) |
738 | * will change. | 726 | return; |
739 | */ | ||
740 | 727 | ||
741 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | 728 | addr = (union sctp_addr *)msgname; |
742 | if (sctp_sk(asoc->base.sk)->v4mapped && | 729 | asoc = event->asoc; |
743 | AF_INET == addr->sa.sa_family) { | 730 | paddr = &asoc->peer.primary_addr; |
744 | sctp_v4_map_v6((union sctp_addr *)sin6); | ||
745 | sin6->sin6_addr.s6_addr32[3] = | ||
746 | addr->v4.sin_addr.s_addr; | ||
747 | return; | ||
748 | } | ||
749 | 731 | ||
750 | sin6from = &asoc->peer.primary_addr.v6; | 732 | if (paddr->sa.sa_family == AF_INET) { |
751 | sin6->sin6_addr = sin6from->sin6_addr; | 733 | addr->v4.sin_family = AF_INET; |
752 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 734 | addr->v4.sin_port = htons(asoc->peer.port); |
753 | sin6->sin6_scope_id = sin6from->sin6_scope_id; | 735 | addr->v4.sin_addr = paddr->v4.sin_addr; |
736 | } else { | ||
737 | addr->v6.sin6_family = AF_INET6; | ||
738 | addr->v6.sin6_flowinfo = 0; | ||
739 | if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) | ||
740 | addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id; | ||
741 | else | ||
742 | addr->v6.sin6_scope_id = 0; | ||
743 | addr->v6.sin6_port = htons(asoc->peer.port); | ||
744 | addr->v6.sin6_addr = paddr->v6.sin6_addr; | ||
754 | } | 745 | } |
746 | |||
747 | *addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr); | ||
755 | } | 748 | } |
756 | 749 | ||
757 | /* Initialize a msg_name from an inbound skb. */ | 750 | /* Initialize a msg_name from an inbound skb. */ |
758 | static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, | 751 | static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, |
759 | int *addr_len) | 752 | int *addr_len) |
760 | { | 753 | { |
754 | union sctp_addr *addr; | ||
761 | struct sctphdr *sh; | 755 | struct sctphdr *sh; |
762 | struct sockaddr_in6 *sin6; | ||
763 | |||
764 | if (msgname) { | ||
765 | sctp_inet6_msgname(msgname, addr_len); | ||
766 | sin6 = (struct sockaddr_in6 *)msgname; | ||
767 | sh = sctp_hdr(skb); | ||
768 | sin6->sin6_port = sh->source; | ||
769 | |||
770 | /* Map ipv4 address into v4-mapped-on-v6 address. */ | ||
771 | if (sctp_sk(skb->sk)->v4mapped && | ||
772 | ip_hdr(skb)->version == 4) { | ||
773 | sctp_v4_map_v6((union sctp_addr *)sin6); | ||
774 | sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr; | ||
775 | return; | ||
776 | } | ||
777 | 756 | ||
778 | /* Otherwise, just copy the v6 address. */ | 757 | if (!msgname) |
779 | sin6->sin6_addr = ipv6_hdr(skb)->saddr; | 758 | return; |
780 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { | 759 | |
760 | addr = (union sctp_addr *)msgname; | ||
761 | sh = sctp_hdr(skb); | ||
762 | |||
763 | if (ip_hdr(skb)->version == 4) { | ||
764 | addr->v4.sin_family = AF_INET; | ||
765 | addr->v4.sin_port = sh->source; | ||
766 | addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr; | ||
767 | } else { | ||
768 | addr->v6.sin6_family = AF_INET6; | ||
769 | addr->v6.sin6_flowinfo = 0; | ||
770 | addr->v6.sin6_port = sh->source; | ||
771 | addr->v6.sin6_addr = ipv6_hdr(skb)->saddr; | ||
772 | if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { | ||
781 | struct sctp_ulpevent *ev = sctp_skb2event(skb); | 773 | struct sctp_ulpevent *ev = sctp_skb2event(skb); |
782 | sin6->sin6_scope_id = ev->iif; | 774 | addr->v6.sin6_scope_id = ev->iif; |
783 | } | 775 | } |
784 | } | 776 | } |
777 | |||
778 | *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr); | ||
785 | } | 779 | } |
786 | 780 | ||
787 | /* Do we support this AF? */ | 781 | /* Do we support this AF? */ |
@@ -857,9 +851,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) | |||
857 | return 0; | 851 | return 0; |
858 | } | 852 | } |
859 | rcu_read_unlock(); | 853 | rcu_read_unlock(); |
860 | } else if (type == IPV6_ADDR_MAPPED) { | ||
861 | if (!opt->v4mapped) | ||
862 | return 0; | ||
863 | } | 854 | } |
864 | 855 | ||
865 | af = opt->pf->af; | 856 | af = opt->pf->af; |
@@ -914,6 +905,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, | |||
914 | return 1; | 905 | return 1; |
915 | } | 906 | } |
916 | 907 | ||
908 | /* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */ | ||
909 | static int sctp_getname(struct socket *sock, struct sockaddr *uaddr, | ||
910 | int *uaddr_len, int peer) | ||
911 | { | ||
912 | int rc; | ||
913 | |||
914 | rc = inet6_getname(sock, uaddr, uaddr_len, peer); | ||
915 | |||
916 | if (rc != 0) | ||
917 | return rc; | ||
918 | |||
919 | *uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk), | ||
920 | (union sctp_addr *)uaddr); | ||
921 | |||
922 | return rc; | ||
923 | } | ||
924 | |||
917 | static const struct proto_ops inet6_seqpacket_ops = { | 925 | static const struct proto_ops inet6_seqpacket_ops = { |
918 | .family = PF_INET6, | 926 | .family = PF_INET6, |
919 | .owner = THIS_MODULE, | 927 | .owner = THIS_MODULE, |
@@ -922,7 +930,7 @@ static const struct proto_ops inet6_seqpacket_ops = { | |||
922 | .connect = inet_dgram_connect, | 930 | .connect = inet_dgram_connect, |
923 | .socketpair = sock_no_socketpair, | 931 | .socketpair = sock_no_socketpair, |
924 | .accept = inet_accept, | 932 | .accept = inet_accept, |
925 | .getname = inet6_getname, | 933 | .getname = sctp_getname, |
926 | .poll = sctp_poll, | 934 | .poll = sctp_poll, |
927 | .ioctl = inet6_ioctl, | 935 | .ioctl = inet6_ioctl, |
928 | .listen = sctp_inet_listen, | 936 | .listen = sctp_inet_listen, |
@@ -974,8 +982,6 @@ static struct sctp_af sctp_af_inet6 = { | |||
974 | .copy_addrlist = sctp_v6_copy_addrlist, | 982 | .copy_addrlist = sctp_v6_copy_addrlist, |
975 | .from_skb = sctp_v6_from_skb, | 983 | .from_skb = sctp_v6_from_skb, |
976 | .from_sk = sctp_v6_from_sk, | 984 | .from_sk = sctp_v6_from_sk, |
977 | .to_sk_saddr = sctp_v6_to_sk_saddr, | ||
978 | .to_sk_daddr = sctp_v6_to_sk_daddr, | ||
979 | .from_addr_param = sctp_v6_from_addr_param, | 985 | .from_addr_param = sctp_v6_from_addr_param, |
980 | .to_addr_param = sctp_v6_to_addr_param, | 986 | .to_addr_param = sctp_v6_to_addr_param, |
981 | .cmp_addr = sctp_v6_cmp_addr, | 987 | .cmp_addr = sctp_v6_cmp_addr, |
@@ -1005,7 +1011,9 @@ static struct sctp_pf sctp_pf_inet6 = { | |||
1005 | .send_verify = sctp_inet6_send_verify, | 1011 | .send_verify = sctp_inet6_send_verify, |
1006 | .supported_addrs = sctp_inet6_supported_addrs, | 1012 | .supported_addrs = sctp_inet6_supported_addrs, |
1007 | .create_accept_sk = sctp_v6_create_accept_sk, | 1013 | .create_accept_sk = sctp_v6_create_accept_sk, |
1008 | .addr_v4map = sctp_v6_addr_v4map, | 1014 | .addr_to_user = sctp_v6_addr_to_user, |
1015 | .to_sk_saddr = sctp_v6_to_sk_saddr, | ||
1016 | .to_sk_daddr = sctp_v6_to_sk_daddr, | ||
1009 | .af = &sctp_af_inet6, | 1017 | .af = &sctp_af_inet6, |
1010 | }; | 1018 | }; |
1011 | 1019 | ||