Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IPV6]: Support Source Address Selection API (RFC5014).

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

+146 -13
+11
include/linux/in6.h
··· 249 249 * IP6T_SO_GET_REVISION_TARGET 69 250 250 */ 251 251 252 + /* RFC5014: Source address selection */ 253 + #define IPV6_ADDR_PREFERENCES 72 254 + 255 + #define IPV6_PREFER_SRC_TMP 0x0001 256 + #define IPV6_PREFER_SRC_PUBLIC 0x0002 257 + #define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 258 + #define IPV6_PREFER_SRC_COA 0x0004 259 + #define IPV6_PREFER_SRC_HOME 0x0400 260 + #define IPV6_PREFER_SRC_CGA 0x0008 261 + #define IPV6_PREFER_SRC_NONCGA 0x0800 262 + 252 263 #endif
+5 -1
include/linux/ipv6.h
··· 322 322 __u8 recverr:1, 323 323 sndflow:1, 324 324 pmtudisc:2, 325 - ipv6only:1; 325 + ipv6only:1, 326 + srcprefs:3; /* 001: prefer temporary address 327 + * 010: prefer public address 328 + * 100: prefer care-of address 329 + */ 326 330 __u8 tclass; 327 331 328 332 __u32 dst_cookie;
+1
include/net/addrconf.h
··· 78 78 79 79 extern int ipv6_dev_get_saddr(struct net_device *dev, 80 80 struct in6_addr *daddr, 81 + unsigned int srcprefs, 81 82 struct in6_addr *saddr); 82 83 extern int ipv6_get_lladdr(struct net_device *dev, 83 84 struct in6_addr *addr,
+6 -3
include/net/ip6_route.h
··· 30 30 #include <linux/ip.h> 31 31 #include <linux/ipv6.h> 32 32 33 - #define RT6_LOOKUP_F_IFACE 0x1 34 - #define RT6_LOOKUP_F_REACHABLE 0x2 35 - #define RT6_LOOKUP_F_HAS_SADDR 0x4 33 + #define RT6_LOOKUP_F_IFACE 0x00000001 34 + #define RT6_LOOKUP_F_REACHABLE 0x00000002 35 + #define RT6_LOOKUP_F_HAS_SADDR 0x00000004 36 + #define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 37 + #define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 38 + #define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 36 39 37 40 extern struct rt6_info *ip6_null_entry; 38 41
+14 -3
net/ipv6/addrconf.c
··· 909 909 int ifindex; 910 910 int scope; 911 911 int label; 912 + unsigned int prefs; 912 913 }; 913 914 914 915 static inline int ipv6_saddr_preferred(int type) ··· 985 984 break; 986 985 #ifdef CONFIG_IPV6_MIP6 987 986 case IPV6_SADDR_RULE_HOA: 987 + { 988 988 /* Rule 4: Prefer home address */ 989 - ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS); 989 + int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA); 990 + ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; 990 991 break; 992 + } 991 993 #endif 992 994 case IPV6_SADDR_RULE_OIF: 993 995 /* Rule 5: Prefer outgoing interface */ ··· 1004 1000 break; 1005 1001 #ifdef CONFIG_IPV6_PRIVACY 1006 1002 case IPV6_SADDR_RULE_PRIVACY: 1003 + { 1007 1004 /* Rule 7: Prefer public address 1008 1005 * Note: prefer temprary address if use_tempaddr >= 2 1009 1006 */ 1010 - ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2); 1007 + int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? 1008 + !!(dst->prefs & IPV6_PREFER_SRC_TMP) : 1009 + score->ifa->idev->cnf.use_tempaddr >= 2; 1010 + ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; 1011 1011 break; 1012 + } 1012 1013 #endif 1013 1014 case IPV6_SADDR_RULE_ORCHID: 1014 1015 /* Rule 8-: Prefer ORCHID vs ORCHID or ··· 1039 1030 } 1040 1031 1041 1032 int ipv6_dev_get_saddr(struct net_device *dst_dev, 1042 - struct in6_addr *daddr, struct in6_addr *saddr) 1033 + struct in6_addr *daddr, unsigned int prefs, 1034 + struct in6_addr *saddr) 1043 1035 { 1044 1036 struct ipv6_saddr_score scores[2], 1045 1037 *score = &scores[0], *hiscore = &scores[1]; ··· 1054 1044 dst.ifindex = dst_dev ? dst_dev->ifindex : 0; 1055 1045 dst.scope = __ipv6_addr_src_scope(dst_type); 1056 1046 dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); 1047 + dst.prefs = prefs; 1057 1048 1058 1049 hiscore->rule = -1; 1059 1050 hiscore->ifa = NULL;
+11 -1
net/ipv6/fib6_rules.c
··· 84 84 if ((rule->flags & FIB_RULE_FIND_SADDR) && 85 85 r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { 86 86 struct in6_addr saddr; 87 + unsigned int srcprefs = 0; 88 + 89 + if (flags & RT6_LOOKUP_F_SRCPREF_TMP) 90 + srcprefs |= IPV6_PREFER_SRC_TMP; 91 + if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC) 92 + srcprefs |= IPV6_PREFER_SRC_PUBLIC; 93 + if (flags & RT6_LOOKUP_F_SRCPREF_COA) 94 + srcprefs |= IPV6_PREFER_SRC_COA; 95 + 87 96 if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, 88 - &flp->fl6_dst, &saddr)) 97 + &flp->fl6_dst, srcprefs, 98 + &saddr)) 89 99 goto again; 90 100 if (!ipv6_prefix_equal(&saddr, &r->src.addr, 91 101 r->src.plen))
+3 -1
net/ipv6/ip6_output.c
··· 920 920 921 921 if (ipv6_addr_any(&fl->fl6_src)) { 922 922 err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev, 923 - &fl->fl6_dst, &fl->fl6_src); 923 + &fl->fl6_dst, 924 + sk ? inet6_sk(sk)->srcprefs : 0, 925 + &fl->fl6_src); 924 926 if (err) 925 927 goto out_err_release; 926 928 }
+78
net/ipv6/ipv6_sockglue.c
··· 617 617 retv = xfrm_user_policy(sk, optname, optval, optlen); 618 618 break; 619 619 620 + case IPV6_ADDR_PREFERENCES: 621 + { 622 + unsigned int pref = 0; 623 + unsigned int prefmask = ~0; 624 + 625 + retv = -EINVAL; 626 + 627 + /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ 628 + switch (val & (IPV6_PREFER_SRC_PUBLIC| 629 + IPV6_PREFER_SRC_TMP| 630 + IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { 631 + case IPV6_PREFER_SRC_PUBLIC: 632 + pref |= IPV6_PREFER_SRC_PUBLIC; 633 + break; 634 + case IPV6_PREFER_SRC_TMP: 635 + pref |= IPV6_PREFER_SRC_TMP; 636 + break; 637 + case IPV6_PREFER_SRC_PUBTMP_DEFAULT: 638 + break; 639 + case 0: 640 + goto pref_skip_pubtmp; 641 + default: 642 + goto e_inval; 643 + } 644 + 645 + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC| 646 + IPV6_PREFER_SRC_TMP); 647 + pref_skip_pubtmp: 648 + 649 + /* check HOME/COA conflicts */ 650 + switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) { 651 + case IPV6_PREFER_SRC_HOME: 652 + break; 653 + case IPV6_PREFER_SRC_COA: 654 + pref |= IPV6_PREFER_SRC_COA; 655 + case 0: 656 + goto pref_skip_coa; 657 + default: 658 + goto e_inval; 659 + } 660 + 661 + prefmask &= ~IPV6_PREFER_SRC_COA; 662 + pref_skip_coa: 663 + 664 + /* check CGA/NONCGA conflicts */ 665 + switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { 666 + case IPV6_PREFER_SRC_CGA: 667 + case IPV6_PREFER_SRC_NONCGA: 668 + case 0: 669 + break; 670 + default: 671 + goto e_inval; 672 + } 673 + 674 + np->srcprefs = (np->srcprefs & prefmask) | pref; 675 + retv = 0; 676 + 677 + break; 678 + } 620 679 } 680 + 621 681 release_sock(sk); 622 682 623 683 return retv; ··· 990 930 991 931 case IPV6_FLOWINFO_SEND: 992 932 val = np->sndflow; 933 + break; 934 + 935 + case IPV6_ADDR_PREFERENCES: 936 + val = 0; 937 + 938 + if (np->srcprefs & IPV6_PREFER_SRC_TMP) 939 + val |= IPV6_PREFER_SRC_TMP; 940 + else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC) 941 + val |= IPV6_PREFER_SRC_PUBLIC; 942 + else { 943 + /* XXX: should we return system default? */ 944 + val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; 945 + } 946 + 947 + if (np->srcprefs & IPV6_PREFER_SRC_COA) 948 + val |= IPV6_PREFER_SRC_COA; 949 + else 950 + val |= IPV6_PREFER_SRC_HOME; 993 951 break; 994 952 995 953 default:
+3 -1
net/ipv6/ndisc.c
··· 546 546 override = 0; 547 547 in6_ifa_put(ifp); 548 548 } else { 549 - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) 549 + if (ipv6_dev_get_saddr(dev, daddr, 550 + inet6_sk(dev->nd_net->ipv6.ndisc_sk)->srcprefs, 551 + &tmpaddr)) 550 552 return; 551 553 src_addr = &tmpaddr; 552 554 }
+10 -1
net/ipv6/route.c
··· 782 782 783 783 if (!ipv6_addr_any(&fl->fl6_src)) 784 784 flags |= RT6_LOOKUP_F_HAS_SADDR; 785 + else if (sk) { 786 + unsigned int prefs = inet6_sk(sk)->srcprefs; 787 + if (prefs & IPV6_PREFER_SRC_TMP) 788 + flags |= RT6_LOOKUP_F_SRCPREF_TMP; 789 + if (prefs & IPV6_PREFER_SRC_PUBLIC) 790 + flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC; 791 + if (prefs & IPV6_PREFER_SRC_COA) 792 + flags |= RT6_LOOKUP_F_SRCPREF_COA; 793 + } 785 794 786 795 return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); 787 796 } ··· 2171 2162 else if (dst) { 2172 2163 struct in6_addr saddr_buf; 2173 2164 if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, 2174 - dst, &saddr_buf) == 0) 2165 + dst, 0, &saddr_buf) == 0) 2175 2166 NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); 2176 2167 } 2177 2168
+1 -1
net/ipv6/xfrm6_policy.c
··· 58 58 return -EHOSTUNREACH; 59 59 60 60 ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev, 61 - (struct in6_addr *)&daddr->a6, 61 + (struct in6_addr *)&daddr->a6, 0, 62 62 (struct in6_addr *)&saddr->a6); 63 63 dst_release(dst); 64 64 return 0;
+3 -1
net/sctp/ipv6.c
··· 316 316 317 317 if (!asoc) { 318 318 ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, 319 - &daddr->v6.sin6_addr, &saddr->v6.sin6_addr); 319 + &daddr->v6.sin6_addr, 320 + inet6_sk(asoc->base.sk)->srcprefs, 321 + &saddr->v6.sin6_addr); 320 322 SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", 321 323 NIP6(saddr->v6.sin6_addr)); 322 324 return;