summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/tcp_usrreq.c')
-rw-r--r--sys/netinet/tcp_usrreq.c113
1 files changed, 68 insertions, 45 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 76bc8aa..4b3150b 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -69,7 +69,6 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
-#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_kdtrace.h>
#include <netinet/in_pcb.h>
@@ -85,11 +84,13 @@ __FBSDID("$FreeBSD$");
#ifdef TCP_RFC7413
#include <netinet/tcp_fastopen.h>
#endif
+#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
+#include <netinet/tcp_cc.h>
#ifdef TCPPCAP
#include <netinet/tcp_pcap.h>
#endif
@@ -1478,8 +1479,34 @@ tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp
u_int ui;
struct tcp_info ti;
struct cc_algo *algo;
- char buf[TCP_CA_NAME_MAX];
-
+ char *buf;
+
+ /*
+ * For TCP_CCALGOOPT forward the control to CC module, for both
+ * SOPT_SET and SOPT_GET.
+ */
+ switch (sopt->sopt_name) {
+ case TCP_CCALGOOPT:
+ INP_WUNLOCK(inp);
+ buf = malloc(sopt->sopt_valsize, M_TEMP, M_WAITOK | M_ZERO);
+ error = sooptcopyin(sopt, buf, sopt->sopt_valsize,
+ sopt->sopt_valsize);
+ if (error) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+ INP_WLOCK_RECHECK(inp);
+ if (CC_ALGO(tp)->ctl_output != NULL)
+ error = CC_ALGO(tp)->ctl_output(tp->ccv, sopt, buf);
+ else
+ error = ENOENT;
+ INP_WUNLOCK(inp);
+ if (error == 0 && sopt->sopt_dir == SOPT_GET)
+ error = sooptcopyout(sopt, buf, sopt->sopt_valsize);
+ free(buf, M_TEMP);
+ return (error);
+ }
+
switch (sopt->sopt_dir) {
case SOPT_SET:
switch (sopt->sopt_name) {
@@ -1573,50 +1600,47 @@ unlock_and_done:
case TCP_CONGESTION:
INP_WUNLOCK(inp);
- bzero(buf, sizeof(buf));
- error = sooptcopyin(sopt, &buf, sizeof(buf), 1);
- if (error)
+ buf = malloc(TCP_CA_NAME_MAX, M_TEMP, M_WAITOK|M_ZERO);
+ error = sooptcopyin(sopt, buf, TCP_CA_NAME_MAX, 1);
+ if (error) {
+ free(buf, M_TEMP);
break;
+ }
+ CC_LIST_RLOCK();
+ STAILQ_FOREACH(algo, &cc_list, entries)
+ if (strncmp(buf, algo->name,
+ TCP_CA_NAME_MAX) == 0)
+ break;
+ CC_LIST_RUNLOCK();
+ free(buf, M_TEMP);
+ if (algo == NULL) {
+ error = EINVAL;
+ break;
+ }
INP_WLOCK_RECHECK(inp);
/*
- * Return EINVAL if we can't find the requested cc algo.
+ * We hold a write lock over the tcb so it's safe to
+ * do these things without ordering concerns.
*/
- error = EINVAL;
- CC_LIST_RLOCK();
- STAILQ_FOREACH(algo, &cc_list, entries) {
- if (strncmp(buf, algo->name, TCP_CA_NAME_MAX)
- == 0) {
- /* We've found the requested algo. */
- error = 0;
- /*
- * We hold a write lock over the tcb
- * so it's safe to do these things
- * without ordering concerns.
- */
- if (CC_ALGO(tp)->cb_destroy != NULL)
- CC_ALGO(tp)->cb_destroy(tp->ccv);
- CC_ALGO(tp) = algo;
- /*
- * If something goes pear shaped
- * initialising the new algo,
- * fall back to newreno (which
- * does not require initialisation).
- */
- if (algo->cb_init != NULL)
- if (algo->cb_init(tp->ccv) > 0) {
- CC_ALGO(tp) = &newreno_cc_algo;
- /*
- * The only reason init
- * should fail is
- * because of malloc.
- */
- error = ENOMEM;
- }
- break; /* Break the STAILQ_FOREACH. */
- }
+ if (CC_ALGO(tp)->cb_destroy != NULL)
+ CC_ALGO(tp)->cb_destroy(tp->ccv);
+ CC_ALGO(tp) = algo;
+ /*
+ * If something goes pear shaped initialising the new
+ * algo, fall back to newreno (which does not
+ * require initialisation).
+ */
+ if (algo->cb_init != NULL &&
+ algo->cb_init(tp->ccv) != 0) {
+ CC_ALGO(tp) = &newreno_cc_algo;
+ /*
+ * The only reason init should fail is
+ * because of malloc.
+ */
+ error = ENOMEM;
}
- CC_LIST_RUNLOCK();
- goto unlock_and_done;
+ INP_WUNLOCK(inp);
+ break;
case TCP_KEEPIDLE:
case TCP_KEEPINTVL:
@@ -1762,10 +1786,9 @@ unlock_and_done:
error = sooptcopyout(sopt, &ti, sizeof ti);
break;
case TCP_CONGESTION:
- bzero(buf, sizeof(buf));
- strlcpy(buf, CC_ALGO(tp)->name, TCP_CA_NAME_MAX);
INP_WUNLOCK(inp);
- error = sooptcopyout(sopt, buf, TCP_CA_NAME_MAX);
+ error = sooptcopyout(sopt, CC_ALGO(tp)->name,
+ TCP_CA_NAME_MAX);
break;
case TCP_KEEPIDLE:
case TCP_KEEPINTVL:
OpenPOWER on IntegriCloud