summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/tcp_subr.c')
-rw-r--r--freebsd/sys/netinet/tcp_subr.c216
1 files changed, 154 insertions, 62 deletions
diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c
index 30464e1b..dff41275 100644
--- a/freebsd/sys/netinet/tcp_subr.c
+++ b/freebsd/sys/netinet/tcp_subr.c
@@ -281,7 +281,7 @@ find_tcp_functions_locked(struct tcp_function_set *fs)
struct tcp_function_block *blk=NULL;
TAILQ_FOREACH(f, &t_functions, tf_next) {
- if (strcmp(f->tf_fb->tfb_tcp_block_name, fs->function_set_name) == 0) {
+ if (strcmp(f->tf_name, fs->function_set_name) == 0) {
blk = f->tf_fb;
break;
}
@@ -382,6 +382,7 @@ sysctl_net_inet_list_available(SYSCTL_HANDLER_ARGS)
struct tcp_function *f;
char *buffer, *cp;
size_t bufsz, outsz;
+ bool alias;
cnt = 0;
rw_rlock(&tcp_function_lock);
@@ -390,22 +391,25 @@ sysctl_net_inet_list_available(SYSCTL_HANDLER_ARGS)
}
rw_runlock(&tcp_function_lock);
- bufsz = (cnt+2) * (TCP_FUNCTION_NAME_LEN_MAX + 12) + 1;
+ bufsz = (cnt+2) * ((TCP_FUNCTION_NAME_LEN_MAX * 2) + 13) + 1;
buffer = malloc(bufsz, M_TEMP, M_WAITOK);
error = 0;
cp = buffer;
- linesz = snprintf(cp, bufsz, "\n%-32s%c %s\n", "Stack", 'D', "PCB count");
+ linesz = snprintf(cp, bufsz, "\n%-32s%c %-32s %s\n", "Stack", 'D',
+ "Alias", "PCB count");
cp += linesz;
bufsz -= linesz;
outsz = linesz;
rw_rlock(&tcp_function_lock);
TAILQ_FOREACH(f, &t_functions, tf_next) {
- linesz = snprintf(cp, bufsz, "%-32s%c %u\n",
+ alias = (f->tf_name != f->tf_fb->tfb_tcp_block_name);
+ linesz = snprintf(cp, bufsz, "%-32s%c %-32s %u\n",
f->tf_fb->tfb_tcp_block_name,
(f->tf_fb == tcp_func_set_ptr) ? '*' : ' ',
+ alias ? f->tf_name : "-",
f->tf_fb->tfb_refcnt);
if (linesz >= bufsz) {
error = EOVERFLOW;
@@ -506,12 +510,31 @@ maketcp_hashsize(int size)
return (hashsize);
}
+/*
+ * Register a TCP function block with the name provided in the names
+ * array. (Note that this function does NOT automatically register
+ * blk->tfb_tcp_block_name as a stack name. Therefore, you should
+ * explicitly include blk->tfb_tcp_block_name in the list of names if
+ * you wish to register the stack with that name.)
+ *
+ * Either all name registrations will succeed or all will fail. If
+ * a name registration fails, the function will update the num_names
+ * argument to point to the array index of the name that encountered
+ * the failure.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
int
-register_tcp_functions(struct tcp_function_block *blk, int wait)
+register_tcp_functions_as_names(struct tcp_function_block *blk, int wait,
+ const char *names[], int *num_names)
{
- struct tcp_function_block *lblk;
struct tcp_function *n;
struct tcp_function_set fs;
+ int error, i;
+
+ KASSERT(names != NULL && *num_names > 0,
+ ("%s: Called with 0-length name list", __func__));
+ KASSERT(names != NULL, ("%s: Called with NULL name list", __func__));
if (t_functions_inited == 0) {
init_tcp_functions();
@@ -524,6 +547,7 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
* These functions are required and you
* need a name.
*/
+ *num_names = 0;
return (EINVAL);
}
if (blk->tfb_tcp_timer_stop_all ||
@@ -538,34 +562,99 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
(blk->tfb_tcp_timer_activate == NULL) ||
(blk->tfb_tcp_timer_active == NULL) ||
(blk->tfb_tcp_timer_stop == NULL)) {
- return (EINVAL);
+ *num_names = 0;
+ return (EINVAL);
}
- }
- n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait);
- if (n == NULL) {
- return (ENOMEM);
- }
- n->tf_fb = blk;
- strcpy(fs.function_set_name, blk->tfb_tcp_block_name);
- rw_wlock(&tcp_function_lock);
- lblk = find_tcp_functions_locked(&fs);
- if (lblk) {
- /* Duplicate name space not allowed */
- rw_wunlock(&tcp_function_lock);
- free(n, M_TCPFUNCTIONS);
- return (EALREADY);
}
+
refcount_init(&blk->tfb_refcnt, 0);
blk->tfb_flags = 0;
- TAILQ_INSERT_TAIL(&t_functions, n, tf_next);
- rw_wunlock(&tcp_function_lock);
+ for (i = 0; i < *num_names; i++) {
+ n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait);
+ if (n == NULL) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+ n->tf_fb = blk;
+
+ (void)strncpy(fs.function_set_name, names[i],
+ TCP_FUNCTION_NAME_LEN_MAX);
+ fs.function_set_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0';
+ rw_wlock(&tcp_function_lock);
+ if (find_tcp_functions_locked(&fs) != NULL) {
+ /* Duplicate name space not allowed */
+ rw_wunlock(&tcp_function_lock);
+ free(n, M_TCPFUNCTIONS);
+ error = EALREADY;
+ goto cleanup;
+ }
+ (void)strncpy(n->tf_name, names[i], TCP_FUNCTION_NAME_LEN_MAX);
+ n->tf_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0';
+ TAILQ_INSERT_TAIL(&t_functions, n, tf_next);
+ rw_wunlock(&tcp_function_lock);
+ }
return(0);
-}
+
+cleanup:
+ /*
+ * Deregister the names we just added. Because registration failed
+ * for names[i], we don't need to deregister that name.
+ */
+ *num_names = i;
+ rw_wlock(&tcp_function_lock);
+ while (--i >= 0) {
+ TAILQ_FOREACH(n, &t_functions, tf_next) {
+ if (!strncmp(n->tf_name, names[i],
+ TCP_FUNCTION_NAME_LEN_MAX)) {
+ TAILQ_REMOVE(&t_functions, n, tf_next);
+ n->tf_fb = NULL;
+ free(n, M_TCPFUNCTIONS);
+ break;
+ }
+ }
+ }
+ rw_wunlock(&tcp_function_lock);
+ return (error);
+}
+
+/*
+ * Register a TCP function block using the name provided in the name
+ * argument.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
+int
+register_tcp_functions_as_name(struct tcp_function_block *blk, const char *name,
+ int wait)
+{
+ const char *name_list[1];
+ int num_names, rv;
+
+ num_names = 1;
+ if (name != NULL)
+ name_list[0] = name;
+ else
+ name_list[0] = blk->tfb_tcp_block_name;
+ rv = register_tcp_functions_as_names(blk, wait, name_list, &num_names);
+ return (rv);
+}
+
+/*
+ * Register a TCP function block using the name defined in
+ * blk->tfb_tcp_block_name.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
+int
+register_tcp_functions(struct tcp_function_block *blk, int wait)
+{
+
+ return (register_tcp_functions_as_name(blk, NULL, wait));
+}
int
deregister_tcp_functions(struct tcp_function_block *blk)
{
- struct tcp_function_block *lblk;
struct tcp_function *f;
int error=ENOENT;
@@ -585,8 +674,7 @@ deregister_tcp_functions(struct tcp_function_block *blk)
rw_wunlock(&tcp_function_lock);
return (EBUSY);
}
- lblk = find_tcp_fb_locked(blk, &f);
- if (lblk) {
+ while (find_tcp_fb_locked(blk, &f) != NULL) {
/* Found */
TAILQ_REMOVE(&t_functions, f, tf_next);
f->tf_fb = NULL;
@@ -1582,7 +1670,6 @@ tcp_close(struct tcpcb *tp)
("tcp_close: !SS_PROTOREF"));
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
sofree(so);
@@ -1969,16 +2056,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ icmp_tcp_seq = th->th_seq;
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -1986,7 +2073,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
* in the route to the suggested new
* value (if given) and then notify.
*/
- mtu = ntohs(icp->icmp_nextmtu);
+ mtu = ntohs(icp->icmp_nextmtu);
/*
* If no alternative MTU was
* proposed, try the next smaller
@@ -2017,16 +2104,17 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
inetctlerrmap[cmd]);
}
}
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fport = th->th_dport;
inc.inc_lport = th->th_sport;
inc.inc_faddr = faddr;
inc.inc_laddr = ip->ip_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET */
@@ -2036,7 +2124,6 @@ void
tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
{
struct in6_addr *dst;
- struct tcphdr *th;
struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify;
struct ip6_hdr *ip6;
struct mbuf *m;
@@ -2046,11 +2133,14 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
struct ip6ctlparam *ip6cp = NULL;
const struct sockaddr_in6 *sa6_src = NULL;
struct in_conninfo inc;
+ struct tcp_ports {
+ uint16_t th_sport;
+ uint16_t th_dport;
+ } t_ports;
tcp_seq icmp_tcp_seq;
unsigned int mtu;
unsigned int off;
-
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
@@ -2099,27 +2189,31 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
/* Check if we can safely get the ports from the tcp hdr */
if (m == NULL ||
(m->m_pkthdr.len <
- (int32_t) (off + offsetof(struct tcphdr, th_seq)))) {
+ (int32_t) (off + sizeof(struct tcp_ports)))) {
return;
}
-
- th = (struct tcphdr *) mtodo(ip6cp->ip6c_m, ip6cp->ip6c_off);
+ bzero(&t_ports, sizeof(struct tcp_ports));
+ m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports);
INP_INFO_RLOCK(&V_tcbinfo);
- inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, th->th_dport,
- &ip6->ip6_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
+ inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport,
+ &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL);
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ off += sizeof(struct tcp_ports);
+ if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) {
+ goto out;
+ }
+ m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -2136,22 +2230,20 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
*/
if (mtu < IPV6_MMTU)
mtu = IPV6_MMTU - 8;
-
-
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
inc.inc6_faddr = *dst;
if (in6_setscope(&inc.inc6_faddr,
m->m_pkthdr.rcvif, NULL))
- goto unlock_inp;
-
+ goto out;
/*
* Only process the offered MTU if it
* is smaller than the current one.
*/
if (mtu < tp->t_maxseg +
- (sizeof (*th) + sizeof (*ip6))) {
+ sizeof (struct tcphdr) +
+ sizeof (struct ip6_hdr)) {
tcp_hc_updatemtu(&inc, mtu);
tcp_mtudisc(inp, mtu);
ICMP6STAT_INC(icp6s_pmtuchg);
@@ -2161,19 +2253,19 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
inet6ctlerrmap[cmd]);
}
}
-unlock_inp:
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
- inc.inc_fport = th->th_dport;
- inc.inc_lport = th->th_sport;
+ inc.inc_fport = t_ports.th_dport;
+ inc.inc_lport = t_ports.th_sport;
inc.inc6_faddr = *dst;
inc.inc6_laddr = ip6->ip6_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET6 */