git: 1ebf46075872 - main - tcp: Access all 12 TCP header flags via inline function

From: Richard Scheffenegger <rscheff_at_FreeBSD.org>
Date: Thu, 03 Feb 2022 15:34:07 UTC
The branch main has been updated by rscheff:

URL: https://cgit.FreeBSD.org/src/commit/?id=1ebf460758723efcdb830aceb89164512d56051a

commit 1ebf460758723efcdb830aceb89164512d56051a
Author:     Richard Scheffenegger <rscheff@FreeBSD.org>
AuthorDate: 2022-02-03 15:21:25 +0000
Commit:     Richard Scheffenegger <rscheff@FreeBSD.org>
CommitDate: 2022-02-03 15:21:58 +0000

    tcp: Access all 12 TCP header flags via inline function
    
    In order to consistently provide access to all
    (including reserved) TCP header flag bits,
    use an accessor function tcp_get_flags and
    tcp_set_flags. Also expand any flag variable from
    uint8_t / char to uint16_t.
    
    Reviewed By: hselasky, tuexen, glebius, #transport
    Sponsored by:        NetApp, Inc.
    Differential Revision: https://reviews.freebsd.org/D34130
---
 sys/netinet/tcp_debug.c       |  4 ++--
 sys/netinet/tcp_input.c       | 16 ++++++++--------
 sys/netinet/tcp_lro.c         | 16 ++++++++--------
 sys/netinet/tcp_output.c      |  2 +-
 sys/netinet/tcp_reass.c       | 16 ++++++++--------
 sys/netinet/tcp_stacks/bbr.c  | 10 +++++-----
 sys/netinet/tcp_stacks/rack.c | 22 +++++++++++-----------
 sys/netinet/tcp_subr.c        | 10 ++++------
 sys/netinet/tcp_syncache.c    | 15 +++++++--------
 sys/netinet/tcp_timewait.c    | 10 +++++-----
 sys/netinet/tcp_var.h         | 15 ++++++++++++++-
 11 files changed, 73 insertions(+), 63 deletions(-)

