xref: /freebsd/sys/dev/cxgbe/crypto/t7_kern_tls.c (revision 4f272a5ef3d8073940e7719401d1e8de2de6100a)
1*4f272a5eSJohn Baldwin /*-
2*4f272a5eSJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3*4f272a5eSJohn Baldwin  *
4*4f272a5eSJohn Baldwin  * Copyright (c) 2025 Chelsio Communications
5*4f272a5eSJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6*4f272a5eSJohn Baldwin  *
7*4f272a5eSJohn Baldwin  * Redistribution and use in source and binary forms, with or without
8*4f272a5eSJohn Baldwin  * modification, are permitted provided that the following conditions
9*4f272a5eSJohn Baldwin  * are met:
10*4f272a5eSJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
11*4f272a5eSJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
12*4f272a5eSJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
13*4f272a5eSJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
14*4f272a5eSJohn Baldwin  *    documentation and/or other materials provided with the distribution.
15*4f272a5eSJohn Baldwin  *
16*4f272a5eSJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*4f272a5eSJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4f272a5eSJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4f272a5eSJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*4f272a5eSJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*4f272a5eSJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*4f272a5eSJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*4f272a5eSJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*4f272a5eSJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*4f272a5eSJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*4f272a5eSJohn Baldwin  * SUCH DAMAGE.
27*4f272a5eSJohn Baldwin  */
28*4f272a5eSJohn Baldwin 
29*4f272a5eSJohn Baldwin #include "opt_inet.h"
30*4f272a5eSJohn Baldwin #include "opt_inet6.h"
31*4f272a5eSJohn Baldwin #include "opt_kern_tls.h"
32*4f272a5eSJohn Baldwin 
33*4f272a5eSJohn Baldwin #include <sys/cdefs.h>
34*4f272a5eSJohn Baldwin __FBSDID("$FreeBSD$");
35*4f272a5eSJohn Baldwin 
36*4f272a5eSJohn Baldwin #include <sys/param.h>
37*4f272a5eSJohn Baldwin #include <sys/ktr.h>
38*4f272a5eSJohn Baldwin #include <sys/ktls.h>
39*4f272a5eSJohn Baldwin #include <sys/sglist.h>
40*4f272a5eSJohn Baldwin #include <sys/socket.h>
41*4f272a5eSJohn Baldwin #include <sys/socketvar.h>
42*4f272a5eSJohn Baldwin #include <sys/sockbuf.h>
43*4f272a5eSJohn Baldwin #include <netinet/in.h>
44*4f272a5eSJohn Baldwin #include <netinet/in_pcb.h>
45*4f272a5eSJohn Baldwin #include <netinet/ip.h>
46*4f272a5eSJohn Baldwin #include <netinet/ip6.h>
47*4f272a5eSJohn Baldwin #include <netinet/tcp_var.h>
48*4f272a5eSJohn Baldwin #include <opencrypto/cryptodev.h>
49*4f272a5eSJohn Baldwin #include <opencrypto/xform.h>
50*4f272a5eSJohn Baldwin 
51*4f272a5eSJohn Baldwin #include "common/common.h"
52*4f272a5eSJohn Baldwin #include "common/t4_regs.h"
53*4f272a5eSJohn Baldwin #include "common/t4_regs_values.h"
54*4f272a5eSJohn Baldwin #include "common/t4_tcb.h"
55*4f272a5eSJohn Baldwin #include "t4_l2t.h"
56*4f272a5eSJohn Baldwin #include "t4_clip.h"
57*4f272a5eSJohn Baldwin #include "t4_mp_ring.h"
58*4f272a5eSJohn Baldwin #include "crypto/t4_crypto.h"
59*4f272a5eSJohn Baldwin 
60*4f272a5eSJohn Baldwin #if defined(INET) || defined(INET6)
61*4f272a5eSJohn Baldwin 
62*4f272a5eSJohn Baldwin #define TLS_HEADER_LENGTH		5
63*4f272a5eSJohn Baldwin 
64*4f272a5eSJohn Baldwin struct tls_scmd {
65*4f272a5eSJohn Baldwin 	__be32 seqno_numivs;
66*4f272a5eSJohn Baldwin 	__be32 ivgen_hdrlen;
67*4f272a5eSJohn Baldwin };
68*4f272a5eSJohn Baldwin 
69*4f272a5eSJohn Baldwin struct tlspcb {
70*4f272a5eSJohn Baldwin 	struct m_snd_tag com;
71*4f272a5eSJohn Baldwin 	struct vi_info *vi;	/* virtual interface */
72*4f272a5eSJohn Baldwin 	struct adapter *sc;
73*4f272a5eSJohn Baldwin 	struct sge_txq *txq;
74*4f272a5eSJohn Baldwin 
75*4f272a5eSJohn Baldwin 	int tx_key_addr;
76*4f272a5eSJohn Baldwin 	bool inline_key;
77*4f272a5eSJohn Baldwin 	unsigned char enc_mode;
78*4f272a5eSJohn Baldwin 
79*4f272a5eSJohn Baldwin 	struct tls_scmd scmd0;
80*4f272a5eSJohn Baldwin 	struct tls_scmd scmd0_short;
81*4f272a5eSJohn Baldwin 
82*4f272a5eSJohn Baldwin 	unsigned int tx_key_info_size;
83*4f272a5eSJohn Baldwin 
84*4f272a5eSJohn Baldwin 	uint16_t prev_mss;
85*4f272a5eSJohn Baldwin 
86*4f272a5eSJohn Baldwin 	/* Only used outside of setup and teardown when using inline keys. */
87*4f272a5eSJohn Baldwin 	struct tls_keyctx keyctx;
88*4f272a5eSJohn Baldwin };
89*4f272a5eSJohn Baldwin 
90*4f272a5eSJohn Baldwin static void t7_tls_tag_free(struct m_snd_tag *mst);
91*4f272a5eSJohn Baldwin static int ktls_setup_keys(struct tlspcb *tlsp,
92*4f272a5eSJohn Baldwin     const struct ktls_session *tls, struct sge_txq *txq);
93*4f272a5eSJohn Baldwin 
94*4f272a5eSJohn Baldwin static const struct if_snd_tag_sw t7_tls_tag_sw = {
95*4f272a5eSJohn Baldwin 	.snd_tag_free = t7_tls_tag_free,
96*4f272a5eSJohn Baldwin 	.type = IF_SND_TAG_TYPE_TLS
97*4f272a5eSJohn Baldwin };
98*4f272a5eSJohn Baldwin 
99*4f272a5eSJohn Baldwin static inline struct tlspcb *
100*4f272a5eSJohn Baldwin mst_to_tls(struct m_snd_tag *t)
101*4f272a5eSJohn Baldwin {
102*4f272a5eSJohn Baldwin 	return (__containerof(t, struct tlspcb, com));
103*4f272a5eSJohn Baldwin }
104*4f272a5eSJohn Baldwin 
105*4f272a5eSJohn Baldwin static struct tlspcb *
106*4f272a5eSJohn Baldwin alloc_tlspcb(struct ifnet *ifp, struct vi_info *vi, int flags)
107*4f272a5eSJohn Baldwin {
108*4f272a5eSJohn Baldwin 	struct port_info *pi = vi->pi;
109*4f272a5eSJohn Baldwin 	struct adapter *sc = pi->adapter;
110*4f272a5eSJohn Baldwin 	struct tlspcb *tlsp;
111*4f272a5eSJohn Baldwin 
112*4f272a5eSJohn Baldwin 	tlsp = malloc(sizeof(*tlsp), M_CXGBE, M_ZERO | flags);
113*4f272a5eSJohn Baldwin 	if (tlsp == NULL)
114*4f272a5eSJohn Baldwin 		return (NULL);
115*4f272a5eSJohn Baldwin 
116*4f272a5eSJohn Baldwin 	m_snd_tag_init(&tlsp->com, ifp, &t7_tls_tag_sw);
117*4f272a5eSJohn Baldwin 	tlsp->vi = vi;
118*4f272a5eSJohn Baldwin 	tlsp->sc = sc;
119*4f272a5eSJohn Baldwin 	tlsp->tx_key_addr = -1;
120*4f272a5eSJohn Baldwin 
121*4f272a5eSJohn Baldwin 	return (tlsp);
122*4f272a5eSJohn Baldwin }
123*4f272a5eSJohn Baldwin 
124*4f272a5eSJohn Baldwin int
125*4f272a5eSJohn Baldwin t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
126*4f272a5eSJohn Baldwin     struct m_snd_tag **pt)
127*4f272a5eSJohn Baldwin {
128*4f272a5eSJohn Baldwin 	const struct ktls_session *tls;
129*4f272a5eSJohn Baldwin 	struct tlspcb *tlsp;
130*4f272a5eSJohn Baldwin 	struct adapter *sc;
131*4f272a5eSJohn Baldwin 	struct vi_info *vi;
132*4f272a5eSJohn Baldwin 	struct inpcb *inp;
133*4f272a5eSJohn Baldwin 	struct sge_txq *txq;
134*4f272a5eSJohn Baldwin 	int error, explicit_iv_size, keyid, mac_first;
135*4f272a5eSJohn Baldwin 
136*4f272a5eSJohn Baldwin 	tls = params->tls.tls;
137*4f272a5eSJohn Baldwin 
138*4f272a5eSJohn Baldwin 	/* Only TLS 1.1 and TLS 1.2 are currently supported. */
139*4f272a5eSJohn Baldwin 	if (tls->params.tls_vmajor != TLS_MAJOR_VER_ONE ||
140*4f272a5eSJohn Baldwin 	    tls->params.tls_vminor < TLS_MINOR_VER_ONE ||
141*4f272a5eSJohn Baldwin 	    tls->params.tls_vminor > TLS_MINOR_VER_TWO)
142*4f272a5eSJohn Baldwin 		return (EPROTONOSUPPORT);
143*4f272a5eSJohn Baldwin 
144*4f272a5eSJohn Baldwin 	/* Sanity check values in *tls. */
145*4f272a5eSJohn Baldwin 	switch (tls->params.cipher_algorithm) {
146*4f272a5eSJohn Baldwin 	case CRYPTO_AES_CBC:
147*4f272a5eSJohn Baldwin 		/* XXX: Explicitly ignore any provided IV. */
148*4f272a5eSJohn Baldwin 		switch (tls->params.cipher_key_len) {
149*4f272a5eSJohn Baldwin 		case 128 / 8:
150*4f272a5eSJohn Baldwin 		case 192 / 8:
151*4f272a5eSJohn Baldwin 		case 256 / 8:
152*4f272a5eSJohn Baldwin 			break;
153*4f272a5eSJohn Baldwin 		default:
154*4f272a5eSJohn Baldwin 			return (EINVAL);
155*4f272a5eSJohn Baldwin 		}
156*4f272a5eSJohn Baldwin 		switch (tls->params.auth_algorithm) {
157*4f272a5eSJohn Baldwin 		case CRYPTO_SHA1_HMAC:
158*4f272a5eSJohn Baldwin 		case CRYPTO_SHA2_256_HMAC:
159*4f272a5eSJohn Baldwin 		case CRYPTO_SHA2_384_HMAC:
160*4f272a5eSJohn Baldwin 			break;
161*4f272a5eSJohn Baldwin 		default:
162*4f272a5eSJohn Baldwin 			return (EPROTONOSUPPORT);
163*4f272a5eSJohn Baldwin 		}
164*4f272a5eSJohn Baldwin 		explicit_iv_size = AES_BLOCK_LEN;
165*4f272a5eSJohn Baldwin 		mac_first = 1;
166*4f272a5eSJohn Baldwin 		break;
167*4f272a5eSJohn Baldwin 	case CRYPTO_AES_NIST_GCM_16:
168*4f272a5eSJohn Baldwin 		if (tls->params.iv_len != SALT_SIZE)
169*4f272a5eSJohn Baldwin 			return (EINVAL);
170*4f272a5eSJohn Baldwin 		switch (tls->params.cipher_key_len) {
171*4f272a5eSJohn Baldwin 		case 128 / 8:
172*4f272a5eSJohn Baldwin 		case 192 / 8:
173*4f272a5eSJohn Baldwin 		case 256 / 8:
174*4f272a5eSJohn Baldwin 			break;
175*4f272a5eSJohn Baldwin 		default:
176*4f272a5eSJohn Baldwin 			return (EINVAL);
177*4f272a5eSJohn Baldwin 		}
178*4f272a5eSJohn Baldwin 		explicit_iv_size = 8;
179*4f272a5eSJohn Baldwin 		mac_first = 0;
180*4f272a5eSJohn Baldwin 		break;
181*4f272a5eSJohn Baldwin 	default:
182*4f272a5eSJohn Baldwin 		return (EPROTONOSUPPORT);
183*4f272a5eSJohn Baldwin 	}
184*4f272a5eSJohn Baldwin 
185*4f272a5eSJohn Baldwin 	vi = if_getsoftc(ifp);
186*4f272a5eSJohn Baldwin 	sc = vi->adapter;
187*4f272a5eSJohn Baldwin 
188*4f272a5eSJohn Baldwin 	tlsp = alloc_tlspcb(ifp, vi, M_WAITOK);
189*4f272a5eSJohn Baldwin 
190*4f272a5eSJohn Baldwin 	if (sc->tlst.inline_keys)
191*4f272a5eSJohn Baldwin 		keyid = -1;
192*4f272a5eSJohn Baldwin 	else
193*4f272a5eSJohn Baldwin 		keyid = t4_alloc_tls_keyid(sc);
194*4f272a5eSJohn Baldwin 	if (keyid < 0) {
195*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p using immediate key ctx", __func__,
196*4f272a5eSJohn Baldwin 		    tlsp);
197*4f272a5eSJohn Baldwin 		tlsp->inline_key = true;
198*4f272a5eSJohn Baldwin 	} else {
199*4f272a5eSJohn Baldwin 		tlsp->tx_key_addr = keyid;
200*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p allocated TX key addr %#x", __func__,
201*4f272a5eSJohn Baldwin 		    tlsp, tlsp->tx_key_addr);
202*4f272a5eSJohn Baldwin 	}
203*4f272a5eSJohn Baldwin 
204*4f272a5eSJohn Baldwin 	inp = params->tls.inp;
205*4f272a5eSJohn Baldwin 	INP_RLOCK(inp);
206*4f272a5eSJohn Baldwin 	if (inp->inp_flags & INP_DROPPED) {
207*4f272a5eSJohn Baldwin 		INP_RUNLOCK(inp);
208*4f272a5eSJohn Baldwin 		error = ECONNRESET;
209*4f272a5eSJohn Baldwin 		goto failed;
210*4f272a5eSJohn Baldwin 	}
211*4f272a5eSJohn Baldwin 
212*4f272a5eSJohn Baldwin 	txq = &sc->sge.txq[vi->first_txq];
213*4f272a5eSJohn Baldwin 	if (inp->inp_flowtype != M_HASHTYPE_NONE)
214*4f272a5eSJohn Baldwin 		txq += ((inp->inp_flowid % (vi->ntxq - vi->rsrv_noflowq)) +
215*4f272a5eSJohn Baldwin 		    vi->rsrv_noflowq);
216*4f272a5eSJohn Baldwin 	tlsp->txq = txq;
217*4f272a5eSJohn Baldwin 	INP_RUNLOCK(inp);
218*4f272a5eSJohn Baldwin 
219*4f272a5eSJohn Baldwin 	error = ktls_setup_keys(tlsp, tls, txq);
220*4f272a5eSJohn Baldwin 	if (error)
221*4f272a5eSJohn Baldwin 		goto failed;
222*4f272a5eSJohn Baldwin 
223*4f272a5eSJohn Baldwin 	tlsp->enc_mode = t4_tls_cipher_mode(tls);
224*4f272a5eSJohn Baldwin 	tlsp->tx_key_info_size = t4_tls_key_info_size(tls);
225*4f272a5eSJohn Baldwin 
226*4f272a5eSJohn Baldwin 	/* The SCMD fields used when encrypting a full TLS record. */
227*4f272a5eSJohn Baldwin 	tlsp->scmd0.seqno_numivs = htobe32(V_SCMD_SEQ_NO_CTRL(3) |
228*4f272a5eSJohn Baldwin 	    V_SCMD_PROTO_VERSION(t4_tls_proto_ver(tls)) |
229*4f272a5eSJohn Baldwin 	    V_SCMD_ENC_DEC_CTRL(SCMD_ENCDECCTRL_ENCRYPT) |
230*4f272a5eSJohn Baldwin 	    V_SCMD_CIPH_AUTH_SEQ_CTRL((mac_first == 0)) |
231*4f272a5eSJohn Baldwin 	    V_SCMD_CIPH_MODE(tlsp->enc_mode) |
232*4f272a5eSJohn Baldwin 	    V_SCMD_AUTH_MODE(t4_tls_auth_mode(tls)) |
233*4f272a5eSJohn Baldwin 	    V_SCMD_HMAC_CTRL(t4_tls_hmac_ctrl(tls)) |
234*4f272a5eSJohn Baldwin 	    V_SCMD_IV_SIZE(explicit_iv_size / 2) | V_SCMD_NUM_IVS(1));
235*4f272a5eSJohn Baldwin 
236*4f272a5eSJohn Baldwin 	tlsp->scmd0.ivgen_hdrlen = V_SCMD_IV_GEN_CTRL(0) |
237*4f272a5eSJohn Baldwin 	    V_SCMD_TLS_FRAG_ENABLE(0);
238*4f272a5eSJohn Baldwin 	if (tlsp->inline_key)
239*4f272a5eSJohn Baldwin 		tlsp->scmd0.ivgen_hdrlen |= V_SCMD_KEY_CTX_INLINE(1);
240*4f272a5eSJohn Baldwin 
241*4f272a5eSJohn Baldwin 	/*
242*4f272a5eSJohn Baldwin 	 * The SCMD fields used when encrypting a partial TLS record
243*4f272a5eSJohn Baldwin 	 * (no trailer and possibly a truncated payload).
244*4f272a5eSJohn Baldwin 	 */
245*4f272a5eSJohn Baldwin 	tlsp->scmd0_short.seqno_numivs = V_SCMD_SEQ_NO_CTRL(0) |
246*4f272a5eSJohn Baldwin 	    V_SCMD_PROTO_VERSION(SCMD_PROTO_VERSION_GENERIC) |
247*4f272a5eSJohn Baldwin 	    V_SCMD_ENC_DEC_CTRL(SCMD_ENCDECCTRL_ENCRYPT) |
248*4f272a5eSJohn Baldwin 	    V_SCMD_CIPH_AUTH_SEQ_CTRL((mac_first == 0)) |
249*4f272a5eSJohn Baldwin 	    V_SCMD_AUTH_MODE(SCMD_AUTH_MODE_NOP) |
250*4f272a5eSJohn Baldwin 	    V_SCMD_HMAC_CTRL(SCMD_HMAC_CTRL_NOP) |
251*4f272a5eSJohn Baldwin 	    V_SCMD_IV_SIZE(AES_BLOCK_LEN / 2) | V_SCMD_NUM_IVS(0);
252*4f272a5eSJohn Baldwin 	if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM)
253*4f272a5eSJohn Baldwin 		tlsp->scmd0_short.seqno_numivs |=
254*4f272a5eSJohn Baldwin 		    V_SCMD_CIPH_MODE(SCMD_CIPH_MODE_AES_CTR);
255*4f272a5eSJohn Baldwin 	else
256*4f272a5eSJohn Baldwin 		tlsp->scmd0_short.seqno_numivs |=
257*4f272a5eSJohn Baldwin 		    V_SCMD_CIPH_MODE(tlsp->enc_mode);
258*4f272a5eSJohn Baldwin 	tlsp->scmd0_short.seqno_numivs =
259*4f272a5eSJohn Baldwin 	    htobe32(tlsp->scmd0_short.seqno_numivs);
260*4f272a5eSJohn Baldwin 
261*4f272a5eSJohn Baldwin 	tlsp->scmd0_short.ivgen_hdrlen = V_SCMD_IV_GEN_CTRL(0) |
262*4f272a5eSJohn Baldwin 	    V_SCMD_TLS_FRAG_ENABLE(0) | V_SCMD_AADIVDROP(1);
263*4f272a5eSJohn Baldwin 	if (tlsp->inline_key)
264*4f272a5eSJohn Baldwin 		tlsp->scmd0_short.ivgen_hdrlen |= V_SCMD_KEY_CTX_INLINE(1);
265*4f272a5eSJohn Baldwin 
266*4f272a5eSJohn Baldwin 	TXQ_LOCK(txq);
267*4f272a5eSJohn Baldwin 	if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM)
268*4f272a5eSJohn Baldwin 		txq->kern_tls_gcm++;
269*4f272a5eSJohn Baldwin 	else
270*4f272a5eSJohn Baldwin 		txq->kern_tls_cbc++;
271*4f272a5eSJohn Baldwin 	TXQ_UNLOCK(txq);
272*4f272a5eSJohn Baldwin 	*pt = &tlsp->com;
273*4f272a5eSJohn Baldwin 	return (0);
274*4f272a5eSJohn Baldwin 
275*4f272a5eSJohn Baldwin failed:
276*4f272a5eSJohn Baldwin 	m_snd_tag_rele(&tlsp->com);
277*4f272a5eSJohn Baldwin 	return (error);
278*4f272a5eSJohn Baldwin }
279*4f272a5eSJohn Baldwin 
280*4f272a5eSJohn Baldwin static int
281*4f272a5eSJohn Baldwin ktls_setup_keys(struct tlspcb *tlsp, const struct ktls_session *tls,
282*4f272a5eSJohn Baldwin     struct sge_txq *txq)
283*4f272a5eSJohn Baldwin {
284*4f272a5eSJohn Baldwin 	struct tls_key_req *kwr;
285*4f272a5eSJohn Baldwin 	struct tls_keyctx *kctx;
286*4f272a5eSJohn Baldwin 	void *items[1];
287*4f272a5eSJohn Baldwin 	struct mbuf *m;
288*4f272a5eSJohn Baldwin 	int error;
289*4f272a5eSJohn Baldwin 
290*4f272a5eSJohn Baldwin 	/*
291*4f272a5eSJohn Baldwin 	 * Store the salt and keys in the key context.  For
292*4f272a5eSJohn Baldwin 	 * connections with an inline key, this key context is passed
293*4f272a5eSJohn Baldwin 	 * as immediate data in each work request.  For connections
294*4f272a5eSJohn Baldwin 	 * storing the key in DDR, a work request is used to store a
295*4f272a5eSJohn Baldwin 	 * copy of the key context in DDR.
296*4f272a5eSJohn Baldwin 	 */
297*4f272a5eSJohn Baldwin 	t4_tls_key_ctx(tls, KTLS_TX, &tlsp->keyctx);
298*4f272a5eSJohn Baldwin 	if (tlsp->inline_key)
299*4f272a5eSJohn Baldwin 		return (0);
300*4f272a5eSJohn Baldwin 
301*4f272a5eSJohn Baldwin 	/* Populate key work request. */
302*4f272a5eSJohn Baldwin         m = alloc_wr_mbuf(TLS_KEY_WR_SZ, M_NOWAIT);
303*4f272a5eSJohn Baldwin 	if (m == NULL) {
304*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p failed to alloc WR mbuf", __func__,
305*4f272a5eSJohn Baldwin 		    tlsp);
306*4f272a5eSJohn Baldwin 		return (ENOMEM);
307*4f272a5eSJohn Baldwin 	}
308*4f272a5eSJohn Baldwin 	m->m_pkthdr.snd_tag = m_snd_tag_ref(&tlsp->com);
309*4f272a5eSJohn Baldwin 	m->m_pkthdr.csum_flags |= CSUM_SND_TAG;
310*4f272a5eSJohn Baldwin 	kwr = mtod(m, void *);
311*4f272a5eSJohn Baldwin 	memset(kwr, 0, TLS_KEY_WR_SZ);
312*4f272a5eSJohn Baldwin 
313*4f272a5eSJohn Baldwin 	t4_write_tlskey_wr(tls, KTLS_TX, 0, 0, tlsp->tx_key_addr, kwr);
314*4f272a5eSJohn Baldwin 	kctx = (struct tls_keyctx *)(kwr + 1);
315*4f272a5eSJohn Baldwin 	memcpy(kctx, &tlsp->keyctx, sizeof(*kctx));
316*4f272a5eSJohn Baldwin 
317*4f272a5eSJohn Baldwin 	/*
318*4f272a5eSJohn Baldwin 	 * Place the key work request in the transmit queue.  It
319*4f272a5eSJohn Baldwin 	 * should be sent to the NIC before any TLS packets using this
320*4f272a5eSJohn Baldwin 	 * session.
321*4f272a5eSJohn Baldwin 	 */
322*4f272a5eSJohn Baldwin 	items[0] = m;
323*4f272a5eSJohn Baldwin 	error = mp_ring_enqueue(txq->r, items, 1, 1);
324*4f272a5eSJohn Baldwin 	if (error)
325*4f272a5eSJohn Baldwin 		m_free(m);
326*4f272a5eSJohn Baldwin 	else
327*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p sent key WR", __func__, tlsp);
328*4f272a5eSJohn Baldwin 	return (error);
329*4f272a5eSJohn Baldwin }
330*4f272a5eSJohn Baldwin 
331*4f272a5eSJohn Baldwin static u_int
332*4f272a5eSJohn Baldwin ktls_base_wr_size(struct tlspcb *tlsp)
333*4f272a5eSJohn Baldwin {
334*4f272a5eSJohn Baldwin 	u_int wr_len;
335*4f272a5eSJohn Baldwin 
336*4f272a5eSJohn Baldwin 	wr_len = sizeof(struct fw_ulptx_wr);	// 16
337*4f272a5eSJohn Baldwin 	wr_len += sizeof(struct ulp_txpkt);	// 8
338*4f272a5eSJohn Baldwin 	wr_len += sizeof(struct ulptx_idata);	// 8
339*4f272a5eSJohn Baldwin 	wr_len += sizeof(struct cpl_tx_sec_pdu);// 32
340*4f272a5eSJohn Baldwin 	if (tlsp->inline_key)
341*4f272a5eSJohn Baldwin 		wr_len += tlsp->tx_key_info_size;
342*4f272a5eSJohn Baldwin 	else {
343*4f272a5eSJohn Baldwin 		wr_len += sizeof(struct ulptx_sc_memrd);// 8
344*4f272a5eSJohn Baldwin 		wr_len += sizeof(struct ulptx_idata);	// 8
345*4f272a5eSJohn Baldwin 	}
346*4f272a5eSJohn Baldwin 	/* SplitMode CPL_RX_PHYS_DSGL here if needed. */
347*4f272a5eSJohn Baldwin 	/* CPL_TX_*_LSO here if needed. */
348*4f272a5eSJohn Baldwin 	wr_len += sizeof(struct cpl_tx_pkt_core);// 16
349*4f272a5eSJohn Baldwin 	return (wr_len);
350*4f272a5eSJohn Baldwin }
351*4f272a5eSJohn Baldwin 
352*4f272a5eSJohn Baldwin static u_int
353*4f272a5eSJohn Baldwin ktls_sgl_size(u_int nsegs)
354*4f272a5eSJohn Baldwin {
355*4f272a5eSJohn Baldwin 	u_int wr_len;
356*4f272a5eSJohn Baldwin 
357*4f272a5eSJohn Baldwin 	/* First segment is part of ulptx_sgl. */
358*4f272a5eSJohn Baldwin 	nsegs--;
359*4f272a5eSJohn Baldwin 
360*4f272a5eSJohn Baldwin 	wr_len = sizeof(struct ulptx_sgl);
361*4f272a5eSJohn Baldwin 	wr_len += 8 * ((3 * nsegs) / 2 + (nsegs & 1));
362*4f272a5eSJohn Baldwin 	return (wr_len);
363*4f272a5eSJohn Baldwin }
364*4f272a5eSJohn Baldwin 
365*4f272a5eSJohn Baldwin /*
366*4f272a5eSJohn Baldwin  * A request that doesn't need to generate the TLS trailer is a short
367*4f272a5eSJohn Baldwin  * record.  For these requests, part of the TLS record payload is
368*4f272a5eSJohn Baldwin  * encrypted without invoking the MAC.
369*4f272a5eSJohn Baldwin  *
370*4f272a5eSJohn Baldwin  * Returns true if this record should be sent as a short record.  In
371*4f272a5eSJohn Baldwin  * either case, the remaining outputs describe the how much of the
372*4f272a5eSJohn Baldwin  * TLS record to send as input to the crypto block and the amount of
373*4f272a5eSJohn Baldwin  * crypto output to trim via SplitMode:
374*4f272a5eSJohn Baldwin  *
375*4f272a5eSJohn Baldwin  * *header_len - Number of bytes of TLS header to pass as immediate
376*4f272a5eSJohn Baldwin  *               data
377*4f272a5eSJohn Baldwin  *
378*4f272a5eSJohn Baldwin  * *offset - Start offset of TLS record payload to pass as DSGL data
379*4f272a5eSJohn Baldwin  *
380*4f272a5eSJohn Baldwin  * *plen - Length of TLS record payload to pass as DSGL data
381*4f272a5eSJohn Baldwin  *
382*4f272a5eSJohn Baldwin  * *leading_waste - amount of non-packet-header bytes to drop at the
383*4f272a5eSJohn Baldwin  *                  start of the crypto output
384*4f272a5eSJohn Baldwin  *
385*4f272a5eSJohn Baldwin  * *trailing_waste - amount of crypto output to drop from the end
386*4f272a5eSJohn Baldwin  */
387*4f272a5eSJohn Baldwin static bool
388*4f272a5eSJohn Baldwin ktls_is_short_record(struct tlspcb *tlsp, struct mbuf *m_tls,
389*4f272a5eSJohn Baldwin     u_int tlen, u_int *header_len, u_int *offset, u_int *plen,
390*4f272a5eSJohn Baldwin     u_int *leading_waste, u_int *trailing_waste)
391*4f272a5eSJohn Baldwin {
392*4f272a5eSJohn Baldwin 	const struct tls_record_layer *hdr;
393*4f272a5eSJohn Baldwin 	u_int new_tlen, rlen;
394*4f272a5eSJohn Baldwin 
395*4f272a5eSJohn Baldwin 	MPASS(tlen > m_tls->m_epg_hdrlen);
396*4f272a5eSJohn Baldwin 
397*4f272a5eSJohn Baldwin 	hdr = (void *)m_tls->m_epg_hdr;
398*4f272a5eSJohn Baldwin 	rlen = TLS_HEADER_LENGTH + ntohs(hdr->tls_length);
399*4f272a5eSJohn Baldwin 
400*4f272a5eSJohn Baldwin 	/*
401*4f272a5eSJohn Baldwin 	 * Default to sending the full record as input to the crypto
402*4f272a5eSJohn Baldwin 	 * engine and relying on SplitMode to drop any waste.
403*4f272a5eSJohn Baldwin 	 */
404*4f272a5eSJohn Baldwin 	*header_len = m_tls->m_epg_hdrlen;
405*4f272a5eSJohn Baldwin 	*offset = 0;
406*4f272a5eSJohn Baldwin 	*plen = rlen - (m_tls->m_epg_hdrlen + m_tls->m_epg_trllen);
407*4f272a5eSJohn Baldwin 	*leading_waste = mtod(m_tls, vm_offset_t);
408*4f272a5eSJohn Baldwin 	*trailing_waste = rlen - tlen;
409*4f272a5eSJohn Baldwin 	if (!tlsp->sc->tlst.short_records)
410*4f272a5eSJohn Baldwin 		return (false);
411*4f272a5eSJohn Baldwin 
412*4f272a5eSJohn Baldwin 	if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_CBC) {
413*4f272a5eSJohn Baldwin 		/*
414*4f272a5eSJohn Baldwin 		 * For AES-CBC we have to send input from the start of
415*4f272a5eSJohn Baldwin 		 * the TLS record payload that is a multiple of the
416*4f272a5eSJohn Baldwin 		 * block size.  new_tlen rounds up tlen to the end of
417*4f272a5eSJohn Baldwin 		 * the containing AES block.  If this last block
418*4f272a5eSJohn Baldwin 		 * overlaps with the trailer, send the full record to
419*4f272a5eSJohn Baldwin 		 * generate the MAC.
420*4f272a5eSJohn Baldwin 		 */
421*4f272a5eSJohn Baldwin 		new_tlen = TLS_HEADER_LENGTH +
422*4f272a5eSJohn Baldwin 		    roundup2(tlen - TLS_HEADER_LENGTH, AES_BLOCK_LEN);
423*4f272a5eSJohn Baldwin 		if (rlen - new_tlen < m_tls->m_epg_trllen)
424*4f272a5eSJohn Baldwin 			return (false);
425*4f272a5eSJohn Baldwin 
426*4f272a5eSJohn Baldwin 		*trailing_waste = new_tlen - tlen;
427*4f272a5eSJohn Baldwin 		*plen = new_tlen - m_tls->m_epg_hdrlen;
428*4f272a5eSJohn Baldwin 	} else {
429*4f272a5eSJohn Baldwin 		/*
430*4f272a5eSJohn Baldwin 		 * For AES-GCM we have to send the full record if
431*4f272a5eSJohn Baldwin 		 * the end overlaps with the trailer.  Otherwise, we
432*4f272a5eSJohn Baldwin 		 * can use AES-CTR to encrypt a partial PDU.
433*4f272a5eSJohn Baldwin 		 */
434*4f272a5eSJohn Baldwin 		if (rlen - tlen < m_tls->m_epg_trllen)
435*4f272a5eSJohn Baldwin 			return (false);
436*4f272a5eSJohn Baldwin 
437*4f272a5eSJohn Baldwin 		/*
438*4f272a5eSJohn Baldwin 		 * The last record can be partially encrypted via
439*4f272a5eSJohn Baldwin 		 * AES-CTR without any trailing waste.
440*4f272a5eSJohn Baldwin 		 */
441*4f272a5eSJohn Baldwin 		*trailing_waste = 0;
442*4f272a5eSJohn Baldwin 		*plen = tlen - m_tls->m_epg_hdrlen;
443*4f272a5eSJohn Baldwin 
444*4f272a5eSJohn Baldwin 		/*
445*4f272a5eSJohn Baldwin 		 * In addition, with AES-CTR, we can minimize leading
446*4f272a5eSJohn Baldwin 		 * waste by starting encryption at the start of the
447*4f272a5eSJohn Baldwin 		 * closest AES block.
448*4f272a5eSJohn Baldwin 		 */
449*4f272a5eSJohn Baldwin 		if (mtod(m_tls, vm_offset_t) >= m_tls->m_epg_hdrlen) {
450*4f272a5eSJohn Baldwin 			*header_len = 0;
451*4f272a5eSJohn Baldwin 			*offset = rounddown2(mtod(m_tls, vm_offset_t) -
452*4f272a5eSJohn Baldwin 			    m_tls->m_epg_hdrlen, AES_BLOCK_LEN);
453*4f272a5eSJohn Baldwin 			*plen -= *offset;
454*4f272a5eSJohn Baldwin 			*leading_waste -= (m_tls->m_epg_hdrlen + *offset);
455*4f272a5eSJohn Baldwin 		}
456*4f272a5eSJohn Baldwin 	}
457*4f272a5eSJohn Baldwin 	return (true);
458*4f272a5eSJohn Baldwin }
459*4f272a5eSJohn Baldwin 
460*4f272a5eSJohn Baldwin static int
461*4f272a5eSJohn Baldwin ktls_wr_len(struct tlspcb *tlsp, struct mbuf *m, struct mbuf *m_tls,
462*4f272a5eSJohn Baldwin     int *nsegsp)
463*4f272a5eSJohn Baldwin {
464*4f272a5eSJohn Baldwin 	u_int header_len, imm_len, offset, plen, tlen, wr_len;
465*4f272a5eSJohn Baldwin 	u_int leading_waste, trailing_waste;
466*4f272a5eSJohn Baldwin 	bool short_record;
467*4f272a5eSJohn Baldwin 
468*4f272a5eSJohn Baldwin 	M_ASSERTEXTPG(m_tls);
469*4f272a5eSJohn Baldwin 
470*4f272a5eSJohn Baldwin 	/*
471*4f272a5eSJohn Baldwin 	 * The relative offset of the last byte to send from the TLS
472*4f272a5eSJohn Baldwin 	 * record.
473*4f272a5eSJohn Baldwin 	 */
474*4f272a5eSJohn Baldwin 	tlen = mtod(m_tls, vm_offset_t) + m_tls->m_len;
475*4f272a5eSJohn Baldwin 	if (tlen <= m_tls->m_epg_hdrlen) {
476*4f272a5eSJohn Baldwin 		/*
477*4f272a5eSJohn Baldwin 		 * For requests that only want to send the TLS header,
478*4f272a5eSJohn Baldwin 		 * send a tunnelled packet as immediate data.
479*4f272a5eSJohn Baldwin 		 */
480*4f272a5eSJohn Baldwin 		wr_len = sizeof(struct fw_eth_tx_pkt_wr) +
481*4f272a5eSJohn Baldwin 		    sizeof(struct cpl_tx_pkt_core) +
482*4f272a5eSJohn Baldwin 		    roundup2(m->m_len + m_tls->m_len, 16);
483*4f272a5eSJohn Baldwin 		if (wr_len > SGE_MAX_WR_LEN) {
484*4f272a5eSJohn Baldwin 			CTR(KTR_CXGBE,
485*4f272a5eSJohn Baldwin 		    "%s: %p TLS header-only packet too long (len %d)",
486*4f272a5eSJohn Baldwin 			    __func__, tlsp, m->m_len + m_tls->m_len);
487*4f272a5eSJohn Baldwin 		}
488*4f272a5eSJohn Baldwin 
489*4f272a5eSJohn Baldwin 		/* This should always be the last TLS record in a chain. */
490*4f272a5eSJohn Baldwin 		MPASS(m_tls->m_next == NULL);
491*4f272a5eSJohn Baldwin 		*nsegsp = 0;
492*4f272a5eSJohn Baldwin 		return (wr_len);
493*4f272a5eSJohn Baldwin 	}
494*4f272a5eSJohn Baldwin 
495*4f272a5eSJohn Baldwin 	short_record = ktls_is_short_record(tlsp, m_tls, tlen, &header_len,
496*4f272a5eSJohn Baldwin 	    &offset, &plen, &leading_waste, &trailing_waste);
497*4f272a5eSJohn Baldwin 
498*4f272a5eSJohn Baldwin 	/* Calculate the size of the work request. */
499*4f272a5eSJohn Baldwin 	wr_len = ktls_base_wr_size(tlsp);
500*4f272a5eSJohn Baldwin 
501*4f272a5eSJohn Baldwin 	if (leading_waste != 0 || trailing_waste != 0) {
502*4f272a5eSJohn Baldwin 		/*
503*4f272a5eSJohn Baldwin 		 * Partial records might require a SplitMode
504*4f272a5eSJohn Baldwin 		 * CPL_RX_PHYS_DSGL.
505*4f272a5eSJohn Baldwin 		 */
506*4f272a5eSJohn Baldwin 		wr_len += sizeof(struct cpl_t7_rx_phys_dsgl);
507*4f272a5eSJohn Baldwin 	}
508*4f272a5eSJohn Baldwin 
509*4f272a5eSJohn Baldwin 	/* Budget for an LSO header even if we don't use it. */
510*4f272a5eSJohn Baldwin 	wr_len += sizeof(struct cpl_tx_pkt_lso_core);
511*4f272a5eSJohn Baldwin 
512*4f272a5eSJohn Baldwin 	/*
513*4f272a5eSJohn Baldwin 	 * Headers (including the TLS header) are always sent as
514*4f272a5eSJohn Baldwin 	 * immediate data.  Short records include a raw AES IV as
515*4f272a5eSJohn Baldwin 	 * immediate data.
516*4f272a5eSJohn Baldwin 	 */
517*4f272a5eSJohn Baldwin 	imm_len = m->m_len + header_len;
518*4f272a5eSJohn Baldwin 	if (short_record)
519*4f272a5eSJohn Baldwin 		imm_len += AES_BLOCK_LEN;
520*4f272a5eSJohn Baldwin 	wr_len += roundup2(imm_len, 16);
521*4f272a5eSJohn Baldwin 
522*4f272a5eSJohn Baldwin 	/* TLS record payload via DSGL. */
523*4f272a5eSJohn Baldwin 	*nsegsp = sglist_count_mbuf_epg(m_tls, m_tls->m_epg_hdrlen + offset,
524*4f272a5eSJohn Baldwin 	    plen);
525*4f272a5eSJohn Baldwin 	wr_len += ktls_sgl_size(*nsegsp);
526*4f272a5eSJohn Baldwin 
527*4f272a5eSJohn Baldwin 	wr_len = roundup2(wr_len, 16);
528*4f272a5eSJohn Baldwin 	return (wr_len);
529*4f272a5eSJohn Baldwin }
530*4f272a5eSJohn Baldwin 
531*4f272a5eSJohn Baldwin int
532*4f272a5eSJohn Baldwin t7_ktls_parse_pkt(struct mbuf *m)
533*4f272a5eSJohn Baldwin {
534*4f272a5eSJohn Baldwin 	struct tlspcb *tlsp;
535*4f272a5eSJohn Baldwin 	struct ether_header *eh;
536*4f272a5eSJohn Baldwin 	struct ip *ip;
537*4f272a5eSJohn Baldwin 	struct ip6_hdr *ip6;
538*4f272a5eSJohn Baldwin 	struct tcphdr *tcp;
539*4f272a5eSJohn Baldwin 	struct mbuf *m_tls;
540*4f272a5eSJohn Baldwin 	void *items[1];
541*4f272a5eSJohn Baldwin 	int nsegs;
542*4f272a5eSJohn Baldwin 	u_int wr_len, tot_len;
543*4f272a5eSJohn Baldwin 	uint16_t eh_type;
544*4f272a5eSJohn Baldwin 
545*4f272a5eSJohn Baldwin 	/*
546*4f272a5eSJohn Baldwin 	 * Locate headers in initial mbuf.
547*4f272a5eSJohn Baldwin 	 *
548*4f272a5eSJohn Baldwin 	 * XXX: This assumes all of the headers are in the initial mbuf.
549*4f272a5eSJohn Baldwin 	 * Could perhaps use m_advance() like parse_pkt() if that turns
550*4f272a5eSJohn Baldwin 	 * out to not be true.
551*4f272a5eSJohn Baldwin 	 */
552*4f272a5eSJohn Baldwin 	M_ASSERTPKTHDR(m);
553*4f272a5eSJohn Baldwin 	MPASS(m->m_pkthdr.snd_tag != NULL);
554*4f272a5eSJohn Baldwin 	tlsp = mst_to_tls(m->m_pkthdr.snd_tag);
555*4f272a5eSJohn Baldwin 
556*4f272a5eSJohn Baldwin 	if (m->m_len <= sizeof(*eh) + sizeof(*ip)) {
557*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p header mbuf too short", __func__, tlsp);
558*4f272a5eSJohn Baldwin 		return (EINVAL);
559*4f272a5eSJohn Baldwin 	}
560*4f272a5eSJohn Baldwin 	eh = mtod(m, struct ether_header *);
561*4f272a5eSJohn Baldwin 	eh_type = ntohs(eh->ether_type);
562*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_VLAN) {
563*4f272a5eSJohn Baldwin 		struct ether_vlan_header *evh = (void *)eh;
564*4f272a5eSJohn Baldwin 
565*4f272a5eSJohn Baldwin 		eh_type = ntohs(evh->evl_proto);
566*4f272a5eSJohn Baldwin 		m->m_pkthdr.l2hlen = sizeof(*evh);
567*4f272a5eSJohn Baldwin 	} else
568*4f272a5eSJohn Baldwin 		m->m_pkthdr.l2hlen = sizeof(*eh);
569*4f272a5eSJohn Baldwin 
570*4f272a5eSJohn Baldwin 	switch (eh_type) {
571*4f272a5eSJohn Baldwin 	case ETHERTYPE_IP:
572*4f272a5eSJohn Baldwin 		ip = (struct ip *)(eh + 1);
573*4f272a5eSJohn Baldwin 		if (ip->ip_p != IPPROTO_TCP) {
574*4f272a5eSJohn Baldwin 			CTR(KTR_CXGBE, "%s: %p mbuf not IPPROTO_TCP", __func__,
575*4f272a5eSJohn Baldwin 			    tlsp);
576*4f272a5eSJohn Baldwin 			return (EINVAL);
577*4f272a5eSJohn Baldwin 		}
578*4f272a5eSJohn Baldwin 		m->m_pkthdr.l3hlen = ip->ip_hl * 4;
579*4f272a5eSJohn Baldwin 		break;
580*4f272a5eSJohn Baldwin 	case ETHERTYPE_IPV6:
581*4f272a5eSJohn Baldwin 		ip6 = (struct ip6_hdr *)(eh + 1);
582*4f272a5eSJohn Baldwin 		if (ip6->ip6_nxt != IPPROTO_TCP) {
583*4f272a5eSJohn Baldwin 			CTR(KTR_CXGBE, "%s: %p, mbuf not IPPROTO_TCP (%u)",
584*4f272a5eSJohn Baldwin 			    __func__, tlsp, ip6->ip6_nxt);
585*4f272a5eSJohn Baldwin 			return (EINVAL);
586*4f272a5eSJohn Baldwin 		}
587*4f272a5eSJohn Baldwin 		m->m_pkthdr.l3hlen = sizeof(struct ip6_hdr);
588*4f272a5eSJohn Baldwin 		break;
589*4f272a5eSJohn Baldwin 	default:
590*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p mbuf not ETHERTYPE_IP{,V6}", __func__,
591*4f272a5eSJohn Baldwin 		    tlsp);
592*4f272a5eSJohn Baldwin 		return (EINVAL);
593*4f272a5eSJohn Baldwin 	}
594*4f272a5eSJohn Baldwin 	if (m->m_len < m->m_pkthdr.l2hlen + m->m_pkthdr.l3hlen +
595*4f272a5eSJohn Baldwin 	    sizeof(*tcp)) {
596*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p header mbuf too short (2)", __func__,
597*4f272a5eSJohn Baldwin 		    tlsp);
598*4f272a5eSJohn Baldwin 		return (EINVAL);
599*4f272a5eSJohn Baldwin 	}
600*4f272a5eSJohn Baldwin 	tcp = (struct tcphdr *)((char *)(eh + 1) + m->m_pkthdr.l3hlen);
601*4f272a5eSJohn Baldwin 	m->m_pkthdr.l4hlen = tcp->th_off * 4;
602*4f272a5eSJohn Baldwin 
603*4f272a5eSJohn Baldwin 	/* Bail if there is TCP payload before the TLS record. */
604*4f272a5eSJohn Baldwin 	if (m->m_len != m->m_pkthdr.l2hlen + m->m_pkthdr.l3hlen +
605*4f272a5eSJohn Baldwin 	    m->m_pkthdr.l4hlen) {
606*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE,
607*4f272a5eSJohn Baldwin 		    "%s: %p header mbuf bad length (%d + %d + %d != %d)",
608*4f272a5eSJohn Baldwin 		    __func__, tlsp, m->m_pkthdr.l2hlen, m->m_pkthdr.l3hlen,
609*4f272a5eSJohn Baldwin 		    m->m_pkthdr.l4hlen, m->m_len);
610*4f272a5eSJohn Baldwin 		return (EINVAL);
611*4f272a5eSJohn Baldwin 	}
612*4f272a5eSJohn Baldwin 
613*4f272a5eSJohn Baldwin 	/* Assume all headers are in 'm' for now. */
614*4f272a5eSJohn Baldwin 	MPASS(m->m_next != NULL);
615*4f272a5eSJohn Baldwin 	MPASS(m->m_next->m_flags & M_EXTPG);
616*4f272a5eSJohn Baldwin 
617*4f272a5eSJohn Baldwin 	tot_len = 0;
618*4f272a5eSJohn Baldwin 
619*4f272a5eSJohn Baldwin 	/*
620*4f272a5eSJohn Baldwin 	 * Each of the remaining mbufs in the chain should reference a
621*4f272a5eSJohn Baldwin 	 * TLS record.
622*4f272a5eSJohn Baldwin 	 */
623*4f272a5eSJohn Baldwin 	for (m_tls = m->m_next; m_tls != NULL; m_tls = m_tls->m_next) {
624*4f272a5eSJohn Baldwin 		MPASS(m_tls->m_flags & M_EXTPG);
625*4f272a5eSJohn Baldwin 
626*4f272a5eSJohn Baldwin 		wr_len = ktls_wr_len(tlsp, m, m_tls, &nsegs);
627*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
628*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p wr_len %d nsegs %d", __func__, tlsp,
629*4f272a5eSJohn Baldwin 		    wr_len, nsegs);
630*4f272a5eSJohn Baldwin #endif
631*4f272a5eSJohn Baldwin 		if (wr_len > SGE_MAX_WR_LEN || nsegs > TX_SGL_SEGS)
632*4f272a5eSJohn Baldwin 			return (EFBIG);
633*4f272a5eSJohn Baldwin 		tot_len += roundup2(wr_len, EQ_ESIZE);
634*4f272a5eSJohn Baldwin 
635*4f272a5eSJohn Baldwin 		/*
636*4f272a5eSJohn Baldwin 		 * Store 'nsegs' for the first TLS record in the
637*4f272a5eSJohn Baldwin 		 * header mbuf's metadata.
638*4f272a5eSJohn Baldwin 		 */
639*4f272a5eSJohn Baldwin 		if (m_tls == m->m_next)
640*4f272a5eSJohn Baldwin 			set_mbuf_nsegs(m, nsegs);
641*4f272a5eSJohn Baldwin 	}
642*4f272a5eSJohn Baldwin 
643*4f272a5eSJohn Baldwin 	MPASS(tot_len != 0);
644*4f272a5eSJohn Baldwin 
645*4f272a5eSJohn Baldwin 	set_mbuf_len16(m, tot_len / 16);
646*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
647*4f272a5eSJohn Baldwin 	CTR(KTR_CXGBE, "%s: %p len16 %d nsegs %d", __func__, tlsp,
648*4f272a5eSJohn Baldwin 	    mbuf_len16(m), mbuf_nsegs(m));
649*4f272a5eSJohn Baldwin #endif
650*4f272a5eSJohn Baldwin 	items[0] = m;
651*4f272a5eSJohn Baldwin 	return (mp_ring_enqueue(tlsp->txq->r, items, 1, 256));
652*4f272a5eSJohn Baldwin }
653*4f272a5eSJohn Baldwin 
654*4f272a5eSJohn Baldwin static inline bool
655*4f272a5eSJohn Baldwin needs_vlan_insertion(struct mbuf *m)
656*4f272a5eSJohn Baldwin {
657*4f272a5eSJohn Baldwin 
658*4f272a5eSJohn Baldwin 	M_ASSERTPKTHDR(m);
659*4f272a5eSJohn Baldwin 
660*4f272a5eSJohn Baldwin 	return (m->m_flags & M_VLANTAG);
661*4f272a5eSJohn Baldwin }
662*4f272a5eSJohn Baldwin 
663*4f272a5eSJohn Baldwin static inline uint64_t
664*4f272a5eSJohn Baldwin pkt_ctrl1(struct sge_txq *txq, struct mbuf *m, uint16_t eh_type)
665*4f272a5eSJohn Baldwin {
666*4f272a5eSJohn Baldwin 	uint64_t ctrl1;
667*4f272a5eSJohn Baldwin 
668*4f272a5eSJohn Baldwin 	/* Checksums are always offloaded */
669*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_IP) {
670*4f272a5eSJohn Baldwin 		ctrl1 = V_TXPKT_CSUM_TYPE(TX_CSUM_TCPIP) |
671*4f272a5eSJohn Baldwin 		    V_T6_TXPKT_ETHHDR_LEN(m->m_pkthdr.l2hlen - ETHER_HDR_LEN) |
672*4f272a5eSJohn Baldwin 		    V_TXPKT_IPHDR_LEN(m->m_pkthdr.l3hlen);
673*4f272a5eSJohn Baldwin 	} else {
674*4f272a5eSJohn Baldwin 		MPASS(m->m_pkthdr.l3hlen == sizeof(struct ip6_hdr));
675*4f272a5eSJohn Baldwin 		ctrl1 = V_TXPKT_CSUM_TYPE(TX_CSUM_TCPIP6) |
676*4f272a5eSJohn Baldwin 		    V_T6_TXPKT_ETHHDR_LEN(m->m_pkthdr.l2hlen - ETHER_HDR_LEN) |
677*4f272a5eSJohn Baldwin 		    V_TXPKT_IPHDR_LEN(m->m_pkthdr.l3hlen);
678*4f272a5eSJohn Baldwin 	}
679*4f272a5eSJohn Baldwin 	txq->txcsum++;
680*4f272a5eSJohn Baldwin 
681*4f272a5eSJohn Baldwin 	/* VLAN tag insertion */
682*4f272a5eSJohn Baldwin 	if (needs_vlan_insertion(m)) {
683*4f272a5eSJohn Baldwin 		ctrl1 |= F_TXPKT_VLAN_VLD |
684*4f272a5eSJohn Baldwin 		    V_TXPKT_VLAN(m->m_pkthdr.ether_vtag);
685*4f272a5eSJohn Baldwin 		txq->vlan_insertion++;
686*4f272a5eSJohn Baldwin 	}
687*4f272a5eSJohn Baldwin 
688*4f272a5eSJohn Baldwin 	return (ctrl1);
689*4f272a5eSJohn Baldwin }
690*4f272a5eSJohn Baldwin 
691*4f272a5eSJohn Baldwin static inline void *
692*4f272a5eSJohn Baldwin write_lso_cpl(void *cpl, struct mbuf *m0, uint16_t mss, uint16_t eh_type,
693*4f272a5eSJohn Baldwin     int total_len)
694*4f272a5eSJohn Baldwin {
695*4f272a5eSJohn Baldwin 	struct cpl_tx_pkt_lso_core *lso;
696*4f272a5eSJohn Baldwin 	uint32_t ctrl;
697*4f272a5eSJohn Baldwin 
698*4f272a5eSJohn Baldwin 	KASSERT(m0->m_pkthdr.l2hlen > 0 && m0->m_pkthdr.l3hlen > 0 &&
699*4f272a5eSJohn Baldwin 	    m0->m_pkthdr.l4hlen > 0,
700*4f272a5eSJohn Baldwin 	    ("%s: mbuf %p needs TSO but missing header lengths",
701*4f272a5eSJohn Baldwin 		__func__, m0));
702*4f272a5eSJohn Baldwin 
703*4f272a5eSJohn Baldwin 	ctrl = V_LSO_OPCODE(CPL_TX_PKT_LSO) |
704*4f272a5eSJohn Baldwin 	    F_LSO_FIRST_SLICE | F_LSO_LAST_SLICE |
705*4f272a5eSJohn Baldwin 	    V_LSO_ETHHDR_LEN((m0->m_pkthdr.l2hlen - ETHER_HDR_LEN) >> 2) |
706*4f272a5eSJohn Baldwin 	    V_LSO_IPHDR_LEN(m0->m_pkthdr.l3hlen >> 2) |
707*4f272a5eSJohn Baldwin 	    V_LSO_TCPHDR_LEN(m0->m_pkthdr.l4hlen >> 2);
708*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_IPV6)
709*4f272a5eSJohn Baldwin 		ctrl |= F_LSO_IPV6;
710*4f272a5eSJohn Baldwin 
711*4f272a5eSJohn Baldwin 	lso = cpl;
712*4f272a5eSJohn Baldwin 	lso->lso_ctrl = htobe32(ctrl);
713*4f272a5eSJohn Baldwin 	lso->ipid_ofst = htobe16(0);
714*4f272a5eSJohn Baldwin 	lso->mss = htobe16(mss);
715*4f272a5eSJohn Baldwin 	lso->seqno_offset = htobe32(0);
716*4f272a5eSJohn Baldwin 	lso->len = htobe32(total_len);
717*4f272a5eSJohn Baldwin 
718*4f272a5eSJohn Baldwin 	return (lso + 1);
719*4f272a5eSJohn Baldwin }
720*4f272a5eSJohn Baldwin 
721*4f272a5eSJohn Baldwin static inline void *
722*4f272a5eSJohn Baldwin write_split_mode_rx_phys(void *dst, struct mbuf *m, struct mbuf *m_tls,
723*4f272a5eSJohn Baldwin     u_int crypto_hdr_len, u_int leading_waste, u_int trailing_waste)
724*4f272a5eSJohn Baldwin {
725*4f272a5eSJohn Baldwin 	struct cpl_t7_rx_phys_dsgl *cpl;
726*4f272a5eSJohn Baldwin 	uint16_t *len;
727*4f272a5eSJohn Baldwin 	uint8_t numsge;
728*4f272a5eSJohn Baldwin 
729*4f272a5eSJohn Baldwin 	/* Forward first (3) and third (1) segments. */
730*4f272a5eSJohn Baldwin 	numsge = 0xa;
731*4f272a5eSJohn Baldwin 
732*4f272a5eSJohn Baldwin 	cpl = dst;
733*4f272a5eSJohn Baldwin 	cpl->ot.opcode = CPL_RX_PHYS_DSGL;
734*4f272a5eSJohn Baldwin 	cpl->PhysAddrFields_lo_to_NumSGE =
735*4f272a5eSJohn Baldwin 	    htobe32(F_CPL_T7_RX_PHYS_DSGL_SPLITMODE |
736*4f272a5eSJohn Baldwin 	    V_CPL_T7_RX_PHYS_DSGL_NUMSGE(numsge));
737*4f272a5eSJohn Baldwin 
738*4f272a5eSJohn Baldwin 	len = (uint16_t *)(cpl->RSSCopy);
739*4f272a5eSJohn Baldwin 
740*4f272a5eSJohn Baldwin 	/*
741*4f272a5eSJohn Baldwin 	 * First segment always contains packet headers as well as
742*4f272a5eSJohn Baldwin 	 * transmit-related CPLs.
743*4f272a5eSJohn Baldwin 	 */
744*4f272a5eSJohn Baldwin 	len[0] = htobe16(crypto_hdr_len);
745*4f272a5eSJohn Baldwin 
746*4f272a5eSJohn Baldwin 	/*
747*4f272a5eSJohn Baldwin 	 * Second segment is "gap" of data to drop at the front of the
748*4f272a5eSJohn Baldwin 	 * TLS record.
749*4f272a5eSJohn Baldwin 	 */
750*4f272a5eSJohn Baldwin 	len[1] = htobe16(leading_waste);
751*4f272a5eSJohn Baldwin 
752*4f272a5eSJohn Baldwin 	/* Third segment is how much of the TLS record to send. */
753*4f272a5eSJohn Baldwin 	len[2] = htobe16(m_tls->m_len);
754*4f272a5eSJohn Baldwin 
755*4f272a5eSJohn Baldwin 	/* Fourth segment is how much data to drop at the end. */
756*4f272a5eSJohn Baldwin 	len[3] = htobe16(trailing_waste);
757*4f272a5eSJohn Baldwin 
758*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
759*4f272a5eSJohn Baldwin 	CTR(KTR_CXGBE, "%s: forward %u skip %u forward %u skip %u",
760*4f272a5eSJohn Baldwin 	    __func__, be16toh(len[0]), be16toh(len[1]), be16toh(len[2]),
761*4f272a5eSJohn Baldwin 	    be16toh(len[3]));
762*4f272a5eSJohn Baldwin #endif
763*4f272a5eSJohn Baldwin 	return (cpl + 1);
764*4f272a5eSJohn Baldwin }
765*4f272a5eSJohn Baldwin 
766*4f272a5eSJohn Baldwin /*
767*4f272a5eSJohn Baldwin  * If the SGL ends on an address that is not 16 byte aligned, this function will
768*4f272a5eSJohn Baldwin  * add a 0 filled flit at the end.
769*4f272a5eSJohn Baldwin  */
770*4f272a5eSJohn Baldwin static void
771*4f272a5eSJohn Baldwin write_gl_to_buf(struct sglist *gl, caddr_t to)
772*4f272a5eSJohn Baldwin {
773*4f272a5eSJohn Baldwin 	struct sglist_seg *seg;
774*4f272a5eSJohn Baldwin 	__be64 *flitp;
775*4f272a5eSJohn Baldwin 	struct ulptx_sgl *usgl;
776*4f272a5eSJohn Baldwin 	int i, nflits, nsegs;
777*4f272a5eSJohn Baldwin 
778*4f272a5eSJohn Baldwin 	KASSERT(((uintptr_t)to & 0xf) == 0,
779*4f272a5eSJohn Baldwin 	    ("%s: SGL must start at a 16 byte boundary: %p", __func__, to));
780*4f272a5eSJohn Baldwin 
781*4f272a5eSJohn Baldwin 	nsegs = gl->sg_nseg;
782*4f272a5eSJohn Baldwin 	MPASS(nsegs > 0);
783*4f272a5eSJohn Baldwin 
784*4f272a5eSJohn Baldwin 	nflits = (3 * (nsegs - 1)) / 2 + ((nsegs - 1) & 1) + 2;
785*4f272a5eSJohn Baldwin 	flitp = (__be64 *)to;
786*4f272a5eSJohn Baldwin 	seg = &gl->sg_segs[0];
787*4f272a5eSJohn Baldwin 	usgl = (void *)flitp;
788*4f272a5eSJohn Baldwin 
789*4f272a5eSJohn Baldwin 	usgl->cmd_nsge = htobe32(V_ULPTX_CMD(ULP_TX_SC_DSGL) |
790*4f272a5eSJohn Baldwin 	    V_ULPTX_NSGE(nsegs));
791*4f272a5eSJohn Baldwin 	usgl->len0 = htobe32(seg->ss_len);
792*4f272a5eSJohn Baldwin 	usgl->addr0 = htobe64(seg->ss_paddr);
793*4f272a5eSJohn Baldwin 	seg++;
794*4f272a5eSJohn Baldwin 
795*4f272a5eSJohn Baldwin 	for (i = 0; i < nsegs - 1; i++, seg++) {
796*4f272a5eSJohn Baldwin 		usgl->sge[i / 2].len[i & 1] = htobe32(seg->ss_len);
797*4f272a5eSJohn Baldwin 		usgl->sge[i / 2].addr[i & 1] = htobe64(seg->ss_paddr);
798*4f272a5eSJohn Baldwin 	}
799*4f272a5eSJohn Baldwin 	if (i & 1)
800*4f272a5eSJohn Baldwin 		usgl->sge[i / 2].len[1] = htobe32(0);
801*4f272a5eSJohn Baldwin 	flitp += nflits;
802*4f272a5eSJohn Baldwin 
803*4f272a5eSJohn Baldwin 	if (nflits & 1) {
804*4f272a5eSJohn Baldwin 		MPASS(((uintptr_t)flitp) & 0xf);
805*4f272a5eSJohn Baldwin 		*flitp++ = 0;
806*4f272a5eSJohn Baldwin 	}
807*4f272a5eSJohn Baldwin 
808*4f272a5eSJohn Baldwin 	MPASS((((uintptr_t)flitp) & 0xf) == 0);
809*4f272a5eSJohn Baldwin }
810*4f272a5eSJohn Baldwin 
811*4f272a5eSJohn Baldwin static inline void
812*4f272a5eSJohn Baldwin copy_to_txd(struct sge_eq *eq, caddr_t from, caddr_t *to, int len)
813*4f272a5eSJohn Baldwin {
814*4f272a5eSJohn Baldwin 
815*4f272a5eSJohn Baldwin 	MPASS((uintptr_t)(*to) >= (uintptr_t)&eq->desc[0]);
816*4f272a5eSJohn Baldwin 	MPASS((uintptr_t)(*to) < (uintptr_t)&eq->desc[eq->sidx]);
817*4f272a5eSJohn Baldwin 
818*4f272a5eSJohn Baldwin 	if (__predict_true((uintptr_t)(*to) + len <=
819*4f272a5eSJohn Baldwin 	    (uintptr_t)&eq->desc[eq->sidx])) {
820*4f272a5eSJohn Baldwin 		bcopy(from, *to, len);
821*4f272a5eSJohn Baldwin 		(*to) += len;
822*4f272a5eSJohn Baldwin 		if ((uintptr_t)(*to) == (uintptr_t)&eq->desc[eq->sidx])
823*4f272a5eSJohn Baldwin 			(*to) = (caddr_t)eq->desc;
824*4f272a5eSJohn Baldwin 	} else {
825*4f272a5eSJohn Baldwin 		int portion = (uintptr_t)&eq->desc[eq->sidx] - (uintptr_t)(*to);
826*4f272a5eSJohn Baldwin 
827*4f272a5eSJohn Baldwin 		bcopy(from, *to, portion);
828*4f272a5eSJohn Baldwin 		from += portion;
829*4f272a5eSJohn Baldwin 		portion = len - portion;	/* remaining */
830*4f272a5eSJohn Baldwin 		bcopy(from, (void *)eq->desc, portion);
831*4f272a5eSJohn Baldwin 		(*to) = (caddr_t)eq->desc + portion;
832*4f272a5eSJohn Baldwin 	}
833*4f272a5eSJohn Baldwin }
834*4f272a5eSJohn Baldwin 
835*4f272a5eSJohn Baldwin static int
836*4f272a5eSJohn Baldwin ktls_write_tunnel_packet(struct sge_txq *txq, void *dst, struct mbuf *m,
837*4f272a5eSJohn Baldwin     struct mbuf *m_tls, u_int available, tcp_seq tcp_seqno, u_int pidx,
838*4f272a5eSJohn Baldwin     uint16_t eh_type)
839*4f272a5eSJohn Baldwin {
840*4f272a5eSJohn Baldwin 	struct tx_sdesc *txsd;
841*4f272a5eSJohn Baldwin 	struct fw_eth_tx_pkt_wr *wr;
842*4f272a5eSJohn Baldwin 	struct cpl_tx_pkt_core *cpl;
843*4f272a5eSJohn Baldwin 	uint32_t ctrl;
844*4f272a5eSJohn Baldwin 	int len16, ndesc, pktlen;
845*4f272a5eSJohn Baldwin 	struct ether_header *eh;
846*4f272a5eSJohn Baldwin 	struct ip *ip, newip;
847*4f272a5eSJohn Baldwin 	struct ip6_hdr *ip6, newip6;
848*4f272a5eSJohn Baldwin 	struct tcphdr *tcp, newtcp;
849*4f272a5eSJohn Baldwin 	caddr_t out;
850*4f272a5eSJohn Baldwin 
851*4f272a5eSJohn Baldwin 	TXQ_LOCK_ASSERT_OWNED(txq);
852*4f272a5eSJohn Baldwin 	M_ASSERTPKTHDR(m);
853*4f272a5eSJohn Baldwin 
854*4f272a5eSJohn Baldwin 	/* Locate the template TLS header. */
855*4f272a5eSJohn Baldwin 	M_ASSERTEXTPG(m_tls);
856*4f272a5eSJohn Baldwin 
857*4f272a5eSJohn Baldwin 	/* This should always be the last TLS record in a chain. */
858*4f272a5eSJohn Baldwin 	MPASS(m_tls->m_next == NULL);
859*4f272a5eSJohn Baldwin 
860*4f272a5eSJohn Baldwin 	wr = dst;
861*4f272a5eSJohn Baldwin 	pktlen = m->m_len + m_tls->m_len;
862*4f272a5eSJohn Baldwin 	ctrl = sizeof(struct cpl_tx_pkt_core) + pktlen;
863*4f272a5eSJohn Baldwin 	len16 = howmany(sizeof(struct fw_eth_tx_pkt_wr) + ctrl, 16);
864*4f272a5eSJohn Baldwin 	ndesc = tx_len16_to_desc(len16);
865*4f272a5eSJohn Baldwin 	MPASS(ndesc <= available);
866*4f272a5eSJohn Baldwin 
867*4f272a5eSJohn Baldwin 	/* Firmware work request header */
868*4f272a5eSJohn Baldwin 	/* TODO: Handle VF work request. */
869*4f272a5eSJohn Baldwin 	wr->op_immdlen = htobe32(V_FW_WR_OP(FW_ETH_TX_PKT_WR) |
870*4f272a5eSJohn Baldwin 	    V_FW_ETH_TX_PKT_WR_IMMDLEN(ctrl));
871*4f272a5eSJohn Baldwin 
872*4f272a5eSJohn Baldwin 	ctrl = V_FW_WR_LEN16(len16);
873*4f272a5eSJohn Baldwin 	wr->equiq_to_len16 = htobe32(ctrl);
874*4f272a5eSJohn Baldwin 	wr->r3 = 0;
875*4f272a5eSJohn Baldwin 
876*4f272a5eSJohn Baldwin 	cpl = (void *)(wr + 1);
877*4f272a5eSJohn Baldwin 
878*4f272a5eSJohn Baldwin 	/* CPL header */
879*4f272a5eSJohn Baldwin 	cpl->ctrl0 = txq->cpl_ctrl0;
880*4f272a5eSJohn Baldwin 	cpl->pack = 0;
881*4f272a5eSJohn Baldwin 	cpl->len = htobe16(pktlen);
882*4f272a5eSJohn Baldwin 
883*4f272a5eSJohn Baldwin 	out = (void *)(cpl + 1);
884*4f272a5eSJohn Baldwin 
885*4f272a5eSJohn Baldwin 	/* Copy over Ethernet header. */
886*4f272a5eSJohn Baldwin 	eh = mtod(m, struct ether_header *);
887*4f272a5eSJohn Baldwin 	copy_to_txd(&txq->eq, (caddr_t)eh, &out, m->m_pkthdr.l2hlen);
888*4f272a5eSJohn Baldwin 
889*4f272a5eSJohn Baldwin 	/* Fixup length in IP header and copy out. */
890*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_IP) {
891*4f272a5eSJohn Baldwin 		ip = (void *)((char *)eh + m->m_pkthdr.l2hlen);
892*4f272a5eSJohn Baldwin 		newip = *ip;
893*4f272a5eSJohn Baldwin 		newip.ip_len = htons(pktlen - m->m_pkthdr.l2hlen);
894*4f272a5eSJohn Baldwin 		copy_to_txd(&txq->eq, (caddr_t)&newip, &out, sizeof(newip));
895*4f272a5eSJohn Baldwin 		if (m->m_pkthdr.l3hlen > sizeof(*ip))
896*4f272a5eSJohn Baldwin 			copy_to_txd(&txq->eq, (caddr_t)(ip + 1), &out,
897*4f272a5eSJohn Baldwin 			    m->m_pkthdr.l3hlen - sizeof(*ip));
898*4f272a5eSJohn Baldwin 	} else {
899*4f272a5eSJohn Baldwin 		ip6 = (void *)((char *)eh + m->m_pkthdr.l2hlen);
900*4f272a5eSJohn Baldwin 		newip6 = *ip6;
901*4f272a5eSJohn Baldwin 		newip6.ip6_plen = htons(pktlen - m->m_pkthdr.l2hlen -
902*4f272a5eSJohn Baldwin 		    sizeof(*ip6));
903*4f272a5eSJohn Baldwin 		copy_to_txd(&txq->eq, (caddr_t)&newip6, &out, sizeof(newip6));
904*4f272a5eSJohn Baldwin 		MPASS(m->m_pkthdr.l3hlen == sizeof(*ip6));
905*4f272a5eSJohn Baldwin 	}
906*4f272a5eSJohn Baldwin 	cpl->ctrl1 = htobe64(pkt_ctrl1(txq, m, eh_type));
907*4f272a5eSJohn Baldwin 
908*4f272a5eSJohn Baldwin 	/* Set sequence number in TCP header. */
909*4f272a5eSJohn Baldwin 	tcp = (void *)((char *)eh + m->m_pkthdr.l2hlen + m->m_pkthdr.l3hlen);
910*4f272a5eSJohn Baldwin 	newtcp = *tcp;
911*4f272a5eSJohn Baldwin 	newtcp.th_seq = htonl(tcp_seqno);
912*4f272a5eSJohn Baldwin 	copy_to_txd(&txq->eq, (caddr_t)&newtcp, &out, sizeof(newtcp));
913*4f272a5eSJohn Baldwin 
914*4f272a5eSJohn Baldwin 	/* Copy rest of TCP header. */
915*4f272a5eSJohn Baldwin 	copy_to_txd(&txq->eq, (caddr_t)(tcp + 1), &out, m->m_len -
916*4f272a5eSJohn Baldwin 	    (m->m_pkthdr.l2hlen + m->m_pkthdr.l3hlen + sizeof(*tcp)));
917*4f272a5eSJohn Baldwin 
918*4f272a5eSJohn Baldwin 	/* Copy the subset of the TLS header requested. */
919*4f272a5eSJohn Baldwin 	copy_to_txd(&txq->eq, (char *)m_tls->m_epg_hdr +
920*4f272a5eSJohn Baldwin 	    mtod(m_tls, vm_offset_t), &out, m_tls->m_len);
921*4f272a5eSJohn Baldwin 	txq->imm_wrs++;
922*4f272a5eSJohn Baldwin 
923*4f272a5eSJohn Baldwin 	txq->txpkt_wrs++;
924*4f272a5eSJohn Baldwin 
925*4f272a5eSJohn Baldwin 	txq->kern_tls_header++;
926*4f272a5eSJohn Baldwin 
927*4f272a5eSJohn Baldwin 	txsd = &txq->sdesc[pidx];
928*4f272a5eSJohn Baldwin 	txsd->m = m;
929*4f272a5eSJohn Baldwin 	txsd->desc_used = ndesc;
930*4f272a5eSJohn Baldwin 
931*4f272a5eSJohn Baldwin 	return (ndesc);
932*4f272a5eSJohn Baldwin }
933*4f272a5eSJohn Baldwin 
934*4f272a5eSJohn Baldwin static int
935*4f272a5eSJohn Baldwin ktls_write_tls_wr(struct tlspcb *tlsp, struct sge_txq *txq,
936*4f272a5eSJohn Baldwin     void *dst, struct mbuf *m, struct tcphdr *tcp, struct mbuf *m_tls,
937*4f272a5eSJohn Baldwin     u_int available, tcp_seq tcp_seqno, u_int pidx, uint16_t eh_type,
938*4f272a5eSJohn Baldwin     uint16_t mss)
939*4f272a5eSJohn Baldwin {
940*4f272a5eSJohn Baldwin 	struct sge_eq *eq = &txq->eq;
941*4f272a5eSJohn Baldwin 	struct tx_sdesc *txsd;
942*4f272a5eSJohn Baldwin 	struct fw_ulptx_wr *wr;
943*4f272a5eSJohn Baldwin 	struct ulp_txpkt *txpkt;
944*4f272a5eSJohn Baldwin 	struct ulptx_sc_memrd *memrd;
945*4f272a5eSJohn Baldwin 	struct ulptx_idata *idata;
946*4f272a5eSJohn Baldwin 	struct cpl_tx_sec_pdu *sec_pdu;
947*4f272a5eSJohn Baldwin 	struct cpl_tx_pkt_core *tx_pkt;
948*4f272a5eSJohn Baldwin 	const struct tls_record_layer *hdr;
949*4f272a5eSJohn Baldwin 	struct ip *ip;
950*4f272a5eSJohn Baldwin 	struct ip6_hdr *ip6;
951*4f272a5eSJohn Baldwin 	struct tcphdr *newtcp;
952*4f272a5eSJohn Baldwin 	char *iv, *out;
953*4f272a5eSJohn Baldwin 	u_int aad_start, aad_stop;
954*4f272a5eSJohn Baldwin 	u_int auth_start, auth_stop, auth_insert;
955*4f272a5eSJohn Baldwin 	u_int cipher_start, cipher_stop, iv_offset;
956*4f272a5eSJohn Baldwin 	u_int header_len, imm_len, ndesc, nsegs, offset, plen, tlen, wr_len;
957*4f272a5eSJohn Baldwin 	u_int cpl_len, crypto_hdr_len, post_key_context_len;
958*4f272a5eSJohn Baldwin 	u_int leading_waste, trailing_waste;
959*4f272a5eSJohn Baldwin 	u_short ip_len;
960*4f272a5eSJohn Baldwin 	bool last_wr, need_lso, short_record, split_mode, using_scratch;
961*4f272a5eSJohn Baldwin 
962*4f272a5eSJohn Baldwin 	MPASS(tlsp->txq == txq);
963*4f272a5eSJohn Baldwin 	M_ASSERTEXTPG(m_tls);
964*4f272a5eSJohn Baldwin 
965*4f272a5eSJohn Baldwin 	/*
966*4f272a5eSJohn Baldwin 	 * The relative offset of the last byte to send from the TLS
967*4f272a5eSJohn Baldwin 	 * record.
968*4f272a5eSJohn Baldwin 	 */
969*4f272a5eSJohn Baldwin 	tlen = mtod(m_tls, vm_offset_t) + m_tls->m_len;
970*4f272a5eSJohn Baldwin 	if (tlen <= m_tls->m_epg_hdrlen) {
971*4f272a5eSJohn Baldwin 		/*
972*4f272a5eSJohn Baldwin 		 * For requests that only want to send the TLS header,
973*4f272a5eSJohn Baldwin 		 * send a tunnelled packet as immediate data.
974*4f272a5eSJohn Baldwin 		 */
975*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
976*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE, "%s: %p header-only TLS record %u", __func__,
977*4f272a5eSJohn Baldwin 		    tlsp, (u_int)m_tls->m_epg_seqno);
978*4f272a5eSJohn Baldwin #endif
979*4f272a5eSJohn Baldwin 		return (ktls_write_tunnel_packet(txq, dst, m, m_tls, available,
980*4f272a5eSJohn Baldwin 		    tcp_seqno, pidx, eh_type));
981*4f272a5eSJohn Baldwin 	}
982*4f272a5eSJohn Baldwin 
983*4f272a5eSJohn Baldwin 	/* Locate the TLS header. */
984*4f272a5eSJohn Baldwin 	hdr = (void *)m_tls->m_epg_hdr;
985*4f272a5eSJohn Baldwin 
986*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
987*4f272a5eSJohn Baldwin 	CTR(KTR_CXGBE, "%s: offset %lu len %u TCP seq %u TLS record %u",
988*4f272a5eSJohn Baldwin 	    __func__, mtod(m_tls, vm_offset_t), m_tls->m_len, tcp_seqno,
989*4f272a5eSJohn Baldwin 	    (u_int)m_tls->m_epg_seqno);
990*4f272a5eSJohn Baldwin #endif
991*4f272a5eSJohn Baldwin 
992*4f272a5eSJohn Baldwin 	short_record = ktls_is_short_record(tlsp, m_tls, tlen, &header_len,
993*4f272a5eSJohn Baldwin 	    &offset, &plen, &leading_waste, &trailing_waste);
994*4f272a5eSJohn Baldwin 	if (short_record) {
995*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
996*4f272a5eSJohn Baldwin 		CTR(KTR_CXGBE,
997*4f272a5eSJohn Baldwin 		    "%s: %p short TLS record %u hdr %u offs %u plen %u",
998*4f272a5eSJohn Baldwin 		    __func__, tlsp, (u_int)m_tls->m_epg_seqno, header_len,
999*4f272a5eSJohn Baldwin 		    offset, plen);
1000*4f272a5eSJohn Baldwin #endif
1001*4f272a5eSJohn Baldwin 	}
1002*4f272a5eSJohn Baldwin 
1003*4f272a5eSJohn Baldwin 	if ((short_record || trailing_waste != 0) && m_tls->m_next == NULL &&
1004*4f272a5eSJohn Baldwin 	    (tcp->th_flags & TH_FIN) != 0) {
1005*4f272a5eSJohn Baldwin 		txq->kern_tls_fin_short++;
1006*4f272a5eSJohn Baldwin #ifdef INVARIANTS
1007*4f272a5eSJohn Baldwin 		panic("%s: FIN on short TLS record", __func__);
1008*4f272a5eSJohn Baldwin #endif
1009*4f272a5eSJohn Baldwin 	}
1010*4f272a5eSJohn Baldwin 
1011*4f272a5eSJohn Baldwin 	/* Use cached value for first record in chain. */
1012*4f272a5eSJohn Baldwin 	if (m->m_next == m_tls)
1013*4f272a5eSJohn Baldwin 		nsegs = mbuf_nsegs(m);
1014*4f272a5eSJohn Baldwin 	else
1015*4f272a5eSJohn Baldwin 		nsegs = sglist_count_mbuf_epg(m_tls,
1016*4f272a5eSJohn Baldwin 		    m_tls->m_epg_hdrlen + offset, plen);
1017*4f272a5eSJohn Baldwin 
1018*4f272a5eSJohn Baldwin 	/* Final work request for this mbuf chain? */
1019*4f272a5eSJohn Baldwin 	last_wr = (m_tls->m_next == NULL);
1020*4f272a5eSJohn Baldwin 
1021*4f272a5eSJohn Baldwin 	/* Determine if we need an LSO header. */
1022*4f272a5eSJohn Baldwin 	need_lso = (m_tls->m_len > mss);
1023*4f272a5eSJohn Baldwin 
1024*4f272a5eSJohn Baldwin 	/* Calculate the size of the TLS work request. */
1025*4f272a5eSJohn Baldwin 	wr_len = ktls_base_wr_size(tlsp);
1026*4f272a5eSJohn Baldwin 
1027*4f272a5eSJohn Baldwin 	/*
1028*4f272a5eSJohn Baldwin 	 * SplitMode is required if there is any thing we need to trim
1029*4f272a5eSJohn Baldwin 	 * from the crypto output, either at the front or end of the
1030*4f272a5eSJohn Baldwin 	 * record.  Note that short records might not need trimming.
1031*4f272a5eSJohn Baldwin 	 */
1032*4f272a5eSJohn Baldwin 	split_mode = leading_waste != 0 || trailing_waste != 0;
1033*4f272a5eSJohn Baldwin 	if (split_mode) {
1034*4f272a5eSJohn Baldwin 		/*
1035*4f272a5eSJohn Baldwin 		 * Partial records require a SplitMode
1036*4f272a5eSJohn Baldwin 		 * CPL_RX_PHYS_DSGL.
1037*4f272a5eSJohn Baldwin 		 */
1038*4f272a5eSJohn Baldwin 		wr_len += sizeof(struct cpl_t7_rx_phys_dsgl);
1039*4f272a5eSJohn Baldwin 	}
1040*4f272a5eSJohn Baldwin 
1041*4f272a5eSJohn Baldwin 	if (need_lso)
1042*4f272a5eSJohn Baldwin 		wr_len += sizeof(struct cpl_tx_pkt_lso_core);
1043*4f272a5eSJohn Baldwin 
1044*4f272a5eSJohn Baldwin 	imm_len = m->m_len + header_len;
1045*4f272a5eSJohn Baldwin 	if (short_record)
1046*4f272a5eSJohn Baldwin 		imm_len += AES_BLOCK_LEN;
1047*4f272a5eSJohn Baldwin 	wr_len += roundup2(imm_len, 16);
1048*4f272a5eSJohn Baldwin 	wr_len += ktls_sgl_size(nsegs);
1049*4f272a5eSJohn Baldwin 
1050*4f272a5eSJohn Baldwin 	wr_len = roundup2(wr_len, 16);
1051*4f272a5eSJohn Baldwin 	ndesc = howmany(wr_len, EQ_ESIZE);
1052*4f272a5eSJohn Baldwin 	MPASS(ndesc <= available);
1053*4f272a5eSJohn Baldwin 
1054*4f272a5eSJohn Baldwin 	/*
1055*4f272a5eSJohn Baldwin 	 * Use the per-txq scratch pad if near the end of the ring to
1056*4f272a5eSJohn Baldwin 	 * simplify handling of wrap-around.
1057*4f272a5eSJohn Baldwin 	 */
1058*4f272a5eSJohn Baldwin 	using_scratch = (eq->sidx - pidx < ndesc);
1059*4f272a5eSJohn Baldwin 	if (using_scratch)
1060*4f272a5eSJohn Baldwin 		wr = (void *)txq->ss;
1061*4f272a5eSJohn Baldwin 	else
1062*4f272a5eSJohn Baldwin 		wr = dst;
1063*4f272a5eSJohn Baldwin 
1064*4f272a5eSJohn Baldwin 	/* FW_ULPTX_WR */
1065*4f272a5eSJohn Baldwin 	wr->op_to_compl = htobe32(V_FW_WR_OP(FW_ULPTX_WR));
1066*4f272a5eSJohn Baldwin 	wr->flowid_len16 = htobe32(F_FW_ULPTX_WR_DATA |
1067*4f272a5eSJohn Baldwin 	    V_FW_WR_LEN16(wr_len / 16));
1068*4f272a5eSJohn Baldwin 	wr->cookie = 0;
1069*4f272a5eSJohn Baldwin 
1070*4f272a5eSJohn Baldwin 	/* ULP_TXPKT */
1071*4f272a5eSJohn Baldwin 	txpkt = (void *)(wr + 1);
1072*4f272a5eSJohn Baldwin 	txpkt->cmd_dest = htobe32(V_ULPTX_CMD(ULP_TX_PKT) |
1073*4f272a5eSJohn Baldwin 	    V_ULP_TXPKT_DATAMODIFY(0) |
1074*4f272a5eSJohn Baldwin 	    V_T7_ULP_TXPKT_CHANNELID(tlsp->vi->pi->port_id) |
1075*4f272a5eSJohn Baldwin 	    V_ULP_TXPKT_DEST(0) |
1076*4f272a5eSJohn Baldwin 	    V_ULP_TXPKT_FID(txq->eq.cntxt_id) | V_ULP_TXPKT_RO(1));
1077*4f272a5eSJohn Baldwin 	txpkt->len = htobe32(howmany(wr_len - sizeof(*wr), 16));
1078*4f272a5eSJohn Baldwin 
1079*4f272a5eSJohn Baldwin 	/* ULPTX_IDATA sub-command */
1080*4f272a5eSJohn Baldwin 	idata = (void *)(txpkt + 1);
1081*4f272a5eSJohn Baldwin 	idata->cmd_more = htobe32(V_ULPTX_CMD(ULP_TX_SC_IMM) |
1082*4f272a5eSJohn Baldwin 	    V_ULP_TX_SC_MORE(1));
1083*4f272a5eSJohn Baldwin 	idata->len = sizeof(struct cpl_tx_sec_pdu);
1084*4f272a5eSJohn Baldwin 
1085*4f272a5eSJohn Baldwin 	/*
1086*4f272a5eSJohn Baldwin 	 * After the key context comes CPL_RX_PHYS_DSGL, CPL_TX_*, and
1087*4f272a5eSJohn Baldwin 	 * immediate data containing headers.  When using an inline
1088*4f272a5eSJohn Baldwin 	 * key, these are counted as part of this ULPTX_IDATA.  When
1089*4f272a5eSJohn Baldwin 	 * reading the key from memory, these are part of a separate
1090*4f272a5eSJohn Baldwin 	 * ULPTX_IDATA.
1091*4f272a5eSJohn Baldwin 	 */
1092*4f272a5eSJohn Baldwin 	cpl_len = sizeof(struct cpl_tx_pkt_core);
1093*4f272a5eSJohn Baldwin 	if (need_lso)
1094*4f272a5eSJohn Baldwin 		cpl_len += sizeof(struct cpl_tx_pkt_lso_core);
1095*4f272a5eSJohn Baldwin 	if (split_mode)
1096*4f272a5eSJohn Baldwin 		cpl_len += sizeof(struct cpl_t7_rx_phys_dsgl);
1097*4f272a5eSJohn Baldwin 	post_key_context_len = cpl_len + imm_len;
1098*4f272a5eSJohn Baldwin 
1099*4f272a5eSJohn Baldwin 	if (tlsp->inline_key)
1100*4f272a5eSJohn Baldwin 		idata->len += tlsp->tx_key_info_size + post_key_context_len;
1101*4f272a5eSJohn Baldwin 	idata->len = htobe32(idata->len);
1102*4f272a5eSJohn Baldwin 
1103*4f272a5eSJohn Baldwin 	/* CPL_TX_SEC_PDU */
1104*4f272a5eSJohn Baldwin 	sec_pdu = (void *)(idata + 1);
1105*4f272a5eSJohn Baldwin 
1106*4f272a5eSJohn Baldwin 	/*
1107*4f272a5eSJohn Baldwin 	 * Packet headers are passed through unchanged by the crypto
1108*4f272a5eSJohn Baldwin 	 * engine by marking them as header data in SCMD0.
1109*4f272a5eSJohn Baldwin 	 */
1110*4f272a5eSJohn Baldwin 	crypto_hdr_len = m->m_len;
1111*4f272a5eSJohn Baldwin 
1112*4f272a5eSJohn Baldwin 	/*
1113*4f272a5eSJohn Baldwin 	 * For short records, the TLS header is counted as header data
1114*4f272a5eSJohn Baldwin 	 * in SCMD0 and the IV is next, followed by a cipher region for
1115*4f272a5eSJohn Baldwin 	 * the payload.
1116*4f272a5eSJohn Baldwin 	 */
1117*4f272a5eSJohn Baldwin 	if (short_record) {
1118*4f272a5eSJohn Baldwin 		aad_start = 0;
1119*4f272a5eSJohn Baldwin 		aad_stop = 0;
1120*4f272a5eSJohn Baldwin 		iv_offset = 1;
1121*4f272a5eSJohn Baldwin 		auth_start = 0;
1122*4f272a5eSJohn Baldwin 		auth_stop = 0;
1123*4f272a5eSJohn Baldwin 		auth_insert = 0;
1124*4f272a5eSJohn Baldwin 		cipher_start = AES_BLOCK_LEN + 1;
1125*4f272a5eSJohn Baldwin 		cipher_stop = 0;
1126*4f272a5eSJohn Baldwin 
1127*4f272a5eSJohn Baldwin 		sec_pdu->pldlen = htobe32(AES_BLOCK_LEN + plen);
1128*4f272a5eSJohn Baldwin 
1129*4f272a5eSJohn Baldwin 		/*
1130*4f272a5eSJohn Baldwin 		 * For short records, the TLS header is treated as
1131*4f272a5eSJohn Baldwin 		 * header data.
1132*4f272a5eSJohn Baldwin 		 */
1133*4f272a5eSJohn Baldwin 		crypto_hdr_len += header_len;
1134*4f272a5eSJohn Baldwin 
1135*4f272a5eSJohn Baldwin 		/* These two flits are actually a CPL_TLS_TX_SCMD_FMT. */
1136*4f272a5eSJohn Baldwin 		sec_pdu->seqno_numivs = tlsp->scmd0_short.seqno_numivs;
1137*4f272a5eSJohn Baldwin 		sec_pdu->ivgen_hdrlen = htobe32(
1138*4f272a5eSJohn Baldwin 		    tlsp->scmd0_short.ivgen_hdrlen |
1139*4f272a5eSJohn Baldwin 		    V_SCMD_HDR_LEN(crypto_hdr_len));
1140*4f272a5eSJohn Baldwin 
1141*4f272a5eSJohn Baldwin 		txq->kern_tls_short++;
1142*4f272a5eSJohn Baldwin 	} else {
1143*4f272a5eSJohn Baldwin 		/*
1144*4f272a5eSJohn Baldwin 		 * AAD is TLS header.  IV is after AAD.  The cipher region
1145*4f272a5eSJohn Baldwin 		 * starts after the IV.  See comments in ccr_authenc() and
1146*4f272a5eSJohn Baldwin 		 * ccr_gmac() in t4_crypto.c regarding cipher and auth
1147*4f272a5eSJohn Baldwin 		 * start/stop values.
1148*4f272a5eSJohn Baldwin 		 */
1149*4f272a5eSJohn Baldwin 		aad_start = 1;
1150*4f272a5eSJohn Baldwin 		aad_stop = TLS_HEADER_LENGTH;
1151*4f272a5eSJohn Baldwin 		iv_offset = TLS_HEADER_LENGTH + 1;
1152*4f272a5eSJohn Baldwin 		cipher_start = m_tls->m_epg_hdrlen + 1;
1153*4f272a5eSJohn Baldwin 		if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM) {
1154*4f272a5eSJohn Baldwin 			cipher_stop = 0;
1155*4f272a5eSJohn Baldwin 			auth_start = cipher_start;
1156*4f272a5eSJohn Baldwin 			auth_stop = 0;
1157*4f272a5eSJohn Baldwin 			auth_insert = 0;
1158*4f272a5eSJohn Baldwin 		} else {
1159*4f272a5eSJohn Baldwin 			cipher_stop = 0;
1160*4f272a5eSJohn Baldwin 			auth_start = cipher_start;
1161*4f272a5eSJohn Baldwin 			auth_stop = 0;
1162*4f272a5eSJohn Baldwin 			auth_insert = 0;
1163*4f272a5eSJohn Baldwin 		}
1164*4f272a5eSJohn Baldwin 
1165*4f272a5eSJohn Baldwin 		sec_pdu->pldlen = htobe32(m_tls->m_epg_hdrlen + plen);
1166*4f272a5eSJohn Baldwin 
1167*4f272a5eSJohn Baldwin 		/* These two flits are actually a CPL_TLS_TX_SCMD_FMT. */
1168*4f272a5eSJohn Baldwin 		sec_pdu->seqno_numivs = tlsp->scmd0.seqno_numivs;
1169*4f272a5eSJohn Baldwin 		sec_pdu->ivgen_hdrlen = htobe32(tlsp->scmd0.ivgen_hdrlen |
1170*4f272a5eSJohn Baldwin 		    V_SCMD_HDR_LEN(crypto_hdr_len));
1171*4f272a5eSJohn Baldwin 
1172*4f272a5eSJohn Baldwin 		if (split_mode)
1173*4f272a5eSJohn Baldwin 			txq->kern_tls_partial++;
1174*4f272a5eSJohn Baldwin 		else
1175*4f272a5eSJohn Baldwin 			txq->kern_tls_full++;
1176*4f272a5eSJohn Baldwin 	}
1177*4f272a5eSJohn Baldwin 	sec_pdu->op_ivinsrtofst = htobe32(
1178*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_OPCODE(CPL_TX_SEC_PDU) |
1179*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_CPLLEN(cpl_len / 8) |
1180*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_PLACEHOLDER(0) |
1181*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_IVINSRTOFST(iv_offset));
1182*4f272a5eSJohn Baldwin 	sec_pdu->aadstart_cipherstop_hi = htobe32(
1183*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_AADSTART(aad_start) |
1184*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_AADSTOP(aad_stop) |
1185*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_CIPHERSTART(cipher_start) |
1186*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_CIPHERSTOP_HI(cipher_stop >> 4));
1187*4f272a5eSJohn Baldwin 	sec_pdu->cipherstop_lo_authinsert = htobe32(
1188*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_CIPHERSTOP_LO(cipher_stop & 0xf) |
1189*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_AUTHSTART(auth_start) |
1190*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_AUTHSTOP(auth_stop) |
1191*4f272a5eSJohn Baldwin 	    V_CPL_TX_SEC_PDU_AUTHINSERT(auth_insert));
1192*4f272a5eSJohn Baldwin 
1193*4f272a5eSJohn Baldwin 	sec_pdu->scmd1 = htobe64(m_tls->m_epg_seqno);
1194*4f272a5eSJohn Baldwin 
1195*4f272a5eSJohn Baldwin 	/* Key context */
1196*4f272a5eSJohn Baldwin 	out = (void *)(sec_pdu + 1);
1197*4f272a5eSJohn Baldwin 	if (tlsp->inline_key) {
1198*4f272a5eSJohn Baldwin 		memcpy(out, &tlsp->keyctx, tlsp->tx_key_info_size);
1199*4f272a5eSJohn Baldwin 		out += tlsp->tx_key_info_size;
1200*4f272a5eSJohn Baldwin 	} else {
1201*4f272a5eSJohn Baldwin 		/* ULPTX_SC_MEMRD to read key context. */
1202*4f272a5eSJohn Baldwin 		memrd = (void *)out;
1203*4f272a5eSJohn Baldwin 		memrd->cmd_to_len = htobe32(V_ULPTX_CMD(ULP_TX_SC_MEMRD) |
1204*4f272a5eSJohn Baldwin 		    V_ULP_TX_SC_MORE(1) |
1205*4f272a5eSJohn Baldwin 		    V_ULPTX_LEN16(tlsp->tx_key_info_size >> 4));
1206*4f272a5eSJohn Baldwin 		memrd->addr = htobe32(tlsp->tx_key_addr >> 5);
1207*4f272a5eSJohn Baldwin 
1208*4f272a5eSJohn Baldwin 		/* ULPTX_IDATA for CPL_TX_* and headers. */
1209*4f272a5eSJohn Baldwin 		idata = (void *)(memrd + 1);
1210*4f272a5eSJohn Baldwin 		idata->cmd_more = htobe32(V_ULPTX_CMD(ULP_TX_SC_IMM) |
1211*4f272a5eSJohn Baldwin 		    V_ULP_TX_SC_MORE(1));
1212*4f272a5eSJohn Baldwin 		idata->len = htobe32(post_key_context_len);
1213*4f272a5eSJohn Baldwin 
1214*4f272a5eSJohn Baldwin 		out = (void *)(idata + 1);
1215*4f272a5eSJohn Baldwin 	}
1216*4f272a5eSJohn Baldwin 
1217*4f272a5eSJohn Baldwin 	/* CPL_RX_PHYS_DSGL */
1218*4f272a5eSJohn Baldwin 	if (split_mode) {
1219*4f272a5eSJohn Baldwin 		out = write_split_mode_rx_phys(out, m, m_tls, cpl_len -
1220*4f272a5eSJohn Baldwin 		    sizeof(struct cpl_t7_rx_phys_dsgl) + m->m_len,
1221*4f272a5eSJohn Baldwin 		    leading_waste, trailing_waste);
1222*4f272a5eSJohn Baldwin 	}
1223*4f272a5eSJohn Baldwin 
1224*4f272a5eSJohn Baldwin 	/* CPL_TX_PKT_LSO */
1225*4f272a5eSJohn Baldwin 	if (need_lso) {
1226*4f272a5eSJohn Baldwin 		out = write_lso_cpl(out, m, mss, eh_type, m->m_len +
1227*4f272a5eSJohn Baldwin 		    m_tls->m_len);
1228*4f272a5eSJohn Baldwin 		txq->tso_wrs++;
1229*4f272a5eSJohn Baldwin 	}
1230*4f272a5eSJohn Baldwin 
1231*4f272a5eSJohn Baldwin 	/* CPL_TX_PKT_XT */
1232*4f272a5eSJohn Baldwin 	tx_pkt = (void *)out;
1233*4f272a5eSJohn Baldwin 	tx_pkt->ctrl0 = txq->cpl_ctrl0;
1234*4f272a5eSJohn Baldwin 	tx_pkt->ctrl1 = htobe64(pkt_ctrl1(txq, m, eh_type));
1235*4f272a5eSJohn Baldwin 	tx_pkt->pack = 0;
1236*4f272a5eSJohn Baldwin 	tx_pkt->len = htobe16(m->m_len + m_tls->m_len);
1237*4f272a5eSJohn Baldwin 
1238*4f272a5eSJohn Baldwin 	/* Copy the packet headers. */
1239*4f272a5eSJohn Baldwin 	out = (void *)(tx_pkt + 1);
1240*4f272a5eSJohn Baldwin 	memcpy(out, mtod(m, char *), m->m_len);
1241*4f272a5eSJohn Baldwin 
1242*4f272a5eSJohn Baldwin 	/* Modify the packet length in the IP header. */
1243*4f272a5eSJohn Baldwin 	ip_len = m->m_len + m_tls->m_len - m->m_pkthdr.l2hlen;
1244*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_IP) {
1245*4f272a5eSJohn Baldwin 		ip = (void *)(out + m->m_pkthdr.l2hlen);
1246*4f272a5eSJohn Baldwin 		be16enc(&ip->ip_len, ip_len);
1247*4f272a5eSJohn Baldwin 	} else {
1248*4f272a5eSJohn Baldwin 		ip6 = (void *)(out + m->m_pkthdr.l2hlen);
1249*4f272a5eSJohn Baldwin 		be16enc(&ip6->ip6_plen, ip_len - sizeof(*ip6));
1250*4f272a5eSJohn Baldwin 	}
1251*4f272a5eSJohn Baldwin 
1252*4f272a5eSJohn Baldwin 	/* Modify sequence number and flags in TCP header. */
1253*4f272a5eSJohn Baldwin 	newtcp = (void *)(out + m->m_pkthdr.l2hlen + m->m_pkthdr.l3hlen);
1254*4f272a5eSJohn Baldwin 	be32enc(&newtcp->th_seq, tcp_seqno);
1255*4f272a5eSJohn Baldwin 	if (!last_wr)
1256*4f272a5eSJohn Baldwin 		newtcp->th_flags = tcp->th_flags & ~(TH_PUSH | TH_FIN);
1257*4f272a5eSJohn Baldwin 	out += m->m_len;
1258*4f272a5eSJohn Baldwin 
1259*4f272a5eSJohn Baldwin 	/* Populate the TLS header */
1260*4f272a5eSJohn Baldwin 	memcpy(out, m_tls->m_epg_hdr, header_len);
1261*4f272a5eSJohn Baldwin 	out += header_len;
1262*4f272a5eSJohn Baldwin 
1263*4f272a5eSJohn Baldwin 	/* AES IV for a short record. */
1264*4f272a5eSJohn Baldwin 	if (short_record) {
1265*4f272a5eSJohn Baldwin 		iv = out;
1266*4f272a5eSJohn Baldwin 		if (tlsp->enc_mode == SCMD_CIPH_MODE_AES_GCM) {
1267*4f272a5eSJohn Baldwin 			memcpy(iv, tlsp->keyctx.u.txhdr.txsalt, SALT_SIZE);
1268*4f272a5eSJohn Baldwin 			memcpy(iv + 4, hdr + 1, 8);
1269*4f272a5eSJohn Baldwin 			be32enc(iv + 12, 2 + offset / AES_BLOCK_LEN);
1270*4f272a5eSJohn Baldwin 		} else
1271*4f272a5eSJohn Baldwin 			memcpy(iv, hdr + 1, AES_BLOCK_LEN);
1272*4f272a5eSJohn Baldwin 		out += AES_BLOCK_LEN;
1273*4f272a5eSJohn Baldwin 	}
1274*4f272a5eSJohn Baldwin 
1275*4f272a5eSJohn Baldwin 	if (imm_len % 16 != 0) {
1276*4f272a5eSJohn Baldwin 		if (imm_len % 8 != 0) {
1277*4f272a5eSJohn Baldwin 			/* Zero pad to an 8-byte boundary. */
1278*4f272a5eSJohn Baldwin 			memset(out, 0, 8 - (imm_len % 8));
1279*4f272a5eSJohn Baldwin 			out += 8 - (imm_len % 8);
1280*4f272a5eSJohn Baldwin 		}
1281*4f272a5eSJohn Baldwin 
1282*4f272a5eSJohn Baldwin 		/*
1283*4f272a5eSJohn Baldwin 		 * Insert a ULP_TX_SC_NOOP if needed so the SGL is
1284*4f272a5eSJohn Baldwin 		 * 16-byte aligned.
1285*4f272a5eSJohn Baldwin 		 */
1286*4f272a5eSJohn Baldwin 		if (imm_len % 16 <= 8) {
1287*4f272a5eSJohn Baldwin 			idata = (void *)out;
1288*4f272a5eSJohn Baldwin 			idata->cmd_more = htobe32(V_ULPTX_CMD(ULP_TX_SC_NOOP) |
1289*4f272a5eSJohn Baldwin 			    V_ULP_TX_SC_MORE(1));
1290*4f272a5eSJohn Baldwin 			idata->len = htobe32(0);
1291*4f272a5eSJohn Baldwin 			out = (void *)(idata + 1);
1292*4f272a5eSJohn Baldwin 		}
1293*4f272a5eSJohn Baldwin 	}
1294*4f272a5eSJohn Baldwin 
1295*4f272a5eSJohn Baldwin 	/* SGL for record payload */
1296*4f272a5eSJohn Baldwin 	sglist_reset(txq->gl);
1297*4f272a5eSJohn Baldwin 	if (sglist_append_mbuf_epg(txq->gl, m_tls, m_tls->m_epg_hdrlen + offset,
1298*4f272a5eSJohn Baldwin 	    plen) != 0) {
1299*4f272a5eSJohn Baldwin #ifdef INVARIANTS
1300*4f272a5eSJohn Baldwin 		panic("%s: failed to append sglist", __func__);
1301*4f272a5eSJohn Baldwin #endif
1302*4f272a5eSJohn Baldwin 	}
1303*4f272a5eSJohn Baldwin 	write_gl_to_buf(txq->gl, out);
1304*4f272a5eSJohn Baldwin 
1305*4f272a5eSJohn Baldwin 	if (using_scratch) {
1306*4f272a5eSJohn Baldwin 		out = dst;
1307*4f272a5eSJohn Baldwin 		copy_to_txd(eq, txq->ss, &out, wr_len);
1308*4f272a5eSJohn Baldwin 	}
1309*4f272a5eSJohn Baldwin 
1310*4f272a5eSJohn Baldwin 	txq->kern_tls_records++;
1311*4f272a5eSJohn Baldwin 	txq->kern_tls_octets += m_tls->m_len;
1312*4f272a5eSJohn Baldwin 	if (split_mode) {
1313*4f272a5eSJohn Baldwin 		txq->kern_tls_splitmode++;
1314*4f272a5eSJohn Baldwin 		txq->kern_tls_waste += leading_waste + trailing_waste;
1315*4f272a5eSJohn Baldwin 	}
1316*4f272a5eSJohn Baldwin 	if (need_lso)
1317*4f272a5eSJohn Baldwin 		txq->kern_tls_lso++;
1318*4f272a5eSJohn Baldwin 
1319*4f272a5eSJohn Baldwin 	txsd = &txq->sdesc[pidx];
1320*4f272a5eSJohn Baldwin 	if (last_wr)
1321*4f272a5eSJohn Baldwin 		txsd->m = m;
1322*4f272a5eSJohn Baldwin 	else
1323*4f272a5eSJohn Baldwin 		txsd->m = NULL;
1324*4f272a5eSJohn Baldwin 	txsd->desc_used = howmany(wr_len, EQ_ESIZE);
1325*4f272a5eSJohn Baldwin 
1326*4f272a5eSJohn Baldwin 	return (ndesc);
1327*4f272a5eSJohn Baldwin }
1328*4f272a5eSJohn Baldwin 
1329*4f272a5eSJohn Baldwin int
1330*4f272a5eSJohn Baldwin t7_ktls_write_wr(struct sge_txq *txq, void *dst, struct mbuf *m,
1331*4f272a5eSJohn Baldwin     u_int available)
1332*4f272a5eSJohn Baldwin {
1333*4f272a5eSJohn Baldwin 	struct sge_eq *eq = &txq->eq;
1334*4f272a5eSJohn Baldwin 	struct tlspcb *tlsp;
1335*4f272a5eSJohn Baldwin 	struct tcphdr *tcp;
1336*4f272a5eSJohn Baldwin 	struct mbuf *m_tls;
1337*4f272a5eSJohn Baldwin 	struct ether_header *eh;
1338*4f272a5eSJohn Baldwin 	tcp_seq tcp_seqno;
1339*4f272a5eSJohn Baldwin 	u_int ndesc, pidx, totdesc;
1340*4f272a5eSJohn Baldwin 	uint16_t eh_type, mss;
1341*4f272a5eSJohn Baldwin 
1342*4f272a5eSJohn Baldwin 	M_ASSERTPKTHDR(m);
1343*4f272a5eSJohn Baldwin 	MPASS(m->m_pkthdr.snd_tag != NULL);
1344*4f272a5eSJohn Baldwin 	tlsp = mst_to_tls(m->m_pkthdr.snd_tag);
1345*4f272a5eSJohn Baldwin 
1346*4f272a5eSJohn Baldwin 	totdesc = 0;
1347*4f272a5eSJohn Baldwin 	eh = mtod(m, struct ether_header *);
1348*4f272a5eSJohn Baldwin 	eh_type = ntohs(eh->ether_type);
1349*4f272a5eSJohn Baldwin 	if (eh_type == ETHERTYPE_VLAN) {
1350*4f272a5eSJohn Baldwin 		struct ether_vlan_header *evh = (void *)eh;
1351*4f272a5eSJohn Baldwin 
1352*4f272a5eSJohn Baldwin 		eh_type = ntohs(evh->evl_proto);
1353*4f272a5eSJohn Baldwin 	}
1354*4f272a5eSJohn Baldwin 
1355*4f272a5eSJohn Baldwin 	tcp = (struct tcphdr *)((char *)eh + m->m_pkthdr.l2hlen +
1356*4f272a5eSJohn Baldwin 	    m->m_pkthdr.l3hlen);
1357*4f272a5eSJohn Baldwin 	pidx = eq->pidx;
1358*4f272a5eSJohn Baldwin 
1359*4f272a5eSJohn Baldwin 	/* Determine MSS. */
1360*4f272a5eSJohn Baldwin 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
1361*4f272a5eSJohn Baldwin 		mss = m->m_pkthdr.tso_segsz;
1362*4f272a5eSJohn Baldwin 		tlsp->prev_mss = mss;
1363*4f272a5eSJohn Baldwin 	} else if (tlsp->prev_mss != 0)
1364*4f272a5eSJohn Baldwin 		mss = tlsp->prev_mss;
1365*4f272a5eSJohn Baldwin 	else
1366*4f272a5eSJohn Baldwin 		mss = if_getmtu(tlsp->vi->ifp) -
1367*4f272a5eSJohn Baldwin 		    (m->m_pkthdr.l3hlen + m->m_pkthdr.l4hlen);
1368*4f272a5eSJohn Baldwin 
1369*4f272a5eSJohn Baldwin 	/* Fetch the starting TCP sequence number for this chain. */
1370*4f272a5eSJohn Baldwin 	tcp_seqno = ntohl(tcp->th_seq);
1371*4f272a5eSJohn Baldwin #ifdef VERBOSE_TRACES
1372*4f272a5eSJohn Baldwin 	CTR(KTR_CXGBE, "%s: pkt len %d TCP seq %u", __func__, m->m_pkthdr.len,
1373*4f272a5eSJohn Baldwin 	    tcp_seqno);
1374*4f272a5eSJohn Baldwin #endif
1375*4f272a5eSJohn Baldwin 
1376*4f272a5eSJohn Baldwin 	/*
1377*4f272a5eSJohn Baldwin 	 * Iterate over each TLS record constructing a work request
1378*4f272a5eSJohn Baldwin 	 * for that record.
1379*4f272a5eSJohn Baldwin 	 */
1380*4f272a5eSJohn Baldwin 	for (m_tls = m->m_next; m_tls != NULL; m_tls = m_tls->m_next) {
1381*4f272a5eSJohn Baldwin 		MPASS(m_tls->m_flags & M_EXTPG);
1382*4f272a5eSJohn Baldwin 
1383*4f272a5eSJohn Baldwin 		ndesc = ktls_write_tls_wr(tlsp, txq, dst, m, tcp, m_tls,
1384*4f272a5eSJohn Baldwin 		    available - totdesc, tcp_seqno, pidx, eh_type, mss);
1385*4f272a5eSJohn Baldwin 		totdesc += ndesc;
1386*4f272a5eSJohn Baldwin 		IDXINCR(pidx, ndesc, eq->sidx);
1387*4f272a5eSJohn Baldwin 		dst = &eq->desc[pidx];
1388*4f272a5eSJohn Baldwin 
1389*4f272a5eSJohn Baldwin 		tcp_seqno += m_tls->m_len;
1390*4f272a5eSJohn Baldwin 	}
1391*4f272a5eSJohn Baldwin 
1392*4f272a5eSJohn Baldwin 	MPASS(totdesc <= available);
1393*4f272a5eSJohn Baldwin 	return (totdesc);
1394*4f272a5eSJohn Baldwin }
1395*4f272a5eSJohn Baldwin 
1396*4f272a5eSJohn Baldwin static void
1397*4f272a5eSJohn Baldwin t7_tls_tag_free(struct m_snd_tag *mst)
1398*4f272a5eSJohn Baldwin {
1399*4f272a5eSJohn Baldwin 	struct adapter *sc;
1400*4f272a5eSJohn Baldwin 	struct tlspcb *tlsp;
1401*4f272a5eSJohn Baldwin 
1402*4f272a5eSJohn Baldwin 	tlsp = mst_to_tls(mst);
1403*4f272a5eSJohn Baldwin 	sc = tlsp->sc;
1404*4f272a5eSJohn Baldwin 
1405*4f272a5eSJohn Baldwin 	CTR2(KTR_CXGBE, "%s: %p", __func__, tlsp);
1406*4f272a5eSJohn Baldwin 
1407*4f272a5eSJohn Baldwin 	if (tlsp->tx_key_addr >= 0)
1408*4f272a5eSJohn Baldwin 		t4_free_tls_keyid(sc, tlsp->tx_key_addr);
1409*4f272a5eSJohn Baldwin 
1410*4f272a5eSJohn Baldwin 	zfree(tlsp, M_CXGBE);
1411*4f272a5eSJohn Baldwin }
1412*4f272a5eSJohn Baldwin 
1413*4f272a5eSJohn Baldwin #else
1414*4f272a5eSJohn Baldwin 
1415*4f272a5eSJohn Baldwin int
1416*4f272a5eSJohn Baldwin t7_tls_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
1417*4f272a5eSJohn Baldwin     struct m_snd_tag **pt)
1418*4f272a5eSJohn Baldwin {
1419*4f272a5eSJohn Baldwin 	return (ENXIO);
1420*4f272a5eSJohn Baldwin }
1421*4f272a5eSJohn Baldwin 
1422*4f272a5eSJohn Baldwin int
1423*4f272a5eSJohn Baldwin t7_ktls_parse_pkt(struct mbuf *m)
1424*4f272a5eSJohn Baldwin {
1425*4f272a5eSJohn Baldwin 	return (EINVAL);
1426*4f272a5eSJohn Baldwin }
1427*4f272a5eSJohn Baldwin 
1428*4f272a5eSJohn Baldwin int
1429*4f272a5eSJohn Baldwin t7_ktls_write_wr(struct sge_txq *txq, void *dst, struct mbuf *m,
1430*4f272a5eSJohn Baldwin     u_int available)
1431*4f272a5eSJohn Baldwin {
1432*4f272a5eSJohn Baldwin 	panic("can't happen");
1433*4f272a5eSJohn Baldwin }
1434*4f272a5eSJohn Baldwin 
1435*4f272a5eSJohn Baldwin #endif
1436