| 395 | |
| 396 | #ifdef INET6 |
| 397 | static int |
| 398 | tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td) |
| 399 | { |
| 400 | int error = 0; |
| 401 | struct inpcb *inp; |
| 402 | struct tcpcb *tp = NULL; |
| 403 | struct sockaddr_in6 *sin6; |
| 404 | u_char vflagsav; |
| 405 | |
| 406 | sin6 = (struct sockaddr_in6 *)nam; |
| 407 | if (nam->sa_len != sizeof (*sin6)) |
| 408 | return (EINVAL); |
| 409 | /* |
| 410 | * Must check for multicast addresses and disallow binding |
| 411 | * to them. |
| 412 | */ |
| 413 | if (sin6->sin6_family == AF_INET6 && |
| 414 | IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) |
| 415 | return (EAFNOSUPPORT); |
| 416 | |
| 417 | TCPDEBUG0; |
| 418 | inp = sotoinpcb(so); |
| 419 | KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL")); |
| 420 | INP_WLOCK(inp); |
| 421 | vflagsav = inp->inp_vflag; |
| 422 | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { |
| 423 | error = EINVAL; |
| 424 | goto out; |
| 425 | } |
| 426 | tp = intotcpcb(inp); |
| 427 | TCPDEBUG1(); |
| 428 | INP_HASH_WLOCK(&V_tcbinfo); |
| 429 | inp->inp_vflag &= ~INP_IPV4; |
| 430 | inp->inp_vflag |= INP_IPV6; |
| 431 | #ifdef INET |
| 432 | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { |
| 433 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) |
| 434 | inp->inp_vflag |= INP_IPV4; |
| 435 | else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { |
| 436 | struct sockaddr_in sin; |
| 437 | |
| 438 | in6_sin6_2_sin(&sin, sin6); |
| 439 | if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { |
| 440 | error = EAFNOSUPPORT; |
| 441 | INP_HASH_WUNLOCK(&V_tcbinfo); |
| 442 | goto out; |
| 443 | } |
| 444 | inp->inp_vflag |= INP_IPV4; |
| 445 | inp->inp_vflag &= ~INP_IPV6; |
| 446 | error = in_pcbbind(inp, (struct sockaddr *)&sin, |
| 447 | td->td_ucred); |
| 448 | INP_HASH_WUNLOCK(&V_tcbinfo); |
| 449 | goto out; |
| 450 | } |
| 451 | } |
| 452 | #endif |
| 453 | error = in6_pcbbind(inp, nam, td->td_ucred); |
| 454 | INP_HASH_WUNLOCK(&V_tcbinfo); |
nothing calls this directly
no test coverage detected