diff options
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 215 |
1 files changed, 123 insertions, 92 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 732689140fb8..0bb0d7cb9f10 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -47,6 +47,8 @@ | |||
47 | * be incorporated into the next SCTP release. | 47 | * be incorporated into the next SCTP release. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
51 | |||
50 | #include <linux/module.h> | 52 | #include <linux/module.h> |
51 | #include <linux/errno.h> | 53 | #include <linux/errno.h> |
52 | #include <linux/types.h> | 54 | #include <linux/types.h> |
@@ -78,6 +80,13 @@ | |||
78 | 80 | ||
79 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
80 | 82 | ||
83 | static inline int sctp_v6_addr_match_len(union sctp_addr *s1, | ||
84 | union sctp_addr *s2); | ||
85 | static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, | ||
86 | __be16 port); | ||
87 | static int sctp_v6_cmp_addr(const union sctp_addr *addr1, | ||
88 | const union sctp_addr *addr2); | ||
89 | |||
81 | /* Event handler for inet6 address addition/deletion events. | 90 | /* Event handler for inet6 address addition/deletion events. |
82 | * The sctp_local_addr_list needs to be protocted by a spin lock since | 91 | * The sctp_local_addr_list needs to be protocted by a spin lock since |
83 | * multiple notifiers (say IPv4 and IPv6) may be running at the same | 92 | * multiple notifiers (say IPv4 and IPv6) may be running at the same |
@@ -121,7 +130,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, | |||
121 | } | 130 | } |
122 | spin_unlock_bh(&sctp_local_addr_lock); | 131 | spin_unlock_bh(&sctp_local_addr_lock); |
123 | if (found) | 132 | if (found) |
124 | call_rcu(&addr->rcu, sctp_local_addr_free); | 133 | kfree_rcu(addr, rcu); |
125 | break; | 134 | break; |
126 | } | 135 | } |
127 | 136 | ||
@@ -199,76 +208,146 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) | |||
199 | { | 208 | { |
200 | struct sock *sk = skb->sk; | 209 | struct sock *sk = skb->sk; |
201 | struct ipv6_pinfo *np = inet6_sk(sk); | 210 | struct ipv6_pinfo *np = inet6_sk(sk); |
202 | struct flowi fl; | 211 | struct flowi6 fl6; |
203 | 212 | ||
204 | memset(&fl, 0, sizeof(fl)); | 213 | memset(&fl6, 0, sizeof(fl6)); |
205 | 214 | ||
206 | fl.proto = sk->sk_protocol; | 215 | fl6.flowi6_proto = sk->sk_protocol; |
207 | 216 | ||
208 | /* Fill in the dest address from the route entry passed with the skb | 217 | /* Fill in the dest address from the route entry passed with the skb |
209 | * and the source address from the transport. | 218 | * and the source address from the transport. |
210 | */ | 219 | */ |
211 | ipv6_addr_copy(&fl.fl6_dst, &transport->ipaddr.v6.sin6_addr); | 220 | ipv6_addr_copy(&fl6.daddr, &transport->ipaddr.v6.sin6_addr); |
212 | ipv6_addr_copy(&fl.fl6_src, &transport->saddr.v6.sin6_addr); | 221 | ipv6_addr_copy(&fl6.saddr, &transport->saddr.v6.sin6_addr); |
213 | 222 | ||
214 | fl.fl6_flowlabel = np->flow_label; | 223 | fl6.flowlabel = np->flow_label; |
215 | IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); | 224 | IP6_ECN_flow_xmit(sk, fl6.flowlabel); |
216 | if (ipv6_addr_type(&fl.fl6_src) & IPV6_ADDR_LINKLOCAL) | 225 | if (ipv6_addr_type(&fl6.saddr) & IPV6_ADDR_LINKLOCAL) |
217 | fl.oif = transport->saddr.v6.sin6_scope_id; | 226 | fl6.flowi6_oif = transport->saddr.v6.sin6_scope_id; |
218 | else | 227 | else |
219 | fl.oif = sk->sk_bound_dev_if; | 228 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
220 | 229 | ||
221 | if (np->opt && np->opt->srcrt) { | 230 | if (np->opt && np->opt->srcrt) { |
222 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | 231 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; |
223 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 232 | ipv6_addr_copy(&fl6.daddr, rt0->addr); |
224 | } | 233 | } |
225 | 234 | ||
226 | SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", | 235 | SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", |
227 | __func__, skb, skb->len, | 236 | __func__, skb, skb->len, |
228 | &fl.fl6_src, &fl.fl6_dst); | 237 | &fl6.saddr, &fl6.daddr); |
229 | 238 | ||
230 | SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); | 239 | SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); |
231 | 240 | ||
232 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) | 241 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) |
233 | skb->local_df = 1; | 242 | skb->local_df = 1; |
234 | 243 | ||
235 | return ip6_xmit(sk, skb, &fl, np->opt); | 244 | return ip6_xmit(sk, skb, &fl6, np->opt); |
236 | } | 245 | } |
237 | 246 | ||
238 | /* Returns the dst cache entry for the given source and destination ip | 247 | /* Returns the dst cache entry for the given source and destination ip |
239 | * addresses. | 248 | * addresses. |
240 | */ | 249 | */ |
241 | static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, | 250 | static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, |
242 | union sctp_addr *daddr, | 251 | struct flowi *fl, struct sock *sk) |
243 | union sctp_addr *saddr) | ||
244 | { | 252 | { |
245 | struct dst_entry *dst; | 253 | struct sctp_association *asoc = t->asoc; |
246 | struct flowi fl; | 254 | struct dst_entry *dst = NULL; |
255 | struct flowi6 *fl6 = &fl->u.ip6; | ||
256 | struct sctp_bind_addr *bp; | ||
257 | struct sctp_sockaddr_entry *laddr; | ||
258 | union sctp_addr *baddr = NULL; | ||
259 | union sctp_addr *daddr = &t->ipaddr; | ||
260 | union sctp_addr dst_saddr; | ||
261 | __u8 matchlen = 0; | ||
262 | __u8 bmatchlen; | ||
263 | sctp_scope_t scope; | ||
247 | 264 | ||
248 | memset(&fl, 0, sizeof(fl)); | 265 | memset(fl6, 0, sizeof(struct flowi6)); |
249 | ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr); | 266 | ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); |
267 | fl6->fl6_dport = daddr->v6.sin6_port; | ||
268 | fl6->flowi6_proto = IPPROTO_SCTP; | ||
250 | if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) | 269 | if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) |
251 | fl.oif = daddr->v6.sin6_scope_id; | 270 | fl6->flowi6_oif = daddr->v6.sin6_scope_id; |
252 | 271 | ||
272 | SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); | ||
253 | 273 | ||
254 | SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst); | 274 | if (asoc) |
275 | fl6->fl6_sport = htons(asoc->base.bind_addr.port); | ||
255 | 276 | ||
256 | if (saddr) { | 277 | if (saddr) { |
257 | ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr); | 278 | ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); |
258 | SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src); | 279 | fl6->fl6_sport = saddr->v6.sin6_port; |
280 | SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); | ||
281 | } | ||
282 | |||
283 | dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); | ||
284 | if (!asoc || saddr) | ||
285 | goto out; | ||
286 | |||
287 | bp = &asoc->base.bind_addr; | ||
288 | scope = sctp_scope(daddr); | ||
289 | /* ip6_dst_lookup has filled in the fl6->saddr for us. Check | ||
290 | * to see if we can use it. | ||
291 | */ | ||
292 | if (!IS_ERR(dst)) { | ||
293 | /* Walk through the bind address list and look for a bind | ||
294 | * address that matches the source address of the returned dst. | ||
295 | */ | ||
296 | sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port)); | ||
297 | rcu_read_lock(); | ||
298 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | ||
299 | if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) | ||
300 | continue; | ||
301 | |||
302 | /* Do not compare against v4 addrs */ | ||
303 | if ((laddr->a.sa.sa_family == AF_INET6) && | ||
304 | (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { | ||
305 | rcu_read_unlock(); | ||
306 | goto out; | ||
307 | } | ||
308 | } | ||
309 | rcu_read_unlock(); | ||
310 | /* None of the bound addresses match the source address of the | ||
311 | * dst. So release it. | ||
312 | */ | ||
313 | dst_release(dst); | ||
314 | dst = NULL; | ||
315 | } | ||
316 | |||
317 | /* Walk through the bind address list and try to get the | ||
318 | * best source address for a given destination. | ||
319 | */ | ||
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | ||
322 | if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) | ||
323 | continue; | ||
324 | if ((laddr->a.sa.sa_family == AF_INET6) && | ||
325 | (scope <= sctp_scope(&laddr->a))) { | ||
326 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | ||
327 | if (!baddr || (matchlen < bmatchlen)) { | ||
328 | baddr = &laddr->a; | ||
329 | matchlen = bmatchlen; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | rcu_read_unlock(); | ||
334 | if (baddr) { | ||
335 | ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); | ||
336 | fl6->fl6_sport = baddr->v6.sin6_port; | ||
337 | dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); | ||
259 | } | 338 | } |
260 | 339 | ||
261 | dst = ip6_route_output(&init_net, NULL, &fl); | 340 | out: |
262 | if (!dst->error) { | 341 | if (!IS_ERR(dst)) { |
263 | struct rt6_info *rt; | 342 | struct rt6_info *rt; |
264 | rt = (struct rt6_info *)dst; | 343 | rt = (struct rt6_info *)dst; |
344 | t->dst = dst; | ||
265 | SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", | 345 | SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", |
266 | &rt->rt6i_dst.addr, &rt->rt6i_src.addr); | 346 | &rt->rt6i_dst.addr, &fl6->saddr); |
267 | return dst; | 347 | } else { |
348 | t->dst = NULL; | ||
349 | SCTP_DEBUG_PRINTK("NO ROUTE\n"); | ||
268 | } | 350 | } |
269 | SCTP_DEBUG_PRINTK("NO ROUTE\n"); | ||
270 | dst_release(dst); | ||
271 | return NULL; | ||
272 | } | 351 | } |
273 | 352 | ||
274 | /* Returns the number of consecutive initial bits that match in the 2 ipv6 | 353 | /* Returns the number of consecutive initial bits that match in the 2 ipv6 |
@@ -284,64 +363,18 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, | |||
284 | * and asoc's bind address list. | 363 | * and asoc's bind address list. |
285 | */ | 364 | */ |
286 | static void sctp_v6_get_saddr(struct sctp_sock *sk, | 365 | static void sctp_v6_get_saddr(struct sctp_sock *sk, |
287 | struct sctp_association *asoc, | 366 | struct sctp_transport *t, |
288 | struct dst_entry *dst, | 367 | struct flowi *fl) |
289 | union sctp_addr *daddr, | ||
290 | union sctp_addr *saddr) | ||
291 | { | 368 | { |
292 | struct sctp_bind_addr *bp; | 369 | struct flowi6 *fl6 = &fl->u.ip6; |
293 | struct sctp_sockaddr_entry *laddr; | 370 | union sctp_addr *saddr = &t->saddr; |
294 | sctp_scope_t scope; | ||
295 | union sctp_addr *baddr = NULL; | ||
296 | __u8 matchlen = 0; | ||
297 | __u8 bmatchlen; | ||
298 | 371 | ||
299 | SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", | 372 | SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst); |
300 | __func__, asoc, dst, &daddr->v6.sin6_addr); | ||
301 | |||
302 | if (!asoc) { | ||
303 | ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), | ||
304 | dst ? ip6_dst_idev(dst)->dev : NULL, | ||
305 | &daddr->v6.sin6_addr, | ||
306 | inet6_sk(&sk->inet.sk)->srcprefs, | ||
307 | &saddr->v6.sin6_addr); | ||
308 | SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", | ||
309 | &saddr->v6.sin6_addr); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | scope = sctp_scope(daddr); | ||
314 | |||
315 | bp = &asoc->base.bind_addr; | ||
316 | 373 | ||
317 | /* Go through the bind address list and find the best source address | 374 | if (t->dst) { |
318 | * that matches the scope of the destination address. | 375 | saddr->v6.sin6_family = AF_INET6; |
319 | */ | 376 | ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr); |
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | ||
322 | if (!laddr->valid) | ||
323 | continue; | ||
324 | if ((laddr->state == SCTP_ADDR_SRC) && | ||
325 | (laddr->a.sa.sa_family == AF_INET6) && | ||
326 | (scope <= sctp_scope(&laddr->a))) { | ||
327 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | ||
328 | if (!baddr || (matchlen < bmatchlen)) { | ||
329 | baddr = &laddr->a; | ||
330 | matchlen = bmatchlen; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | |||
335 | if (baddr) { | ||
336 | memcpy(saddr, baddr, sizeof(union sctp_addr)); | ||
337 | SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); | ||
338 | } else { | ||
339 | printk(KERN_ERR "%s: asoc:%p Could not find a valid source " | ||
340 | "address for the dest:%pI6\n", | ||
341 | __func__, asoc, &daddr->v6.sin6_addr); | ||
342 | } | 377 | } |
343 | |||
344 | rcu_read_unlock(); | ||
345 | } | 378 | } |
346 | 379 | ||
347 | /* Make a copy of all potential local addresses. */ | 380 | /* Make a copy of all potential local addresses. */ |
@@ -463,14 +496,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr, | |||
463 | return length; | 496 | return length; |
464 | } | 497 | } |
465 | 498 | ||
466 | /* Initialize a sctp_addr from a dst_entry. */ | 499 | /* Initialize a sctp_addr from struct in6_addr. */ |
467 | static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, | 500 | static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, |
468 | __be16 port) | 501 | __be16 port) |
469 | { | 502 | { |
470 | struct rt6_info *rt = (struct rt6_info *)dst; | ||
471 | addr->sa.sa_family = AF_INET6; | 503 | addr->sa.sa_family = AF_INET6; |
472 | addr->v6.sin6_port = port; | 504 | addr->v6.sin6_port = port; |
473 | ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); | 505 | ipv6_addr_copy(&addr->v6.sin6_addr, saddr); |
474 | } | 506 | } |
475 | 507 | ||
476 | /* Compare addresses exactly. | 508 | /* Compare addresses exactly. |
@@ -529,7 +561,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) | |||
529 | static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) | 561 | static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) |
530 | { | 562 | { |
531 | int type; | 563 | int type; |
532 | struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; | 564 | const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr; |
533 | 565 | ||
534 | type = ipv6_addr_type(in6); | 566 | type = ipv6_addr_type(in6); |
535 | if (IPV6_ADDR_ANY == type) | 567 | if (IPV6_ADDR_ANY == type) |
@@ -957,7 +989,6 @@ static struct sctp_af sctp_af_inet6 = { | |||
957 | .to_sk_daddr = sctp_v6_to_sk_daddr, | 989 | .to_sk_daddr = sctp_v6_to_sk_daddr, |
958 | .from_addr_param = sctp_v6_from_addr_param, | 990 | .from_addr_param = sctp_v6_from_addr_param, |
959 | .to_addr_param = sctp_v6_to_addr_param, | 991 | .to_addr_param = sctp_v6_to_addr_param, |
960 | .dst_saddr = sctp_v6_dst_saddr, | ||
961 | .cmp_addr = sctp_v6_cmp_addr, | 992 | .cmp_addr = sctp_v6_cmp_addr, |
962 | .scope = sctp_v6_scope, | 993 | .scope = sctp_v6_scope, |
963 | .addr_valid = sctp_v6_addr_valid, | 994 | .addr_valid = sctp_v6_addr_valid, |