| 633 | |
| 634 | #ifdef INET6 |
| 635 | static int |
| 636 | tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) |
| 637 | { |
| 638 | struct epoch_tracker et; |
| 639 | int error = 0; |
| 640 | struct inpcb *inp; |
| 641 | struct tcpcb *tp = NULL; |
| 642 | struct sockaddr_in6 *sin6; |
| 643 | u_int8_t incflagsav; |
| 644 | u_char vflagsav; |
| 645 | |
| 646 | TCPDEBUG0; |
| 647 | |
| 648 | sin6 = (struct sockaddr_in6 *)nam; |
| 649 | if (nam->sa_len != sizeof (*sin6)) |
| 650 | return (EINVAL); |
| 651 | /* |
| 652 | * Must disallow TCP ``connections'' to multicast addresses. |
| 653 | */ |
| 654 | if (sin6->sin6_family == AF_INET6 |
| 655 | && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) |
| 656 | return (EAFNOSUPPORT); |
| 657 | |
| 658 | inp = sotoinpcb(so); |
| 659 | KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL")); |
| 660 | INP_WLOCK(inp); |
| 661 | vflagsav = inp->inp_vflag; |
| 662 | incflagsav = inp->inp_inc.inc_flags; |
| 663 | if (inp->inp_flags & INP_TIMEWAIT) { |
| 664 | error = EADDRINUSE; |
| 665 | goto out; |
| 666 | } |
| 667 | if (inp->inp_flags & INP_DROPPED) { |
| 668 | error = ECONNREFUSED; |
| 669 | goto out; |
| 670 | } |
| 671 | tp = intotcpcb(inp); |
| 672 | TCPDEBUG1(); |
| 673 | #ifdef INET |
| 674 | /* |
| 675 | * XXXRW: Some confusion: V4/V6 flags relate to binding, and |
| 676 | * therefore probably require the hash lock, which isn't held here. |
| 677 | * Is this a significant problem? |
| 678 | */ |
| 679 | if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { |
| 680 | struct sockaddr_in sin; |
| 681 | |
| 682 | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { |
| 683 | error = EINVAL; |
| 684 | goto out; |
| 685 | } |
| 686 | if ((inp->inp_vflag & INP_IPV4) == 0) { |
| 687 | error = EAFNOSUPPORT; |
| 688 | goto out; |
| 689 | } |
| 690 | |
| 691 | in6_sin6_2_sin(&sin, sin6); |
| 692 | if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { |
nothing calls this directly
no test coverage detected