Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_usrreq.c
Show First 20 Lines • Show All 987 Lines • ▼ Show 20 Lines | #endif | ||||
KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL")); | KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL")); | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
vflagsav = inp->inp_vflag; | vflagsav = inp->inp_vflag; | ||||
incflagsav = inp->inp_inc.inc_flags; | incflagsav = inp->inp_inc.inc_flags; | ||||
restoreflags = false; | restoreflags = false; | ||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | ||||
if (control) | if (control) | ||||
m_freem(control); | m_freem(control); | ||||
/* | /* | ||||
* In case of PRUS_NOTREADY, tcp_usr_ready() is responsible | * In case of PRUS_NOTREADY, tcp_usr_ready() is responsible | ||||
* for freeing memory. | * for freeing memory. | ||||
*/ | */ | ||||
if (m && (flags & PRUS_NOTREADY) == 0) | if ((flags & PRUS_NOTREADY) == 0) | ||||
m_freem(m); | m_freem(m); | ||||
error = ECONNRESET; | error = ECONNRESET; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (control != NULL) { | |||||
/* TCP doesn't do control messages (rights, creds, etc) */ | |||||
if (control->m_len) { | |||||
m_freem(control); | |||||
m_freem(m); | |||||
error = EINVAL; | |||||
goto out; | |||||
} | |||||
m_freem(control); /* empty control, just free it */ | |||||
control = NULL; | |||||
} | |||||
tp = intotcpcb(inp); | tp = intotcpcb(inp); | ||||
if (flags & PRUS_OOB) { | if (flags & PRUS_OOB) { | ||||
if ((error = tcp_pru_options_support(tp, PRUS_OOB)) != 0) { | if ((error = tcp_pru_options_support(tp, PRUS_OOB)) != 0) { | ||||
if (control) | if ((flags & PRUS_NOTREADY) == 0) | ||||
m_freem(control); | |||||
if (m && (flags & PRUS_NOTREADY) == 0) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
TCPDEBUG1(); | TCPDEBUG1(); | ||||
if (nam != NULL && tp->t_state < TCPS_SYN_SENT) { | if (nam != NULL && tp->t_state < TCPS_SYN_SENT) { | ||||
switch (nam->sa_family) { | switch (nam->sa_family) { | ||||
#ifdef INET | #ifdef INET | ||||
case AF_INET: | case AF_INET: | ||||
sinp = (struct sockaddr_in *)nam; | sinp = (struct sockaddr_in *)nam; | ||||
if (sinp->sin_len != sizeof(struct sockaddr_in)) { | if (sinp->sin_len != sizeof(struct sockaddr_in)) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((inp->inp_vflag & INP_IPV6) != 0) { | if ((inp->inp_vflag & INP_IPV6) != 0) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { | if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST) { | if (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EACCES; | error = EACCES; | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((error = prison_remote_ip4(td->td_ucred, | if ((error = prison_remote_ip4(td->td_ucred, | ||||
&sinp->sin_addr))) { | &sinp->sin_addr))) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
#ifdef INET6 | #ifdef INET6 | ||||
isipv6 = 0; | isipv6 = 0; | ||||
#endif | #endif | ||||
break; | break; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case AF_INET6: | case AF_INET6: | ||||
{ | { | ||||
struct sockaddr_in6 *sin6; | struct sockaddr_in6 *sin6; | ||||
sin6 = (struct sockaddr_in6 *)nam; | sin6 = (struct sockaddr_in6 *)nam; | ||||
if (sin6->sin6_len != sizeof(*sin6)) { | if (sin6->sin6_len != sizeof(*sin6)) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((inp->inp_vflag & INP_IPV6PROTO) == 0) { | if ((inp->inp_vflag & INP_IPV6PROTO) == 0) { | ||||
if (m != NULL) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { | if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | ||||
#ifdef INET | #ifdef INET | ||||
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { | if ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) { | if ((inp->inp_vflag & INP_IPV4) == 0) { | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
restoreflags = true; | restoreflags = true; | ||||
inp->inp_vflag &= ~INP_IPV6; | inp->inp_vflag &= ~INP_IPV6; | ||||
sinp = &sin; | sinp = &sin; | ||||
in6_sin6_2_sin(sinp, sin6); | in6_sin6_2_sin(sinp, sin6); | ||||
if (IN_MULTICAST( | if (IN_MULTICAST( | ||||
ntohl(sinp->sin_addr.s_addr))) { | ntohl(sinp->sin_addr.s_addr))) { | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
if ((error = prison_remote_ip4(td->td_ucred, | if ((error = prison_remote_ip4(td->td_ucred, | ||||
&sinp->sin_addr))) { | &sinp->sin_addr))) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
isipv6 = 0; | isipv6 = 0; | ||||
#else /* !INET */ | #else /* !INET */ | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
} else { | } else { | ||||
if ((inp->inp_vflag & INP_IPV6) == 0) { | if ((inp->inp_vflag & INP_IPV6) == 0) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
restoreflags = true; | restoreflags = true; | ||||
inp->inp_vflag &= ~INP_IPV4; | inp->inp_vflag &= ~INP_IPV4; | ||||
inp->inp_inc.inc_flags |= INC_ISIPV6; | inp->inp_inc.inc_flags |= INC_ISIPV6; | ||||
if ((error = prison_remote_ip6(td->td_ucred, | if ((error = prison_remote_ip6(td->td_ucred, | ||||
&sin6->sin6_addr))) { | &sin6->sin6_addr))) { | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
goto out; | goto out; | ||||
} | } | ||||
isipv6 = 1; | isipv6 = 1; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
default: | default: | ||||
if (m) | |||||
m_freem(m); | m_freem(m); | ||||
error = EAFNOSUPPORT; | error = EAFNOSUPPORT; | ||||
goto out; | goto out; | ||||
} | } | ||||
} | |||||
if (control) { | |||||
/* TCP doesn't do control messages (rights, creds, etc) */ | |||||
if (control->m_len) { | |||||
m_freem(control); | |||||
if (m) | |||||
m_freem(m); | |||||
error = EINVAL; | |||||
goto out; | |||||
} | |||||
m_freem(control); /* empty control, just free it */ | |||||
} | } | ||||
if (!(flags & PRUS_OOB)) { | if (!(flags & PRUS_OOB)) { | ||||
sbappendstream(&so->so_snd, m, flags); | sbappendstream(&so->so_snd, m, flags); | ||||
if (nam && tp->t_state < TCPS_SYN_SENT) { | if (nam && tp->t_state < TCPS_SYN_SENT) { | ||||
/* | /* | ||||
* Do implied connect if not yet connected, | * Do implied connect if not yet connected, | ||||
* initialize window to default value, and | * initialize window to default value, and | ||||
* initialize maxseg using peer's cached MSS. | * initialize maxseg using peer's cached MSS. | ||||
▲ Show 20 Lines • Show All 1,849 Lines • Show Last 20 Lines |