diff options
Diffstat (limited to 'net/ipv6/af_inet6.c')
-rw-r--r-- | net/ipv6/af_inet6.c | 70 |
1 files changed, 34 insertions, 36 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 56b9bf2516f4..3b5669a2582d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -272,6 +272,10 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
272 | 272 | ||
273 | if (addr_len < SIN6_LEN_RFC2133) | 273 | if (addr_len < SIN6_LEN_RFC2133) |
274 | return -EINVAL; | 274 | return -EINVAL; |
275 | |||
276 | if (addr->sin6_family != AF_INET6) | ||
277 | return -EAFNOSUPPORT; | ||
278 | |||
275 | addr_type = ipv6_addr_type(&addr->sin6_addr); | 279 | addr_type = ipv6_addr_type(&addr->sin6_addr); |
276 | if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) | 280 | if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) |
277 | return -EINVAL; | 281 | return -EINVAL; |
@@ -300,7 +304,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
300 | goto out; | 304 | goto out; |
301 | } | 305 | } |
302 | 306 | ||
303 | /* Reproduce AF_INET checks to make the bindings consitant */ | 307 | /* Reproduce AF_INET checks to make the bindings consistent */ |
304 | v4addr = addr->sin6_addr.s6_addr32[3]; | 308 | v4addr = addr->sin6_addr.s6_addr32[3]; |
305 | chk_addr_ret = inet_addr_type(net, v4addr); | 309 | chk_addr_ret = inet_addr_type(net, v4addr); |
306 | if (!sysctl_ip_nonlocal_bind && | 310 | if (!sysctl_ip_nonlocal_bind && |
@@ -343,7 +347,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
343 | */ | 347 | */ |
344 | v4addr = LOOPBACK4_IPV6; | 348 | v4addr = LOOPBACK4_IPV6; |
345 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { | 349 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { |
346 | if (!ipv6_chk_addr(net, &addr->sin6_addr, | 350 | if (!inet->transparent && |
351 | !ipv6_chk_addr(net, &addr->sin6_addr, | ||
347 | dev, 0)) { | 352 | dev, 0)) { |
348 | err = -EADDRNOTAVAIL; | 353 | err = -EADDRNOTAVAIL; |
349 | goto out_unlock; | 354 | goto out_unlock; |
@@ -467,7 +472,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
467 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 472 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
468 | sin->sin6_scope_id = sk->sk_bound_dev_if; | 473 | sin->sin6_scope_id = sk->sk_bound_dev_if; |
469 | *uaddr_len = sizeof(*sin); | 474 | *uaddr_len = sizeof(*sin); |
470 | return(0); | 475 | return 0; |
471 | } | 476 | } |
472 | 477 | ||
473 | EXPORT_SYMBOL(inet6_getname); | 478 | EXPORT_SYMBOL(inet6_getname); |
@@ -488,7 +493,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
488 | case SIOCADDRT: | 493 | case SIOCADDRT: |
489 | case SIOCDELRT: | 494 | case SIOCDELRT: |
490 | 495 | ||
491 | return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); | 496 | return ipv6_route_ioctl(net, cmd, (void __user *)arg); |
492 | 497 | ||
493 | case SIOCSIFADDR: | 498 | case SIOCSIFADDR: |
494 | return addrconf_add_ifaddr(net, (void __user *) arg); | 499 | return addrconf_add_ifaddr(net, (void __user *) arg); |
@@ -502,7 +507,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
502 | return sk->sk_prot->ioctl(sk, cmd, arg); | 507 | return sk->sk_prot->ioctl(sk, cmd, arg); |
503 | } | 508 | } |
504 | /*NOTREACHED*/ | 509 | /*NOTREACHED*/ |
505 | return(0); | 510 | return 0; |
506 | } | 511 | } |
507 | 512 | ||
508 | EXPORT_SYMBOL(inet6_ioctl); | 513 | EXPORT_SYMBOL(inet6_ioctl); |
@@ -643,41 +648,34 @@ EXPORT_SYMBOL(inet6_unregister_protosw); | |||
643 | 648 | ||
644 | int inet6_sk_rebuild_header(struct sock *sk) | 649 | int inet6_sk_rebuild_header(struct sock *sk) |
645 | { | 650 | { |
646 | int err; | ||
647 | struct dst_entry *dst; | ||
648 | struct ipv6_pinfo *np = inet6_sk(sk); | 651 | struct ipv6_pinfo *np = inet6_sk(sk); |
652 | struct dst_entry *dst; | ||
649 | 653 | ||
650 | dst = __sk_dst_check(sk, np->dst_cookie); | 654 | dst = __sk_dst_check(sk, np->dst_cookie); |
651 | 655 | ||
652 | if (dst == NULL) { | 656 | if (dst == NULL) { |
653 | struct inet_sock *inet = inet_sk(sk); | 657 | struct inet_sock *inet = inet_sk(sk); |
654 | struct in6_addr *final_p, final; | 658 | struct in6_addr *final_p, final; |
655 | struct flowi fl; | 659 | struct flowi6 fl6; |
656 | 660 | ||
657 | memset(&fl, 0, sizeof(fl)); | 661 | memset(&fl6, 0, sizeof(fl6)); |
658 | fl.proto = sk->sk_protocol; | 662 | fl6.flowi6_proto = sk->sk_protocol; |
659 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 663 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
660 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 664 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
661 | fl.fl6_flowlabel = np->flow_label; | 665 | fl6.flowlabel = np->flow_label; |
662 | fl.oif = sk->sk_bound_dev_if; | 666 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
663 | fl.mark = sk->sk_mark; | 667 | fl6.flowi6_mark = sk->sk_mark; |
664 | fl.fl_ip_dport = inet->inet_dport; | 668 | fl6.fl6_dport = inet->inet_dport; |
665 | fl.fl_ip_sport = inet->inet_sport; | 669 | fl6.fl6_sport = inet->inet_sport; |
666 | security_sk_classify_flow(sk, &fl); | 670 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
667 | 671 | ||
668 | final_p = fl6_update_dst(&fl, np->opt, &final); | 672 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
669 | 673 | ||
670 | err = ip6_dst_lookup(sk, &dst, &fl); | 674 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); |
671 | if (err) { | 675 | if (IS_ERR(dst)) { |
672 | sk->sk_route_caps = 0; | 676 | sk->sk_route_caps = 0; |
673 | return err; | 677 | sk->sk_err_soft = -PTR_ERR(dst); |
674 | } | 678 | return PTR_ERR(dst); |
675 | if (final_p) | ||
676 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
677 | |||
678 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { | ||
679 | sk->sk_err_soft = -err; | ||
680 | return err; | ||
681 | } | 679 | } |
682 | 680 | ||
683 | __ip6_dst_store(sk, dst, NULL, NULL); | 681 | __ip6_dst_store(sk, dst, NULL, NULL); |
@@ -746,7 +744,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) | |||
746 | 744 | ||
747 | static int ipv6_gso_send_check(struct sk_buff *skb) | 745 | static int ipv6_gso_send_check(struct sk_buff *skb) |
748 | { | 746 | { |
749 | struct ipv6hdr *ipv6h; | 747 | const struct ipv6hdr *ipv6h; |
750 | const struct inet6_protocol *ops; | 748 | const struct inet6_protocol *ops; |
751 | int err = -EINVAL; | 749 | int err = -EINVAL; |
752 | 750 | ||
@@ -771,7 +769,7 @@ out: | |||
771 | return err; | 769 | return err; |
772 | } | 770 | } |
773 | 771 | ||
774 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | 772 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) |
775 | { | 773 | { |
776 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 774 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
777 | struct ipv6hdr *ipv6h; | 775 | struct ipv6hdr *ipv6h; |
@@ -809,7 +807,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
809 | } | 807 | } |
810 | rcu_read_unlock(); | 808 | rcu_read_unlock(); |
811 | 809 | ||
812 | if (unlikely(IS_ERR(segs))) | 810 | if (IS_ERR(segs)) |
813 | goto out; | 811 | goto out; |
814 | 812 | ||
815 | for (skb = segs; skb; skb = skb->next) { | 813 | for (skb = segs; skb; skb = skb->next) { |
@@ -1119,7 +1117,7 @@ static int __init inet6_init(void) | |||
1119 | /* | 1117 | /* |
1120 | * ipngwg API draft makes clear that the correct semantics | 1118 | * ipngwg API draft makes clear that the correct semantics |
1121 | * for TCP and UDP is to consider one TCP and UDP instance | 1119 | * for TCP and UDP is to consider one TCP and UDP instance |
1122 | * in a host availiable by both INET and INET6 APIs and | 1120 | * in a host available by both INET and INET6 APIs and |
1123 | * able to communicate via both network protocols. | 1121 | * able to communicate via both network protocols. |
1124 | */ | 1122 | */ |
1125 | 1123 | ||