diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-01 20:48:21 -0500 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-24 21:23:58 -0400 |
commit | a9b05723ffa2e427b0257b81ea74363fcd7c304f (patch) | |
tree | 89f51b7d3fa28a83ab3f378f2fb6798e37bd21f0 /net/ipv6/addrconf.c | |
parent | 9bb182a7007515239091b237fe7169b1328a61d3 (diff) |
[IPV6] ADDRCONF: Clean-up ipv6_dev_get_saddr().
old:
| text data bss dec hex filename
| 28599 1416 96 30111 759f net/ipv6/addrconf.o
new:
| text data bss dec hex filename
| 28007 1416 96 29519 734f net/ipv6/addrconf.o
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 420 |
1 files changed, 206 insertions, 214 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4b86d388bf63..787e90af166c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -877,20 +877,39 @@ out: | |||
877 | /* | 877 | /* |
878 | * Choose an appropriate source address (RFC3484) | 878 | * Choose an appropriate source address (RFC3484) |
879 | */ | 879 | */ |
880 | enum { | ||
881 | IPV6_SADDR_RULE_INIT = 0, | ||
882 | IPV6_SADDR_RULE_LOCAL, | ||
883 | IPV6_SADDR_RULE_SCOPE, | ||
884 | IPV6_SADDR_RULE_PREFERRED, | ||
885 | #ifdef CONFIG_IPV6_MIP6 | ||
886 | IPV6_SADDR_RULE_HOA, | ||
887 | #endif | ||
888 | IPV6_SADDR_RULE_OIF, | ||
889 | IPV6_SADDR_RULE_LABEL, | ||
890 | #ifdef CONFIG_IPV6_PRIVACY | ||
891 | IPV6_SADDR_RULE_PRIVACY, | ||
892 | #endif | ||
893 | IPV6_SADDR_RULE_ORCHID, | ||
894 | IPV6_SADDR_RULE_PREFIX, | ||
895 | IPV6_SADDR_RULE_MAX | ||
896 | }; | ||
897 | |||
880 | struct ipv6_saddr_score { | 898 | struct ipv6_saddr_score { |
881 | int addr_type; | 899 | int rule; |
882 | unsigned int attrs; | 900 | int addr_type; |
883 | int matchlen; | 901 | struct inet6_ifaddr *ifa; |
884 | int scope; | 902 | DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX); |
885 | unsigned int rule; | 903 | int scopedist; |
904 | int matchlen; | ||
886 | }; | 905 | }; |
887 | 906 | ||
888 | #define IPV6_SADDR_SCORE_LOCAL 0x0001 | 907 | struct ipv6_saddr_dst { |
889 | #define IPV6_SADDR_SCORE_PREFERRED 0x0004 | 908 | struct in6_addr *addr; |
890 | #define IPV6_SADDR_SCORE_HOA 0x0008 | 909 | int ifindex; |
891 | #define IPV6_SADDR_SCORE_OIF 0x0010 | 910 | int scope; |
892 | #define IPV6_SADDR_SCORE_LABEL 0x0020 | 911 | int label; |
893 | #define IPV6_SADDR_SCORE_PRIVACY 0x0040 | 912 | }; |
894 | 913 | ||
895 | static inline int ipv6_saddr_preferred(int type) | 914 | static inline int ipv6_saddr_preferred(int type) |
896 | { | 915 | { |
@@ -900,28 +919,142 @@ static inline int ipv6_saddr_preferred(int type) | |||
900 | return 0; | 919 | return 0; |
901 | } | 920 | } |
902 | 921 | ||
903 | int ipv6_dev_get_saddr(struct net_device *daddr_dev, | 922 | static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, |
923 | struct ipv6_saddr_dst *dst, | ||
924 | int i) | ||
925 | { | ||
926 | int ret; | ||
927 | |||
928 | if (i <= score->rule) { | ||
929 | switch (i) { | ||
930 | case IPV6_SADDR_RULE_SCOPE: | ||
931 | ret = score->scopedist; | ||
932 | break; | ||
933 | case IPV6_SADDR_RULE_PREFIX: | ||
934 | ret = score->matchlen; | ||
935 | break; | ||
936 | default: | ||
937 | ret = !!test_bit(i, score->scorebits); | ||
938 | } | ||
939 | goto out; | ||
940 | } | ||
941 | |||
942 | switch (i) { | ||
943 | case IPV6_SADDR_RULE_INIT: | ||
944 | /* Rule 0: remember if hiscore is not ready yet */ | ||
945 | ret = !!score->ifa; | ||
946 | break; | ||
947 | case IPV6_SADDR_RULE_LOCAL: | ||
948 | /* Rule 1: Prefer same address */ | ||
949 | ret = ipv6_addr_equal(&score->ifa->addr, dst->addr); | ||
950 | break; | ||
951 | case IPV6_SADDR_RULE_SCOPE: | ||
952 | /* Rule 2: Prefer appropriate scope | ||
953 | * | ||
954 | * ret | ||
955 | * ^ | ||
956 | * -1 | d 15 | ||
957 | * ---+--+-+---> scope | ||
958 | * | | ||
959 | * | d is scope of the destination. | ||
960 | * B-d | \ | ||
961 | * | \ <- smaller scope is better if | ||
962 | * B-15 | \ if scope is enough for destinaion. | ||
963 | * | ret = B - scope (-1 <= scope >= d <= 15). | ||
964 | * d-C-1 | / | ||
965 | * |/ <- greater is better | ||
966 | * -C / if scope is not enough for destination. | ||
967 | * /| ret = scope - C (-1 <= d < scope <= 15). | ||
968 | * | ||
969 | * d - C - 1 < B -15 (for all -1 <= d <= 15). | ||
970 | * C > d + 14 - B >= 15 + 14 - B = 29 - B. | ||
971 | * Assume B = 0 and we get C > 29. | ||
972 | */ | ||
973 | ret = __ipv6_addr_src_scope(score->addr_type); | ||
974 | if (ret >= dst->scope) | ||
975 | ret = -ret; | ||
976 | else | ||
977 | ret -= 128; /* 30 is enough */ | ||
978 | score->scopedist = ret; | ||
979 | break; | ||
980 | case IPV6_SADDR_RULE_PREFERRED: | ||
981 | /* Rule 3: Avoid deprecated and optimistic addresses */ | ||
982 | ret = ipv6_saddr_preferred(score->addr_type) || | ||
983 | !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); | ||
984 | break; | ||
985 | #ifdef CONFIG_IPV6_MIP6 | ||
986 | case IPV6_SADDR_RULE_HOA: | ||
987 | /* Rule 4: Prefer home address */ | ||
988 | ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS); | ||
989 | break; | ||
990 | #endif | ||
991 | case IPV6_SADDR_RULE_OIF: | ||
992 | /* Rule 5: Prefer outgoing interface */ | ||
993 | ret = (!dst->ifindex || | ||
994 | dst->ifindex == score->ifa->idev->dev->ifindex); | ||
995 | break; | ||
996 | case IPV6_SADDR_RULE_LABEL: | ||
997 | /* Rule 6: Prefer matching label */ | ||
998 | ret = ipv6_addr_label(&score->ifa->addr, score->addr_type, | ||
999 | score->ifa->idev->dev->ifindex) == dst->label; | ||
1000 | break; | ||
1001 | #ifdef CONFIG_IPV6_PRIVACY | ||
1002 | case IPV6_SADDR_RULE_PRIVACY: | ||
1003 | /* Rule 7: Prefer public address | ||
1004 | * Note: prefer temprary address if use_tempaddr >= 2 | ||
1005 | */ | ||
1006 | ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2); | ||
1007 | break; | ||
1008 | #endif | ||
1009 | case IPV6_SADDR_RULE_ORCHID: | ||
1010 | /* Rule 8-: Prefer ORCHID vs ORCHID or | ||
1011 | * non-ORCHID vs non-ORCHID | ||
1012 | */ | ||
1013 | ret = !(ipv6_addr_orchid(&score->ifa->addr) ^ | ||
1014 | ipv6_addr_orchid(dst->addr)); | ||
1015 | break; | ||
1016 | case IPV6_SADDR_RULE_PREFIX: | ||
1017 | /* Rule 8: Use longest matching prefix */ | ||
1018 | score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr, | ||
1019 | dst->addr); | ||
1020 | break; | ||
1021 | default: | ||
1022 | ret = 0; | ||
1023 | } | ||
1024 | |||
1025 | if (ret) | ||
1026 | __set_bit(i, score->scorebits); | ||
1027 | score->rule = i; | ||
1028 | out: | ||
1029 | return ret; | ||
1030 | } | ||
1031 | |||
1032 | int ipv6_dev_get_saddr(struct net_device *dst_dev, | ||
904 | struct in6_addr *daddr, struct in6_addr *saddr) | 1033 | struct in6_addr *daddr, struct in6_addr *saddr) |
905 | { | 1034 | { |
906 | struct ipv6_saddr_score hiscore; | 1035 | struct ipv6_saddr_score scores[2], |
907 | struct inet6_ifaddr *ifa_result = NULL; | 1036 | *score = &scores[0], *hiscore = &scores[1]; |
908 | struct net *net = daddr_dev->nd_net; | 1037 | struct net *net = dst_dev->nd_net; |
909 | int daddr_type = __ipv6_addr_type(daddr); | 1038 | struct ipv6_saddr_dst dst; |
910 | int daddr_scope = __ipv6_addr_src_scope(daddr_type); | ||
911 | int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0; | ||
912 | u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex); | ||
913 | struct net_device *dev; | 1039 | struct net_device *dev; |
1040 | int dst_type; | ||
1041 | |||
1042 | dst_type = __ipv6_addr_type(daddr); | ||
1043 | dst.addr = daddr; | ||
1044 | dst.ifindex = dst_dev ? dst_dev->ifindex : 0; | ||
1045 | dst.scope = __ipv6_addr_src_scope(dst_type); | ||
1046 | dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); | ||
914 | 1047 | ||
915 | memset(&hiscore, 0, sizeof(hiscore)); | 1048 | hiscore->rule = -1; |
1049 | hiscore->ifa = NULL; | ||
916 | 1050 | ||
917 | read_lock(&dev_base_lock); | 1051 | read_lock(&dev_base_lock); |
918 | rcu_read_lock(); | 1052 | rcu_read_lock(); |
919 | 1053 | ||
920 | for_each_netdev(net, dev) { | 1054 | for_each_netdev(net, dev) { |
921 | struct inet6_dev *idev; | 1055 | struct inet6_dev *idev; |
922 | struct inet6_ifaddr *ifa; | ||
923 | 1056 | ||
924 | /* Rule 0: Candidate Source Address (section 4) | 1057 | /* Candidate Source Address (section 4) |
925 | * - multicast and link-local destination address, | 1058 | * - multicast and link-local destination address, |
926 | * the set of candidate source address MUST only | 1059 | * the set of candidate source address MUST only |
927 | * include addresses assigned to interfaces | 1060 | * include addresses assigned to interfaces |
@@ -933,9 +1066,9 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
933 | * belonging to the same site as the outgoing | 1066 | * belonging to the same site as the outgoing |
934 | * interface.) | 1067 | * interface.) |
935 | */ | 1068 | */ |
936 | if ((daddr_type & IPV6_ADDR_MULTICAST || | 1069 | if (((dst_type & IPV6_ADDR_MULTICAST) || |
937 | daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && | 1070 | dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && |
938 | daddr_dev && dev != daddr_dev) | 1071 | dst.ifindex && dev->ifindex != dst.ifindex) |
939 | continue; | 1072 | continue; |
940 | 1073 | ||
941 | idev = __in6_dev_get(dev); | 1074 | idev = __in6_dev_get(dev); |
@@ -943,12 +1076,10 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
943 | continue; | 1076 | continue; |
944 | 1077 | ||
945 | read_lock_bh(&idev->lock); | 1078 | read_lock_bh(&idev->lock); |
946 | for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { | 1079 | for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) { |
947 | struct ipv6_saddr_score score; | 1080 | int i; |
948 | 1081 | ||
949 | score.addr_type = __ipv6_addr_type(&ifa->addr); | 1082 | /* |
950 | |||
951 | /* Rule 0: | ||
952 | * - Tentative Address (RFC2462 section 5.4) | 1083 | * - Tentative Address (RFC2462 section 5.4) |
953 | * - A tentative address is not considered | 1084 | * - A tentative address is not considered |
954 | * "assigned to an interface" in the traditional | 1085 | * "assigned to an interface" in the traditional |
@@ -958,11 +1089,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
958 | * addresses, and the unspecified address MUST | 1089 | * addresses, and the unspecified address MUST |
959 | * NOT be included in a candidate set. | 1090 | * NOT be included in a candidate set. |
960 | */ | 1091 | */ |
961 | if ((ifa->flags & IFA_F_TENTATIVE) && | 1092 | if ((score->ifa->flags & IFA_F_TENTATIVE) && |
962 | (!(ifa->flags & IFA_F_OPTIMISTIC))) | 1093 | (!(score->ifa->flags & IFA_F_OPTIMISTIC))) |
963 | continue; | 1094 | continue; |
964 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || | 1095 | |
965 | score.addr_type & IPV6_ADDR_MULTICAST)) { | 1096 | score->addr_type = __ipv6_addr_type(&score->ifa->addr); |
1097 | |||
1098 | if (unlikely(score->addr_type == IPV6_ADDR_ANY || | ||
1099 | score->addr_type & IPV6_ADDR_MULTICAST)) { | ||
966 | LIMIT_NETDEBUG(KERN_DEBUG | 1100 | LIMIT_NETDEBUG(KERN_DEBUG |
967 | "ADDRCONF: unspecified / multicast address " | 1101 | "ADDRCONF: unspecified / multicast address " |
968 | "assigned as unicast address on %s", | 1102 | "assigned as unicast address on %s", |
@@ -970,201 +1104,59 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
970 | continue; | 1104 | continue; |
971 | } | 1105 | } |
972 | 1106 | ||
973 | score.attrs = 0; | 1107 | score->rule = -1; |
974 | score.matchlen = 0; | 1108 | bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); |
975 | score.scope = 0; | 1109 | |
976 | score.rule = 0; | 1110 | for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { |
977 | 1111 | int minihiscore, miniscore; | |
978 | if (ifa_result == NULL) { | 1112 | |
979 | /* record it if the first available entry */ | 1113 | minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i); |
980 | goto record_it; | 1114 | miniscore = ipv6_get_saddr_eval(score, &dst, i); |
981 | } | 1115 | |
982 | 1116 | if (minihiscore > miniscore) { | |
983 | /* Rule 1: Prefer same address */ | 1117 | if (i == IPV6_SADDR_RULE_SCOPE && |
984 | if (hiscore.rule < 1) { | 1118 | score->scopedist > 0) { |
985 | if (ipv6_addr_equal(&ifa_result->addr, daddr)) | 1119 | /* |
986 | hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL; | 1120 | * special case: |
987 | hiscore.rule++; | 1121 | * each remaining entry |
988 | } | 1122 | * has too small (not enough) |
989 | if (ipv6_addr_equal(&ifa->addr, daddr)) { | 1123 | * scope, because ifa entries |
990 | score.attrs |= IPV6_SADDR_SCORE_LOCAL; | 1124 | * are sorted by their scope |
991 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) { | 1125 | * values. |
992 | score.rule = 1; | 1126 | */ |
993 | goto record_it; | 1127 | goto try_nextdev; |
994 | } | 1128 | } |
995 | } else { | 1129 | break; |
996 | if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL) | 1130 | } else if (minihiscore < miniscore) { |
997 | continue; | 1131 | struct ipv6_saddr_score *tmp; |
998 | } | ||
999 | 1132 | ||
1000 | /* Rule 2: Prefer appropriate scope */ | 1133 | if (hiscore->ifa) |
1001 | if (hiscore.rule < 2) { | 1134 | in6_ifa_put(hiscore->ifa); |
1002 | hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type); | ||
1003 | hiscore.rule++; | ||
1004 | } | ||
1005 | score.scope = __ipv6_addr_src_scope(score.addr_type); | ||
1006 | if (hiscore.scope < score.scope) { | ||
1007 | if (hiscore.scope < daddr_scope) { | ||
1008 | score.rule = 2; | ||
1009 | goto record_it; | ||
1010 | } else | ||
1011 | continue; | ||
1012 | } else if (score.scope < hiscore.scope) { | ||
1013 | if (score.scope < daddr_scope) | ||
1014 | break; /* addresses sorted by scope */ | ||
1015 | else { | ||
1016 | score.rule = 2; | ||
1017 | goto record_it; | ||
1018 | } | ||
1019 | } | ||
1020 | 1135 | ||
1021 | /* Rule 3: Avoid deprecated and optimistic addresses */ | 1136 | in6_ifa_hold(score->ifa); |
1022 | if (hiscore.rule < 3) { | ||
1023 | if (ipv6_saddr_preferred(hiscore.addr_type) || | ||
1024 | (((ifa_result->flags & | ||
1025 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) | ||
1026 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; | ||
1027 | hiscore.rule++; | ||
1028 | } | ||
1029 | if (ipv6_saddr_preferred(score.addr_type) || | ||
1030 | (((ifa->flags & | ||
1031 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) { | ||
1032 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; | ||
1033 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { | ||
1034 | score.rule = 3; | ||
1035 | goto record_it; | ||
1036 | } | ||
1037 | } else { | ||
1038 | if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED) | ||
1039 | continue; | ||
1040 | } | ||
1041 | 1137 | ||
1042 | /* Rule 4: Prefer home address */ | 1138 | tmp = hiscore; |
1043 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 1139 | hiscore = score; |
1044 | if (hiscore.rule < 4) { | 1140 | score = tmp; |
1045 | if (ifa_result->flags & IFA_F_HOMEADDRESS) | ||
1046 | hiscore.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1047 | hiscore.rule++; | ||
1048 | } | ||
1049 | if (ifa->flags & IFA_F_HOMEADDRESS) { | ||
1050 | score.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1051 | if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) { | ||
1052 | score.rule = 4; | ||
1053 | goto record_it; | ||
1054 | } | ||
1055 | } else { | ||
1056 | if (hiscore.attrs & IPV6_SADDR_SCORE_HOA) | ||
1057 | continue; | ||
1058 | } | ||
1059 | #else | ||
1060 | if (hiscore.rule < 4) | ||
1061 | hiscore.rule++; | ||
1062 | #endif | ||
1063 | 1141 | ||
1064 | /* Rule 5: Prefer outgoing interface */ | 1142 | /* restore our iterator */ |
1065 | if (hiscore.rule < 5) { | 1143 | score->ifa = hiscore->ifa; |
1066 | if (daddr_dev == NULL || | ||
1067 | daddr_dev == ifa_result->idev->dev) | ||
1068 | hiscore.attrs |= IPV6_SADDR_SCORE_OIF; | ||
1069 | hiscore.rule++; | ||
1070 | } | ||
1071 | if (daddr_dev == NULL || | ||
1072 | daddr_dev == ifa->idev->dev) { | ||
1073 | score.attrs |= IPV6_SADDR_SCORE_OIF; | ||
1074 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) { | ||
1075 | score.rule = 5; | ||
1076 | goto record_it; | ||
1077 | } | ||
1078 | } else { | ||
1079 | if (hiscore.attrs & IPV6_SADDR_SCORE_OIF) | ||
1080 | continue; | ||
1081 | } | ||
1082 | |||
1083 | /* Rule 6: Prefer matching label */ | ||
1084 | if (hiscore.rule < 6) { | ||
1085 | if (ipv6_addr_label(&ifa_result->addr, | ||
1086 | hiscore.addr_type, | ||
1087 | ifa_result->idev->dev->ifindex) == daddr_label) | ||
1088 | hiscore.attrs |= IPV6_SADDR_SCORE_LABEL; | ||
1089 | hiscore.rule++; | ||
1090 | } | ||
1091 | if (ipv6_addr_label(&ifa->addr, | ||
1092 | score.addr_type, | ||
1093 | ifa->idev->dev->ifindex) == daddr_label) { | ||
1094 | score.attrs |= IPV6_SADDR_SCORE_LABEL; | ||
1095 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) { | ||
1096 | score.rule = 6; | ||
1097 | goto record_it; | ||
1098 | } | ||
1099 | } else { | ||
1100 | if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) | ||
1101 | continue; | ||
1102 | } | ||
1103 | 1144 | ||
1104 | #ifdef CONFIG_IPV6_PRIVACY | 1145 | break; |
1105 | /* Rule 7: Prefer public address | ||
1106 | * Note: prefer temprary address if use_tempaddr >= 2 | ||
1107 | */ | ||
1108 | if (hiscore.rule < 7) { | ||
1109 | if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ | ||
1110 | (ifa_result->idev->cnf.use_tempaddr >= 2)) | ||
1111 | hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
1112 | hiscore.rule++; | ||
1113 | } | ||
1114 | if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ | ||
1115 | (ifa->idev->cnf.use_tempaddr >= 2)) { | ||
1116 | score.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
1117 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { | ||
1118 | score.rule = 7; | ||
1119 | goto record_it; | ||
1120 | } | 1146 | } |
1121 | } else { | ||
1122 | if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) | ||
1123 | continue; | ||
1124 | } | ||
1125 | #else | ||
1126 | if (hiscore.rule < 7) | ||
1127 | hiscore.rule++; | ||
1128 | #endif | ||
1129 | |||
1130 | /* Skip rule 8 for orchid -> non-orchid address pairs. */ | ||
1131 | if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr)) | ||
1132 | continue; | ||
1133 | |||
1134 | /* Rule 8: Use longest matching prefix */ | ||
1135 | if (hiscore.rule < 8) { | ||
1136 | hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); | ||
1137 | hiscore.rule++; | ||
1138 | } | ||
1139 | score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); | ||
1140 | if (score.matchlen > hiscore.matchlen) { | ||
1141 | score.rule = 8; | ||
1142 | goto record_it; | ||
1143 | } | 1147 | } |
1144 | #if 0 | ||
1145 | else if (score.matchlen < hiscore.matchlen) | ||
1146 | continue; | ||
1147 | #endif | ||
1148 | |||
1149 | /* Final Rule: choose first available one */ | ||
1150 | continue; | ||
1151 | record_it: | ||
1152 | if (ifa_result) | ||
1153 | in6_ifa_put(ifa_result); | ||
1154 | in6_ifa_hold(ifa); | ||
1155 | ifa_result = ifa; | ||
1156 | hiscore = score; | ||
1157 | } | 1148 | } |
1149 | try_nextdev: | ||
1158 | read_unlock_bh(&idev->lock); | 1150 | read_unlock_bh(&idev->lock); |
1159 | } | 1151 | } |
1160 | rcu_read_unlock(); | 1152 | rcu_read_unlock(); |
1161 | read_unlock(&dev_base_lock); | 1153 | read_unlock(&dev_base_lock); |
1162 | 1154 | ||
1163 | if (!ifa_result) | 1155 | if (!hiscore->ifa) |
1164 | return -EADDRNOTAVAIL; | 1156 | return -EADDRNOTAVAIL; |
1165 | 1157 | ||
1166 | ipv6_addr_copy(saddr, &ifa_result->addr); | 1158 | ipv6_addr_copy(saddr, &hiscore->ifa->addr); |
1167 | in6_ifa_put(ifa_result); | 1159 | in6_ifa_put(hiscore->ifa); |
1168 | return 0; | 1160 | return 0; |
1169 | } | 1161 | } |
1170 | 1162 | ||