diff options
-rw-r--r-- | net/ipv6/fib6_rules.c | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 6547fc6491a6..d040c4bff3a0 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -96,6 +96,31 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, | |||
96 | return &net->ipv6.ip6_null_entry->dst; | 96 | return &net->ipv6.ip6_null_entry->dst; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags, | ||
100 | struct flowi6 *flp6, const struct net_device *dev) | ||
101 | { | ||
102 | struct fib6_rule *r = (struct fib6_rule *)rule; | ||
103 | |||
104 | /* If we need to find a source address for this traffic, | ||
105 | * we check the result if it meets requirement of the rule. | ||
106 | */ | ||
107 | if ((rule->flags & FIB_RULE_FIND_SADDR) && | ||
108 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { | ||
109 | struct in6_addr saddr; | ||
110 | |||
111 | if (ipv6_dev_get_saddr(net, dev, &flp6->daddr, | ||
112 | rt6_flags2srcprefs(flags), &saddr)) | ||
113 | return -EAGAIN; | ||
114 | |||
115 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) | ||
116 | return -EAGAIN; | ||
117 | |||
118 | flp6->saddr = saddr; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
99 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | 124 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, |
100 | int flags, struct fib_lookup_arg *arg) | 125 | int flags, struct fib_lookup_arg *arg) |
101 | { | 126 | { |
@@ -134,27 +159,12 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
134 | 159 | ||
135 | rt = lookup(net, table, flp6, arg->lookup_data, flags); | 160 | rt = lookup(net, table, flp6, arg->lookup_data, flags); |
136 | if (rt != net->ipv6.ip6_null_entry) { | 161 | if (rt != net->ipv6.ip6_null_entry) { |
137 | struct fib6_rule *r = (struct fib6_rule *)rule; | 162 | err = fib6_rule_saddr(net, rule, flags, flp6, |
138 | 163 | ip6_dst_idev(&rt->dst)->dev); | |
139 | /* | 164 | |
140 | * If we need to find a source address for this traffic, | 165 | if (err == -EAGAIN) |
141 | * we check the result if it meets requirement of the rule. | 166 | goto again; |
142 | */ | 167 | |
143 | if ((rule->flags & FIB_RULE_FIND_SADDR) && | ||
144 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { | ||
145 | struct in6_addr saddr; | ||
146 | |||
147 | if (ipv6_dev_get_saddr(net, | ||
148 | ip6_dst_idev(&rt->dst)->dev, | ||
149 | &flp6->daddr, | ||
150 | rt6_flags2srcprefs(flags), | ||
151 | &saddr)) | ||
152 | goto again; | ||
153 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, | ||
154 | r->src.plen)) | ||
155 | goto again; | ||
156 | flp6->saddr = saddr; | ||
157 | } | ||
158 | err = rt->dst.error; | 168 | err = rt->dst.error; |
159 | if (err != -EAGAIN) | 169 | if (err != -EAGAIN) |
160 | goto out; | 170 | goto out; |