aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2026-04-12 18:33:07 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2026-04-12 18:33:07 +0000
commit40dbb06fa73cac37d57563c07e55efd0cabbd488 (patch)
treec11f41fa7c8baac00322576c2a72446f3fbf2eb7 /sys/netinet
parentce283e115b023514a8886c1c1f1c68df7cd5e9a9 (diff)
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_pcb.c74
-rw-r--r--sys/netinet/in_pcb.h9
-rw-r--r--sys/netinet/in_pcb_var.h2
-rw-r--r--sys/netinet/tcp_hpts.c12
-rw-r--r--sys/netinet/tcp_hpts_test.c3
-rw-r--r--sys/netinet/tcp_log_buf.c17
-rw-r--r--sys/netinet/tcp_output.c1
-rw-r--r--sys/netinet/tcp_stacks/bbr.c2
-rw-r--r--sys/netinet/tcp_stacks/rack.c4
-rw-r--r--sys/netinet/tcp_subr.c3
-rw-r--r--sys/netinet/tcp_timewait.c5
-rw-r--r--sys/netinet/tcp_usrreq.c198
-rw-r--r--sys/netinet/tcp_var.h2
-rw-r--r--sys/netinet/toecore.c10
14 files changed, 134 insertions, 208 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 8bc90de239c2..f1053f6abe03 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -692,6 +692,7 @@ in_pcballoc(struct socket *so, struct inpcbinfo *pcbinfo)
*/
inp->inp_route.ro_flags = RT_LLE_CACHE;
refcount_init(&inp->inp_refcount, 1); /* Reference from socket. */
+ inp->inp_flags |= INP_UNCONNECTED;
INP_WLOCK(inp);
INP_HASH_WLOCK(pcbinfo);
pcbinfo->ipi_count++;
@@ -1158,14 +1159,14 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
lport = inp->inp_lport;
MPASS(!in_nullhost(inp->inp_laddr) || inp->inp_lport != 0 ||
- !(inp->inp_flags & INP_INHASHLIST));
+ (inp->inp_flags & INP_UNCONNECTED));
inp->inp_faddr = faddr;
inp->inp_fport = sin->sin_port;
inp->inp_laddr = laddr;
inp->inp_lport = lport;
- if ((inp->inp_flags & INP_INHASHLIST) == 0) {
+ if (inp->inp_flags & INP_UNCONNECTED) {
error = in_pcbinshash(inp);
MPASS(error == 0);
} else
@@ -1426,11 +1427,15 @@ in_pcbdisconnect(struct inpcb *inp)
KASSERT(inp->inp_smr == SMR_SEQ_INVALID,
("%s: inp %p was already disconnected", __func__, inp));
+ if (inp->inp_flags & INP_UNCONNECTED)
+ return;
+
INP_HASH_WLOCK(inp->inp_pcbinfo);
in_pcbremhash(inp);
CK_LIST_INSERT_HEAD(&inp->inp_pcbinfo->ipi_list_unconn, inp,
inp_unconn_list);
INP_HASH_WUNLOCK(inp->inp_pcbinfo);
+ inp->inp_flags |= INP_UNCONNECTED;
if ((inp->inp_socket->so_proto->pr_flags & PR_CONNREQUIRED) == 0) {
/* See the comment in in_pcbinshash(). */
@@ -1538,11 +1543,11 @@ inp_smr_lock(struct inpcb *inp, const inp_lookup_t lock)
{
/*
- * in_pcblookup() family of functions ignore not only freed entries,
- * that may be found due to lockless access to the hash, but dropped
- * entries, too.
+ * in_pcblookup() family of functions shall ignore not onlu pcbs that
+ * had been freed that may be found due to lockless access to the hash,
+ * but also pcbs that were removed from the hash, but are still around.
*/
- return (_inp_smr_lock(inp, lock, INP_FREED | INP_DROPPED));
+ return (_inp_smr_lock(inp, lock, INP_FREED | INP_UNCONNECTED));
}
/*
@@ -1837,10 +1842,10 @@ in_pcbfree(struct inpcb *inp)
* lock, thus in_pcbremhash() should be the first action.
*/
INP_HASH_WLOCK(pcbinfo);
- if (inp->inp_flags & INP_INHASHLIST)
- in_pcbremhash(inp);
- else
+ if (inp->inp_flags & INP_UNCONNECTED)
CK_LIST_REMOVE(inp, inp_unconn_list);
+ else
+ in_pcbremhash(inp);
inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
pcbinfo->ipi_count--;
INP_HASH_WUNLOCK(pcbinfo);
@@ -1901,36 +1906,6 @@ inpcb_fini(void *mem, int size)
INP_LOCK_DESTROY(inp);
}
-/*
- * in_pcbdrop() removes an inpcb from hashed lists, releasing its address and
- * port reservation, and preventing it from being returned by inpcb lookups.
- *
- * It is used by TCP to mark an inpcb as unused and avoid future packet
- * delivery or event notification when a socket remains open but TCP has
- * closed. This might occur as a result of a shutdown()-initiated TCP close
- * or a RST on the wire, and allows the port binding to be reused while still
- * maintaining the invariant that so_pcb always points to a valid inpcb until
- * in_pcbdetach().
- *
- * XXXRW: Possibly in_pcbdrop() should also prevent future notifications by
- * in_pcbpurgeif0()?
- */
-void
-in_pcbdrop(struct inpcb *inp)
-{
-
- INP_WLOCK_ASSERT(inp);
-
- inp->inp_flags |= INP_DROPPED;
- if (inp->inp_flags & INP_INHASHLIST) {
- INP_HASH_WLOCK(inp->inp_pcbinfo);
- in_pcbremhash(inp);
- CK_LIST_INSERT_HEAD(&inp->inp_pcbinfo->ipi_list_unconn, inp,
- inp_unconn_list);
- INP_HASH_WUNLOCK(inp->inp_pcbinfo);
- }
-}
-
#ifdef INET
/*
* Common routines to return the socket addresses associated with inpcbs.
@@ -2691,8 +2666,7 @@ in_pcbinshash(struct inpcb *inp)
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(pcbinfo);
- KASSERT((inp->inp_flags & INP_INHASHLIST) == 0,
- ("in_pcbinshash: INP_INHASHLIST"));
+ MPASS(inp->inp_flags & INP_UNCONNECTED);
#ifdef INET6
if (inp->inp_vflag & INP_IPV6) {
@@ -2751,7 +2725,7 @@ in_pcbinshash(struct inpcb *inp)
_in_pcbinshash_wild(pcbhash, inp);
}
CK_LIST_INSERT_HEAD(pcbporthash, inp, inp_portlist);
- inp->inp_flags |= INP_INHASHLIST;
+ inp->inp_flags &= ~INP_UNCONNECTED;
return (0);
}
@@ -2762,7 +2736,7 @@ in_pcbremhash(struct inpcb *inp)
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
- MPASS(inp->inp_flags & INP_INHASHLIST);
+ MPASS(!(inp->inp_flags & INP_UNCONNECTED));
if ((inp->inp_flags & INP_INLBGROUP) != 0)
in_pcbremlbgrouphash(inp);
@@ -2781,7 +2755,6 @@ in_pcbremhash(struct inpcb *inp)
CK_LIST_REMOVE(inp, inp_hash_exact);
}
CK_LIST_REMOVE(inp, inp_portlist);
- inp->inp_flags &= ~INP_INHASHLIST;
}
/*
@@ -2800,8 +2773,7 @@ in_pcbrehash(struct inpcb *inp)
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(pcbinfo);
- KASSERT(inp->inp_flags & INP_INHASHLIST,
- ("%s: !INP_INHASHLIST", __func__));
+ MPASS(!(inp->inp_flags & INP_UNCONNECTED));
KASSERT(inp->inp_smr == SMR_SEQ_INVALID,
("%s: inp was disconnected", __func__));
@@ -3040,7 +3012,13 @@ sysctl_setsockopt(SYSCTL_HANDLER_ARGS, struct inpcbinfo *pcbinfo,
}
while ((inp = inp_next(&inpi)) != NULL)
if (inp->inp_gencnt == params->sop_id) {
- if (inp->inp_flags & INP_DROPPED) {
+ /*
+ * XXXGL
+ * 1) the inp_next() that ignores INP_UNCONNECTED needs
+ * to be generally supported.
+ * 2) Why do we ECONNRESET instead of continueing?
+ */
+ if (inp->inp_flags & INP_UNCONNECTED) {
INP_WUNLOCK(inp);
return (ECONNRESET);
}
@@ -3269,7 +3247,7 @@ in_pcbattach_txrtlmt(struct inpcb *inp, struct ifnet *ifp,
* down, allocating a new send tag is not allowed. Else send
* tags may leak.
*/
- if (*st != NULL || (inp->inp_flags & INP_DROPPED) != 0)
+ if (*st != NULL || (inp->inp_flags & INP_UNCONNECTED))
return (EINVAL);
error = m_snd_tag_alloc(ifp, &params, st);
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 592d951c018f..d34c88941c7f 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -181,7 +181,7 @@ struct xinpgen {
#define INP_RECVTTL 0x00000400 /* receive incoming IP TTL */
#define INP_DONTFRAG 0x00000800 /* don't fragment packet */
#define INP_BINDANY 0x00001000 /* allow bind to any address */
-#define INP_INHASHLIST 0x00002000 /* in_pcbinshash() has been called */
+/* available 0x00002000 */
#define INP_RECVTOS 0x00004000 /* receive incoming IP TOS */
#define IN6P_IPV6_V6ONLY 0x00008000 /* restrict AF_INET6 socket for v6 */
#define IN6P_PKTINFO 0x00010000 /* receive IP6 dst and I/F */
@@ -194,7 +194,7 @@ struct xinpgen {
#define IN6P_AUTOFLOWLABEL 0x00800000 /* attach flowlabel automatically */
/* INP_INLBGROUP 0x01000000 private to in_pcb.c */
#define INP_ONESBCAST 0x02000000 /* send all-ones broadcast */
-#define INP_DROPPED 0x04000000 /* protocol drop flag */
+/* INP_UNCONNECTED 0x04000000 private to in_pcb.c/in6_pcb.c */
#define INP_SOCKREF 0x08000000 /* strong socket reference */
#define INP_RESERVED_0 0x10000000 /* reserved field */
#define INP_BOUNDFIB 0x20000000 /* Bound to a specific FIB. */
@@ -213,10 +213,10 @@ struct xinpgen {
"\1INP_RECVOPTS\2INP_RECVRETOPTS\3INP_RECVDSTADDR\4INP_HDRINCL" \
"\5INP_HIGHPORT\6INP_LOWPORT\7INP_ANONPORT\10INP_RECVIF" \
"\11INP_MTUDISC\12INP_FREED\13INP_RECVTTL\14INP_DONTFRAG" \
- "\15INP_BINDANY\16INP_INHASHLIST\17INP_RECVTOS\20IN6P_IPV6_V6ONLY" \
+ "\15INP_BINDANY\17INP_RECVTOS\20IN6P_IPV6_V6ONLY" \
"\21IN6P_PKTINFO\22IN6P_HOPLIMIT\23IN6P_HOPOPTS\24IN6P_DSTOPTS" \
"\25IN6P_RTHDR\26IN6P_RTHDRDSTOPTS\27IN6P_TCLASS\30IN6P_AUTOFLOWLABEL" \
- "\31INP_INLBGROUP\32INP_ONESBCAST\33INP_DROPPED\34INP_SOCKREF" \
+ "\31INP_INLBGROUP\32INP_ONESBCAST\33INP_UNCONNECTED\34INP_SOCKREF" \
"\35INP_RESERVED_0\36INP_BOUNDFIB\37IN6P_RFC2292\40IN6P_MTU"
/*
@@ -650,7 +650,6 @@ int in_pcbbind_setup(struct inpcb *, struct sockaddr_in *, in_addr_t *,
u_short *, int, struct ucred *);
int in_pcbconnect(struct inpcb *, struct sockaddr_in *, struct ucred *);
void in_pcbdisconnect(struct inpcb *);
-void in_pcbdrop(struct inpcb *);
void in_pcbfree(struct inpcb *);
int in_pcbladdr(const struct inpcb *, struct in_addr *, struct in_addr *,
struct ucred *);
diff --git a/sys/netinet/in_pcb_var.h b/sys/netinet/in_pcb_var.h
index 7a5c489f26d7..1f46e1bd8f3d 100644
--- a/sys/netinet/in_pcb_var.h
+++ b/sys/netinet/in_pcb_var.h
@@ -41,6 +41,8 @@
* Definitions shared between netinet/in_pcb.c and netinet6/in6_pcb.c
*/
+#define INP_UNCONNECTED 0x04000000 /* Not inserted into hashes. */
+
VNET_DECLARE(uint32_t, in_pcbhashseed);
#define V_in_pcbhashseed VNET(in_pcbhashseed)
diff --git a/sys/netinet/tcp_hpts.c b/sys/netinet/tcp_hpts.c
index 67b028d7603b..8dfbe126d46a 100644
--- a/sys/netinet/tcp_hpts.c
+++ b/sys/netinet/tcp_hpts.c
@@ -510,7 +510,7 @@ tcp_hpts_insert_internal(struct tcpcb *tp, struct tcp_hpts_entry *hpts)
INP_WLOCK_ASSERT(inp);
HPTS_MTX_ASSERT(hpts);
MPASS(hpts->p_cpu == tp->t_hpts_cpu);
- MPASS(!(inp->inp_flags & INP_DROPPED));
+ MPASS(!(tp->t_flags & TF_DISCONNECTED));
hptsh = &hpts->p_hptss[tp->t_hpts_slot];
@@ -615,8 +615,10 @@ __tcp_hpts_remove(struct tcp_hptsi *pace, struct tcpcb *tp)
* tcp_hptsi() moves inpcb to detached tailq
* tcp_hpts_remove() marks as IHPTS_MOVING, slot = -1
* tcp_hpts_insert() sets slot to a meaningful value
- * tcp_hpts_remove() again (we are here!), then in_pcbdrop()
- * tcp_hptsi() finds pcb with meaningful slot and INP_DROPPED
+ * The connection is terminated with the final call to
+ tcp_hpts_remove() again (we are here!) and we fail to call
+ tcp_hpts_release() since it is IHPTS_MOVING. Set slot to -1
+ to delegate the release to the owner of the detached tailq.
*/
tp->t_hpts_slot = -1;
}
@@ -828,7 +830,7 @@ __tcp_hpts_insert(struct tcp_hptsi *pace, struct tcpcb *tp, uint32_t usecs,
bool need_wakeup = false;
INP_WLOCK_ASSERT(tptoinpcb(tp));
- MPASS(!(tptoinpcb(tp)->inp_flags & INP_DROPPED));
+ MPASS(!(tp->t_flags & TF_DISCONNECTED));
MPASS(!(tp->t_in_hpts == IHPTS_ONQUEUE));
/*
@@ -1292,7 +1294,7 @@ again:
}
MPASS(tp->t_in_hpts == IHPTS_ONQUEUE);
- MPASS(!(inp->inp_flags & INP_DROPPED));
+ MPASS(!(tp->t_flags & TF_DISCONNECTED));
KASSERT(runningslot == tp->t_hpts_slot,
("Hpts:%p inp:%p slot mis-aligned %u vs %u",
hpts, inp, runningslot, tp->t_hpts_slot));
diff --git a/sys/netinet/tcp_hpts_test.c b/sys/netinet/tcp_hpts_test.c
index 61082adc9063..ea088f5c71cf 100644
--- a/sys/netinet/tcp_hpts_test.c
+++ b/sys/netinet/tcp_hpts_test.c
@@ -175,7 +175,6 @@ dump_tcpcb(struct tcpcb *tp)
/* Input PCB fields that HPTS uses */
KTEST_LOG(ctx, " inp_flags: 0x%x", inp->inp_flags);
- KTEST_LOG(ctx, " INP_DROPPED: %s", (inp->inp_flags & INP_DROPPED) ? "YES" : "NO");
KTEST_LOG(ctx, " inp_flowid: 0x%x", inp->inp_flowid);
KTEST_LOG(ctx, " inp_flowtype: %u", inp->inp_flowtype);
KTEST_LOG(ctx, " inp_numa_domain: %d", inp->inp_numa_domain);
@@ -585,7 +584,7 @@ KTEST_FUNC(tcpcb_initialization)
KTEST_EQUAL(tp->t_lro_cpu, 0);
KTEST_VERIFY(tp->t_hpts_cpu < pace->rp_num_hptss);
KTEST_EQUAL(tp->t_inpcb.inp_refcount, 1);
- KTEST_VERIFY(!(tp->t_inpcb.inp_flags & INP_DROPPED));
+ KTEST_VERIFY(!(tp->t_flags & TF_DISCONNECTED));
test_hpts_free_tcpcb(tp);
tcp_hptsi_stop(pace);
diff --git a/sys/netinet/tcp_log_buf.c b/sys/netinet/tcp_log_buf.c
index 4505171d94d0..3e5955e5db4e 100644
--- a/sys/netinet/tcp_log_buf.c
+++ b/sys/netinet/tcp_log_buf.c
@@ -517,12 +517,12 @@ tcp_log_remove_id_node(struct inpcb *inp, struct tcpcb *tp,
}
#define RECHECK_INP_CLEAN(cleanup) do { \
- if (inp->inp_flags & INP_DROPPED) { \
+ tp = intotcpcb(inp); \
+ if (tp->t_flags & TF_DISCONNECTED) { \
rv = ECONNRESET; \
cleanup; \
goto done; \
} \
- tp = intotcpcb(inp); \
} while (0)
#define RECHECK_INP() RECHECK_INP_CLEAN(/* noop */)
@@ -2254,10 +2254,9 @@ tcp_log_getlogbuf(struct sockopt *sopt, struct tcpcb *tp)
if (error) {
/* Restore list */
+ tp = intotcpcb(inp);
INP_WLOCK(inp);
- if ((inp->inp_flags & INP_DROPPED) == 0) {
- tp = intotcpcb(inp);
-
+ if ((tp->t_flags & TF_DISCONNECTED) == 0) {
/* Merge the two lists. */
STAILQ_CONCAT(&log_tailq, &tp->t_logs);
tp->t_logs = log_tailq;
@@ -2428,14 +2427,14 @@ tcp_log_dump_tp_logbuf(struct tcpcb *tp, char *reason, int how, bool force)
* may end up dropping some entries. That seems like a
* small price to pay for safety.
*/
- if (inp->inp_flags & INP_DROPPED) {
+ tp = intotcpcb(inp);
+ if (tp->t_flags & TF_DISCONNECTED) {
free(entry, M_TCPLOGDEV);
#ifdef TCPLOG_DEBUG_COUNTERS
counter_u64_add(tcp_log_que_fail2, 1);
#endif
return (ECONNRESET);
}
- tp = intotcpcb(inp);
if (tp->t_lognum == 0) {
free(entry, M_TCPLOGDEV);
return (0);
@@ -2871,14 +2870,14 @@ tcp_log_sendfile(struct socket *so, off_t offset, size_t nbytes, int flags)
/* quick check to see if logging is enabled for this connection */
tp = intotcpcb(inp);
- if ((inp->inp_flags & INP_DROPPED) ||
+ if ((tp->t_flags & TF_DISCONNECTED) ||
(tp->_t_logstate == TCP_LOG_STATE_OFF)) {
return;
}
INP_WLOCK(inp);
/* double check log state now that we have the lock */
- if (inp->inp_flags & INP_DROPPED)
+ if (tp->t_flags & TF_DISCONNECTED)
goto done;
if (tcp_bblogging_on(tp)) {
struct timeval tv;
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 23085f67d5f9..8d88c4f734f6 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -220,6 +220,7 @@ tcp_default_output(struct tcpcb *tp)
NET_EPOCH_ASSERT();
INP_WLOCK_ASSERT(inp);
+ MPASS(!(tp->t_flags & TF_DISCONNECTED));
#ifdef TCP_OFFLOAD
if (tp->t_flags & TF_TOE)
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index 10383bc0801e..6697b6ecc7db 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -14217,7 +14217,7 @@ bbr_set_sockopt(struct tcpcb *tp, struct sockopt *sopt)
if (error)
return (error);
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (tp->t_flags & TF_DISCONNECTED) {
INP_WUNLOCK(inp);
return (ECONNRESET);
}
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 2e3fcc7a9762..346468fe9a48 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -14750,8 +14750,8 @@ rack_init(struct tcpcb *tp, void **ptr)
*/
rack_convert_rtts(tp);
rack_log_hystart_event(rack, rack->r_ctl.roundends, 20);
- if ((tptoinpcb(tp)->inp_flags & INP_DROPPED) == 0) {
- /* We do not start any timers on DROPPED connections */
+ if ((tp->t_flags & TF_DISCONNECTED) == 0) {
+ /* We do not start any timers on disconnected connections */
if (tp->t_fb->tfb_chg_query == NULL) {
rack_start_hpts_timer(rack, tp, tcp_get_usecs(NULL), 0, 0, 0);
} else {
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 43c430708926..443af020848f 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2551,10 +2551,11 @@ tcp_close(struct tcpcb *tp)
tcp_timer_stop(tp);
if (tp->t_fb->tfb_tcp_timer_stop_all != NULL)
tp->t_fb->tfb_tcp_timer_stop_all(tp);
- in_pcbdrop(inp);
+ in_pcbdisconnect(inp);
TCPSTAT_INC(tcps_closed);
if (tp->t_state != TCPS_CLOSED)
tcp_state_change(tp, TCPS_CLOSED);
+ tp->t_flags |= TF_DISCONNECTED;
KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
tcp_free_sackholes(tp);
soisdisconnected(so);
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index ba5c90c91e43..430e98910743 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -126,10 +126,7 @@ tcp_twstart(struct tcpcb *tp)
NET_EPOCH_ASSERT();
INP_WLOCK_ASSERT(inp);
-
- /* A dropped inp should never transition to TIME_WAIT state. */
- KASSERT((inp->inp_flags & INP_DROPPED) == 0, ("tcp_twstart: "
- "(inp->inp_flags & INP_DROPPED) != 0"));
+ MPASS(!(tp->t_flags & TF_DISCONNECTED));
tcp_state_change(tp, TCPS_TIME_WAIT);
tcp_free_sackholes(tp);
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 07c436a1f2e0..ce13f1a9cefe 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -205,9 +205,9 @@ tcp_usr_detach(struct socket *so)
tp = intotcpcb(inp);
- KASSERT(inp->inp_flags & INP_DROPPED ||
+ KASSERT(tp->t_flags & TF_DISCONNECTED ||
tp->t_state < TCPS_SYN_SENT,
- ("%s: inp %p not dropped or embryonic", __func__, inp));
+ ("%s: inp %p not disconnected or embryonic", __func__, inp));
tcp_discardcb(tp);
in_pcbfree(inp);
@@ -220,19 +220,16 @@ tcp_usr_detach(struct socket *so)
static int
tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
- int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
struct sockaddr_in *sinp;
+ int error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (EINVAL);
}
- tp = intotcpcb(inp);
sinp = (struct sockaddr_in *)nam;
if (nam->sa_family != AF_INET) {
@@ -276,20 +273,17 @@ out:
static int
tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
- int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
struct sockaddr_in6 *sin6;
+ int error = 0;
u_char vflagsav;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (EINVAL);
}
- tp = intotcpcb(inp);
vflagsav = inp->inp_vflag;
@@ -355,19 +349,16 @@ out:
static int
tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
{
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int error = 0;
bool already_listening;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (EINVAL);
}
- tp = intotcpcb(inp);
SOCK_LOCK(so);
already_listening = SOLISTENING(so);
@@ -414,20 +405,17 @@ out:
static int
tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
{
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
u_char vflagsav;
int error = 0;
bool already_listening;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (EINVAL);
}
- tp = intotcpcb(inp);
vflagsav = inp->inp_vflag;
@@ -488,19 +476,16 @@ static int
tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct epoch_tracker et;
- int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
struct sockaddr_in *sinp;
+ int error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (ECONNREFUSED);
}
- tp = intotcpcb(inp);
sinp = (struct sockaddr_in *)nam;
if (nam->sa_family != AF_INET) {
@@ -556,21 +541,18 @@ static int
tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct epoch_tracker et;
- int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
struct sockaddr_in6 *sin6;
+ int error = 0;
u_int8_t incflagsav;
u_char vflagsav;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (ECONNREFUSED);
}
- tp = intotcpcb(inp);
vflagsav = inp->inp_vflag;
incflagsav = inp->inp_inc.inc_flags;
@@ -725,18 +707,15 @@ out:
static int
tcp_usr_accept(struct socket *so, struct sockaddr *sa)
{
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_accept: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (ECONNABORTED);
}
- tp = intotcpcb(inp);
if (so->so_state & SS_ISDISCONNECTED)
error = ECONNABORTED;
@@ -759,18 +738,15 @@ tcp_usr_accept(struct socket *so, struct sockaddr *sa)
static int
tcp6_usr_accept(struct socket *so, struct sockaddr *sa)
{
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (ECONNABORTED);
}
- tp = intotcpcb(inp);
if (so->so_state & SS_ISDISCONNECTED) {
error = ECONNABORTED;
@@ -842,7 +818,7 @@ tcp_usr_shutdown(struct socket *so, enum shutdown_how how)
* return ECONNRESEST for SHUT_RD as well?
*/
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (tp->t_flags & TF_DISCONNECTED) {
INP_WUNLOCK(inp);
return (ECONNRESET);
}
@@ -868,18 +844,16 @@ static int
tcp_usr_rcvd(struct socket *so, int flags)
{
struct epoch_tracker et;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int outrv = 0, error = 0;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_rcvd: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
+ /* XXXGL: how could this happen?! */
INP_WUNLOCK(inp);
return (ECONNRESET);
}
- tp = intotcpcb(inp);
NET_EPOCH_ENTER(et);
/*
@@ -917,9 +891,8 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
struct sockaddr *nam, struct mbuf *control, struct thread *td)
{
struct epoch_tracker et;
- int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
#ifdef INET
#ifdef INET6
struct sockaddr_in sin;
@@ -930,20 +903,18 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
struct sockaddr_in6 *sin6;
int isipv6;
#endif
+ int error = 0;
u_int8_t incflagsav;
u_char vflagsav;
bool restoreflags;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
if (m != NULL && (flags & PRUS_NOTREADY) == 0)
m_freem(m);
INP_WUNLOCK(inp);
return (ECONNRESET);
}
- tp = intotcpcb(inp);
vflagsav = inp->inp_vflag;
incflagsav = inp->inp_inc.inc_flags;
@@ -1121,8 +1092,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
if (tp->t_fbyte_out && tp->t_fbyte_in)
tp->t_flags2 |= TF2_FBYTES_COMPLETE;
}
- if (!(inp->inp_flags & INP_DROPPED) &&
- !(flags & PRUS_NOTREADY)) {
+ if (!(flags & PRUS_NOTREADY)) {
if (flags & PRUS_MORETOCOME)
tp->t_flags |= TF_MORETOCOME;
error = tcp_output_nodrop(tp);
@@ -1232,18 +1202,16 @@ static int
tcp_usr_ready(struct socket *so, struct mbuf *m, int count)
{
struct epoch_tracker et;
- struct inpcb *inp;
- struct tcpcb *tp;
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int error;
- inp = sotoinpcb(so);
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
mb_free_notready(m, count);
return (ECONNRESET);
}
- tp = intotcpcb(inp);
SOCK_SENDBUF_LOCK(so);
error = sbready(&so->so_snd, m, count);
@@ -1265,30 +1233,23 @@ tcp_usr_ready(struct socket *so, struct mbuf *m, int count)
static void
tcp_usr_abort(struct socket *so)
{
- struct inpcb *inp;
- struct tcpcb *tp;
struct epoch_tracker et;
-
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_abort: inp == NULL"));
-
- NET_EPOCH_ENTER(et);
- INP_WLOCK(inp);
- KASSERT(inp->inp_socket != NULL,
- ("tcp_usr_abort: inp_socket == NULL"));
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
/*
* If we still have full TCP state, and we're not dropped, drop.
*/
- if (!(inp->inp_flags & INP_DROPPED)) {
- tp = intotcpcb(inp);
+ NET_EPOCH_ENTER(et);
+ INP_WLOCK(inp);
+ if (!(tp->t_flags & TF_DISCONNECTED)) {
tp = tcp_drop(tp, ECONNABORTED);
if (tp == NULL)
goto dropped;
tcp_bblog_pru(tp, PRU_ABORT, 0);
TCP_PROBE2(debug__user, tp, PRU_ABORT);
}
- if (!(inp->inp_flags & INP_DROPPED)) {
+ if (!(tp->t_flags & TF_DISCONNECTED)) {
soref(so);
inp->inp_flags |= INP_SOCKREF;
}
@@ -1303,24 +1264,17 @@ dropped:
static void
tcp_usr_close(struct socket *so)
{
- struct inpcb *inp;
- struct tcpcb *tp;
struct epoch_tracker et;
-
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_close: inp == NULL"));
-
- NET_EPOCH_ENTER(et);
- INP_WLOCK(inp);
- KASSERT(inp->inp_socket != NULL,
- ("tcp_usr_close: inp_socket == NULL"));
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
/*
* If we are still connected and we're not dropped, initiate
* a disconnect.
*/
- if (!(inp->inp_flags & INP_DROPPED)) {
- tp = intotcpcb(inp);
+ NET_EPOCH_ENTER(et);
+ INP_WLOCK(inp);
+ if (!(tp->t_flags & TF_DISCONNECTED)) {
if (tp->t_state != TCPS_TIME_WAIT) {
tp->t_flags |= TF_CLOSED;
tcp_disconnect(tp);
@@ -1328,7 +1282,7 @@ tcp_usr_close(struct socket *so)
TCP_PROBE2(debug__user, tp, PRU_CLOSE);
}
}
- if (!(inp->inp_flags & INP_DROPPED)) {
+ if (!(tp->t_flags & TF_DISCONNECTED)) {
soref(so);
inp->inp_flags |= INP_SOCKREF;
}
@@ -1360,18 +1314,16 @@ tcp_pru_options_support(struct tcpcb *tp, int flags)
static int
tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
{
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
int error = 0;
- struct inpcb *inp;
- struct tcpcb *tp;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_usr_rcvoob: inp == NULL"));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
+ /* XXXGL: how could this happen?! */
INP_WUNLOCK(inp);
return (ECONNRESET);
}
- tp = intotcpcb(inp);
error = tcp_pru_options_support(tp, PRUS_OOB);
if (error) {
@@ -1650,15 +1602,16 @@ tcp_fill_info(const struct tcpcb *tp, struct tcp_info *ti)
* socket option arguments. When it re-acquires the lock after the copy, it
* has to revalidate that the connection is still valid for the socket
* option.
+ * XXXGL: review if this is really needed
*/
#define INP_WLOCK_RECHECK_CLEANUP(inp, cleanup) do { \
INP_WLOCK(inp); \
- if (inp->inp_flags & INP_DROPPED) { \
+ tp = intotcpcb(inp); \
+ if (tp->t_flags & TF_DISCONNECTED) { \
INP_WUNLOCK(inp); \
cleanup; \
return (ECONNRESET); \
} \
- tp = intotcpcb(inp); \
} while(0)
#define INP_WLOCK_RECHECK(inp) INP_WLOCK_RECHECK_CLEANUP((inp), /* noop */)
@@ -1671,8 +1624,8 @@ tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
MPASS(sopt->sopt_dir == SOPT_SET);
INP_WLOCK_ASSERT(inp);
- KASSERT((inp->inp_flags & INP_DROPPED) == 0,
- ("inp_flags == %x", inp->inp_flags));
+ KASSERT((tp->t_flags & TF_DISCONNECTED) == 0,
+ ("tp_flags == %x", tp->t_flags));
KASSERT(so != NULL, ("inp_socket == NULL"));
if (sopt->sopt_level != IPPROTO_TCP) {
@@ -1839,8 +1792,8 @@ tcp_ctloutput_get(struct inpcb *inp, struct sockopt *sopt)
MPASS(sopt->sopt_dir == SOPT_GET);
INP_WLOCK_ASSERT(inp);
- KASSERT((inp->inp_flags & INP_DROPPED) == 0,
- ("inp_flags == %x", inp->inp_flags));
+ KASSERT((tp->t_flags & TF_DISCONNECTED) == 0,
+ ("tp_flags == %x", tp->t_flags));
KASSERT(so != NULL, ("inp_socket == NULL"));
if (sopt->sopt_level != IPPROTO_TCP) {
@@ -1883,13 +1836,11 @@ tcp_ctloutput_get(struct inpcb *inp, struct sockopt *sopt)
int
tcp_ctloutput(struct socket *so, struct sockopt *sopt)
{
- struct inpcb *inp;
-
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
+ struct inpcb *inp = sotoinpcb(so);
+ struct tcpcb *tp = intotcpcb(inp);
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
return (ECONNRESET);
}
@@ -1917,7 +1868,7 @@ tcp_set_cc_mod(struct inpcb *inp, struct sockopt *sopt)
{
struct cc_algo *algo;
void *ptr = NULL;
- struct tcpcb *tp;
+ struct tcpcb *tp = intotcpcb(inp);
struct cc_var cc_mem;
char buf[TCP_CA_NAME_MAX];
size_t mem_sz;
@@ -1967,7 +1918,7 @@ no_mem_needed:
*/
memset(&cc_mem, 0, sizeof(cc_mem));
INP_WLOCK(inp);
- if (inp->inp_flags & INP_DROPPED) {
+ if (__predict_false(tp->t_flags & TF_DISCONNECTED)) {
INP_WUNLOCK(inp);
if (ptr)
free(ptr, M_CC_MEM);
@@ -1977,7 +1928,6 @@ no_mem_needed:
CC_LIST_RUNLOCK();
return (ECONNRESET);
}
- tp = intotcpcb(inp);
if (ptr != NULL)
memset(ptr, 0, mem_sz);
cc_mem.tp = tp;
@@ -2043,8 +1993,8 @@ tcp_default_ctloutput(struct tcpcb *tp, struct sockopt *sopt)
size_t len;
INP_WLOCK_ASSERT(inp);
- KASSERT((inp->inp_flags & INP_DROPPED) == 0,
- ("inp_flags == %x", inp->inp_flags));
+ KASSERT((tp->t_flags & TF_DISCONNECTED) == 0,
+ ("tp_flags == %x", tp->t_flags));
KASSERT(inp->inp_socket != NULL, ("inp_socket == NULL"));
switch (sopt->sopt_level) {
@@ -2673,7 +2623,7 @@ tcp_disconnect(struct tcpcb *tp)
soisdisconnecting(so);
sbflush(&so->so_rcv);
tcp_usrclosed(tp);
- if (!(inp->inp_flags & INP_DROPPED))
+ if (!(tp->t_flags & TF_DISCONNECTED))
/* Ignore stack's drop request, we already at it. */
(void)tcp_output_nodrop(tp);
}
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 95c4e4c52ba0..987bb98c19af 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -789,7 +789,7 @@ tcp_packets_this_ack(struct tcpcb *tp, tcp_seq ack)
#define TF_TSO 0x01000000 /* TSO enabled on this connection */
#define TF_TOE 0x02000000 /* this connection is offloaded */
#define TF_CLOSED 0x04000000 /* close(2) called on socket */
-#define TF_UNUSED 0x08000000 /* was TF_SENTSYN */
+#define TF_DISCONNECTED 0x08000000 /* went through tcp_close() */
#define TF_LRD 0x10000000 /* Lost Retransmission Detection */
#define TF_CONGRECOVERY 0x20000000 /* congestion recovery mode */
#define TF_WASCRECOVERY 0x40000000 /* was in congestion recovery */
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index 1c4e89069a4b..38171f3439be 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -212,16 +212,15 @@ static void
toe_listen_start(struct inpcb *inp, void *arg)
{
struct toedev *t, *tod;
- struct tcpcb *tp;
+ struct tcpcb *tp = intotcpcb(inp);
INP_WLOCK_ASSERT(inp);
KASSERT(inp->inp_pcbinfo == &V_tcbinfo,
("%s: inp is not a TCP inp", __func__));
- if (inp->inp_flags & INP_DROPPED)
+ if (tp->t_flags & TF_DISCONNECTED)
return;
- tp = intotcpcb(inp);
if (tp->t_state != TCPS_LISTEN)
return;
@@ -510,13 +509,12 @@ toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
void
toe_connect_failed(struct toedev *tod, struct inpcb *inp, int err)
{
+ struct tcpcb *tp = intotcpcb(inp);
NET_EPOCH_ASSERT();
INP_WLOCK_ASSERT(inp);
- if (!(inp->inp_flags & INP_DROPPED)) {
- struct tcpcb *tp = intotcpcb(inp);
-
+ if (!(tp->t_flags & TF_DISCONNECTED)) {
KASSERT(tp->t_flags & TF_TOE,
("%s: tp %p not offloaded.", __func__, tp));