diff options
author | ngie <ngie@FreeBSD.org> | 2015-12-17 06:55:25 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-12-17 06:55:25 +0000 |
commit | 490921132f201193a73d81699cb455aa2ae87357 (patch) | |
tree | 447ebf673b9e1d362dbcf1b55fd34fa0de86d693 /sys/netinet/tcp_usrreq.c | |
parent | 3fed53d02350ae9cbd7b2786b72b83d2e292b8d1 (diff) | |
parent | a7e4d91c2357d6f2c732cccc35fd4ddda5f2d58e (diff) | |
download | FreeBSD-src-490921132f201193a73d81699cb455aa2ae87357.zip FreeBSD-src-490921132f201193a73d81699cb455aa2ae87357.tar.gz |
MFhead @ r292396
Diffstat (limited to 'sys/netinet/tcp_usrreq.c')
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 105 |
1 files changed, 90 insertions, 15 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index a1f8a0c..42e2ea7 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/limits.h> #include <sys/malloc.h> +#include <sys/refcount.h> #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/mbuf.h> @@ -509,7 +510,7 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) goto out; #endif tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_CONNECT); INP_WUNLOCK(inp); @@ -579,7 +580,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) (error = tcp_offload_connect(so, nam)) == 0) goto out; #endif - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); goto out; } #endif @@ -597,7 +598,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) goto out; #endif tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_CONNECT); @@ -773,7 +774,7 @@ tcp_usr_shutdown(struct socket *so) socantsendmore(so); tcp_usrclosed(tp); if (!(inp->inp_flags & INP_DROPPED)) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_SHUTDOWN); @@ -809,7 +810,7 @@ tcp_usr_rcvd(struct socket *so, int flags) tcp_offload_rcvd(tp); else #endif - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_RCVD); @@ -911,7 +912,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, !(flags & PRUS_NOTREADY)) { if (flags & PRUS_MORETOCOME) tp->t_flags |= TF_MORETOCOME; - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); if (flags & PRUS_MORETOCOME) tp->t_flags &= ~TF_MORETOCOME; } @@ -961,7 +962,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, tp->snd_up = tp->snd_una + sbavail(&so->so_snd); if (!(flags & PRUS_NOTREADY)) { tp->t_flags |= TF_FORCEDATA; - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); tp->t_flags &= ~TF_FORCEDATA; } } @@ -997,7 +998,7 @@ tcp_usr_ready(struct socket *so, struct mbuf *m, int count) error = sbready(&so->so_snd, m, count); SOCKBUF_UNLOCK(&so->so_snd); if (error == 0) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); INP_WUNLOCK(inp); return (error); @@ -1349,13 +1350,11 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) int tcp_ctloutput(struct socket *so, struct sockopt *sopt) { - int error, opt, optval; - u_int ui; + int error; struct inpcb *inp; struct tcpcb *tp; - struct tcp_info ti; - char buf[TCP_CA_NAME_MAX]; - struct cc_algo *algo; + struct tcp_function_block *blk; + struct tcp_function_set fsn; error = 0; inp = sotoinpcb(so); @@ -1383,7 +1382,83 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) INP_WUNLOCK(inp); 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) { case SOPT_SET: switch (sopt->sopt_name) { @@ -1451,7 +1526,7 @@ unlock_and_done: else if (tp->t_flags & TF_NOPUSH) { tp->t_flags &= ~TF_NOPUSH; if (TCPS_HAVEESTABLISHED(tp->t_state)) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); } goto unlock_and_done; @@ -1770,7 +1845,7 @@ tcp_disconnect(struct tcpcb *tp) sbflush(&so->so_rcv); tcp_usrclosed(tp); if (!(inp->inp_flags & INP_DROPPED)) - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); } } |