Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_usrreq.c
Show First 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | #define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ | ||||
tcp_trace(TA_USER, ostate, tp, 0, 0, req) | tcp_trace(TA_USER, ostate, tp, 0, 0, req) | ||||
#else | #else | ||||
#define TCPDEBUG0 | #define TCPDEBUG0 | ||||
#define TCPDEBUG1() | #define TCPDEBUG1() | ||||
#define TCPDEBUG2(req) | #define TCPDEBUG2(req) | ||||
#endif | #endif | ||||
/* | /* | ||||
* tcp_require_unique port requires a globally-unique source port for each | |||||
* outgoing connection. The default is to require the 4-tuple to be unique. | |||||
*/ | |||||
VNET_DEFINE(int, tcp_require_unique_port) = 0; | |||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, require_unique_port, | |||||
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_require_unique_port), 0, | |||||
"Require globally-unique ephemeral port for outgoing connections"); | |||||
#define V_tcp_require_unique_port VNET(tcp_require_unique_port) | |||||
/* | |||||
* TCP attaches to socket via pru_attach(), reserving space, | * TCP attaches to socket via pru_attach(), reserving space, | ||||
* and an internet control block. | * and an internet control block. | ||||
*/ | */ | ||||
static int | static int | ||||
tcp_usr_attach(struct socket *so, int proto, struct thread *td) | tcp_usr_attach(struct socket *so, int proto, struct thread *td) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct tcpcb *tp = NULL; | struct tcpcb *tp = NULL; | ||||
▲ Show 20 Lines • Show All 1,351 Lines • ▼ Show 20 Lines | tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) | ||||
struct in_addr laddr; | struct in_addr laddr; | ||||
u_short lport; | u_short lport; | ||||
int error; | int error; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_HASH_WLOCK(&V_tcbinfo); | INP_HASH_WLOCK(&V_tcbinfo); | ||||
if (inp->inp_lport == 0) { | if (V_tcp_require_unique_port && inp->inp_lport == 0) { | ||||
error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Cannot simply call in_pcbconnect, because there might be an | * Cannot simply call in_pcbconnect, because there might be an | ||||
* earlier incarnation of this same connection still in | * earlier incarnation of this same connection still in | ||||
* TIME_WAIT state, creating an ADDRINUSE error. | * TIME_WAIT state, creating an ADDRINUSE error. | ||||
*/ | */ | ||||
laddr = inp->inp_laddr; | laddr = inp->inp_laddr; | ||||
lport = inp->inp_lport; | lport = inp->inp_lport; | ||||
error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport, | error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport, | ||||
&inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred); | &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred); | ||||
if (error && oinp == NULL) | if (error && oinp == NULL) | ||||
goto out; | goto out; | ||||
if (oinp) { | if (oinp) { | ||||
error = EADDRINUSE; | error = EADDRINUSE; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* Handle initial bind if it hadn't been done in advance. */ | |||||
if (inp->inp_lport == 0) { | |||||
inp->inp_lport = lport; | |||||
if (in_pcbinshash(inp) != 0) { | |||||
inp->inp_lport = 0; | |||||
error = EAGAIN; | |||||
goto out; | |||||
} | |||||
} | |||||
inp->inp_laddr = laddr; | inp->inp_laddr = laddr; | ||||
in_pcbrehash(inp); | in_pcbrehash(inp); | ||||
INP_HASH_WUNLOCK(&V_tcbinfo); | INP_HASH_WUNLOCK(&V_tcbinfo); | ||||
/* | /* | ||||
* Compute window scaling to request: | * Compute window scaling to request: | ||||
* Scale to fit into sweet spot. See tcp_syncache.c. | * Scale to fit into sweet spot. See tcp_syncache.c. | ||||
* XXX: This should move to tcp_output(). | * XXX: This should move to tcp_output(). | ||||
Show All 23 Lines | |||||
tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) | tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) | ||||
{ | { | ||||
struct inpcb *inp = tp->t_inpcb; | struct inpcb *inp = tp->t_inpcb; | ||||
int error; | int error; | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_HASH_WLOCK(&V_tcbinfo); | INP_HASH_WLOCK(&V_tcbinfo); | ||||
if (inp->inp_lport == 0) { | if (V_tcp_require_unique_port && inp->inp_lport == 0) { | ||||
error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
} | } | ||||
error = in6_pcbconnect(inp, nam, td->td_ucred); | error = in6_pcbconnect(inp, nam, td->td_ucred); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
INP_HASH_WUNLOCK(&V_tcbinfo); | INP_HASH_WUNLOCK(&V_tcbinfo); | ||||
▲ Show 20 Lines • Show All 1,328 Lines • Show Last 20 Lines |