diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 434 |
1 files changed, 287 insertions, 147 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2c5f57299d63..ddcf7754eec2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -35,6 +35,9 @@ | |||
35 | * YOSHIFUJI Hideaki @USAGI : ARCnet support | 35 | * YOSHIFUJI Hideaki @USAGI : ARCnet support |
36 | * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to | 36 | * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to |
37 | * seq_file. | 37 | * seq_file. |
38 | * YOSHIFUJI Hideaki @USAGI : improved source address | ||
39 | * selection; consider scope, | ||
40 | * status etc. | ||
38 | */ | 41 | */ |
39 | 42 | ||
40 | #include <linux/config.h> | 43 | #include <linux/config.h> |
@@ -193,46 +196,51 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; | |||
193 | #endif | 196 | #endif |
194 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; | 197 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; |
195 | 198 | ||
196 | int ipv6_addr_type(const struct in6_addr *addr) | 199 | #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) |
200 | |||
201 | static inline unsigned ipv6_addr_scope2type(unsigned scope) | ||
202 | { | ||
203 | switch(scope) { | ||
204 | case IPV6_ADDR_SCOPE_NODELOCAL: | ||
205 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | | ||
206 | IPV6_ADDR_LOOPBACK); | ||
207 | case IPV6_ADDR_SCOPE_LINKLOCAL: | ||
208 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | | ||
209 | IPV6_ADDR_LINKLOCAL); | ||
210 | case IPV6_ADDR_SCOPE_SITELOCAL: | ||
211 | return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | | ||
212 | IPV6_ADDR_SITELOCAL); | ||
213 | } | ||
214 | return IPV6_ADDR_SCOPE_TYPE(scope); | ||
215 | } | ||
216 | |||
217 | int __ipv6_addr_type(const struct in6_addr *addr) | ||
197 | { | 218 | { |
198 | int type; | ||
199 | u32 st; | 219 | u32 st; |
200 | 220 | ||
201 | st = addr->s6_addr32[0]; | 221 | st = addr->s6_addr32[0]; |
202 | 222 | ||
203 | if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { | ||
204 | type = IPV6_ADDR_MULTICAST; | ||
205 | |||
206 | switch((st & htonl(0x00FF0000))) { | ||
207 | case __constant_htonl(0x00010000): | ||
208 | type |= IPV6_ADDR_LOOPBACK; | ||
209 | break; | ||
210 | |||
211 | case __constant_htonl(0x00020000): | ||
212 | type |= IPV6_ADDR_LINKLOCAL; | ||
213 | break; | ||
214 | |||
215 | case __constant_htonl(0x00050000): | ||
216 | type |= IPV6_ADDR_SITELOCAL; | ||
217 | break; | ||
218 | }; | ||
219 | return type; | ||
220 | } | ||
221 | |||
222 | type = IPV6_ADDR_UNICAST; | ||
223 | |||
224 | /* Consider all addresses with the first three bits different of | 223 | /* Consider all addresses with the first three bits different of |
225 | 000 and 111 as finished. | 224 | 000 and 111 as unicasts. |
226 | */ | 225 | */ |
227 | if ((st & htonl(0xE0000000)) != htonl(0x00000000) && | 226 | if ((st & htonl(0xE0000000)) != htonl(0x00000000) && |
228 | (st & htonl(0xE0000000)) != htonl(0xE0000000)) | 227 | (st & htonl(0xE0000000)) != htonl(0xE0000000)) |
229 | return type; | 228 | return (IPV6_ADDR_UNICAST | |
230 | 229 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); | |
231 | if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) | 230 | |
232 | return (IPV6_ADDR_LINKLOCAL | type); | 231 | if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { |
232 | /* multicast */ | ||
233 | /* addr-select 3.1 */ | ||
234 | return (IPV6_ADDR_MULTICAST | | ||
235 | ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); | ||
236 | } | ||
233 | 237 | ||
238 | if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) | ||
239 | return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | | ||
240 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ | ||
234 | if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) | 241 | if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) |
235 | return (IPV6_ADDR_SITELOCAL | type); | 242 | return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | |
243 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ | ||
236 | 244 | ||
237 | if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { | 245 | if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { |
238 | if (addr->s6_addr32[2] == 0) { | 246 | if (addr->s6_addr32[2] == 0) { |
@@ -240,24 +248,20 @@ int ipv6_addr_type(const struct in6_addr *addr) | |||
240 | return IPV6_ADDR_ANY; | 248 | return IPV6_ADDR_ANY; |
241 | 249 | ||
242 | if (addr->s6_addr32[3] == htonl(0x00000001)) | 250 | if (addr->s6_addr32[3] == htonl(0x00000001)) |
243 | return (IPV6_ADDR_LOOPBACK | type); | 251 | return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | |
252 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ | ||
244 | 253 | ||
245 | return (IPV6_ADDR_COMPATv4 | type); | 254 | return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | |
255 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ | ||
246 | } | 256 | } |
247 | 257 | ||
248 | if (addr->s6_addr32[2] == htonl(0x0000ffff)) | 258 | if (addr->s6_addr32[2] == htonl(0x0000ffff)) |
249 | return IPV6_ADDR_MAPPED; | 259 | return (IPV6_ADDR_MAPPED | |
260 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ | ||
250 | } | 261 | } |
251 | 262 | ||
252 | st &= htonl(0xFF000000); | 263 | return (IPV6_ADDR_RESERVED | |
253 | if (st == 0) | 264 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ |
254 | return IPV6_ADDR_RESERVED; | ||
255 | st &= htonl(0xFE000000); | ||
256 | if (st == htonl(0x02000000)) | ||
257 | return IPV6_ADDR_RESERVED; /* for NSAP */ | ||
258 | if (st == htonl(0x04000000)) | ||
259 | return IPV6_ADDR_RESERVED; /* for IPX */ | ||
260 | return type; | ||
261 | } | 265 | } |
262 | 266 | ||
263 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 267 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -805,138 +809,275 @@ out: | |||
805 | #endif | 809 | #endif |
806 | 810 | ||
807 | /* | 811 | /* |
808 | * Choose an appropriate source address | 812 | * Choose an appropriate source address (RFC3484) |
809 | * should do: | ||
810 | * i) get an address with an appropriate scope | ||
811 | * ii) see if there is a specific route for the destination and use | ||
812 | * an address of the attached interface | ||
813 | * iii) don't use deprecated addresses | ||
814 | */ | 813 | */ |
815 | 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) | ||
816 | { | 830 | { |
817 | int pref; | 831 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| |
818 | pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2; | 832 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) |
819 | #ifdef CONFIG_IPV6_PRIVACY | 833 | return 1; |
820 | pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1; | 834 | return 0; |
821 | #endif | ||
822 | return pref; | ||
823 | } | 835 | } |
824 | 836 | ||
825 | #ifdef CONFIG_IPV6_PRIVACY | 837 | /* static matching label */ |
826 | #define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3) | 838 | static int inline ipv6_saddr_label(const struct in6_addr *addr, int type) |
827 | #else | 839 | { |
828 | #define IPV6_GET_SADDR_MAXSCORE(score) (score) | 840 | /* |
829 | #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 | } | ||
830 | 859 | ||
831 | int ipv6_dev_get_saddr(struct net_device *dev, | 860 | int ipv6_dev_get_saddr(struct net_device *daddr_dev, |
832 | struct in6_addr *daddr, struct in6_addr *saddr) | 861 | struct in6_addr *daddr, struct in6_addr *saddr) |
833 | { | 862 | { |
834 | struct inet6_ifaddr *ifp = NULL; | 863 | struct ipv6_saddr_score hiscore; |
835 | struct inet6_ifaddr *match = NULL; | 864 | struct inet6_ifaddr *ifa_result = NULL; |
836 | struct inet6_dev *idev; | 865 | int daddr_type = __ipv6_addr_type(daddr); |
837 | int scope; | 866 | int daddr_scope = __ipv6_addr_src_scope(daddr_type); |
838 | int err; | 867 | u32 daddr_label = ipv6_saddr_label(daddr, daddr_type); |
839 | int hiscore = -1, score; | 868 | struct net_device *dev; |
840 | 869 | ||
841 | scope = ipv6_addr_scope(daddr); | 870 | memset(&hiscore, 0, sizeof(hiscore)); |
842 | 871 | ||
843 | /* | 872 | read_lock(&dev_base_lock); |
844 | * known dev | 873 | read_lock(&addrconf_lock); |
845 | * search dev and walk through dev addresses | ||
846 | */ | ||
847 | 874 | ||
848 | if (dev) { | 875 | for (dev = dev_base; dev; dev=dev->next) { |
849 | if (dev->flags & IFF_LOOPBACK) | 876 | struct inet6_dev *idev; |
850 | 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; | ||
851 | 895 | ||
852 | read_lock(&addrconf_lock); | ||
853 | idev = __in6_dev_get(dev); | 896 | idev = __in6_dev_get(dev); |
854 | if (idev) { | 897 | if (!idev) |
855 | read_lock_bh(&idev->lock); | 898 | continue; |
856 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | ||
857 | if (ifp->scope == scope) { | ||
858 | if (ifp->flags&IFA_F_TENTATIVE) | ||
859 | continue; | ||
860 | #ifdef CONFIG_IPV6_PRIVACY | ||
861 | score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); | ||
862 | #else | ||
863 | score = ipv6_saddr_pref(ifp, 0); | ||
864 | #endif | ||
865 | if (score <= hiscore) | ||
866 | continue; | ||
867 | 899 | ||
868 | if (match) | 900 | read_lock_bh(&idev->lock); |
869 | in6_ifa_put(match); | 901 | for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { |
870 | match = ifp; | 902 | struct ipv6_saddr_score score; |
871 | hiscore = score; | ||
872 | in6_ifa_hold(ifp); | ||
873 | 903 | ||
874 | if (IPV6_GET_SADDR_MAXSCORE(score)) { | 904 | score.addr_type = __ipv6_addr_type(&ifa->addr); |
875 | read_unlock_bh(&idev->lock); | 905 | |
876 | read_unlock(&addrconf_lock); | 906 | /* Rule 0: Candidate Source Address (section 4) |
877 | goto out; | 907 | * - In any case, anycast addresses, multicast |
878 | } | 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; | ||
879 | } | 941 | } |
942 | } else { | ||
943 | if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL) | ||
944 | continue; | ||
880 | } | 945 | } |
881 | read_unlock_bh(&idev->lock); | ||
882 | } | ||
883 | read_unlock(&addrconf_lock); | ||
884 | } | ||
885 | 946 | ||
886 | if (scope == IFA_LINK) | 947 | /* Rule 2: Prefer appropriate scope */ |
887 | 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 | } | ||
888 | 967 | ||
889 | /* | 968 | /* Rule 3: Avoid deprecated address */ |
890 | * dev == NULL or search failed for specified dev | 969 | if (hiscore.rule < 3) { |
891 | */ | 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 | } | ||
892 | 986 | ||
893 | read_lock(&dev_base_lock); | 987 | /* Rule 4: Prefer home address -- not implemented yet */ |
894 | read_lock(&addrconf_lock); | ||
895 | for (dev = dev_base; dev; dev=dev->next) { | ||
896 | idev = __in6_dev_get(dev); | ||
897 | if (idev) { | ||
898 | read_lock_bh(&idev->lock); | ||
899 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | ||
900 | if (ifp->scope == scope) { | ||
901 | if (ifp->flags&IFA_F_TENTATIVE) | ||
902 | continue; | ||
903 | #ifdef CONFIG_IPV6_PRIVACY | ||
904 | score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); | ||
905 | #else | ||
906 | score = ipv6_saddr_pref(ifp, 0); | ||
907 | #endif | ||
908 | if (score <= hiscore) | ||
909 | continue; | ||
910 | 988 | ||
911 | if (match) | 989 | /* Rule 5: Prefer outgoing interface */ |
912 | in6_ifa_put(match); | 990 | if (hiscore.rule < 5) { |
913 | match = ifp; | 991 | if (daddr_dev == NULL || |
914 | hiscore = score; | 992 | daddr_dev == ifa_result->idev->dev) |
915 | 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 | } | ||
916 | 1007 | ||
917 | if (IPV6_GET_SADDR_MAXSCORE(score)) { | 1008 | /* Rule 6: Prefer matching label */ |
918 | read_unlock_bh(&idev->lock); | 1009 | if (hiscore.rule < 6) { |
919 | goto out_unlock_base; | 1010 | if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label) |
920 | } | 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; | ||
921 | } | 1019 | } |
1020 | } else { | ||
1021 | if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) | ||
1022 | continue; | ||
922 | } | 1023 | } |
923 | read_unlock_bh(&idev->lock); | 1024 | |
1025 | #ifdef CONFIG_IPV6_PRIVACY | ||
1026 | /* Rule 7: Prefer public address | ||
1027 | * Note: prefer temprary address if use_tempaddr >= 2 | ||
1028 | */ | ||
1029 | if (hiscore.rule < 7) { | ||
1030 | if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ | ||
1031 | (ifa_result->idev->cnf.use_tempaddr >= 2)) | ||
1032 | hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
1033 | hiscore.rule++; | ||
1034 | } | ||
1035 | if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ | ||
1036 | (ifa->idev->cnf.use_tempaddr >= 2)) { | ||
1037 | score.attrs |= IPV6_SADDR_SCORE_PRIVACY; | ||
1038 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { | ||
1039 | score.rule = 7; | ||
1040 | goto record_it; | ||
1041 | } | ||
1042 | } else { | ||
1043 | if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) | ||
1044 | continue; | ||
1045 | } | ||
1046 | #endif | ||
1047 | /* Rule 8: Use longest matching prefix */ | ||
1048 | if (hiscore.rule < 8) | ||
1049 | hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); | ||
1050 | score.rule++; | ||
1051 | score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); | ||
1052 | if (score.matchlen > hiscore.matchlen) { | ||
1053 | score.rule = 8; | ||
1054 | goto record_it; | ||
1055 | } | ||
1056 | #if 0 | ||
1057 | else if (score.matchlen < hiscore.matchlen) | ||
1058 | continue; | ||
1059 | #endif | ||
1060 | |||
1061 | /* Final Rule: choose first available one */ | ||
1062 | continue; | ||
1063 | record_it: | ||
1064 | if (ifa_result) | ||
1065 | in6_ifa_put(ifa_result); | ||
1066 | in6_ifa_hold(ifa); | ||
1067 | ifa_result = ifa; | ||
1068 | hiscore = score; | ||
924 | } | 1069 | } |
1070 | read_unlock_bh(&idev->lock); | ||
925 | } | 1071 | } |
926 | |||
927 | out_unlock_base: | ||
928 | read_unlock(&addrconf_lock); | 1072 | read_unlock(&addrconf_lock); |
929 | read_unlock(&dev_base_lock); | 1073 | read_unlock(&dev_base_lock); |
930 | 1074 | ||
931 | out: | 1075 | if (!ifa_result) |
932 | err = -EADDRNOTAVAIL; | 1076 | return -EADDRNOTAVAIL; |
933 | if (match) { | 1077 | |
934 | ipv6_addr_copy(saddr, &match->addr); | 1078 | ipv6_addr_copy(saddr, &ifa_result->addr); |
935 | err = 0; | 1079 | in6_ifa_put(ifa_result); |
936 | in6_ifa_put(match); | 1080 | return 0; |
937 | } | ||
938 | |||
939 | return err; | ||
940 | } | 1081 | } |
941 | 1082 | ||
942 | 1083 | ||
@@ -2950,8 +3091,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
2950 | 3091 | ||
2951 | nlmsg_failure: | 3092 | nlmsg_failure: |
2952 | rtattr_failure: | 3093 | rtattr_failure: |
2953 | if (array) | 3094 | kfree(array); |
2954 | kfree(array); | ||
2955 | skb_trim(skb, b - skb->data); | 3095 | skb_trim(skb, b - skb->data); |
2956 | return -1; | 3096 | return -1; |
2957 | } | 3097 | } |