diff --git a/sys/netinet/tcp_debug.c b/sys/netinet/tcp_debug.c
index aedaa131095f..1c8924ea09dd 100644
--- a/sys/netinet/tcp_debug.c
+++ b/sys/netinet/tcp_debug.c
@@ -189,11 +189,11 @@ tcp_trace(short act, short ostate, struct tcpcb *tp, void *ipgen,
 		else
 			printf("%x", seq);
 		printf("@%x, urp=%x", ack, th->th_urp);
-		flags = th->th_flags;
+		flags = tcp_get_flags(th);
 		if (flags) {
 			char *cp = "<";
 #define pf(f) {					\
-	if (th->th_flags & TH_##f) {		\
+	if (tcp_get_flags(th) & TH_##f) {	\
 		printf("%s%s", cp, #f);		\
 		cp = ",";			\
 	}					\
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 5ffbf18b5991..9a1f3ace2541 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -548,7 +548,7 @@ cc_ecnpkt_handler_flags(struct tcpcb *tp, uint16_t flags, uint8_t iptos)
 void inline
 cc_ecnpkt_handler(struct tcpcb *tp, struct tcphdr *th, uint8_t iptos)
 {
-	cc_ecnpkt_handler_flags(tp, th->th_flags, iptos);
+	cc_ecnpkt_handler_flags(tp, tcp_get_flags(th), iptos);
 }
 
 /*
@@ -799,7 +799,7 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port)
 		optlen = off - sizeof (struct tcphdr);
 		optp = (u_char *)(th + 1);
 	}
-	thflags = th->th_flags;
+	thflags = tcp_get_flags(th);
 
 	/*
 	 * Convert TCP protocol specific fields to host format.
@@ -1537,7 +1537,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	struct tcphdr tcp_savetcp;
 	short ostate = 0;
 #endif
-	thflags = th->th_flags;
+	thflags = tcp_get_flags(th);
 	inc = &tp->t_inpcb->inp_inc;
 	tp->sackhint.last_sack_ack = 0;
 	sack_changed = 0;
@@ -3176,7 +3176,7 @@ dodata:							/* XXX */
 				if (tp->t_fbyte_out && tp->t_fbyte_in)
 					tp->t_flags2 |= TF2_FBYTES_COMPLETE;
 			}
-			thflags = th->th_flags & TH_FIN;
+			thflags = tcp_get_flags(th) & TH_FIN;
 			TCPSTAT_INC(tcps_rcvpack);
 			TCPSTAT_ADD(tcps_rcvbyte, tlen);
 			SOCKBUF_LOCK(&so->so_rcv);
@@ -3401,7 +3401,7 @@ tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp,
 	}
 
 	/* Don't bother if destination was broadcast/multicast. */
-	if ((th->th_flags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
+	if ((tcp_get_flags(th) & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
 		goto drop;
 #ifdef INET6
 	if (mtod(m, struct ip *)->ip_v == 6) {
@@ -3431,13 +3431,13 @@ tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp,
 		goto drop;
 
 	/* tcp_respond consumes the mbuf chain. */
-	if (th->th_flags & TH_ACK) {
+	if (tcp_get_flags(th) & TH_ACK) {
 		tcp_respond(tp, mtod(m, void *), th, m, (tcp_seq)0,
 		    th->th_ack, TH_RST);
 	} else {
-		if (th->th_flags & TH_SYN)
+		if (tcp_get_flags(th) & TH_SYN)
 			tlen++;
-		if (th->th_flags & TH_FIN)
+		if (tcp_get_flags(th) & TH_FIN)
 			tlen++;
 		tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen,
 		    (tcp_seq)0, TH_RST|TH_ACK);
diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
index c1d3b0d4f13f..2a20a5ce4e6d 100644
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -921,7 +921,7 @@ tcp_set_entry_to_mbuf(struct lro_ctrl *lc, struct lro_entry *le,
 	le->next_seq = ntohl(th->th_seq) + tcp_data_len;
 	le->ack_seq = th->th_ack;
 	le->window = th->th_win;
-	le->flags = (th->th_x2 << 8) | th->th_flags;
+	le->flags = tcp_get_flags(th);
 	le->needs_merge = 0;
 
 	/* Setup new data pointers. */
@@ -1033,7 +1033,7 @@ again:
 		tcp_push_and_replace(lc, le, m);
 		goto again;
 	}
-	if ((((th->th_x2 << 8) | th->th_flags) & ~(TH_ACK | TH_PUSH)) != 0) {
+	if ((tcp_get_flags(th) & ~(TH_ACK | TH_PUSH)) != 0) {
 		/*
 		 * Make sure that previously seen segments/ACKs are delivered
 		 * before this segment, e.g. FIN.
@@ -1077,7 +1077,7 @@ again:
 			tcp_push_and_replace(lc, le, m);
 			goto again;
 		}
-		if ((((th->th_x2 << 8) | th->th_flags) & ~(TH_ACK | TH_PUSH)) != 0) {
+		if ((tcp_get_flags(th) & ~(TH_ACK | TH_PUSH)) != 0) {
 			tcp_push_and_replace(lc, le, m);
 			goto again;
 		}
@@ -1093,7 +1093,7 @@ again:
 		}
 		/* Try to append the new segment. */
 		if (__predict_false(ntohl(th->th_seq) != le->next_seq ||
-				    ((th->th_flags & TH_ACK) !=
+				    ((tcp_get_flags(th) & TH_ACK) !=
 				      (le->flags & TH_ACK)) ||
 				    (tcp_data_len == 0 &&
 				     le->ack_seq == th->th_ack &&
@@ -1265,14 +1265,14 @@ tcp_lro_ack_valid(struct mbuf *m, struct tcphdr *th, uint32_t **ppts, bool *othe
 		break;
 	}
 	/* For ACKCMP we only accept ACK, PUSH, ECE and CWR. */
-	if ((((th->th_x2 << 8) | th->th_flags) & ~(TH_ACK | TH_PUSH | TH_ECE | TH_CWR)) != 0)
+	if ((tcp_get_flags(th) & ~(TH_ACK | TH_PUSH | TH_ECE | TH_CWR)) != 0)
 		ret = false;
 	/* If it has data on it we cannot compress it */
 	if (m->m_pkthdr.lro_tcp_d_len)
 		ret = false;
 
 	/* ACK flag must be set. */
-	if (!(th->th_flags & TH_ACK))
+	if (!(tcp_get_flags(th) & TH_ACK))
 		ret = false;
 	return (ret);
 }
@@ -1576,7 +1576,7 @@ build_ack_entry(struct tcp_ackent *ae, struct tcphdr *th, struct mbuf *m,
 		ae->flags = TSTMP_HDWR;
 	ae->seq = ntohl(th->th_seq);
 	ae->ack = ntohl(th->th_ack);
-	ae->flags |= (th->th_x2 << 8) | th->th_flags;
+	ae->flags |= tcp_get_flags(th);
 	if (ts_ptr != NULL) {
 		ae->ts_value = ntohl(ts_ptr[1]);
 		ae->ts_echo = ntohl(ts_ptr[2]);
@@ -1831,7 +1831,7 @@ tcp_lro_rx_common(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, bool use_h
 	th = pa->tcp;
 
 	/* Don't process SYN packets. */
-	if (__predict_false(th->th_flags & TH_SYN))
+	if (__predict_false(tcp_get_flags(th) & TH_SYN))
 		return (TCP_LRO_CANNOT);
 
 	/* Get total TCP header length and compute payload length. */
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index ff40e67767ab..dc512c8aad39 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1287,7 +1287,7 @@ send:
 		bcopy(opt, th + 1, optlen);
 		th->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
 	}
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	/*
 	 * Calculate receive window.  Don't shrink window,
 	 * but avoid silly window syndrome.
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 5b9255da3acf..27839c7d066e 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -332,7 +332,7 @@ tcp_reass_append(struct tcpcb *tp, struct tseg_qent *last,
 	last->tqe_len += tlen;
 	last->tqe_m->m_pkthdr.len += tlen;
 	/* Preserve the FIN bit if its there */
-	last->tqe_flags |= (th->th_flags & TH_FIN);
+	last->tqe_flags |= (tcp_get_flags(th) & TH_FIN);
 	last->tqe_last->m_next = m;
 	last->tqe_last = mlast;
 	last->tqe_mbuf_cnt += lenofoh;
@@ -384,7 +384,7 @@ tcp_reass_prepend(struct tcpcb *tp, struct tseg_qent *first, struct mbuf *m, str
 
 static void
 tcp_reass_replace(struct tcpcb *tp, struct tseg_qent *q, struct mbuf *m,
-    tcp_seq seq, int len, struct mbuf *mlast, int mbufoh, uint8_t flags)
+    tcp_seq seq, int len, struct mbuf *mlast, int mbufoh, uint16_t flags)
 {
 	/*
 	 * Free the data in q, and replace
@@ -564,7 +564,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, tcp_seq *seq_start,
 	/*
 	 * Check for zero length data.
 	 */
-	if ((*tlenp == 0) && ((th->th_flags & TH_FIN) == 0)) {
+	if ((*tlenp == 0) && ((tcp_get_flags(th) & TH_FIN) == 0)) {
 		/*
 		 * A zero length segment does no
 		 * one any good. We could check
@@ -581,7 +581,7 @@ strip_fin:
 #endif
 		return (0);
 	} else if ((*tlenp == 0) &&
-		   (th->th_flags & TH_FIN) &&
+		   (tcp_get_flags(th) & TH_FIN) &&
 		   !TCPS_HAVEESTABLISHED(tp->t_state)) {
 		/*
 		 * We have not established, and we
@@ -628,7 +628,7 @@ strip_fin:
 	 */
 	last = TAILQ_LAST_FAST(&tp->t_segq, tseg_qent, tqe_q);
 	if (last != NULL) {
-		if ((th->th_flags & TH_FIN) &&
+		if ((tcp_get_flags(th) & TH_FIN) &&
 		    SEQ_LT((th->th_seq + *tlenp), (last->tqe_start + last->tqe_len))) {
 			/*
 			 * Someone is trying to game us, dump
@@ -915,7 +915,7 @@ strip_fin:
 #ifdef TCP_REASS_COUNTERS
 			counter_u64_add(reass_path7, 1);
 #endif
-			tcp_reass_replace(tp, q, m, th->th_seq, *tlenp, mlast, lenofoh, th->th_flags);
+			tcp_reass_replace(tp, q, m, th->th_seq, *tlenp, mlast, lenofoh, tcp_get_flags(th));
 		} else {
 			/*
 			 * We just need to prepend the data
@@ -964,7 +964,7 @@ strip_fin:
 new_entry:
 	if (th->th_seq == tp->rcv_nxt && TCPS_HAVEESTABLISHED(tp->t_state)) {
 		tp->rcv_nxt += *tlenp;
-		flags = th->th_flags & TH_FIN;
+		flags = tcp_get_flags(th) & TH_FIN;
 		TCPSTAT_INC(tcps_rcvoopack);
 		TCPSTAT_ADD(tcps_rcvoobyte, *tlenp);
 		SOCKBUF_LOCK(&so->so_rcv);
@@ -1039,7 +1039,7 @@ new_entry:
 	TCPSTAT_ADD(tcps_rcvoobyte, *tlenp);
 	/* Insert the new segment queue entry into place. */
 	te->tqe_m = m;
-	te->tqe_flags = th->th_flags;
+	te->tqe_flags = tcp_get_flags(th);
 	te->tqe_len = *tlenp;
 	te->tqe_start = th->th_seq;
 	te->tqe_last = mlast;
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index c5cf8a46880f..a9abf72c3f93 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -5907,7 +5907,7 @@ tcp_bbr_tso_size_check(struct tcp_bbr *bbr, uint32_t cts)
 
 static void
 bbr_log_output(struct tcp_bbr *bbr, struct tcpcb *tp, struct tcpopt *to, int32_t len,
-    uint32_t seq_out, uint8_t th_flags, int32_t err, uint32_t cts,
+    uint32_t seq_out, uint16_t th_flags, int32_t err, uint32_t cts,
     struct mbuf *mb, int32_t * abandon, struct bbr_sendmap *hintrsm, uint32_t delay_calc,
     struct sockbuf *sb)
 {
@@ -7337,7 +7337,7 @@ bbr_log_ack(struct tcpcb *tp, struct tcpopt *to, struct tcphdr *th,
 	uint32_t p_maxseg, maxseg, p_acked = 0;
 
 	INP_WLOCK_ASSERT(tp->t_inpcb);
-	if (th->th_flags & TH_RST) {
+	if (tcp_get_flags(th) & TH_RST) {
 		/* We don't log resets */
 		return (0);
 	}
@@ -8282,7 +8282,7 @@ bbr_process_data(struct mbuf *m, struct tcphdr *th, struct socket *so,
 				if (tp->t_fbyte_out && tp->t_fbyte_in)
 					tp->t_flags2 |= TF2_FBYTES_COMPLETE;
 			}
-			thflags = th->th_flags & TH_FIN;
+			thflags = tcp_get_flags(th) & TH_FIN;
 			KMOD_TCPSTAT_ADD(tcps_rcvpack, (int)nsegs);
 			KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
 			SOCKBUF_LOCK(&so->so_rcv);
@@ -11363,7 +11363,7 @@ bbr_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	/* add in our stats */
 	kern_prefetch(bbr, &prev_state);
 	prev_state = 0;
-	thflags = th->th_flags;
+	thflags = tcp_get_flags(th);
 	/*
 	 * If this is either a state-changing packet or current state isn't
 	 * established, we require a write lock on tcbinfo.  Otherwise, we
@@ -13450,7 +13450,7 @@ send:
 		bcopy(opt, th + 1, optlen);
 		th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
 	}
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	/*
 	 * Calculate receive window.  Don't shrink window, but avoid silly
 	 * window syndrome.
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 93f5adc08a5b..7983c18620e2 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -489,7 +489,7 @@ rack_log_ack(struct tcpcb *tp, struct tcpopt *to,
     struct tcphdr *th, int entered_rec, int dup_ack_struck);
 static void
 rack_log_output(struct tcpcb *tp, struct tcpopt *to, int32_t len,
-    uint32_t seq_out, uint8_t th_flags, int32_t err, uint64_t ts,
+    uint32_t seq_out, uint16_t th_flags, int32_t err, uint64_t ts,
     struct rack_sendmap *hintrsm, uint16_t add_flags, struct mbuf *s_mb, uint32_t s_moff, int hw_tls);
 
 static void
@@ -7413,7 +7413,7 @@ rack_update_entry(struct tcpcb *tp, struct tcp_rack *rack,
 
 static void
 rack_log_output(struct tcpcb *tp, struct tcpopt *to, int32_t len,
-		uint32_t seq_out, uint8_t th_flags, int32_t err, uint64_t cts,
+		uint32_t seq_out, uint16_t th_flags, int32_t err, uint64_t cts,
 		struct rack_sendmap *hintrsm, uint16_t add_flag, struct mbuf *s_mb, uint32_t s_moff, int hw_tls)
 {
 	struct tcp_rack *rack;
@@ -9648,7 +9648,7 @@ rack_log_ack(struct tcpcb *tp, struct tcpopt *to, struct tcphdr *th, int entered
 
 
 	INP_WLOCK_ASSERT(tp->t_inpcb);
-	if (th->th_flags & TH_RST) {
+	if (tcp_get_flags(th) & TH_RST) {
 		/* We don't log resets */
 		return;
 	}
@@ -10800,7 +10800,7 @@ rack_process_data(struct mbuf *m, struct tcphdr *th, struct socket *so,
 				if (tp->t_fbyte_out && tp->t_fbyte_in)
 					tp->t_flags2 |= TF2_FBYTES_COMPLETE;
 			}
-			thflags = th->th_flags & TH_FIN;
+			thflags = tcp_get_flags(th) & TH_FIN;
 			KMOD_TCPSTAT_ADD(tcps_rcvpack, nsegs);
 			KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
 			SOCKBUF_LOCK(&so->so_rcv);
@@ -13409,7 +13409,7 @@ rack_log_input_packet(struct tcpcb *tp, struct tcp_rack *rack, struct tcp_ackent
 		/* Now fill in the ports */
 		th->th_sport = tp->t_inpcb->inp_fport;
 		th->th_dport = tp->t_inpcb->inp_lport;
-		th->th_flags = ae->flags & 0xff;
+		tcp_set_flags(th, ae->flags);
 		/* Now do we have a timestamp option? */
 		if (ae->flags & HAS_TSTMP) {
 			u_char *cp;
@@ -14242,7 +14242,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	ms_cts =  tcp_tv_to_mssectick(tv);
 	nsegs = m->m_pkthdr.lro_nsegs;
 	counter_u64_add(rack_proc_non_comp_ack, 1);
-	thflags = th->th_flags;
+	thflags = tcp_get_flags(th);
 #ifdef TCP_ACCOUNTING
 	sched_pin();
 	if (thflags & TH_ACK)
@@ -14598,7 +14598,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	}
 	rack_clear_rate_sample(rack);
 	if ((rack->forced_ack) &&
-	    ((th->th_flags & TH_RST) == 0)) {
+	    ((tcp_get_flags(th) & TH_RST) == 0)) {
 		rack_handle_probe_response(rack, tiwin, us_cts);
 	}
 	/*
@@ -16006,7 +16006,7 @@ rack_fast_rsm_output(struct tcpcb *tp, struct tcp_rack *rack, struct rack_sendma
 	if ((rsm->r_flags & RACK_HAD_PUSH) &&
 	    (len == (rsm->r_end - rsm->r_start)))
 		flags |= TH_PUSH;
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	th->th_win = htons((u_short)(rack->r_ctl.fsb.recwin >> tp->rcv_scale));
 	if (th->th_win == 0) {
 		tp->t_sndzerowin++;
@@ -16483,7 +16483,7 @@ again:
 	sb_offset = tp->snd_max - tp->snd_una;
 	th->th_seq = htonl(tp->snd_max);
 	th->th_ack = htonl(tp->rcv_nxt);
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	th->th_win = htons((u_short)(rack->r_ctl.fsb.recwin >> tp->rcv_scale));
 	if (th->th_win == 0) {
 		tp->t_sndzerowin++;
@@ -16514,7 +16514,7 @@ again:
 	}
 	if (rack->r_ctl.fsb.rfo_apply_push &&
 	    (len == rack->r_ctl.fsb.left_to_send)) {
-		th->th_flags |= TH_PUSH;
+		tcp_set_flags(th, flags | TH_PUSH);
 		add_flag |= RACK_HAD_PUSH;
 	}
 	if ((m->m_next == NULL) || (len <= 0)){
@@ -18656,7 +18656,7 @@ send:
 		rack_seq = rsm->r_start;
 	}
 	th->th_ack = htonl(tp->rcv_nxt);
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	/*
 	 * Calculate receive window.  Don't shrink window, but avoid silly
 	 * window syndrome.
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 47b6ff173afe..1cd53db3bf99 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1686,9 +1686,8 @@ tcpip_fillheaders(struct inpcb *inp, uint16_t port, void *ip_ptr, void *tcp_ptr)
 	th->th_dport = inp->inp_fport;
 	th->th_seq = 0;
 	th->th_ack = 0;
-	th->th_x2 = 0;
 	th->th_off = 5;
-	th->th_flags = 0;
+	tcp_set_flags(th, 0);
 	th->th_win = 0;
 	th->th_urp = 0;
 	th->th_sum = 0;		/* in_pseudo() is called later for ipv4 */
@@ -1746,7 +1745,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
 	uint16_t port;
 	int output_ret;
 #ifdef INVARIANTS
-	int thflags = th->th_flags;
+	int thflags = tcp_get_flags(th);
 #endif
 
 	KASSERT(tp != NULL || m != NULL, ("tcp_respond: tp and m both NULL"));
@@ -2016,9 +2015,8 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
 #endif
 	nth->th_seq = htonl(seq);
 	nth->th_ack = htonl(ack);
-	nth->th_x2 = 0;
 	nth->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
-	nth->th_flags = flags;
+	tcp_set_flags(nth, flags);
 	if (tp != NULL)
 		nth->th_win = htons((u_short) (win >> tp->rcv_scale));
 	else
@@ -4061,7 +4059,7 @@ tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr,
 	}
 	sp = s + strlen(s);
 	if (th)
-		sprintf(sp, " tcpflags 0x%b", th->th_flags, PRINT_TH_FLAGS);
+		sprintf(sp, " tcpflags 0x%b", tcp_get_flags(th), PRINT_TH_FLAGS);
 	if (*(s + size - 1) != '\0')
 		panic("%s: string too long", __func__);
 	return (s);
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 32ca3bc2209b..5fcafa44cc97 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -627,7 +627,7 @@ syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th, struct mbuf *m,
 	 * Any RST to our SYN|ACK must not carry ACK, SYN or FIN flags.
 	 * See RFC 793 page 65, section SEGMENT ARRIVES.
 	 */
-	if (th->th_flags & (TH_ACK|TH_SYN|TH_FIN)) {
+	if (tcp_get_flags(th) & (TH_ACK|TH_SYN|TH_FIN)) {
 		if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
 			log(LOG_DEBUG, "%s; %s: Spurious RST with ACK, SYN or "
 			    "FIN flag set, segment ignored\n", s, __func__);
@@ -1097,7 +1097,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 	bool locked;
 
 	NET_EPOCH_ASSERT();
-	KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK,
+	KASSERT((tcp_get_flags(th) & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK,
 	    ("%s: can handle only ACK", __func__));
 
 	if (syncache_cookiesonly()) {
@@ -1426,7 +1426,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 	bool locked;
 
 	INP_RLOCK_ASSERT(inp);			/* listen socket */
-	KASSERT((th->th_flags & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN,
+	KASSERT((tcp_get_flags(th) & (TH_RST|TH_ACK|TH_SYN)) == TH_SYN,
 	    ("%s: unexpected tcp flags", __func__));
 
 	/*
@@ -1579,7 +1579,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
 		 * Disable ECN if needed.
 		 */
 		if ((sc->sc_flags & SCF_ECN) &&
-		    ((th->th_flags & (TH_ECE|TH_CWR)) != (TH_ECE|TH_CWR))) {
+		    ((tcp_get_flags(th) & (TH_ECE|TH_CWR)) != (TH_ECE|TH_CWR))) {
 			sc->sc_flags &= ~SCF_ECN;
 		}
 #ifdef MAC
@@ -1743,7 +1743,7 @@ skip_alloc:
 		sc->sc_peer_mss = to->to_mss;	/* peer mss may be zero */
 	if (ltflags & TF_NOOPT)
 		sc->sc_flags |= SCF_NOOPT;
-	if (((th->th_flags & (TH_ECE|TH_CWR)) == (TH_ECE|TH_CWR)) &&
+	if (((tcp_get_flags(th) & (TH_ECE|TH_CWR)) == (TH_ECE|TH_CWR)) &&
 	    V_tcp_do_ecn)
 		sc->sc_flags |= SCF_ECN;
 
@@ -1935,15 +1935,14 @@ syncache_respond(struct syncache *sc, const struct mbuf *m0, int flags)
 		th->th_seq = htonl(sc->sc_iss + 1);
 	th->th_ack = htonl(sc->sc_irs + 1);
 	th->th_off = sizeof(struct tcphdr) >> 2;
-	th->th_x2 = 0;
-	th->th_flags = flags;
 	th->th_win = htons(sc->sc_wnd);
 	th->th_urp = 0;
 
 	if ((flags & TH_SYN) && (sc->sc_flags & SCF_ECN)) {
-		th->th_flags |= TH_ECE;
+		flags |= TH_ECE;
 		TCPSTAT_INC(tcps_ecn_shs);
 	}
+	tcp_set_flags(th, flags);
 
 	/* Tack on the TCP options. */
 	if ((sc->sc_flags & SCF_NOOPT) == 0) {
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 1efc93aef1f9..3a87821108c4 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -409,7 +409,7 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
 	if (tw == NULL)
 		goto drop;
 
-	thflags = th->th_flags;
+	thflags = tcp_get_flags(th);
 #ifdef INVARIANTS
 	if ((thflags & (TH_SYN | TH_ACK)) == TH_SYN)
 		INP_RLOCK_ASSERT(inp);
@@ -475,13 +475,13 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
 	 * Send RST if UDP port numbers don't match
 	 */
 	if (tw->t_port != m->m_pkthdr.tcp_tun_port) {
-		if (th->th_flags & TH_ACK) {
+		if (tcp_get_flags(th) & TH_ACK) {
 			tcp_respond(NULL, mtod(m, void *), th, m,
 			    (tcp_seq)0, th->th_ack, TH_RST);
 		} else {
-			if (th->th_flags & TH_SYN)
+			if (tcp_get_flags(th) & TH_SYN)
 				tlen++;
-			if (th->th_flags & TH_FIN)
+			if (tcp_get_flags(th) & TH_FIN)
 				tlen++;
 			tcp_respond(NULL, mtod(m, void *), th, m,
 			    th->th_seq+tlen, (tcp_seq)0, TH_RST|TH_ACK);
@@ -692,7 +692,7 @@ tcp_twrespond(struct tcptw *tw, int flags)
 	th->th_seq = htonl(tw->snd_nxt);
 	th->th_ack = htonl(tw->rcv_nxt);
 	th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;
-	th->th_flags = flags;
+	tcp_set_flags(th, flags);
 	th->th_win = htons(tw->last_win);
 
 #if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index ccfd9a8f11e2..4f2db050799e 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -88,7 +88,7 @@ struct tseg_qent {
 	struct  mbuf   *tqe_last;	/* last mbuf in chain */
 	tcp_seq tqe_start;		/* TCP Sequence number start */
 	int	tqe_len;		/* TCP segment data length */
-	uint32_t tqe_flags;		/* The flags from the th->th_flags */
+	uint32_t tqe_flags;		/* The flags from tcp_get_flags() */
 	uint32_t tqe_mbuf_cnt;		/* Count of mbuf overhead */
 };
 TAILQ_HEAD(tsegqe_head, tseg_qent);
@@ -1257,6 +1257,19 @@ tcp_fields_to_net(struct tcphdr *th)
 	th->th_urp = htons(th->th_urp);
 }
 
+static inline uint16_t
+tcp_get_flags(const struct tcphdr *th)
+{
+        return (((uint16_t)th->th_x2 << 8) | th->th_flags);
+}
+
+static inline void
+tcp_set_flags(struct tcphdr *th, uint16_t flags)
+{
+        th->th_x2    = (flags >> 8) & 0x0f;
+        th->th_flags = flags & 0xff;
+}
+
 static inline void
 tcp_account_for_send(struct tcpcb *tp, uint32_t len, uint8_t is_rxt,
     uint8_t is_tlp, int hw_tls)