-/* $OpenBSD: tcp_input.c,v 1.379 2022/08/30 11:53:04 bluhm Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.380 2022/09/03 19:22:19 bluhm Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
void syn_cache_put(struct syn_cache *);
void syn_cache_rm(struct syn_cache *);
-int syn_cache_respond(struct syn_cache *, struct mbuf *);
+int syn_cache_respond(struct syn_cache *, struct mbuf *, uint32_t);
void syn_cache_timer(void *);
void syn_cache_reaper(void *);
void syn_cache_insert(struct syn_cache *, struct tcpcb *);
struct tcphdr *, u_int);
int syn_cache_add(struct sockaddr *, struct sockaddr *, struct tcphdr *,
unsigned int, struct socket *, struct mbuf *, u_char *, int,
- struct tcp_opt_info *, tcp_seq *);
+ struct tcp_opt_info *, tcp_seq *, uint32_t);
struct socket *syn_cache_get(struct sockaddr *, struct sockaddr *,
struct tcphdr *, unsigned int, unsigned int, struct socket *,
- struct mbuf *);
+ struct mbuf *, uint32_t);
struct syn_cache *syn_cache_lookup(struct sockaddr *, struct sockaddr *,
struct syn_cache_head **, u_int);
short ostate;
caddr_t saveti;
tcp_seq iss, *reuse = NULL;
+ uint32_t now;
u_long tiwin;
struct tcp_opt_info opti;
struct tcphdr *th;
opti.ts_present = 0;
opti.maxseg = 0;
+ now = READ_ONCE(tcp_now);
/*
* RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
case TH_ACK:
so = syn_cache_get(&src.sa, &dst.sa,
- th, iphlen, tlen, so, m);
+ th, iphlen, tlen, so, m, now);
if (so == NULL) {
/*
* We don't have a SYN for
*/
if (so->so_qlen > so->so_qlimit ||
syn_cache_add(&src.sa, &dst.sa, th, iphlen,
- so, m, optp, optlen, &opti, reuse) == -1) {
+ so, m, optp, optlen, &opti, reuse, now)
+ == -1) {
tcpstat_inc(tcps_dropsyn);
goto drop;
}
* Segment received on connection.
* Reset idle time and keep-alive timer.
*/
- tp->t_rcvtime = tcp_now;
+ tp->t_rcvtime = now;
if (TCPS_HAVEESTABLISHED(tp->t_state))
TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
if (optp)
#endif
if (tcp_dooptions(tp, optp, optlen, th, m, iphlen, &opti,
- m->m_pkthdr.ph_rtableid))
+ m->m_pkthdr.ph_rtableid, now))
goto drop;
if (opti.ts_present && opti.ts_ecr) {
opti.ts_ecr -= tp->ts_modulate;
/* make sure ts_ecr is sensible */
- rtt_test = tcp_now - opti.ts_ecr;
+ rtt_test = now - opti.ts_ecr;
if (rtt_test < 0 || rtt_test > TCP_RTT_MAX)
opti.ts_ecr = 0;
}
* Fix from Braden, see Stevens p. 870
*/
if (opti.ts_present && SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
- tp->ts_recent_age = tcp_now;
+ tp->ts_recent_age = now;
tp->ts_recent = opti.ts_val;
}
*/
tcpstat_inc(tcps_predack);
if (opti.ts_present && opti.ts_ecr)
- tcp_xmit_timer(tp, tcp_now - opti.ts_ecr);
+ tcp_xmit_timer(tp, now - opti.ts_ecr);
else if (tp->t_rtttime &&
SEQ_GT(th->th_ack, tp->t_rtseq))
- tcp_xmit_timer(tp,
- tcp_now - tp->t_rtttime);
+ tcp_xmit_timer(tp, now - tp->t_rtttime);
acked = th->th_ack - tp->snd_una;
tcpstat_pkt(tcps_rcvackpack, tcps_rcvackbyte,
acked);
- tp->t_rcvacktime = tcp_now;
+ tp->t_rcvacktime = now;
ND6_HINT(tp);
sbdrop(so, &so->so_snd, acked);
* use its rtt as our initial srtt & rtt var.
*/
if (tp->t_rtttime)
- tcp_xmit_timer(tp, tcp_now - tp->t_rtttime);
+ tcp_xmit_timer(tp, now - tp->t_rtttime);
/*
* Since new data was acked (the SYN), open the
* congestion window by one MSS. We do this
TSTMP_LT(opti.ts_val, tp->ts_recent)) {
/* Check to see if ts_recent is over 24 days old. */
- if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
+ if ((int)(now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
/*
* Invalidate ts_recent. If this segment updates
* ts_recent, the age will be reset later and ts_recent
*/
if (opti.ts_present && TSTMP_GEQ(opti.ts_val, tp->ts_recent) &&
SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
- tp->ts_recent_age = tcp_now;
+ tp->ts_recent_age = now;
tp->ts_recent = opti.ts_val;
}
}
acked = th->th_ack - tp->snd_una;
tcpstat_pkt(tcps_rcvackpack, tcps_rcvackbyte, acked);
- tp->t_rcvacktime = tcp_now;
+ tp->t_rcvacktime = now;
/*
* If we have a timestamp reply, update smoothed
* Recompute the initial retransmit timer.
*/
if (opti.ts_present && opti.ts_ecr)
- tcp_xmit_timer(tp, tcp_now - opti.ts_ecr);
+ tcp_xmit_timer(tp, now - opti.ts_ecr);
else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq))
- tcp_xmit_timer(tp, tcp_now - tp->t_rtttime);
+ tcp_xmit_timer(tp, now - tp->t_rtttime);
/*
* If all outstanding data is acked, stop retransmit
goto drop;
if (tiflags & TH_ACK) {
tcp_respond(tp, mtod(m, caddr_t), th, (tcp_seq)0, th->th_ack,
- TH_RST, m->m_pkthdr.ph_rtableid);
+ TH_RST, m->m_pkthdr.ph_rtableid, now);
} else {
if (tiflags & TH_SYN)
tlen++;
tcp_respond(tp, mtod(m, caddr_t), th, th->th_seq + tlen,
- (tcp_seq)0, TH_RST|TH_ACK, m->m_pkthdr.ph_rtableid);
+ (tcp_seq)0, TH_RST|TH_ACK, m->m_pkthdr.ph_rtableid, now);
}
m_freem(m);
in_pcbunref(inp);
int
tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcphdr *th,
struct mbuf *m, int iphlen, struct tcp_opt_info *oi,
- u_int rtableid)
+ u_int rtableid, uint32_t now)
{
u_int16_t mss = 0;
int opt, optlen;
*/
tp->t_flags |= TF_RCVD_TSTMP;
tp->ts_recent = oi->ts_val;
- tp->ts_recent_age = tcp_now;
+ tp->ts_recent_age = now;
break;
case TCPOPT_SACK_PERMITTED:
timeout_add(&(sc)->sc_timer, (sc)->sc_rxtcur * (hz / PR_SLOWHZ)); \
} while (/*CONSTCOND*/0)
-#define SYN_CACHE_TIMESTAMP(sc) tcp_now + (sc)->sc_modulate
-
void
syn_cache_init(void)
{
syn_cache_timer(void *arg)
{
struct syn_cache *sc = arg;
+ uint32_t now;
NET_LOCK();
if (sc->sc_flags & SCF_DEAD)
goto out;
+ now = READ_ONCE(tcp_now);
+
if (__predict_false(sc->sc_rxtshift == TCP_MAXRXTSHIFT)) {
/* Drop it -- too many retransmissions. */
goto dropit;
goto dropit;
tcpstat_inc(tcps_sc_retransmitted);
- (void) syn_cache_respond(sc, NULL);
+ (void) syn_cache_respond(sc, NULL, now);
/* Advance the timer back-off. */
sc->sc_rxtshift++;
*/
struct socket *
syn_cache_get(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
- u_int hlen, u_int tlen, struct socket *so, struct mbuf *m)
+ u_int hlen, u_int tlen, struct socket *so, struct mbuf *m, uint32_t now)
{
struct syn_cache *sc;
struct syn_cache_head *scp;
if ((th->th_ack != sc->sc_iss + 1) ||
SEQ_LEQ(th->th_seq, sc->sc_irs) ||
SEQ_GT(th->th_seq, sc->sc_irs + 1 + sc->sc_win)) {
- (void) syn_cache_respond(sc, m);
+ (void) syn_cache_respond(sc, m, now);
return ((struct socket *)(-1));
}
#endif
tcp_rcvseqinit(tp);
tp->t_state = TCPS_SYN_RECEIVED;
- tp->t_rcvtime = tcp_now;
- tp->t_sndtime = tcp_now;
- tp->t_rcvacktime = tcp_now;
- tp->t_sndacktime = tcp_now;
+ tp->t_rcvtime = now;
+ tp->t_sndtime = now;
+ tp->t_rcvacktime = now;
+ tp->t_sndacktime = now;
TCP_TIMER_ARM(tp, TCPT_KEEP, tcptv_keep_init);
tcpstat_inc(tcps_accepts);
resetandabort:
tcp_respond(NULL, mtod(m, caddr_t), th, (tcp_seq)0, th->th_ack, TH_RST,
- m->m_pkthdr.ph_rtableid);
+ m->m_pkthdr.ph_rtableid, now);
abort:
m_freem(m);
if (so != NULL)
int
syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
u_int iphlen, struct socket *so, struct mbuf *m, u_char *optp, int optlen,
- struct tcp_opt_info *oi, tcp_seq *issp)
+ struct tcp_opt_info *oi, tcp_seq *issp, uint32_t now)
{
struct tcpcb tb, *tp;
long win;
#endif
tb.t_state = TCPS_LISTEN;
if (tcp_dooptions(&tb, optp, optlen, th, m, iphlen, oi,
- sotoinpcb(so)->inp_rtableid))
+ sotoinpcb(so)->inp_rtableid, now))
return (-1);
}
sc->sc_ipopts = ipopts;
}
sc->sc_timestamp = tb.ts_recent;
- if (syn_cache_respond(sc, m) == 0) {
+ if (syn_cache_respond(sc, m, now) == 0) {
tcpstat_inc(tcps_sndacks);
tcpstat_inc(tcps_sndtotal);
}
sc->sc_flags |= SCF_SIGNATURE;
#endif
sc->sc_tp = tp;
- if (syn_cache_respond(sc, m) == 0) {
+ if (syn_cache_respond(sc, m, now) == 0) {
syn_cache_insert(sc, tp);
tcpstat_inc(tcps_sndacks);
tcpstat_inc(tcps_sndtotal);
}
int
-syn_cache_respond(struct syn_cache *sc, struct mbuf *m)
+syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint32_t now)
{
u_int8_t *optp;
int optlen, error;
u_int32_t *lp = (u_int32_t *)(optp);
/* Form timestamp option as shown in appendix A of RFC 1323. */
*lp++ = htonl(TCPOPT_TSTAMP_HDR);
- *lp++ = htonl(SYN_CACHE_TIMESTAMP(sc));
+ *lp++ = htonl(now + sc->sc_modulate);
*lp = htonl(sc->sc_timestamp);
optp += TCPOLEN_TSTAMP_APPA;
}
-/* $OpenBSD: tcp_subr.c,v 1.186 2022/08/30 11:53:04 bluhm Exp $ */
+/* $OpenBSD: tcp_subr.c,v 1.187 2022/09/03 19:22:19 bluhm Exp $ */
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
/*
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
+#include <sys/mutex.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/timeout.h>
#include <crypto/md5.h>
#include <crypto/sha2.h>
+/*
+ * Locks used to protect struct members in this file:
+ * I immutable after creation
+ * T tcp_timer_mtx global tcp timer data structures
+ */
+
+struct mutex tcp_timer_mtx;
+
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
#endif
int tcp_do_rfc3390 = 2; /* Increase TCP's Initial Window to 10*mss */
-u_int32_t tcp_now = 1;
-
#ifndef TCB_INITIAL_HASH_SIZE
#define TCB_INITIAL_HASH_SIZE 128
#endif
struct cpumem *tcpcounters; /* tcp statistics */
-u_char tcp_secret[16];
-SHA2_CTX tcp_secret_ctx;
-tcp_seq tcp_iss;
+u_char tcp_secret[16]; /* [I] */
+SHA2_CTX tcp_secret_ctx; /* [I] */
+tcp_seq tcp_iss; /* [T] updated by timer and connection */
+uint32_t tcp_now; /* [T] incremented by slow timer */
/*
* Tcp initialization
tcp_init(void)
{
tcp_iss = 1; /* wrong */
+ tcp_now = 1;
pool_init(&tcpcb_pool, sizeof(struct tcpcb), 0, IPL_SOFTNET, 0,
"tcpcb", NULL);
pool_init(&tcpqe_pool, sizeof(struct tcpqent), 0, IPL_SOFTNET, 0,
*/
void
tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0,
- tcp_seq ack, tcp_seq seq, int flags, u_int rtableid)
+ tcp_seq ack, tcp_seq seq, int flags, u_int rtableid, uint32_t now)
{
int tlen;
int win = 0;
u_int32_t *lp = (u_int32_t *)(th + 1);
/* Form timestamp option as shown in appendix A of RFC 1323. */
*lp++ = htonl(TCPOPT_TSTAMP_HDR);
- *lp++ = htonl(tcp_now + tp->ts_modulate);
+ *lp++ = htonl(now + tp->ts_modulate);
*lp = htonl(tp->ts_recent);
tlen += TCPOLEN_TSTAMP_APPA;
th->th_off = (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_APPA) >> 2;
uint32_t words[2];
} digest;
u_int rdomain = rtable_l2(tp->t_inpcb->inp_rtableid);
+ tcp_seq iss;
+
+ mtx_enter(&tcp_timer_mtx);
+ tcp_iss += TCP_ISS_CONN_INC;
+ iss = tcp_iss;
+ mtx_leave(&tcp_timer_mtx);
ctx = tcp_secret_ctx;
SHA512Update(&ctx, &rdomain, sizeof(rdomain));
sizeof(struct in_addr));
}
SHA512Final(digest.bytes, &ctx);
- tcp_iss += TCP_ISS_CONN_INC;
- tp->iss = digest.words[0] + tcp_iss;
+ tp->iss = digest.words[0] + iss;
tp->ts_modulate = digest.words[1];
}
-/* $OpenBSD: tcp_timer.c,v 1.69 2022/01/02 22:36:04 jsg Exp $ */
+/* $OpenBSD: tcp_timer.c,v 1.70 2022/09/03 19:22:19 bluhm Exp $ */
/* $NetBSD: tcp_timer.c,v 1.14 1996/02/13 23:44:09 christos Exp $ */
/*
#include <netinet/ip_icmp.h>
#include <netinet/tcp_seq.h>
+/*
+ * Locks used to protect struct members in this file:
+ * T tcp_timer_mtx global tcp timer data structures
+ */
+
int tcp_always_keepalive;
int tcp_keepidle;
int tcp_keepintvl;
int tcp_maxpersistidle; /* max idle time in persist */
-int tcp_maxidle;
+int tcp_maxidle; /* [T] max idle time for keep alive */
/*
* Time to delay the ACK. This is initialized in tcp_init(), unless
void
tcp_slowtimo(void)
{
- NET_LOCK();
-
+ mtx_enter(&tcp_timer_mtx);
tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
tcp_iss += TCP_ISSINCR2/PR_SLOWHZ; /* increment iss */
tcp_now++; /* for timestamps */
-
- NET_UNLOCK();
+ mtx_leave(&tcp_timer_mtx);
}
/*
struct tcpcb *otp = NULL, *tp = arg;
uint32_t rto;
short ostate;
+ uint32_t now;
NET_LOCK();
/* Ignore canceled timeouts or timeouts that have been rescheduled. */
rto = TCP_REXMTVAL(tp);
if (rto < tp->t_rttmin)
rto = tp->t_rttmin;
+ now = READ_ONCE(tcp_now);
if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
- ((tcp_now - tp->t_rcvtime) >= tcp_maxpersistidle ||
- (tcp_now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
+ ((now - tp->t_rcvtime) >= tcp_maxpersistidle ||
+ (now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
tcpstat_inc(tcps_persistdrop);
tp = tcp_drop(tp, ETIMEDOUT);
goto out;
if ((tcp_always_keepalive ||
tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) &&
tp->t_state <= TCPS_CLOSING) {
- if ((tcp_maxidle > 0) &&
- ((tcp_now - tp->t_rcvtime) >= tcp_keepidle + tcp_maxidle))
+ int maxidle;
+ uint32_t now;
+
+ maxidle = READ_ONCE(tcp_maxidle);
+ now = READ_ONCE(tcp_now);
+ if ((maxidle > 0) &&
+ ((now - tp->t_rcvtime) >= tcp_keepidle + maxidle))
goto dropit;
/*
* Send a packet designed to force a response
*/
tcpstat_inc(tcps_keepprobe);
tcp_respond(tp, mtod(tp->t_template, caddr_t),
- NULL, tp->rcv_nxt, tp->snd_una - 1, 0, 0);
+ NULL, tp->rcv_nxt, tp->snd_una - 1, 0, 0, now);
TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepintvl);
} else
TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
{
struct tcpcb *otp = NULL, *tp = arg;
short ostate;
+ int maxidle;
+ uint32_t now;
NET_LOCK();
/* Ignore canceled timeouts or timeouts that have been rescheduled. */
}
tcp_timer_freesack(tp);
+ maxidle = READ_ONCE(tcp_maxidle);
+ now = READ_ONCE(tcp_now);
if (tp->t_state != TCPS_TIME_WAIT &&
- ((tcp_maxidle == 0) || ((tcp_now - tp->t_rcvtime) <= tcp_maxidle)))
+ ((maxidle == 0) || ((now - tp->t_rcvtime) <= maxidle)))
TCP_TIMER_ARM(tp, TCPT_2MSL, tcp_keepintvl);
else
tp = tcp_close(tp);