Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_usrreq.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_tcpdebug.h" | #include "opt_tcpdebug.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/refcount.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
#include <sys/domain.h> | #include <sys/domain.h> | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/socketvar.h> | #include <sys/socketvar.h> | ||||
▲ Show 20 Lines • Show All 446 Lines • ▼ Show 20 Lines | if ((error = tcp_connect(tp, nam, td)) != 0) | ||||
goto out; | goto out; | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (registered_toedevs > 0 && | if (registered_toedevs > 0 && | ||||
(so->so_options & SO_NO_OFFLOAD) == 0 && | (so->so_options & SO_NO_OFFLOAD) == 0 && | ||||
(error = tcp_offload_connect(so, nam)) == 0) | (error = tcp_offload_connect(so, nam)) == 0) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); | tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
out: | out: | ||||
TCPDEBUG2(PRU_CONNECT); | TCPDEBUG2(PRU_CONNECT); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#ifdef INET6 | #ifdef INET6 | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { | ||||
if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0) | if ((error = tcp_connect(tp, (struct sockaddr *)&sin, td)) != 0) | ||||
goto out; | goto out; | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (registered_toedevs > 0 && | if (registered_toedevs > 0 && | ||||
(so->so_options & SO_NO_OFFLOAD) == 0 && | (so->so_options & SO_NO_OFFLOAD) == 0 && | ||||
(error = tcp_offload_connect(so, nam)) == 0) | (error = tcp_offload_connect(so, nam)) == 0) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
goto out; | goto out; | ||||
} | } | ||||
#endif | #endif | ||||
inp->inp_vflag &= ~INP_IPV4; | inp->inp_vflag &= ~INP_IPV4; | ||||
inp->inp_vflag |= INP_IPV6; | inp->inp_vflag |= INP_IPV6; | ||||
inp->inp_inc.inc_flags |= INC_ISIPV6; | inp->inp_inc.inc_flags |= INC_ISIPV6; | ||||
if ((error = prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr)) != 0) | if ((error = prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr)) != 0) | ||||
goto out; | goto out; | ||||
if ((error = tcp6_connect(tp, nam, td)) != 0) | if ((error = tcp6_connect(tp, nam, td)) != 0) | ||||
goto out; | goto out; | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (registered_toedevs > 0 && | if (registered_toedevs > 0 && | ||||
(so->so_options & SO_NO_OFFLOAD) == 0 && | (so->so_options & SO_NO_OFFLOAD) == 0 && | ||||
(error = tcp_offload_connect(so, nam)) == 0) | (error = tcp_offload_connect(so, nam)) == 0) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); | tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
out: | out: | ||||
TCPDEBUG2(PRU_CONNECT); | TCPDEBUG2(PRU_CONNECT); | ||||
TCP_PROBE2(debug__user, tp, PRU_CONNECT); | TCP_PROBE2(debug__user, tp, PRU_CONNECT); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | ||||
error = ECONNRESET; | error = ECONNRESET; | ||||
goto out; | goto out; | ||||
} | } | ||||
tp = intotcpcb(inp); | tp = intotcpcb(inp); | ||||
TCPDEBUG1(); | TCPDEBUG1(); | ||||
socantsendmore(so); | socantsendmore(so); | ||||
tcp_usrclosed(tp); | tcp_usrclosed(tp); | ||||
if (!(inp->inp_flags & INP_DROPPED)) | if (!(inp->inp_flags & INP_DROPPED)) | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
out: | out: | ||||
TCPDEBUG2(PRU_SHUTDOWN); | TCPDEBUG2(PRU_SHUTDOWN); | ||||
TCP_PROBE2(debug__user, tp, PRU_SHUTDOWN); | TCP_PROBE2(debug__user, tp, PRU_SHUTDOWN); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_RUNLOCK(&V_tcbinfo); | INP_INFO_RUNLOCK(&V_tcbinfo); | ||||
return (error); | return (error); | ||||
Show All 19 Lines | tcp_usr_rcvd(struct socket *so, int flags) | ||||
} | } | ||||
tp = intotcpcb(inp); | tp = intotcpcb(inp); | ||||
TCPDEBUG1(); | TCPDEBUG1(); | ||||
#ifdef TCP_OFFLOAD | #ifdef TCP_OFFLOAD | ||||
if (tp->t_flags & TF_TOE) | if (tp->t_flags & TF_TOE) | ||||
tcp_offload_rcvd(tp); | tcp_offload_rcvd(tp); | ||||
else | else | ||||
#endif | #endif | ||||
tcp_output(tp); | tp->t_fb->tfb_tcp_output(tp); | ||||
out: | out: | ||||
TCPDEBUG2(PRU_RCVD); | TCPDEBUG2(PRU_RCVD); | ||||
TCP_PROBE2(debug__user, tp, PRU_RCVD); | TCP_PROBE2(debug__user, tp, PRU_RCVD); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | if (flags & PRUS_EOF) { | ||||
INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | INP_INFO_RLOCK_ASSERT(&V_tcbinfo); | ||||
socantsendmore(so); | socantsendmore(so); | ||||
tcp_usrclosed(tp); | tcp_usrclosed(tp); | ||||
} | } | ||||
if (!(inp->inp_flags & INP_DROPPED) && | if (!(inp->inp_flags & INP_DROPPED) && | ||||
!(flags & PRUS_NOTREADY)) { | !(flags & PRUS_NOTREADY)) { | ||||
if (flags & PRUS_MORETOCOME) | if (flags & PRUS_MORETOCOME) | ||||
tp->t_flags |= TF_MORETOCOME; | tp->t_flags |= TF_MORETOCOME; | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
if (flags & PRUS_MORETOCOME) | if (flags & PRUS_MORETOCOME) | ||||
tp->t_flags &= ~TF_MORETOCOME; | tp->t_flags &= ~TF_MORETOCOME; | ||||
} | } | ||||
} else { | } else { | ||||
/* | /* | ||||
* XXXRW: PRUS_EOF not implemented with PRUS_OOB? | * XXXRW: PRUS_EOF not implemented with PRUS_OOB? | ||||
*/ | */ | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
Show All 33 Lines | #endif | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
tp->snd_wnd = TTCP_CLIENT_SND_WND; | tp->snd_wnd = TTCP_CLIENT_SND_WND; | ||||
tcp_mss(tp, -1); | tcp_mss(tp, -1); | ||||
} | } | ||||
tp->snd_up = tp->snd_una + sbavail(&so->so_snd); | tp->snd_up = tp->snd_una + sbavail(&so->so_snd); | ||||
if (!(flags & PRUS_NOTREADY)) { | if (!(flags & PRUS_NOTREADY)) { | ||||
tp->t_flags |= TF_FORCEDATA; | tp->t_flags |= TF_FORCEDATA; | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
tp->t_flags &= ~TF_FORCEDATA; | tp->t_flags &= ~TF_FORCEDATA; | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB : | TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB : | ||||
((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); | ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); | ||||
TCP_PROBE2(debug__user, tp, (flags & PRUS_OOB) ? PRU_SENDOOB : | TCP_PROBE2(debug__user, tp, (flags & PRUS_OOB) ? PRU_SENDOOB : | ||||
((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); | ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND)); | ||||
Show All 19 Lines | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | ||||
return (ECONNRESET); | return (ECONNRESET); | ||||
} | } | ||||
tp = intotcpcb(inp); | tp = intotcpcb(inp); | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
error = sbready(&so->so_snd, m, count); | error = sbready(&so->so_snd, m, count); | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
if (error == 0) | if (error == 0) | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Abort the TCP. Drop the connection abruptly. | * Abort the TCP. Drop the connection abruptly. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 335 Lines • ▼ Show 20 Lines | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { \ | ||||
return (ECONNRESET); \ | return (ECONNRESET); \ | ||||
} \ | } \ | ||||
tp = intotcpcb(inp); \ | tp = intotcpcb(inp); \ | ||||
} while(0) | } while(0) | ||||
int | int | ||||
tcp_ctloutput(struct socket *so, struct sockopt *sopt) | tcp_ctloutput(struct socket *so, struct sockopt *sopt) | ||||
{ | { | ||||
int error, opt, optval; | int error; | ||||
u_int ui; | |||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct tcpcb *tp; | struct tcpcb *tp; | ||||
struct tcp_info ti; | struct tcp_function_block *blk; | ||||
char buf[TCP_CA_NAME_MAX]; | struct tcp_function_set fsn; | ||||
struct cc_algo *algo; | |||||
error = 0; | error = 0; | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL")); | KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL")); | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
if (sopt->sopt_level != IPPROTO_TCP) { | if (sopt->sopt_level != IPPROTO_TCP) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (inp->inp_vflag & INP_IPV6PROTO) { | if (inp->inp_vflag & INP_IPV6PROTO) { | ||||
Show All 11 Lines | #ifdef INET | ||||
} | } | ||||
#endif | #endif | ||||
return (error); | return (error); | ||||
} | } | ||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (ECONNRESET); | return (ECONNRESET); | ||||
} | } | ||||
tp = intotcpcb(inp); | |||||
/* | |||||
* Protect the TCP option TCP_FUNCTION_BLK so | |||||
* that a sub-function can *never* overwrite this. | |||||
*/ | |||||
if ((sopt->sopt_dir == SOPT_SET) && | |||||
(sopt->sopt_name == TCP_FUNCTION_BLK)) { | |||||
INP_WUNLOCK(inp); | |||||
error = sooptcopyin(sopt, &fsn, sizeof fsn, | |||||
sizeof fsn); | |||||
if (error) | |||||
return (error); | |||||
INP_WLOCK_RECHECK(inp); | |||||
if (tp->t_state != TCPS_CLOSED) { | |||||
/* | |||||
* The user has advanced the state | |||||
* past the initial point, we can't | |||||
* switch since we are down the road | |||||
* and a new set of functions may | |||||
* not be compatibile. | |||||
*/ | |||||
INP_WUNLOCK(inp); | |||||
return(EINVAL); | |||||
} | |||||
blk = find_and_ref_tcp_functions(&fsn); | |||||
if (blk == NULL) { | |||||
INP_WUNLOCK(inp); | |||||
return (ENOENT); | |||||
} | |||||
if (tp->t_fb != blk) { | |||||
if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { | |||||
refcount_release(&blk->tfb_refcnt); | |||||
INP_WUNLOCK(inp); | |||||
return (ENOENT); | |||||
} | |||||
/* | |||||
* Release the old refcnt, the | |||||
* lookup acquires a ref on the | |||||
* new one. | |||||
*/ | |||||
if (tp->t_fb->tfb_tcp_fb_fini) | |||||
(*tp->t_fb->tfb_tcp_fb_fini)(tp); | |||||
refcount_release(&tp->t_fb->tfb_refcnt); | |||||
tp->t_fb = blk; | |||||
if (tp->t_fb->tfb_tcp_fb_init) { | |||||
(*tp->t_fb->tfb_tcp_fb_init)(tp); | |||||
} | |||||
} | |||||
#ifdef TCP_OFFLOAD | |||||
if (tp->t_flags & TF_TOE) { | |||||
tcp_offload_ctloutput(tp, sopt->sopt_dir, | |||||
sopt->sopt_name); | |||||
} | |||||
#endif | |||||
INP_WUNLOCK(inp); | |||||
return (error); | |||||
} else if ((sopt->sopt_dir == SOPT_GET) && | |||||
(sopt->sopt_name == TCP_FUNCTION_BLK)) { | |||||
strcpy(fsn.function_set_name, tp->t_fb->tfb_tcp_block_name); | |||||
fsn.pcbcnt = tp->t_fb->tfb_refcnt; | |||||
INP_WUNLOCK(inp); | |||||
error = sooptcopyout(sopt, &fsn, sizeof fsn); | |||||
return (error); | |||||
} | |||||
/* Pass in the INP locked, called must unlock it */ | |||||
return (tp->t_fb->tfb_tcp_ctloutput(so, sopt, inp, tp)); | |||||
} | |||||
int | |||||
tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp) | |||||
{ | |||||
int error, opt, optval; | |||||
u_int ui; | |||||
struct tcp_info ti; | |||||
struct cc_algo *algo; | |||||
char buf[TCP_CA_NAME_MAX]; | |||||
switch (sopt->sopt_dir) { | switch (sopt->sopt_dir) { | ||||
case SOPT_SET: | case SOPT_SET: | ||||
switch (sopt->sopt_name) { | switch (sopt->sopt_name) { | ||||
#ifdef TCP_SIGNATURE | #ifdef TCP_SIGNATURE | ||||
case TCP_MD5SIG: | case TCP_MD5SIG: | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
error = sooptcopyin(sopt, &optval, sizeof optval, | error = sooptcopyin(sopt, &optval, sizeof optval, | ||||
sizeof optval); | sizeof optval); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | case TCP_NOPUSH: | ||||
return (error); | return (error); | ||||
INP_WLOCK_RECHECK(inp); | INP_WLOCK_RECHECK(inp); | ||||
if (optval) | if (optval) | ||||
tp->t_flags |= TF_NOPUSH; | tp->t_flags |= TF_NOPUSH; | ||||
else if (tp->t_flags & TF_NOPUSH) { | else if (tp->t_flags & TF_NOPUSH) { | ||||
tp->t_flags &= ~TF_NOPUSH; | tp->t_flags &= ~TF_NOPUSH; | ||||
if (TCPS_HAVEESTABLISHED(tp->t_state)) | if (TCPS_HAVEESTABLISHED(tp->t_state)) | ||||
error = tcp_output(tp); | error = tp->t_fb->tfb_tcp_output(tp); | ||||
} | } | ||||
goto unlock_and_done; | goto unlock_and_done; | ||||
case TCP_MAXSEG: | case TCP_MAXSEG: | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
error = sooptcopyin(sopt, &optval, sizeof optval, | error = sooptcopyin(sopt, &optval, sizeof optval, | ||||
sizeof optval); | sizeof optval); | ||||
if (error) | if (error) | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | if (tp->t_state < TCPS_ESTABLISHED) { | ||||
tp = tcp_drop(tp, 0); | tp = tcp_drop(tp, 0); | ||||
KASSERT(tp != NULL, | KASSERT(tp != NULL, | ||||
("tcp_disconnect: tcp_drop() returned NULL")); | ("tcp_disconnect: tcp_drop() returned NULL")); | ||||
} else { | } else { | ||||
soisdisconnecting(so); | soisdisconnecting(so); | ||||
sbflush(&so->so_rcv); | sbflush(&so->so_rcv); | ||||
tcp_usrclosed(tp); | tcp_usrclosed(tp); | ||||
if (!(inp->inp_flags & INP_DROPPED)) | if (!(inp->inp_flags & INP_DROPPED)) | ||||
tcp_output(tp); | tp->t_fb->tfb_tcp_output(tp); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* User issued close, and wish to trail through shutdown states: | * User issued close, and wish to trail through shutdown states: | ||||
* if never received SYN, just forget it. If got a SYN from peer, | * if never received SYN, just forget it. If got a SYN from peer, | ||||
* but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. | * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. | ||||
* If already got a FIN from peer, then almost done; go to LAST_ACK | * If already got a FIN from peer, then almost done; go to LAST_ACK | ||||
▲ Show 20 Lines • Show All 366 Lines • Show Last 20 Lines |