Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_usrreq.c
Show First 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
static void tcp_disconnect(struct tcpcb *); | static void tcp_disconnect(struct tcpcb *); | ||||
static void tcp_usrclosed(struct tcpcb *); | static void tcp_usrclosed(struct tcpcb *); | ||||
static void tcp_fill_info(struct tcpcb *, struct tcp_info *); | static void tcp_fill_info(struct tcpcb *, struct tcp_info *); | ||||
static int tcp_pru_options_support(struct tcpcb *tp, int flags); | static int tcp_pru_options_support(struct tcpcb *tp, int flags); | ||||
/* | /* | ||||
* 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,263 Lines • ▼ Show 20 Lines | tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) | ||||
struct inpcb *inp = tptoinpcb(tp), *oinp; | struct inpcb *inp = tptoinpcb(tp), *oinp; | ||||
struct socket *so = tptosocket(tp); | struct socket *so = tptosocket(tp); | ||||
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); | |||||
if (V_tcp_require_unique_port && inp->inp_lport == 0) { | INP_HASH_WLOCK(&V_tcbinfo); | ||||
error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | |||||
if (error) | |||||
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, | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
static int | static int | ||||
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 = tptoinpcb(tp); | struct inpcb *inp = tptoinpcb(tp); | ||||
int error; | int error; | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_HASH_WLOCK(&V_tcbinfo); | |||||
if (V_tcp_require_unique_port && inp->inp_lport == 0) { | INP_HASH_WLOCK(&V_tcbinfo); | ||||
error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred); | |||||
if (error) | |||||
goto out; | |||||
} | |||||
error = in6_pcbconnect(inp, nam, td->td_ucred); | error = in6_pcbconnect(inp, nam, td->td_ucred); | ||||
if (error != 0) | |||||
goto out; | |||||
INP_HASH_WUNLOCK(&V_tcbinfo); | INP_HASH_WUNLOCK(&V_tcbinfo); | ||||
if (error != 0) | |||||
return (error); | |||||
/* Compute window scaling to request. */ | /* Compute window scaling to request. */ | ||||
while (tp->request_r_scale < TCP_MAX_WINSHIFT && | while (tp->request_r_scale < TCP_MAX_WINSHIFT && | ||||
(TCP_MAXWIN << tp->request_r_scale) < sb_max) | (TCP_MAXWIN << tp->request_r_scale) < sb_max) | ||||
tp->request_r_scale++; | tp->request_r_scale++; | ||||
soisconnecting(inp->inp_socket); | soisconnecting(inp->inp_socket); | ||||
TCPSTAT_INC(tcps_connattempt); | TCPSTAT_INC(tcps_connattempt); | ||||
tcp_state_change(tp, TCPS_SYN_SENT); | tcp_state_change(tp, TCPS_SYN_SENT); | ||||
tp->iss = tcp_new_isn(&inp->inp_inc); | tp->iss = tcp_new_isn(&inp->inp_inc); | ||||
if (tp->t_flags & TF_REQ_TSTMP) | if (tp->t_flags & TF_REQ_TSTMP) | ||||
tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc); | tp->ts_offset = tcp_new_ts_offset(&inp->inp_inc); | ||||
tcp_sendseqinit(tp); | tcp_sendseqinit(tp); | ||||
return 0; | return (0); | ||||
out: | |||||
INP_HASH_WUNLOCK(&V_tcbinfo); | |||||
return error; | |||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
/* | /* | ||||
* Export TCP internal state information via a struct tcp_info, based on the | * Export TCP internal state information via a struct tcp_info, based on the | ||||
* Linux 2.6 API. Not ABI compatible as our constants are mapped differently | * Linux 2.6 API. Not ABI compatible as our constants are mapped differently | ||||
* (TCP state machine, etc). We export all information using FreeBSD-native | * (TCP state machine, etc). We export all information using FreeBSD-native | ||||
* constants -- for example, the numeric values for tcpi_state will differ | * constants -- for example, the numeric values for tcpi_state will differ | ||||
▲ Show 20 Lines • Show All 1,593 Lines • Show Last 20 Lines |