diff options
| -rw-r--r-- | net/ipv6/addrconf.c | 344 |
1 files changed, 240 insertions, 104 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ff895da6395b..a34d1504deb9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -809,138 +809,274 @@ out: | |||
| 809 | #endif | 809 | #endif |
| 810 | 810 | ||
| 811 | /* | 811 | /* |
| 812 | * Choose an appropriate source address | 812 | * Choose an appropriate source address (RFC3484) |
| 813 | * should do: | ||
| 814 | * i) get an address with an appropriate scope | ||
| 815 | * ii) see if there is a specific route for the destination and use | ||
| 816 | * an address of the attached interface | ||
| 817 | * iii) don't use deprecated addresses | ||
| 818 | */ | 813 | */ |
| 819 | static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref) | 814 | struct ipv6_saddr_score { |
| 815 | int addr_type; | ||
| 816 | unsigned int attrs; | ||
| 817 | int matchlen; | ||
| 818 | unsigned int scope; | ||
| 819 | unsigned int rule; | ||
| 820 | }; | ||
| 821 | |||
| 822 | #define IPV6_SADDR_SCORE_LOCAL 0x0001 | ||
| 823 | #define IPV6_SADDR_SCORE_PREFERRED 0x0004 | ||
| 824 | #define IPV6_SADDR_SCORE_HOA 0x0008 | ||
| 825 | #define IPV6_SADDR_SCORE_OIF 0x0010 | ||
| 826 | #define IPV6_SADDR_SCORE_LABEL 0x0020 | ||
| 827 | #define IPV6_SADDR_SCORE_PRIVACY 0x0040 | ||
| 828 | |||
| 829 | static int inline ipv6_saddr_preferred(int type) | ||
| 820 | { | 830 | { |
| 821 | int pref; | 831 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| |
| 822 | pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2; | 832 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) |
| 823 | #ifdef CONFIG_IPV6_PRIVACY | 833 | return 1; |
| 824 | pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1; | 834 | return 0; |
| 825 | #endif | ||
| 826 | return pref; | ||
| 827 | } | 835 | } |
| 828 | 836 | ||
| 829 | #ifdef CONFIG_IPV6_PRIVACY | 837 | /* static matching label */ |
| 830 | #define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3) | 838 | static int inline ipv6_saddr_label(const struct in6_addr *addr, int type) |
| 831 | #else | 839 | { |
| 832 | #define IPV6_GET_SADDR_MAXSCORE(score) (score) | 840 | /* |
| 833 | #endif | 841 | * prefix (longest match) label |
| 842 | * ----------------------------- | ||
| 843 | * ::1/128 0 | ||
| 844 | * ::/0 1 | ||
| 845 | * 2002::/16 2 | ||
| 846 | * ::/96 3 | ||
| 847 | * ::ffff:0:0/96 4 | ||
| 848 | */ | ||
| 849 | if (type & IPV6_ADDR_LOOPBACK) | ||
| 850 | return 0; | ||
| 851 | else if (type & IPV6_ADDR_COMPATv4) | ||
| 852 | return 3; | ||
| 853 | else if (type & IPV6_ADDR_MAPPED) | ||
| 854 | return 4; | ||
| 855 | else if (addr->s6_addr16[0] == htons(0x2002)) | ||
| 856 | return 2; | ||
| 857 | return 1; | ||
| 858 | } | ||
| 834 | 859 | ||
| 835 | int ipv6_dev_get_saddr(struct net_device *dev, | 860 | int ipv6_dev_get_saddr(struct net_device *daddr_dev, |
| 836 | struct in6_addr *daddr, struct in6_addr *saddr) | 861 | struct in6_addr *daddr, struct in6_addr *saddr) |
| 837 | { | 862 | { |
| 838 | struct inet6_ifaddr *ifp = NULL; | 863 | struct ipv6_saddr_score hiscore; |
| 839 | struct inet6_ifaddr *match = NULL; | 864 | struct inet6_ifaddr *ifa_result = NULL; |
| 840 | struct inet6_dev *idev; | 865 | int daddr_type = __ipv6_addr_type(daddr); |
| 841 | int scope; | 866 | int daddr_scope = __ipv6_addr_src_scope(daddr_type); |
| 842 | int err; | 867 | u32 daddr_label = ipv6_saddr_label(daddr, daddr_type); |
| 843 | int hiscore = -1, score; | 868 | struct net_device *dev; |
| 844 | 869 | ||
| 845 | scope = ipv6_addr_scope(daddr); | 870 | memset(&hiscore, 0, sizeof(hiscore)); |
| 846 | 871 | ||
| 847 | /* | 872 | read_lock(&dev_base_lock); |
| 848 | * known dev | 873 | read_lock(&addrconf_lock); |
| 849 | * search dev and walk through dev addresses | ||
| 850 | */ | ||
| 851 | 874 | ||
| 852 | if (dev) { | 875 | for (dev = dev_base; dev; dev=dev->next) { |
| 853 | if (dev->flags & IFF_LOOPBACK) | 876 | struct inet6_dev *idev; |
| 854 | scope = IFA_HOST; | 877 | struct inet6_ifaddr *ifa; |
| 878 | |||
| 879 | /* Rule 0: Candidate Source Address (section 4) | ||
| 880 | * - multicast and link-local destination address, | ||
| 881 | * the set of candidate source address MUST only | ||
| 882 | * include addresses assigned to interfaces | ||
| 883 | * belonging to the same link as the outgoing | ||
| 884 | * interface. | ||
| 885 | * (- For site-local destination addresses, the | ||
| 886 | * set of candidate source addresses MUST only | ||
| 887 | * include addresses assigned to interfaces | ||
| 888 | * belonging to the same site as the outgoing | ||
| 889 | * interface.) | ||
| 890 | */ | ||
| 891 | if ((daddr_type & IPV6_ADDR_MULTICAST || | ||
| 892 | daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && | ||
| 893 | daddr_dev && dev != daddr_dev) | ||
| 894 | continue; | ||
| 855 | 895 | ||
| 856 | read_lock(&addrconf_lock); | ||
| 857 | idev = __in6_dev_get(dev); | 896 | idev = __in6_dev_get(dev); |
| 858 | if (idev) { | 897 | if (!idev) |
| 859 | read_lock_bh(&idev->lock); | 898 | continue; |
| 860 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | ||
| 861 | if (ifp->scope == scope) { | ||
| 862 | if (ifp->flags&IFA_F_TENTATIVE) | ||
| 863 | continue; | ||
| 864 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 865 | score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); | ||
| 866 | #else | ||
| 867 | score = ipv6_saddr_pref(ifp, 0); | ||
| 868 | #endif | ||
| 869 | if (score <= hiscore) | ||
| 870 | continue; | ||
| 871 | 899 | ||
| 872 | if (match) | 900 | read_lock_bh(&idev->lock); |
| 873 | in6_ifa_put(match); | 901 | for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { |
| 874 | match = ifp; | 902 | struct ipv6_saddr_score score; |
| 875 | hiscore = score; | ||
| 876 | in6_ifa_hold(ifp); | ||
| 877 | 903 | ||
| 878 | if (IPV6_GET_SADDR_MAXSCORE(score)) { | 904 | score.addr_type = __ipv6_addr_type(&ifa->addr); |
| 879 | read_unlock_bh(&idev->lock); | 905 | |
| 880 | read_unlock(&addrconf_lock); | 906 | /* Rule 0: Candidate Source Address (section 4) |
| 881 | goto out; | 907 | * - In any case, anycast addresses, multicast |
| 882 | } | 908 | * addresses, and the unspecified address MUST |
| 909 | * NOT be included in a candidate set. | ||
| 910 | */ | ||
| 911 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || | ||
| 912 | score.addr_type & IPV6_ADDR_MULTICAST)) { | ||
| 913 | LIMIT_NETDEBUG(KERN_DEBUG | ||
| 914 | "ADDRCONF: unspecified / multicast address" | ||
| 915 | "assigned as unicast address on %s", | ||
| 916 | dev->name); | ||
| 917 | continue; | ||
| 918 | } | ||
| 919 | |||
| 920 | score.attrs = 0; | ||
| 921 | score.matchlen = 0; | ||
| 922 | score.scope = 0; | ||
| 923 | score.rule = 0; | ||
| 924 | |||
| 925 | if (ifa_result == NULL) { | ||
| 926 | /* record it if the first available entry */ | ||
| 927 | goto record_it; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* Rule 1: Prefer same address */ | ||
| 931 | if (hiscore.rule < 1) { | ||
| 932 | if (ipv6_addr_equal(&ifa_result->addr, daddr)) | ||
| 933 | hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL; | ||
| 934 | hiscore.rule++; | ||
| 935 | } | ||
| 936 | if (ipv6_addr_equal(&ifa->addr, daddr)) { | ||
| 937 | score.attrs |= IPV6_SADDR_SCORE_LOCAL; | ||
| 938 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) { | ||
| 939 | score.rule = 1; | ||
| 940 | goto record_it; | ||
| 883 | } | 941 | } |
| 942 | } else { | ||
| 943 | if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL) | ||
| 944 | continue; | ||
| 884 | } | 945 | } |
| 885 | read_unlock_bh(&idev->lock); | ||
| 886 | } | ||
| 887 | read_unlock(&addrconf_lock); | ||
| 888 | } | ||
| 889 | 946 | ||
| 890 | if (scope == IFA_LINK) | 947 | /* Rule 2: Prefer appropriate scope */ |
| 891 | goto out; | 948 | if (hiscore.rule < 2) { |
| 949 | hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type); | ||
| 950 | hiscore.rule++; | ||
| 951 | } | ||
| 952 | score.scope = __ipv6_addr_src_scope(score.addr_type); | ||
| 953 | if (hiscore.scope < score.scope) { | ||
| 954 | if (hiscore.scope < daddr_scope) { | ||
| 955 | score.rule = 2; | ||
| 956 | goto record_it; | ||
| 957 | } else | ||
| 958 | continue; | ||
| 959 | } else if (score.scope < hiscore.scope) { | ||
| 960 | if (score.scope < daddr_scope) | ||
| 961 | continue; | ||
| 962 | else { | ||
| 963 | score.rule = 2; | ||
| 964 | goto record_it; | ||
| 965 | } | ||
| 966 | } | ||
| 892 | 967 | ||
| 893 | /* | 968 | /* Rule 3: Avoid deprecated address */ |
| 894 | * dev == NULL or search failed for specified dev | 969 | if (hiscore.rule < 3) { |
| 895 | */ | 970 | if (ipv6_saddr_preferred(hiscore.addr_type) || |
| 971 | !(ifa_result->flags & IFA_F_DEPRECATED)) | ||
| 972 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; | ||
| 973 | hiscore.rule++; | ||
| 974 | } | ||
| 975 | if (ipv6_saddr_preferred(score.addr_type) || | ||
| 976 | !(ifa->flags & IFA_F_DEPRECATED)) { | ||
| 977 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; | ||
| 978 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { | ||
| 979 | score.rule = 3; | ||
| 980 | goto record_it; | ||
| 981 | } | ||
| 982 | } else { | ||
| 983 | if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED) | ||
| 984 | continue; | ||
| 985 | } | ||
| 896 | 986 | ||
| 897 | read_lock(&dev_base_lock); | 987 | /* Rule 4: Prefer home address -- not implemented yet */ |
| 898 | read_lock(&addrconf_lock); | ||
| 899 | for (dev = dev_base; dev; dev=dev->next) { | ||
| 900 | idev = __in6_dev_get(dev); | ||
| 901 | if (idev) { | ||
| 902 | read_lock_bh(&idev->lock); | ||
| 903 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | ||
| 904 | if (ifp->scope == scope) { | ||
| 905 | if (ifp->flags&IFA_F_TENTATIVE) | ||
| 906 | continue; | ||
| 907 | #ifdef CONFIG_IPV6_PRIVACY | ||
| 908 | score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); | ||
| 909 | #else | ||
| 910 | score = ipv6_saddr_pref(ifp, 0); | ||
| 911 | #endif | ||
| 912 | if (score <= hiscore) | ||
| 913 | continue; | ||
| 914 | 988 | ||
| 915 | if (match) | 989 | /* Rule 5: Prefer outgoing interface */ |
| 916 | in6_ifa_put(match); | 990 | if (hiscore.rule < 5) { |
| 917 | match = ifp; | 991 | if (daddr_dev == NULL || |
| 918 | hiscore = score; | 992 | daddr_dev == ifa_result->idev->dev) |
| 919 | in6_ifa_hold(ifp); | 993 | hiscore.attrs |= IPV6_SADDR_SCORE_OIF; |
| 994 | hiscore.rule++; | ||
| 995 | } | ||
| 996 | if (daddr_dev == NULL || | ||
| 997 | daddr_dev == ifa->idev->dev) { | ||
| 998 | score.attrs |= IPV6_SADDR_SCORE_OIF; | ||
| 999 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) { | ||
| 1000 | score.rule = 5; | ||
| 1001 | goto record_it; | ||
| 1002 | } | ||
| 1003 | } else { | ||
| 1004 | if (hiscore.attrs & IPV6_SADDR_SCORE_OIF) | ||
| 1005 | continue; | ||
| 1006 | } | ||
| 920 | 1007 | ||
| 921 | if (IPV6_GET_SADDR_MAXSCORE(score)) { | 1008 | /* Rule 6: Prefer matching label */ |
| 922 | read_unlock_bh(&idev->lock); | 1009 | if (hiscore.rule < 6) { |
| 923 | goto out_unlock_base; | 1010 | if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label) |
| 924 | } | 1011 | hiscore.attrs |= IPV6_SADDR_SCORE_LABEL; |
| 1012 | hiscore.rule++; | ||
| 1013 | } | ||
| 1014 | if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) { | ||
| 1015 | score.attrs |= IPV6_SADDR_SCORE_LABEL; | ||
| 1016 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) { | ||
| 1017 | score.rule = 6; | ||
| 1018 | goto record_it; | ||
| 925 | } | 1019 | } |
| 1020 | } else { | ||
| 1021 | if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) | ||
| 1022 | continue; | ||
| 926 | } | 1023 | } |
| 927 | read_unlock_bh(&idev->lock); | 1024 | |
| 1025 | /* Rule 7: Prefer public address | ||
| 1026 | * Note: prefer temprary address if use_tempaddr >= 2 | ||
| 1027 | */ | ||
| 1028 | if (hiscore.rule < 7) { | ||
| 1029 | if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ | ||
| 1030 | (ifa_result->idev->cnf.use_tempaddr >= 2)) | ||
| 1031 | hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
| 1032 | hiscore.rule++; | ||
| 1033 | } | ||
| 1034 | if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ | ||
| 1035 | (ifa->idev->cnf.use_tempaddr >= 2)) { | ||
| 1036 | score.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
| 1037 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { | ||
| 1038 | score.rule = 7; | ||
| 1039 | goto record_it; | ||
| 1040 | } | ||
| 1041 | } else { | ||
| 1042 | if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) | ||
| 1043 | continue; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | /* Rule 8: Use longest matching prefix */ | ||
| 1047 | if (hiscore.rule < 8) | ||
| 1048 | hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); | ||
| 1049 | score.rule++; | ||
| 1050 | score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); | ||
| 1051 | if (score.matchlen > hiscore.matchlen) { | ||
| 1052 | score.rule = 8; | ||
| 1053 | goto record_it; | ||
| 1054 | } | ||
| 1055 | #if 0 | ||
| 1056 | else if (score.matchlen < hiscore.matchlen) | ||
| 1057 | continue; | ||
| 1058 | #endif | ||
| 1059 | |||
| 1060 | /* Final Rule: choose first available one */ | ||
| 1061 | continue; | ||
| 1062 | record_it: | ||
| 1063 | if (ifa_result) | ||
| 1064 | in6_ifa_put(ifa_result); | ||
| 1065 | in6_ifa_hold(ifa); | ||
| 1066 | ifa_result = ifa; | ||
| 1067 | hiscore = score; | ||
| 928 | } | 1068 | } |
| 1069 | read_unlock_bh(&idev->lock); | ||
| 929 | } | 1070 | } |
| 930 | |||
| 931 | out_unlock_base: | ||
| 932 | read_unlock(&addrconf_lock); | 1071 | read_unlock(&addrconf_lock); |
| 933 | read_unlock(&dev_base_lock); | 1072 | read_unlock(&dev_base_lock); |
| 934 | 1073 | ||
| 935 | out: | 1074 | if (!ifa_result) |
| 936 | err = -EADDRNOTAVAIL; | 1075 | return -EADDRNOTAVAIL; |
| 937 | if (match) { | 1076 | |
| 938 | ipv6_addr_copy(saddr, &match->addr); | 1077 | ipv6_addr_copy(saddr, &ifa_result->addr); |
| 939 | err = 0; | 1078 | in6_ifa_put(ifa_result); |
| 940 | in6_ifa_put(match); | 1079 | return 0; |
| 941 | } | ||
| 942 | |||
| 943 | return err; | ||
| 944 | } | 1080 | } |
| 945 | 1081 | ||
| 946 | 1082 | ||
