162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Ceph msgr2 protocol implementation
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Ilya Dryomov <idryomov@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <crypto/aead.h>
1162306a36Sopenharmony_ci#include <crypto/hash.h>
1262306a36Sopenharmony_ci#include <crypto/sha2.h>
1362306a36Sopenharmony_ci#include <crypto/utils.h>
1462306a36Sopenharmony_ci#include <linux/bvec.h>
1562306a36Sopenharmony_ci#include <linux/crc32c.h>
1662306a36Sopenharmony_ci#include <linux/net.h>
1762306a36Sopenharmony_ci#include <linux/scatterlist.h>
1862306a36Sopenharmony_ci#include <linux/socket.h>
1962306a36Sopenharmony_ci#include <linux/sched/mm.h>
2062306a36Sopenharmony_ci#include <net/sock.h>
2162306a36Sopenharmony_ci#include <net/tcp.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/ceph/ceph_features.h>
2462306a36Sopenharmony_ci#include <linux/ceph/decode.h>
2562306a36Sopenharmony_ci#include <linux/ceph/libceph.h>
2662306a36Sopenharmony_ci#include <linux/ceph/messenger.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "crypto.h"  /* for CEPH_KEY_LEN and CEPH_MAX_CON_SECRET_LEN */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define FRAME_TAG_HELLO			1
3162306a36Sopenharmony_ci#define FRAME_TAG_AUTH_REQUEST		2
3262306a36Sopenharmony_ci#define FRAME_TAG_AUTH_BAD_METHOD	3
3362306a36Sopenharmony_ci#define FRAME_TAG_AUTH_REPLY_MORE	4
3462306a36Sopenharmony_ci#define FRAME_TAG_AUTH_REQUEST_MORE	5
3562306a36Sopenharmony_ci#define FRAME_TAG_AUTH_DONE		6
3662306a36Sopenharmony_ci#define FRAME_TAG_AUTH_SIGNATURE	7
3762306a36Sopenharmony_ci#define FRAME_TAG_CLIENT_IDENT		8
3862306a36Sopenharmony_ci#define FRAME_TAG_SERVER_IDENT		9
3962306a36Sopenharmony_ci#define FRAME_TAG_IDENT_MISSING_FEATURES 10
4062306a36Sopenharmony_ci#define FRAME_TAG_SESSION_RECONNECT	11
4162306a36Sopenharmony_ci#define FRAME_TAG_SESSION_RESET		12
4262306a36Sopenharmony_ci#define FRAME_TAG_SESSION_RETRY		13
4362306a36Sopenharmony_ci#define FRAME_TAG_SESSION_RETRY_GLOBAL	14
4462306a36Sopenharmony_ci#define FRAME_TAG_SESSION_RECONNECT_OK	15
4562306a36Sopenharmony_ci#define FRAME_TAG_WAIT			16
4662306a36Sopenharmony_ci#define FRAME_TAG_MESSAGE		17
4762306a36Sopenharmony_ci#define FRAME_TAG_KEEPALIVE2		18
4862306a36Sopenharmony_ci#define FRAME_TAG_KEEPALIVE2_ACK	19
4962306a36Sopenharmony_ci#define FRAME_TAG_ACK			20
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define FRAME_LATE_STATUS_ABORTED	0x1
5262306a36Sopenharmony_ci#define FRAME_LATE_STATUS_COMPLETE	0xe
5362306a36Sopenharmony_ci#define FRAME_LATE_STATUS_ABORTED_MASK	0xf
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define IN_S_HANDLE_PREAMBLE			1
5662306a36Sopenharmony_ci#define IN_S_HANDLE_CONTROL			2
5762306a36Sopenharmony_ci#define IN_S_HANDLE_CONTROL_REMAINDER		3
5862306a36Sopenharmony_ci#define IN_S_PREPARE_READ_DATA			4
5962306a36Sopenharmony_ci#define IN_S_PREPARE_READ_DATA_CONT		5
6062306a36Sopenharmony_ci#define IN_S_PREPARE_READ_ENC_PAGE		6
6162306a36Sopenharmony_ci#define IN_S_PREPARE_SPARSE_DATA		7
6262306a36Sopenharmony_ci#define IN_S_PREPARE_SPARSE_DATA_CONT		8
6362306a36Sopenharmony_ci#define IN_S_HANDLE_EPILOGUE			9
6462306a36Sopenharmony_ci#define IN_S_FINISH_SKIP			10
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define OUT_S_QUEUE_DATA		1
6762306a36Sopenharmony_ci#define OUT_S_QUEUE_DATA_CONT		2
6862306a36Sopenharmony_ci#define OUT_S_QUEUE_ENC_PAGE		3
6962306a36Sopenharmony_ci#define OUT_S_QUEUE_ZEROS		4
7062306a36Sopenharmony_ci#define OUT_S_FINISH_MESSAGE		5
7162306a36Sopenharmony_ci#define OUT_S_GET_NEXT			6
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define CTRL_BODY(p)	((void *)(p) + CEPH_PREAMBLE_LEN)
7462306a36Sopenharmony_ci#define FRONT_PAD(p)	((void *)(p) + CEPH_EPILOGUE_SECURE_LEN)
7562306a36Sopenharmony_ci#define MIDDLE_PAD(p)	(FRONT_PAD(p) + CEPH_GCM_BLOCK_LEN)
7662306a36Sopenharmony_ci#define DATA_PAD(p)	(MIDDLE_PAD(p) + CEPH_GCM_BLOCK_LEN)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define CEPH_MSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int do_recvmsg(struct socket *sock, struct iov_iter *it)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS };
8362306a36Sopenharmony_ci	int ret;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	msg.msg_iter = *it;
8662306a36Sopenharmony_ci	while (iov_iter_count(it)) {
8762306a36Sopenharmony_ci		ret = sock_recvmsg(sock, &msg, msg.msg_flags);
8862306a36Sopenharmony_ci		if (ret <= 0) {
8962306a36Sopenharmony_ci			if (ret == -EAGAIN)
9062306a36Sopenharmony_ci				ret = 0;
9162306a36Sopenharmony_ci			return ret;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		iov_iter_advance(it, ret);
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	WARN_ON(msg_data_left(&msg));
9862306a36Sopenharmony_ci	return 1;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * Read as much as possible.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * Return:
10562306a36Sopenharmony_ci *   1 - done, nothing (else) to read
10662306a36Sopenharmony_ci *   0 - socket is empty, need to wait
10762306a36Sopenharmony_ci *  <0 - error
10862306a36Sopenharmony_ci */
10962306a36Sopenharmony_cistatic int ceph_tcp_recv(struct ceph_connection *con)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	int ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	dout("%s con %p %s %zu\n", __func__, con,
11462306a36Sopenharmony_ci	     iov_iter_is_discard(&con->v2.in_iter) ? "discard" : "need",
11562306a36Sopenharmony_ci	     iov_iter_count(&con->v2.in_iter));
11662306a36Sopenharmony_ci	ret = do_recvmsg(con->sock, &con->v2.in_iter);
11762306a36Sopenharmony_ci	dout("%s con %p ret %d left %zu\n", __func__, con, ret,
11862306a36Sopenharmony_ci	     iov_iter_count(&con->v2.in_iter));
11962306a36Sopenharmony_ci	return ret;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int do_sendmsg(struct socket *sock, struct iov_iter *it)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS };
12562306a36Sopenharmony_ci	int ret;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	msg.msg_iter = *it;
12862306a36Sopenharmony_ci	while (iov_iter_count(it)) {
12962306a36Sopenharmony_ci		ret = sock_sendmsg(sock, &msg);
13062306a36Sopenharmony_ci		if (ret <= 0) {
13162306a36Sopenharmony_ci			if (ret == -EAGAIN)
13262306a36Sopenharmony_ci				ret = 0;
13362306a36Sopenharmony_ci			return ret;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		iov_iter_advance(it, ret);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	WARN_ON(msg_data_left(&msg));
14062306a36Sopenharmony_ci	return 1;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int do_try_sendpage(struct socket *sock, struct iov_iter *it)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS };
14662306a36Sopenharmony_ci	struct bio_vec bv;
14762306a36Sopenharmony_ci	int ret;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (WARN_ON(!iov_iter_is_bvec(it)))
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	while (iov_iter_count(it)) {
15362306a36Sopenharmony_ci		/* iov_iter_iovec() for ITER_BVEC */
15462306a36Sopenharmony_ci		bvec_set_page(&bv, it->bvec->bv_page,
15562306a36Sopenharmony_ci			      min(iov_iter_count(it),
15662306a36Sopenharmony_ci				  it->bvec->bv_len - it->iov_offset),
15762306a36Sopenharmony_ci			      it->bvec->bv_offset + it->iov_offset);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		/*
16062306a36Sopenharmony_ci		 * MSG_SPLICE_PAGES cannot properly handle pages with
16162306a36Sopenharmony_ci		 * page_count == 0, we need to fall back to sendmsg if
16262306a36Sopenharmony_ci		 * that's the case.
16362306a36Sopenharmony_ci		 *
16462306a36Sopenharmony_ci		 * Same goes for slab pages: skb_can_coalesce() allows
16562306a36Sopenharmony_ci		 * coalescing neighboring slab objects into a single frag
16662306a36Sopenharmony_ci		 * which triggers one of hardened usercopy checks.
16762306a36Sopenharmony_ci		 */
16862306a36Sopenharmony_ci		if (sendpage_ok(bv.bv_page))
16962306a36Sopenharmony_ci			msg.msg_flags |= MSG_SPLICE_PAGES;
17062306a36Sopenharmony_ci		else
17162306a36Sopenharmony_ci			msg.msg_flags &= ~MSG_SPLICE_PAGES;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, bv.bv_len);
17462306a36Sopenharmony_ci		ret = sock_sendmsg(sock, &msg);
17562306a36Sopenharmony_ci		if (ret <= 0) {
17662306a36Sopenharmony_ci			if (ret == -EAGAIN)
17762306a36Sopenharmony_ci				ret = 0;
17862306a36Sopenharmony_ci			return ret;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		iov_iter_advance(it, ret);
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return 1;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/*
18862306a36Sopenharmony_ci * Write as much as possible.  The socket is expected to be corked,
18962306a36Sopenharmony_ci * so we don't bother with MSG_MORE here.
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * Return:
19262306a36Sopenharmony_ci *   1 - done, nothing (else) to write
19362306a36Sopenharmony_ci *   0 - socket is full, need to wait
19462306a36Sopenharmony_ci *  <0 - error
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic int ceph_tcp_send(struct ceph_connection *con)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	dout("%s con %p have %zu try_sendpage %d\n", __func__, con,
20162306a36Sopenharmony_ci	     iov_iter_count(&con->v2.out_iter), con->v2.out_iter_sendpage);
20262306a36Sopenharmony_ci	if (con->v2.out_iter_sendpage)
20362306a36Sopenharmony_ci		ret = do_try_sendpage(con->sock, &con->v2.out_iter);
20462306a36Sopenharmony_ci	else
20562306a36Sopenharmony_ci		ret = do_sendmsg(con->sock, &con->v2.out_iter);
20662306a36Sopenharmony_ci	dout("%s con %p ret %d left %zu\n", __func__, con, ret,
20762306a36Sopenharmony_ci	     iov_iter_count(&con->v2.out_iter));
20862306a36Sopenharmony_ci	return ret;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic void add_in_kvec(struct ceph_connection *con, void *buf, int len)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	BUG_ON(con->v2.in_kvec_cnt >= ARRAY_SIZE(con->v2.in_kvecs));
21462306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	con->v2.in_kvecs[con->v2.in_kvec_cnt].iov_base = buf;
21762306a36Sopenharmony_ci	con->v2.in_kvecs[con->v2.in_kvec_cnt].iov_len = len;
21862306a36Sopenharmony_ci	con->v2.in_kvec_cnt++;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	con->v2.in_iter.nr_segs++;
22162306a36Sopenharmony_ci	con->v2.in_iter.count += len;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic void reset_in_kvecs(struct ceph_connection *con)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.in_iter));
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	con->v2.in_kvec_cnt = 0;
22962306a36Sopenharmony_ci	iov_iter_kvec(&con->v2.in_iter, ITER_DEST, con->v2.in_kvecs, 0, 0);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void set_in_bvec(struct ceph_connection *con, const struct bio_vec *bv)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.in_iter));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	con->v2.in_bvec = *bv;
23762306a36Sopenharmony_ci	iov_iter_bvec(&con->v2.in_iter, ITER_DEST, &con->v2.in_bvec, 1, bv->bv_len);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void set_in_skip(struct ceph_connection *con, int len)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.in_iter));
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	dout("%s con %p len %d\n", __func__, con, len);
24562306a36Sopenharmony_ci	iov_iter_discard(&con->v2.in_iter, ITER_DEST, len);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void add_out_kvec(struct ceph_connection *con, void *buf, int len)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	BUG_ON(con->v2.out_kvec_cnt >= ARRAY_SIZE(con->v2.out_kvecs));
25162306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter));
25262306a36Sopenharmony_ci	WARN_ON(con->v2.out_zero);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	con->v2.out_kvecs[con->v2.out_kvec_cnt].iov_base = buf;
25562306a36Sopenharmony_ci	con->v2.out_kvecs[con->v2.out_kvec_cnt].iov_len = len;
25662306a36Sopenharmony_ci	con->v2.out_kvec_cnt++;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	con->v2.out_iter.nr_segs++;
25962306a36Sopenharmony_ci	con->v2.out_iter.count += len;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void reset_out_kvecs(struct ceph_connection *con)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.out_iter));
26562306a36Sopenharmony_ci	WARN_ON(con->v2.out_zero);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	con->v2.out_kvec_cnt = 0;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	iov_iter_kvec(&con->v2.out_iter, ITER_SOURCE, con->v2.out_kvecs, 0, 0);
27062306a36Sopenharmony_ci	con->v2.out_iter_sendpage = false;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic void set_out_bvec(struct ceph_connection *con, const struct bio_vec *bv,
27462306a36Sopenharmony_ci			 bool zerocopy)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.out_iter));
27762306a36Sopenharmony_ci	WARN_ON(con->v2.out_zero);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	con->v2.out_bvec = *bv;
28062306a36Sopenharmony_ci	con->v2.out_iter_sendpage = zerocopy;
28162306a36Sopenharmony_ci	iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
28262306a36Sopenharmony_ci		      con->v2.out_bvec.bv_len);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void set_out_bvec_zero(struct ceph_connection *con)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.out_iter));
28862306a36Sopenharmony_ci	WARN_ON(!con->v2.out_zero);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	bvec_set_page(&con->v2.out_bvec, ceph_zero_page,
29162306a36Sopenharmony_ci		      min(con->v2.out_zero, (int)PAGE_SIZE), 0);
29262306a36Sopenharmony_ci	con->v2.out_iter_sendpage = true;
29362306a36Sopenharmony_ci	iov_iter_bvec(&con->v2.out_iter, ITER_SOURCE, &con->v2.out_bvec, 1,
29462306a36Sopenharmony_ci		      con->v2.out_bvec.bv_len);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void out_zero_add(struct ceph_connection *con, int len)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	dout("%s con %p len %d\n", __func__, con, len);
30062306a36Sopenharmony_ci	con->v2.out_zero += len;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void *alloc_conn_buf(struct ceph_connection *con, int len)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	void *buf;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	dout("%s con %p len %d\n", __func__, con, len);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (WARN_ON(con->v2.conn_buf_cnt >= ARRAY_SIZE(con->v2.conn_bufs)))
31062306a36Sopenharmony_ci		return NULL;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	buf = kvmalloc(len, GFP_NOIO);
31362306a36Sopenharmony_ci	if (!buf)
31462306a36Sopenharmony_ci		return NULL;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	con->v2.conn_bufs[con->v2.conn_buf_cnt++] = buf;
31762306a36Sopenharmony_ci	return buf;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic void free_conn_bufs(struct ceph_connection *con)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	while (con->v2.conn_buf_cnt)
32362306a36Sopenharmony_ci		kvfree(con->v2.conn_bufs[--con->v2.conn_buf_cnt]);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void add_in_sign_kvec(struct ceph_connection *con, void *buf, int len)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	BUG_ON(con->v2.in_sign_kvec_cnt >= ARRAY_SIZE(con->v2.in_sign_kvecs));
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	con->v2.in_sign_kvecs[con->v2.in_sign_kvec_cnt].iov_base = buf;
33162306a36Sopenharmony_ci	con->v2.in_sign_kvecs[con->v2.in_sign_kvec_cnt].iov_len = len;
33262306a36Sopenharmony_ci	con->v2.in_sign_kvec_cnt++;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void clear_in_sign_kvecs(struct ceph_connection *con)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	con->v2.in_sign_kvec_cnt = 0;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic void add_out_sign_kvec(struct ceph_connection *con, void *buf, int len)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	BUG_ON(con->v2.out_sign_kvec_cnt >= ARRAY_SIZE(con->v2.out_sign_kvecs));
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	con->v2.out_sign_kvecs[con->v2.out_sign_kvec_cnt].iov_base = buf;
34562306a36Sopenharmony_ci	con->v2.out_sign_kvecs[con->v2.out_sign_kvec_cnt].iov_len = len;
34662306a36Sopenharmony_ci	con->v2.out_sign_kvec_cnt++;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic void clear_out_sign_kvecs(struct ceph_connection *con)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	con->v2.out_sign_kvec_cnt = 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic bool con_secure(struct ceph_connection *con)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	return con->v2.con_mode == CEPH_CON_MODE_SECURE;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int front_len(const struct ceph_msg *msg)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return le32_to_cpu(msg->hdr.front_len);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int middle_len(const struct ceph_msg *msg)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	return le32_to_cpu(msg->hdr.middle_len);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic int data_len(const struct ceph_msg *msg)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	return le32_to_cpu(msg->hdr.data_len);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic bool need_padding(int len)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	return !IS_ALIGNED(len, CEPH_GCM_BLOCK_LEN);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic int padded_len(int len)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	return ALIGN(len, CEPH_GCM_BLOCK_LEN);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int padding_len(int len)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	return padded_len(len) - len;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/* preamble + control segment */
39062306a36Sopenharmony_cistatic int head_onwire_len(int ctrl_len, bool secure)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int head_len;
39362306a36Sopenharmony_ci	int rem_len;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	BUG_ON(ctrl_len < 0 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (secure) {
39862306a36Sopenharmony_ci		head_len = CEPH_PREAMBLE_SECURE_LEN;
39962306a36Sopenharmony_ci		if (ctrl_len > CEPH_PREAMBLE_INLINE_LEN) {
40062306a36Sopenharmony_ci			rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN;
40162306a36Sopenharmony_ci			head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci	} else {
40462306a36Sopenharmony_ci		head_len = CEPH_PREAMBLE_PLAIN_LEN;
40562306a36Sopenharmony_ci		if (ctrl_len)
40662306a36Sopenharmony_ci			head_len += ctrl_len + CEPH_CRC_LEN;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci	return head_len;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/* front, middle and data segments + epilogue */
41262306a36Sopenharmony_cistatic int __tail_onwire_len(int front_len, int middle_len, int data_len,
41362306a36Sopenharmony_ci			     bool secure)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	BUG_ON(front_len < 0 || front_len > CEPH_MSG_MAX_FRONT_LEN ||
41662306a36Sopenharmony_ci	       middle_len < 0 || middle_len > CEPH_MSG_MAX_MIDDLE_LEN ||
41762306a36Sopenharmony_ci	       data_len < 0 || data_len > CEPH_MSG_MAX_DATA_LEN);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (!front_len && !middle_len && !data_len)
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (!secure)
42362306a36Sopenharmony_ci		return front_len + middle_len + data_len +
42462306a36Sopenharmony_ci		       CEPH_EPILOGUE_PLAIN_LEN;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	return padded_len(front_len) + padded_len(middle_len) +
42762306a36Sopenharmony_ci	       padded_len(data_len) + CEPH_EPILOGUE_SECURE_LEN;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic int tail_onwire_len(const struct ceph_msg *msg, bool secure)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	return __tail_onwire_len(front_len(msg), middle_len(msg),
43362306a36Sopenharmony_ci				 data_len(msg), secure);
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/* head_onwire_len(sizeof(struct ceph_msg_header2), false) */
43762306a36Sopenharmony_ci#define MESSAGE_HEAD_PLAIN_LEN	(CEPH_PREAMBLE_PLAIN_LEN +		\
43862306a36Sopenharmony_ci				 sizeof(struct ceph_msg_header2) +	\
43962306a36Sopenharmony_ci				 CEPH_CRC_LEN)
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic const int frame_aligns[] = {
44262306a36Sopenharmony_ci	sizeof(void *),
44362306a36Sopenharmony_ci	sizeof(void *),
44462306a36Sopenharmony_ci	sizeof(void *),
44562306a36Sopenharmony_ci	PAGE_SIZE
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/*
44962306a36Sopenharmony_ci * Discards trailing empty segments, unless there is just one segment.
45062306a36Sopenharmony_ci * A frame always has at least one (possibly empty) segment.
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cistatic int calc_segment_count(const int *lens, int len_cnt)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	int i;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = len_cnt - 1; i >= 0; i--) {
45762306a36Sopenharmony_ci		if (lens[i])
45862306a36Sopenharmony_ci			return i + 1;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return 1;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void init_frame_desc(struct ceph_frame_desc *desc, int tag,
46562306a36Sopenharmony_ci			    const int *lens, int len_cnt)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	int i;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	memset(desc, 0, sizeof(*desc));
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	desc->fd_tag = tag;
47262306a36Sopenharmony_ci	desc->fd_seg_cnt = calc_segment_count(lens, len_cnt);
47362306a36Sopenharmony_ci	BUG_ON(desc->fd_seg_cnt > CEPH_FRAME_MAX_SEGMENT_COUNT);
47462306a36Sopenharmony_ci	for (i = 0; i < desc->fd_seg_cnt; i++) {
47562306a36Sopenharmony_ci		desc->fd_lens[i] = lens[i];
47662306a36Sopenharmony_ci		desc->fd_aligns[i] = frame_aligns[i];
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/*
48162306a36Sopenharmony_ci * Preamble crc covers everything up to itself (28 bytes) and
48262306a36Sopenharmony_ci * is calculated and verified irrespective of the connection mode
48362306a36Sopenharmony_ci * (i.e. even if the frame is encrypted).
48462306a36Sopenharmony_ci */
48562306a36Sopenharmony_cistatic void encode_preamble(const struct ceph_frame_desc *desc, void *p)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	void *crcp = p + CEPH_PREAMBLE_LEN - CEPH_CRC_LEN;
48862306a36Sopenharmony_ci	void *start = p;
48962306a36Sopenharmony_ci	int i;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	memset(p, 0, CEPH_PREAMBLE_LEN);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ceph_encode_8(&p, desc->fd_tag);
49462306a36Sopenharmony_ci	ceph_encode_8(&p, desc->fd_seg_cnt);
49562306a36Sopenharmony_ci	for (i = 0; i < desc->fd_seg_cnt; i++) {
49662306a36Sopenharmony_ci		ceph_encode_32(&p, desc->fd_lens[i]);
49762306a36Sopenharmony_ci		ceph_encode_16(&p, desc->fd_aligns[i]);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	put_unaligned_le32(crc32c(0, start, crcp - start), crcp);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int decode_preamble(void *p, struct ceph_frame_desc *desc)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	void *crcp = p + CEPH_PREAMBLE_LEN - CEPH_CRC_LEN;
50662306a36Sopenharmony_ci	u32 crc, expected_crc;
50762306a36Sopenharmony_ci	int i;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	crc = crc32c(0, p, crcp - p);
51062306a36Sopenharmony_ci	expected_crc = get_unaligned_le32(crcp);
51162306a36Sopenharmony_ci	if (crc != expected_crc) {
51262306a36Sopenharmony_ci		pr_err("bad preamble crc, calculated %u, expected %u\n",
51362306a36Sopenharmony_ci		       crc, expected_crc);
51462306a36Sopenharmony_ci		return -EBADMSG;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	memset(desc, 0, sizeof(*desc));
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	desc->fd_tag = ceph_decode_8(&p);
52062306a36Sopenharmony_ci	desc->fd_seg_cnt = ceph_decode_8(&p);
52162306a36Sopenharmony_ci	if (desc->fd_seg_cnt < 1 ||
52262306a36Sopenharmony_ci	    desc->fd_seg_cnt > CEPH_FRAME_MAX_SEGMENT_COUNT) {
52362306a36Sopenharmony_ci		pr_err("bad segment count %d\n", desc->fd_seg_cnt);
52462306a36Sopenharmony_ci		return -EINVAL;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci	for (i = 0; i < desc->fd_seg_cnt; i++) {
52762306a36Sopenharmony_ci		desc->fd_lens[i] = ceph_decode_32(&p);
52862306a36Sopenharmony_ci		desc->fd_aligns[i] = ceph_decode_16(&p);
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (desc->fd_lens[0] < 0 ||
53262306a36Sopenharmony_ci	    desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) {
53362306a36Sopenharmony_ci		pr_err("bad control segment length %d\n", desc->fd_lens[0]);
53462306a36Sopenharmony_ci		return -EINVAL;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	if (desc->fd_lens[1] < 0 ||
53762306a36Sopenharmony_ci	    desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
53862306a36Sopenharmony_ci		pr_err("bad front segment length %d\n", desc->fd_lens[1]);
53962306a36Sopenharmony_ci		return -EINVAL;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	if (desc->fd_lens[2] < 0 ||
54262306a36Sopenharmony_ci	    desc->fd_lens[2] > CEPH_MSG_MAX_MIDDLE_LEN) {
54362306a36Sopenharmony_ci		pr_err("bad middle segment length %d\n", desc->fd_lens[2]);
54462306a36Sopenharmony_ci		return -EINVAL;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	if (desc->fd_lens[3] < 0 ||
54762306a36Sopenharmony_ci	    desc->fd_lens[3] > CEPH_MSG_MAX_DATA_LEN) {
54862306a36Sopenharmony_ci		pr_err("bad data segment length %d\n", desc->fd_lens[3]);
54962306a36Sopenharmony_ci		return -EINVAL;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/*
55362306a36Sopenharmony_ci	 * This would fire for FRAME_TAG_WAIT (it has one empty
55462306a36Sopenharmony_ci	 * segment), but we should never get it as client.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	if (!desc->fd_lens[desc->fd_seg_cnt - 1]) {
55762306a36Sopenharmony_ci		pr_err("last segment empty, segment count %d\n",
55862306a36Sopenharmony_ci		       desc->fd_seg_cnt);
55962306a36Sopenharmony_ci		return -EINVAL;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return 0;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void encode_epilogue_plain(struct ceph_connection *con, bool aborted)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	con->v2.out_epil.late_status = aborted ? FRAME_LATE_STATUS_ABORTED :
56862306a36Sopenharmony_ci						 FRAME_LATE_STATUS_COMPLETE;
56962306a36Sopenharmony_ci	cpu_to_le32s(&con->v2.out_epil.front_crc);
57062306a36Sopenharmony_ci	cpu_to_le32s(&con->v2.out_epil.middle_crc);
57162306a36Sopenharmony_ci	cpu_to_le32s(&con->v2.out_epil.data_crc);
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic void encode_epilogue_secure(struct ceph_connection *con, bool aborted)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	memset(&con->v2.out_epil, 0, sizeof(con->v2.out_epil));
57762306a36Sopenharmony_ci	con->v2.out_epil.late_status = aborted ? FRAME_LATE_STATUS_ABORTED :
57862306a36Sopenharmony_ci						 FRAME_LATE_STATUS_COMPLETE;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int decode_epilogue(void *p, u32 *front_crc, u32 *middle_crc,
58262306a36Sopenharmony_ci			   u32 *data_crc)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	u8 late_status;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	late_status = ceph_decode_8(&p);
58762306a36Sopenharmony_ci	if ((late_status & FRAME_LATE_STATUS_ABORTED_MASK) !=
58862306a36Sopenharmony_ci			FRAME_LATE_STATUS_COMPLETE) {
58962306a36Sopenharmony_ci		/* we should never get an aborted message as client */
59062306a36Sopenharmony_ci		pr_err("bad late_status 0x%x\n", late_status);
59162306a36Sopenharmony_ci		return -EINVAL;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (front_crc && middle_crc && data_crc) {
59562306a36Sopenharmony_ci		*front_crc = ceph_decode_32(&p);
59662306a36Sopenharmony_ci		*middle_crc = ceph_decode_32(&p);
59762306a36Sopenharmony_ci		*data_crc = ceph_decode_32(&p);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	return 0;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void fill_header(struct ceph_msg_header *hdr,
60462306a36Sopenharmony_ci			const struct ceph_msg_header2 *hdr2,
60562306a36Sopenharmony_ci			int front_len, int middle_len, int data_len,
60662306a36Sopenharmony_ci			const struct ceph_entity_name *peer_name)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	hdr->seq = hdr2->seq;
60962306a36Sopenharmony_ci	hdr->tid = hdr2->tid;
61062306a36Sopenharmony_ci	hdr->type = hdr2->type;
61162306a36Sopenharmony_ci	hdr->priority = hdr2->priority;
61262306a36Sopenharmony_ci	hdr->version = hdr2->version;
61362306a36Sopenharmony_ci	hdr->front_len = cpu_to_le32(front_len);
61462306a36Sopenharmony_ci	hdr->middle_len = cpu_to_le32(middle_len);
61562306a36Sopenharmony_ci	hdr->data_len = cpu_to_le32(data_len);
61662306a36Sopenharmony_ci	hdr->data_off = hdr2->data_off;
61762306a36Sopenharmony_ci	hdr->src = *peer_name;
61862306a36Sopenharmony_ci	hdr->compat_version = hdr2->compat_version;
61962306a36Sopenharmony_ci	hdr->reserved = 0;
62062306a36Sopenharmony_ci	hdr->crc = 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void fill_header2(struct ceph_msg_header2 *hdr2,
62462306a36Sopenharmony_ci			 const struct ceph_msg_header *hdr, u64 ack_seq)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	hdr2->seq = hdr->seq;
62762306a36Sopenharmony_ci	hdr2->tid = hdr->tid;
62862306a36Sopenharmony_ci	hdr2->type = hdr->type;
62962306a36Sopenharmony_ci	hdr2->priority = hdr->priority;
63062306a36Sopenharmony_ci	hdr2->version = hdr->version;
63162306a36Sopenharmony_ci	hdr2->data_pre_padding_len = 0;
63262306a36Sopenharmony_ci	hdr2->data_off = hdr->data_off;
63362306a36Sopenharmony_ci	hdr2->ack_seq = cpu_to_le64(ack_seq);
63462306a36Sopenharmony_ci	hdr2->flags = 0;
63562306a36Sopenharmony_ci	hdr2->compat_version = hdr->compat_version;
63662306a36Sopenharmony_ci	hdr2->reserved = 0;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic int verify_control_crc(struct ceph_connection *con)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	int ctrl_len = con->v2.in_desc.fd_lens[0];
64262306a36Sopenharmony_ci	u32 crc, expected_crc;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	WARN_ON(con->v2.in_kvecs[0].iov_len != ctrl_len);
64562306a36Sopenharmony_ci	WARN_ON(con->v2.in_kvecs[1].iov_len != CEPH_CRC_LEN);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	crc = crc32c(-1, con->v2.in_kvecs[0].iov_base, ctrl_len);
64862306a36Sopenharmony_ci	expected_crc = get_unaligned_le32(con->v2.in_kvecs[1].iov_base);
64962306a36Sopenharmony_ci	if (crc != expected_crc) {
65062306a36Sopenharmony_ci		pr_err("bad control crc, calculated %u, expected %u\n",
65162306a36Sopenharmony_ci		       crc, expected_crc);
65262306a36Sopenharmony_ci		return -EBADMSG;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return 0;
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int verify_epilogue_crcs(struct ceph_connection *con, u32 front_crc,
65962306a36Sopenharmony_ci				u32 middle_crc, u32 data_crc)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	if (front_len(con->in_msg)) {
66262306a36Sopenharmony_ci		con->in_front_crc = crc32c(-1, con->in_msg->front.iov_base,
66362306a36Sopenharmony_ci					   front_len(con->in_msg));
66462306a36Sopenharmony_ci	} else {
66562306a36Sopenharmony_ci		WARN_ON(!middle_len(con->in_msg) && !data_len(con->in_msg));
66662306a36Sopenharmony_ci		con->in_front_crc = -1;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (middle_len(con->in_msg))
67062306a36Sopenharmony_ci		con->in_middle_crc = crc32c(-1,
67162306a36Sopenharmony_ci					    con->in_msg->middle->vec.iov_base,
67262306a36Sopenharmony_ci					    middle_len(con->in_msg));
67362306a36Sopenharmony_ci	else if (data_len(con->in_msg))
67462306a36Sopenharmony_ci		con->in_middle_crc = -1;
67562306a36Sopenharmony_ci	else
67662306a36Sopenharmony_ci		con->in_middle_crc = 0;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (!data_len(con->in_msg))
67962306a36Sopenharmony_ci		con->in_data_crc = 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	dout("%s con %p msg %p crcs %u %u %u\n", __func__, con, con->in_msg,
68262306a36Sopenharmony_ci	     con->in_front_crc, con->in_middle_crc, con->in_data_crc);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (con->in_front_crc != front_crc) {
68562306a36Sopenharmony_ci		pr_err("bad front crc, calculated %u, expected %u\n",
68662306a36Sopenharmony_ci		       con->in_front_crc, front_crc);
68762306a36Sopenharmony_ci		return -EBADMSG;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci	if (con->in_middle_crc != middle_crc) {
69062306a36Sopenharmony_ci		pr_err("bad middle crc, calculated %u, expected %u\n",
69162306a36Sopenharmony_ci		       con->in_middle_crc, middle_crc);
69262306a36Sopenharmony_ci		return -EBADMSG;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	if (con->in_data_crc != data_crc) {
69562306a36Sopenharmony_ci		pr_err("bad data crc, calculated %u, expected %u\n",
69662306a36Sopenharmony_ci		       con->in_data_crc, data_crc);
69762306a36Sopenharmony_ci		return -EBADMSG;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic int setup_crypto(struct ceph_connection *con,
70462306a36Sopenharmony_ci			const u8 *session_key, int session_key_len,
70562306a36Sopenharmony_ci			const u8 *con_secret, int con_secret_len)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	unsigned int noio_flag;
70862306a36Sopenharmony_ci	int ret;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	dout("%s con %p con_mode %d session_key_len %d con_secret_len %d\n",
71162306a36Sopenharmony_ci	     __func__, con, con->v2.con_mode, session_key_len, con_secret_len);
71262306a36Sopenharmony_ci	WARN_ON(con->v2.hmac_tfm || con->v2.gcm_tfm || con->v2.gcm_req);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (con->v2.con_mode != CEPH_CON_MODE_CRC &&
71562306a36Sopenharmony_ci	    con->v2.con_mode != CEPH_CON_MODE_SECURE) {
71662306a36Sopenharmony_ci		pr_err("bad con_mode %d\n", con->v2.con_mode);
71762306a36Sopenharmony_ci		return -EINVAL;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (!session_key_len) {
72162306a36Sopenharmony_ci		WARN_ON(con->v2.con_mode != CEPH_CON_MODE_CRC);
72262306a36Sopenharmony_ci		WARN_ON(con_secret_len);
72362306a36Sopenharmony_ci		return 0;  /* auth_none */
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	noio_flag = memalloc_noio_save();
72762306a36Sopenharmony_ci	con->v2.hmac_tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
72862306a36Sopenharmony_ci	memalloc_noio_restore(noio_flag);
72962306a36Sopenharmony_ci	if (IS_ERR(con->v2.hmac_tfm)) {
73062306a36Sopenharmony_ci		ret = PTR_ERR(con->v2.hmac_tfm);
73162306a36Sopenharmony_ci		con->v2.hmac_tfm = NULL;
73262306a36Sopenharmony_ci		pr_err("failed to allocate hmac tfm context: %d\n", ret);
73362306a36Sopenharmony_ci		return ret;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	WARN_ON((unsigned long)session_key &
73762306a36Sopenharmony_ci		crypto_shash_alignmask(con->v2.hmac_tfm));
73862306a36Sopenharmony_ci	ret = crypto_shash_setkey(con->v2.hmac_tfm, session_key,
73962306a36Sopenharmony_ci				  session_key_len);
74062306a36Sopenharmony_ci	if (ret) {
74162306a36Sopenharmony_ci		pr_err("failed to set hmac key: %d\n", ret);
74262306a36Sopenharmony_ci		return ret;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (con->v2.con_mode == CEPH_CON_MODE_CRC) {
74662306a36Sopenharmony_ci		WARN_ON(con_secret_len);
74762306a36Sopenharmony_ci		return 0;  /* auth_x, plain mode */
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (con_secret_len < CEPH_GCM_KEY_LEN + 2 * CEPH_GCM_IV_LEN) {
75162306a36Sopenharmony_ci		pr_err("con_secret too small %d\n", con_secret_len);
75262306a36Sopenharmony_ci		return -EINVAL;
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	noio_flag = memalloc_noio_save();
75662306a36Sopenharmony_ci	con->v2.gcm_tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
75762306a36Sopenharmony_ci	memalloc_noio_restore(noio_flag);
75862306a36Sopenharmony_ci	if (IS_ERR(con->v2.gcm_tfm)) {
75962306a36Sopenharmony_ci		ret = PTR_ERR(con->v2.gcm_tfm);
76062306a36Sopenharmony_ci		con->v2.gcm_tfm = NULL;
76162306a36Sopenharmony_ci		pr_err("failed to allocate gcm tfm context: %d\n", ret);
76262306a36Sopenharmony_ci		return ret;
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	WARN_ON((unsigned long)con_secret &
76662306a36Sopenharmony_ci		crypto_aead_alignmask(con->v2.gcm_tfm));
76762306a36Sopenharmony_ci	ret = crypto_aead_setkey(con->v2.gcm_tfm, con_secret, CEPH_GCM_KEY_LEN);
76862306a36Sopenharmony_ci	if (ret) {
76962306a36Sopenharmony_ci		pr_err("failed to set gcm key: %d\n", ret);
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	WARN_ON(crypto_aead_ivsize(con->v2.gcm_tfm) != CEPH_GCM_IV_LEN);
77462306a36Sopenharmony_ci	ret = crypto_aead_setauthsize(con->v2.gcm_tfm, CEPH_GCM_TAG_LEN);
77562306a36Sopenharmony_ci	if (ret) {
77662306a36Sopenharmony_ci		pr_err("failed to set gcm tag size: %d\n", ret);
77762306a36Sopenharmony_ci		return ret;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	con->v2.gcm_req = aead_request_alloc(con->v2.gcm_tfm, GFP_NOIO);
78162306a36Sopenharmony_ci	if (!con->v2.gcm_req) {
78262306a36Sopenharmony_ci		pr_err("failed to allocate gcm request\n");
78362306a36Sopenharmony_ci		return -ENOMEM;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	crypto_init_wait(&con->v2.gcm_wait);
78762306a36Sopenharmony_ci	aead_request_set_callback(con->v2.gcm_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
78862306a36Sopenharmony_ci				  crypto_req_done, &con->v2.gcm_wait);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	memcpy(&con->v2.in_gcm_nonce, con_secret + CEPH_GCM_KEY_LEN,
79162306a36Sopenharmony_ci	       CEPH_GCM_IV_LEN);
79262306a36Sopenharmony_ci	memcpy(&con->v2.out_gcm_nonce,
79362306a36Sopenharmony_ci	       con_secret + CEPH_GCM_KEY_LEN + CEPH_GCM_IV_LEN,
79462306a36Sopenharmony_ci	       CEPH_GCM_IV_LEN);
79562306a36Sopenharmony_ci	return 0;  /* auth_x, secure mode */
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs,
79962306a36Sopenharmony_ci		       int kvec_cnt, u8 *hmac)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(desc, con->v2.hmac_tfm);  /* tfm arg is ignored */
80262306a36Sopenharmony_ci	int ret;
80362306a36Sopenharmony_ci	int i;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	dout("%s con %p hmac_tfm %p kvec_cnt %d\n", __func__, con,
80662306a36Sopenharmony_ci	     con->v2.hmac_tfm, kvec_cnt);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (!con->v2.hmac_tfm) {
80962306a36Sopenharmony_ci		memset(hmac, 0, SHA256_DIGEST_SIZE);
81062306a36Sopenharmony_ci		return 0;  /* auth_none */
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	desc->tfm = con->v2.hmac_tfm;
81462306a36Sopenharmony_ci	ret = crypto_shash_init(desc);
81562306a36Sopenharmony_ci	if (ret)
81662306a36Sopenharmony_ci		goto out;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	for (i = 0; i < kvec_cnt; i++) {
81962306a36Sopenharmony_ci		WARN_ON((unsigned long)kvecs[i].iov_base &
82062306a36Sopenharmony_ci			crypto_shash_alignmask(con->v2.hmac_tfm));
82162306a36Sopenharmony_ci		ret = crypto_shash_update(desc, kvecs[i].iov_base,
82262306a36Sopenharmony_ci					  kvecs[i].iov_len);
82362306a36Sopenharmony_ci		if (ret)
82462306a36Sopenharmony_ci			goto out;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ret = crypto_shash_final(desc, hmac);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ciout:
83062306a36Sopenharmony_ci	shash_desc_zero(desc);
83162306a36Sopenharmony_ci	return ret;  /* auth_x, both plain and secure modes */
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic void gcm_inc_nonce(struct ceph_gcm_nonce *nonce)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	u64 counter;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	counter = le64_to_cpu(nonce->counter);
83962306a36Sopenharmony_ci	nonce->counter = cpu_to_le64(counter + 1);
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic int gcm_crypt(struct ceph_connection *con, bool encrypt,
84362306a36Sopenharmony_ci		     struct scatterlist *src, struct scatterlist *dst,
84462306a36Sopenharmony_ci		     int src_len)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct ceph_gcm_nonce *nonce;
84762306a36Sopenharmony_ci	int ret;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	nonce = encrypt ? &con->v2.out_gcm_nonce : &con->v2.in_gcm_nonce;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	aead_request_set_ad(con->v2.gcm_req, 0);  /* no AAD */
85262306a36Sopenharmony_ci	aead_request_set_crypt(con->v2.gcm_req, src, dst, src_len, (u8 *)nonce);
85362306a36Sopenharmony_ci	ret = crypto_wait_req(encrypt ? crypto_aead_encrypt(con->v2.gcm_req) :
85462306a36Sopenharmony_ci					crypto_aead_decrypt(con->v2.gcm_req),
85562306a36Sopenharmony_ci			      &con->v2.gcm_wait);
85662306a36Sopenharmony_ci	if (ret)
85762306a36Sopenharmony_ci		return ret;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	gcm_inc_nonce(nonce);
86062306a36Sopenharmony_ci	return 0;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic void get_bvec_at(struct ceph_msg_data_cursor *cursor,
86462306a36Sopenharmony_ci			struct bio_vec *bv)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct page *page;
86762306a36Sopenharmony_ci	size_t off, len;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	WARN_ON(!cursor->total_resid);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* skip zero-length data items */
87262306a36Sopenharmony_ci	while (!cursor->resid)
87362306a36Sopenharmony_ci		ceph_msg_data_advance(cursor, 0);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	/* get a piece of data, cursor isn't advanced */
87662306a36Sopenharmony_ci	page = ceph_msg_data_next(cursor, &off, &len);
87762306a36Sopenharmony_ci	bvec_set_page(bv, page, len, off);
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int calc_sg_cnt(void *buf, int buf_len)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	int sg_cnt;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	if (!buf_len)
88562306a36Sopenharmony_ci		return 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	sg_cnt = need_padding(buf_len) ? 1 : 0;
88862306a36Sopenharmony_ci	if (is_vmalloc_addr(buf)) {
88962306a36Sopenharmony_ci		WARN_ON(offset_in_page(buf));
89062306a36Sopenharmony_ci		sg_cnt += PAGE_ALIGN(buf_len) >> PAGE_SHIFT;
89162306a36Sopenharmony_ci	} else {
89262306a36Sopenharmony_ci		sg_cnt++;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return sg_cnt;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic int calc_sg_cnt_cursor(struct ceph_msg_data_cursor *cursor)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	int data_len = cursor->total_resid;
90162306a36Sopenharmony_ci	struct bio_vec bv;
90262306a36Sopenharmony_ci	int sg_cnt;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (!data_len)
90562306a36Sopenharmony_ci		return 0;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	sg_cnt = need_padding(data_len) ? 1 : 0;
90862306a36Sopenharmony_ci	do {
90962306a36Sopenharmony_ci		get_bvec_at(cursor, &bv);
91062306a36Sopenharmony_ci		sg_cnt++;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		ceph_msg_data_advance(cursor, bv.bv_len);
91362306a36Sopenharmony_ci	} while (cursor->total_resid);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	return sg_cnt;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic void init_sgs(struct scatterlist **sg, void *buf, int buf_len, u8 *pad)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	void *end = buf + buf_len;
92162306a36Sopenharmony_ci	struct page *page;
92262306a36Sopenharmony_ci	int len;
92362306a36Sopenharmony_ci	void *p;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (!buf_len)
92662306a36Sopenharmony_ci		return;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (is_vmalloc_addr(buf)) {
92962306a36Sopenharmony_ci		p = buf;
93062306a36Sopenharmony_ci		do {
93162306a36Sopenharmony_ci			page = vmalloc_to_page(p);
93262306a36Sopenharmony_ci			len = min_t(int, end - p, PAGE_SIZE);
93362306a36Sopenharmony_ci			WARN_ON(!page || !len || offset_in_page(p));
93462306a36Sopenharmony_ci			sg_set_page(*sg, page, len, 0);
93562306a36Sopenharmony_ci			*sg = sg_next(*sg);
93662306a36Sopenharmony_ci			p += len;
93762306a36Sopenharmony_ci		} while (p != end);
93862306a36Sopenharmony_ci	} else {
93962306a36Sopenharmony_ci		sg_set_buf(*sg, buf, buf_len);
94062306a36Sopenharmony_ci		*sg = sg_next(*sg);
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (need_padding(buf_len)) {
94462306a36Sopenharmony_ci		sg_set_buf(*sg, pad, padding_len(buf_len));
94562306a36Sopenharmony_ci		*sg = sg_next(*sg);
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void init_sgs_cursor(struct scatterlist **sg,
95062306a36Sopenharmony_ci			    struct ceph_msg_data_cursor *cursor, u8 *pad)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	int data_len = cursor->total_resid;
95362306a36Sopenharmony_ci	struct bio_vec bv;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!data_len)
95662306a36Sopenharmony_ci		return;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	do {
95962306a36Sopenharmony_ci		get_bvec_at(cursor, &bv);
96062306a36Sopenharmony_ci		sg_set_page(*sg, bv.bv_page, bv.bv_len, bv.bv_offset);
96162306a36Sopenharmony_ci		*sg = sg_next(*sg);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		ceph_msg_data_advance(cursor, bv.bv_len);
96462306a36Sopenharmony_ci	} while (cursor->total_resid);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (need_padding(data_len)) {
96762306a36Sopenharmony_ci		sg_set_buf(*sg, pad, padding_len(data_len));
96862306a36Sopenharmony_ci		*sg = sg_next(*sg);
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci/**
97362306a36Sopenharmony_ci * init_sgs_pages: set up scatterlist on an array of page pointers
97462306a36Sopenharmony_ci * @sg:		scatterlist to populate
97562306a36Sopenharmony_ci * @pages:	pointer to page array
97662306a36Sopenharmony_ci * @dpos:	position in the array to start (bytes)
97762306a36Sopenharmony_ci * @dlen:	len to add to sg (bytes)
97862306a36Sopenharmony_ci * @pad:	pointer to pad destination (if any)
97962306a36Sopenharmony_ci *
98062306a36Sopenharmony_ci * Populate the scatterlist from the page array, starting at an arbitrary
98162306a36Sopenharmony_ci * byte in the array and running for a specified length.
98262306a36Sopenharmony_ci */
98362306a36Sopenharmony_cistatic void init_sgs_pages(struct scatterlist **sg, struct page **pages,
98462306a36Sopenharmony_ci			   int dpos, int dlen, u8 *pad)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	int idx = dpos >> PAGE_SHIFT;
98762306a36Sopenharmony_ci	int off = offset_in_page(dpos);
98862306a36Sopenharmony_ci	int resid = dlen;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	do {
99162306a36Sopenharmony_ci		int len = min(resid, (int)PAGE_SIZE - off);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		sg_set_page(*sg, pages[idx], len, off);
99462306a36Sopenharmony_ci		*sg = sg_next(*sg);
99562306a36Sopenharmony_ci		off = 0;
99662306a36Sopenharmony_ci		++idx;
99762306a36Sopenharmony_ci		resid -= len;
99862306a36Sopenharmony_ci	} while (resid);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (need_padding(dlen)) {
100162306a36Sopenharmony_ci		sg_set_buf(*sg, pad, padding_len(dlen));
100262306a36Sopenharmony_ci		*sg = sg_next(*sg);
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic int setup_message_sgs(struct sg_table *sgt, struct ceph_msg *msg,
100762306a36Sopenharmony_ci			     u8 *front_pad, u8 *middle_pad, u8 *data_pad,
100862306a36Sopenharmony_ci			     void *epilogue, struct page **pages, int dpos,
100962306a36Sopenharmony_ci			     bool add_tag)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct ceph_msg_data_cursor cursor;
101262306a36Sopenharmony_ci	struct scatterlist *cur_sg;
101362306a36Sopenharmony_ci	int dlen = data_len(msg);
101462306a36Sopenharmony_ci	int sg_cnt;
101562306a36Sopenharmony_ci	int ret;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
101862306a36Sopenharmony_ci		return 0;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	sg_cnt = 1;  /* epilogue + [auth tag] */
102162306a36Sopenharmony_ci	if (front_len(msg))
102262306a36Sopenharmony_ci		sg_cnt += calc_sg_cnt(msg->front.iov_base,
102362306a36Sopenharmony_ci				      front_len(msg));
102462306a36Sopenharmony_ci	if (middle_len(msg))
102562306a36Sopenharmony_ci		sg_cnt += calc_sg_cnt(msg->middle->vec.iov_base,
102662306a36Sopenharmony_ci				      middle_len(msg));
102762306a36Sopenharmony_ci	if (dlen) {
102862306a36Sopenharmony_ci		if (pages) {
102962306a36Sopenharmony_ci			sg_cnt += calc_pages_for(dpos, dlen);
103062306a36Sopenharmony_ci			if (need_padding(dlen))
103162306a36Sopenharmony_ci				sg_cnt++;
103262306a36Sopenharmony_ci		} else {
103362306a36Sopenharmony_ci			ceph_msg_data_cursor_init(&cursor, msg, dlen);
103462306a36Sopenharmony_ci			sg_cnt += calc_sg_cnt_cursor(&cursor);
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ret = sg_alloc_table(sgt, sg_cnt, GFP_NOIO);
103962306a36Sopenharmony_ci	if (ret)
104062306a36Sopenharmony_ci		return ret;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	cur_sg = sgt->sgl;
104362306a36Sopenharmony_ci	if (front_len(msg))
104462306a36Sopenharmony_ci		init_sgs(&cur_sg, msg->front.iov_base, front_len(msg),
104562306a36Sopenharmony_ci			 front_pad);
104662306a36Sopenharmony_ci	if (middle_len(msg))
104762306a36Sopenharmony_ci		init_sgs(&cur_sg, msg->middle->vec.iov_base, middle_len(msg),
104862306a36Sopenharmony_ci			 middle_pad);
104962306a36Sopenharmony_ci	if (dlen) {
105062306a36Sopenharmony_ci		if (pages) {
105162306a36Sopenharmony_ci			init_sgs_pages(&cur_sg, pages, dpos, dlen, data_pad);
105262306a36Sopenharmony_ci		} else {
105362306a36Sopenharmony_ci			ceph_msg_data_cursor_init(&cursor, msg, dlen);
105462306a36Sopenharmony_ci			init_sgs_cursor(&cur_sg, &cursor, data_pad);
105562306a36Sopenharmony_ci		}
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	WARN_ON(!sg_is_last(cur_sg));
105962306a36Sopenharmony_ci	sg_set_buf(cur_sg, epilogue,
106062306a36Sopenharmony_ci		   CEPH_GCM_BLOCK_LEN + (add_tag ? CEPH_GCM_TAG_LEN : 0));
106162306a36Sopenharmony_ci	return 0;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int decrypt_preamble(struct ceph_connection *con)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct scatterlist sg;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	sg_init_one(&sg, con->v2.in_buf, CEPH_PREAMBLE_SECURE_LEN);
106962306a36Sopenharmony_ci	return gcm_crypt(con, false, &sg, &sg, CEPH_PREAMBLE_SECURE_LEN);
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic int decrypt_control_remainder(struct ceph_connection *con)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	int ctrl_len = con->v2.in_desc.fd_lens[0];
107562306a36Sopenharmony_ci	int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN;
107662306a36Sopenharmony_ci	int pt_len = padding_len(rem_len) + CEPH_GCM_TAG_LEN;
107762306a36Sopenharmony_ci	struct scatterlist sgs[2];
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	WARN_ON(con->v2.in_kvecs[0].iov_len != rem_len);
108062306a36Sopenharmony_ci	WARN_ON(con->v2.in_kvecs[1].iov_len != pt_len);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	sg_init_table(sgs, 2);
108362306a36Sopenharmony_ci	sg_set_buf(&sgs[0], con->v2.in_kvecs[0].iov_base, rem_len);
108462306a36Sopenharmony_ci	sg_set_buf(&sgs[1], con->v2.in_buf, pt_len);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	return gcm_crypt(con, false, sgs, sgs,
108762306a36Sopenharmony_ci			 padded_len(rem_len) + CEPH_GCM_TAG_LEN);
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci/* Process sparse read data that lives in a buffer */
109162306a36Sopenharmony_cistatic int process_v2_sparse_read(struct ceph_connection *con,
109262306a36Sopenharmony_ci				  struct page **pages, int spos)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	struct ceph_msg_data_cursor *cursor = &con->v2.in_cursor;
109562306a36Sopenharmony_ci	int ret;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	for (;;) {
109862306a36Sopenharmony_ci		char *buf = NULL;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		ret = con->ops->sparse_read(con, cursor, &buf);
110162306a36Sopenharmony_ci		if (ret <= 0)
110262306a36Sopenharmony_ci			return ret;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci		dout("%s: sparse_read return %x buf %p\n", __func__, ret, buf);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		do {
110762306a36Sopenharmony_ci			int idx = spos >> PAGE_SHIFT;
110862306a36Sopenharmony_ci			int soff = offset_in_page(spos);
110962306a36Sopenharmony_ci			struct page *spage = con->v2.in_enc_pages[idx];
111062306a36Sopenharmony_ci			int len = min_t(int, ret, PAGE_SIZE - soff);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci			if (buf) {
111362306a36Sopenharmony_ci				memcpy_from_page(buf, spage, soff, len);
111462306a36Sopenharmony_ci				buf += len;
111562306a36Sopenharmony_ci			} else {
111662306a36Sopenharmony_ci				struct bio_vec bv;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci				get_bvec_at(cursor, &bv);
111962306a36Sopenharmony_ci				len = min_t(int, len, bv.bv_len);
112062306a36Sopenharmony_ci				memcpy_page(bv.bv_page, bv.bv_offset,
112162306a36Sopenharmony_ci					    spage, soff, len);
112262306a36Sopenharmony_ci				ceph_msg_data_advance(cursor, len);
112362306a36Sopenharmony_ci			}
112462306a36Sopenharmony_ci			spos += len;
112562306a36Sopenharmony_ci			ret -= len;
112662306a36Sopenharmony_ci		} while (ret);
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic int decrypt_tail(struct ceph_connection *con)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct sg_table enc_sgt = {};
113362306a36Sopenharmony_ci	struct sg_table sgt = {};
113462306a36Sopenharmony_ci	struct page **pages = NULL;
113562306a36Sopenharmony_ci	bool sparse = !!con->in_msg->sparse_read_total;
113662306a36Sopenharmony_ci	int dpos = 0;
113762306a36Sopenharmony_ci	int tail_len;
113862306a36Sopenharmony_ci	int ret;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	tail_len = tail_onwire_len(con->in_msg, true);
114162306a36Sopenharmony_ci	ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
114262306a36Sopenharmony_ci					con->v2.in_enc_page_cnt, 0, tail_len,
114362306a36Sopenharmony_ci					GFP_NOIO);
114462306a36Sopenharmony_ci	if (ret)
114562306a36Sopenharmony_ci		goto out;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	if (sparse) {
114862306a36Sopenharmony_ci		dpos = padded_len(front_len(con->in_msg) + padded_len(middle_len(con->in_msg)));
114962306a36Sopenharmony_ci		pages = con->v2.in_enc_pages;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
115362306a36Sopenharmony_ci				MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
115462306a36Sopenharmony_ci				con->v2.in_buf, pages, dpos, true);
115562306a36Sopenharmony_ci	if (ret)
115662306a36Sopenharmony_ci		goto out;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
115962306a36Sopenharmony_ci	     con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
116062306a36Sopenharmony_ci	ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
116162306a36Sopenharmony_ci	if (ret)
116262306a36Sopenharmony_ci		goto out;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (sparse && data_len(con->in_msg)) {
116562306a36Sopenharmony_ci		ret = process_v2_sparse_read(con, con->v2.in_enc_pages, dpos);
116662306a36Sopenharmony_ci		if (ret)
116762306a36Sopenharmony_ci			goto out;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	WARN_ON(!con->v2.in_enc_page_cnt);
117162306a36Sopenharmony_ci	ceph_release_page_vector(con->v2.in_enc_pages,
117262306a36Sopenharmony_ci				 con->v2.in_enc_page_cnt);
117362306a36Sopenharmony_ci	con->v2.in_enc_pages = NULL;
117462306a36Sopenharmony_ci	con->v2.in_enc_page_cnt = 0;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ciout:
117762306a36Sopenharmony_ci	sg_free_table(&sgt);
117862306a36Sopenharmony_ci	sg_free_table(&enc_sgt);
117962306a36Sopenharmony_ci	return ret;
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic int prepare_banner(struct ceph_connection *con)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	int buf_len = CEPH_BANNER_V2_LEN + 2 + 8 + 8;
118562306a36Sopenharmony_ci	void *buf, *p;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	buf = alloc_conn_buf(con, buf_len);
118862306a36Sopenharmony_ci	if (!buf)
118962306a36Sopenharmony_ci		return -ENOMEM;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	p = buf;
119262306a36Sopenharmony_ci	ceph_encode_copy(&p, CEPH_BANNER_V2, CEPH_BANNER_V2_LEN);
119362306a36Sopenharmony_ci	ceph_encode_16(&p, sizeof(u64) + sizeof(u64));
119462306a36Sopenharmony_ci	ceph_encode_64(&p, CEPH_MSGR2_SUPPORTED_FEATURES);
119562306a36Sopenharmony_ci	ceph_encode_64(&p, CEPH_MSGR2_REQUIRED_FEATURES);
119662306a36Sopenharmony_ci	WARN_ON(p != buf + buf_len);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	add_out_kvec(con, buf, buf_len);
119962306a36Sopenharmony_ci	add_out_sign_kvec(con, buf, buf_len);
120062306a36Sopenharmony_ci	ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING);
120162306a36Sopenharmony_ci	return 0;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci/*
120562306a36Sopenharmony_ci * base:
120662306a36Sopenharmony_ci *   preamble
120762306a36Sopenharmony_ci *   control body (ctrl_len bytes)
120862306a36Sopenharmony_ci *   space for control crc
120962306a36Sopenharmony_ci *
121062306a36Sopenharmony_ci * extdata (optional):
121162306a36Sopenharmony_ci *   control body (extdata_len bytes)
121262306a36Sopenharmony_ci *
121362306a36Sopenharmony_ci * Compute control crc and gather base and extdata into:
121462306a36Sopenharmony_ci *
121562306a36Sopenharmony_ci *   preamble
121662306a36Sopenharmony_ci *   control body (ctrl_len + extdata_len bytes)
121762306a36Sopenharmony_ci *   control crc
121862306a36Sopenharmony_ci *
121962306a36Sopenharmony_ci * Preamble should already be encoded at the start of base.
122062306a36Sopenharmony_ci */
122162306a36Sopenharmony_cistatic void prepare_head_plain(struct ceph_connection *con, void *base,
122262306a36Sopenharmony_ci			       int ctrl_len, void *extdata, int extdata_len,
122362306a36Sopenharmony_ci			       bool to_be_signed)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	int base_len = CEPH_PREAMBLE_LEN + ctrl_len + CEPH_CRC_LEN;
122662306a36Sopenharmony_ci	void *crcp = base + base_len - CEPH_CRC_LEN;
122762306a36Sopenharmony_ci	u32 crc;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	crc = crc32c(-1, CTRL_BODY(base), ctrl_len);
123062306a36Sopenharmony_ci	if (extdata_len)
123162306a36Sopenharmony_ci		crc = crc32c(crc, extdata, extdata_len);
123262306a36Sopenharmony_ci	put_unaligned_le32(crc, crcp);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	if (!extdata_len) {
123562306a36Sopenharmony_ci		add_out_kvec(con, base, base_len);
123662306a36Sopenharmony_ci		if (to_be_signed)
123762306a36Sopenharmony_ci			add_out_sign_kvec(con, base, base_len);
123862306a36Sopenharmony_ci		return;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	add_out_kvec(con, base, crcp - base);
124262306a36Sopenharmony_ci	add_out_kvec(con, extdata, extdata_len);
124362306a36Sopenharmony_ci	add_out_kvec(con, crcp, CEPH_CRC_LEN);
124462306a36Sopenharmony_ci	if (to_be_signed) {
124562306a36Sopenharmony_ci		add_out_sign_kvec(con, base, crcp - base);
124662306a36Sopenharmony_ci		add_out_sign_kvec(con, extdata, extdata_len);
124762306a36Sopenharmony_ci		add_out_sign_kvec(con, crcp, CEPH_CRC_LEN);
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int prepare_head_secure_small(struct ceph_connection *con,
125262306a36Sopenharmony_ci				     void *base, int ctrl_len)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct scatterlist sg;
125562306a36Sopenharmony_ci	int ret;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	/* inline buffer padding? */
125862306a36Sopenharmony_ci	if (ctrl_len < CEPH_PREAMBLE_INLINE_LEN)
125962306a36Sopenharmony_ci		memset(CTRL_BODY(base) + ctrl_len, 0,
126062306a36Sopenharmony_ci		       CEPH_PREAMBLE_INLINE_LEN - ctrl_len);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	sg_init_one(&sg, base, CEPH_PREAMBLE_SECURE_LEN);
126362306a36Sopenharmony_ci	ret = gcm_crypt(con, true, &sg, &sg,
126462306a36Sopenharmony_ci			CEPH_PREAMBLE_SECURE_LEN - CEPH_GCM_TAG_LEN);
126562306a36Sopenharmony_ci	if (ret)
126662306a36Sopenharmony_ci		return ret;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	add_out_kvec(con, base, CEPH_PREAMBLE_SECURE_LEN);
126962306a36Sopenharmony_ci	return 0;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/*
127362306a36Sopenharmony_ci * base:
127462306a36Sopenharmony_ci *   preamble
127562306a36Sopenharmony_ci *   control body (ctrl_len bytes)
127662306a36Sopenharmony_ci *   space for padding, if needed
127762306a36Sopenharmony_ci *   space for control remainder auth tag
127862306a36Sopenharmony_ci *   space for preamble auth tag
127962306a36Sopenharmony_ci *
128062306a36Sopenharmony_ci * Encrypt preamble and the inline portion, then encrypt the remainder
128162306a36Sopenharmony_ci * and gather into:
128262306a36Sopenharmony_ci *
128362306a36Sopenharmony_ci *   preamble
128462306a36Sopenharmony_ci *   control body (48 bytes)
128562306a36Sopenharmony_ci *   preamble auth tag
128662306a36Sopenharmony_ci *   control body (ctrl_len - 48 bytes)
128762306a36Sopenharmony_ci *   zero padding, if needed
128862306a36Sopenharmony_ci *   control remainder auth tag
128962306a36Sopenharmony_ci *
129062306a36Sopenharmony_ci * Preamble should already be encoded at the start of base.
129162306a36Sopenharmony_ci */
129262306a36Sopenharmony_cistatic int prepare_head_secure_big(struct ceph_connection *con,
129362306a36Sopenharmony_ci				   void *base, int ctrl_len)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN;
129662306a36Sopenharmony_ci	void *rem = CTRL_BODY(base) + CEPH_PREAMBLE_INLINE_LEN;
129762306a36Sopenharmony_ci	void *rem_tag = rem + padded_len(rem_len);
129862306a36Sopenharmony_ci	void *pmbl_tag = rem_tag + CEPH_GCM_TAG_LEN;
129962306a36Sopenharmony_ci	struct scatterlist sgs[2];
130062306a36Sopenharmony_ci	int ret;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	sg_init_table(sgs, 2);
130362306a36Sopenharmony_ci	sg_set_buf(&sgs[0], base, rem - base);
130462306a36Sopenharmony_ci	sg_set_buf(&sgs[1], pmbl_tag, CEPH_GCM_TAG_LEN);
130562306a36Sopenharmony_ci	ret = gcm_crypt(con, true, sgs, sgs, rem - base);
130662306a36Sopenharmony_ci	if (ret)
130762306a36Sopenharmony_ci		return ret;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	/* control remainder padding? */
131062306a36Sopenharmony_ci	if (need_padding(rem_len))
131162306a36Sopenharmony_ci		memset(rem + rem_len, 0, padding_len(rem_len));
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	sg_init_one(&sgs[0], rem, pmbl_tag - rem);
131462306a36Sopenharmony_ci	ret = gcm_crypt(con, true, sgs, sgs, rem_tag - rem);
131562306a36Sopenharmony_ci	if (ret)
131662306a36Sopenharmony_ci		return ret;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	add_out_kvec(con, base, rem - base);
131962306a36Sopenharmony_ci	add_out_kvec(con, pmbl_tag, CEPH_GCM_TAG_LEN);
132062306a36Sopenharmony_ci	add_out_kvec(con, rem, pmbl_tag - rem);
132162306a36Sopenharmony_ci	return 0;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic int __prepare_control(struct ceph_connection *con, int tag,
132562306a36Sopenharmony_ci			     void *base, int ctrl_len, void *extdata,
132662306a36Sopenharmony_ci			     int extdata_len, bool to_be_signed)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	int total_len = ctrl_len + extdata_len;
132962306a36Sopenharmony_ci	struct ceph_frame_desc desc;
133062306a36Sopenharmony_ci	int ret;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	dout("%s con %p tag %d len %d (%d+%d)\n", __func__, con, tag,
133362306a36Sopenharmony_ci	     total_len, ctrl_len, extdata_len);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	/* extdata may be vmalloc'ed but not base */
133662306a36Sopenharmony_ci	if (WARN_ON(is_vmalloc_addr(base) || !ctrl_len))
133762306a36Sopenharmony_ci		return -EINVAL;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	init_frame_desc(&desc, tag, &total_len, 1);
134062306a36Sopenharmony_ci	encode_preamble(&desc, base);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (con_secure(con)) {
134362306a36Sopenharmony_ci		if (WARN_ON(extdata_len || to_be_signed))
134462306a36Sopenharmony_ci			return -EINVAL;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci		if (ctrl_len <= CEPH_PREAMBLE_INLINE_LEN)
134762306a36Sopenharmony_ci			/* fully inlined, inline buffer may need padding */
134862306a36Sopenharmony_ci			ret = prepare_head_secure_small(con, base, ctrl_len);
134962306a36Sopenharmony_ci		else
135062306a36Sopenharmony_ci			/* partially inlined, inline buffer is full */
135162306a36Sopenharmony_ci			ret = prepare_head_secure_big(con, base, ctrl_len);
135262306a36Sopenharmony_ci		if (ret)
135362306a36Sopenharmony_ci			return ret;
135462306a36Sopenharmony_ci	} else {
135562306a36Sopenharmony_ci		prepare_head_plain(con, base, ctrl_len, extdata, extdata_len,
135662306a36Sopenharmony_ci				   to_be_signed);
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING);
136062306a36Sopenharmony_ci	return 0;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cistatic int prepare_control(struct ceph_connection *con, int tag,
136462306a36Sopenharmony_ci			   void *base, int ctrl_len)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	return __prepare_control(con, tag, base, ctrl_len, NULL, 0, false);
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic int prepare_hello(struct ceph_connection *con)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	void *buf, *p;
137262306a36Sopenharmony_ci	int ctrl_len;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	ctrl_len = 1 + ceph_entity_addr_encoding_len(&con->peer_addr);
137562306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false));
137662306a36Sopenharmony_ci	if (!buf)
137762306a36Sopenharmony_ci		return -ENOMEM;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	p = CTRL_BODY(buf);
138062306a36Sopenharmony_ci	ceph_encode_8(&p, CEPH_ENTITY_TYPE_CLIENT);
138162306a36Sopenharmony_ci	ceph_encode_entity_addr(&p, &con->peer_addr);
138262306a36Sopenharmony_ci	WARN_ON(p != CTRL_BODY(buf) + ctrl_len);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	return __prepare_control(con, FRAME_TAG_HELLO, buf, ctrl_len,
138562306a36Sopenharmony_ci				 NULL, 0, true);
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci/* so that head_onwire_len(AUTH_BUF_LEN, false) is 512 */
138962306a36Sopenharmony_ci#define AUTH_BUF_LEN	(512 - CEPH_CRC_LEN - CEPH_PREAMBLE_PLAIN_LEN)
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic int prepare_auth_request(struct ceph_connection *con)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	void *authorizer, *authorizer_copy;
139462306a36Sopenharmony_ci	int ctrl_len, authorizer_len;
139562306a36Sopenharmony_ci	void *buf;
139662306a36Sopenharmony_ci	int ret;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	ctrl_len = AUTH_BUF_LEN;
139962306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false));
140062306a36Sopenharmony_ci	if (!buf)
140162306a36Sopenharmony_ci		return -ENOMEM;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	mutex_unlock(&con->mutex);
140462306a36Sopenharmony_ci	ret = con->ops->get_auth_request(con, CTRL_BODY(buf), &ctrl_len,
140562306a36Sopenharmony_ci					 &authorizer, &authorizer_len);
140662306a36Sopenharmony_ci	mutex_lock(&con->mutex);
140762306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_HELLO) {
140862306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
140962306a36Sopenharmony_ci		     con->state);
141062306a36Sopenharmony_ci		return -EAGAIN;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	dout("%s con %p get_auth_request ret %d\n", __func__, con, ret);
141462306a36Sopenharmony_ci	if (ret)
141562306a36Sopenharmony_ci		return ret;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	authorizer_copy = alloc_conn_buf(con, authorizer_len);
141862306a36Sopenharmony_ci	if (!authorizer_copy)
141962306a36Sopenharmony_ci		return -ENOMEM;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	memcpy(authorizer_copy, authorizer, authorizer_len);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	return __prepare_control(con, FRAME_TAG_AUTH_REQUEST, buf, ctrl_len,
142462306a36Sopenharmony_ci				 authorizer_copy, authorizer_len, true);
142562306a36Sopenharmony_ci}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_cistatic int prepare_auth_request_more(struct ceph_connection *con,
142862306a36Sopenharmony_ci				     void *reply, int reply_len)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	int ctrl_len, authorizer_len;
143162306a36Sopenharmony_ci	void *authorizer;
143262306a36Sopenharmony_ci	void *buf;
143362306a36Sopenharmony_ci	int ret;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	ctrl_len = AUTH_BUF_LEN;
143662306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false));
143762306a36Sopenharmony_ci	if (!buf)
143862306a36Sopenharmony_ci		return -ENOMEM;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	mutex_unlock(&con->mutex);
144162306a36Sopenharmony_ci	ret = con->ops->handle_auth_reply_more(con, reply, reply_len,
144262306a36Sopenharmony_ci					       CTRL_BODY(buf), &ctrl_len,
144362306a36Sopenharmony_ci					       &authorizer, &authorizer_len);
144462306a36Sopenharmony_ci	mutex_lock(&con->mutex);
144562306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
144662306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
144762306a36Sopenharmony_ci		     con->state);
144862306a36Sopenharmony_ci		return -EAGAIN;
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	dout("%s con %p handle_auth_reply_more ret %d\n", __func__, con, ret);
145262306a36Sopenharmony_ci	if (ret)
145362306a36Sopenharmony_ci		return ret;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return __prepare_control(con, FRAME_TAG_AUTH_REQUEST_MORE, buf,
145662306a36Sopenharmony_ci				 ctrl_len, authorizer, authorizer_len, true);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic int prepare_auth_signature(struct ceph_connection *con)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	void *buf;
146262306a36Sopenharmony_ci	int ret;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(SHA256_DIGEST_SIZE,
146562306a36Sopenharmony_ci						  con_secure(con)));
146662306a36Sopenharmony_ci	if (!buf)
146762306a36Sopenharmony_ci		return -ENOMEM;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	ret = hmac_sha256(con, con->v2.in_sign_kvecs, con->v2.in_sign_kvec_cnt,
147062306a36Sopenharmony_ci			  CTRL_BODY(buf));
147162306a36Sopenharmony_ci	if (ret)
147262306a36Sopenharmony_ci		return ret;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	return prepare_control(con, FRAME_TAG_AUTH_SIGNATURE, buf,
147562306a36Sopenharmony_ci			       SHA256_DIGEST_SIZE);
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cistatic int prepare_client_ident(struct ceph_connection *con)
147962306a36Sopenharmony_ci{
148062306a36Sopenharmony_ci	struct ceph_entity_addr *my_addr = &con->msgr->inst.addr;
148162306a36Sopenharmony_ci	struct ceph_client *client = from_msgr(con->msgr);
148262306a36Sopenharmony_ci	u64 global_id = ceph_client_gid(client);
148362306a36Sopenharmony_ci	void *buf, *p;
148462306a36Sopenharmony_ci	int ctrl_len;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	WARN_ON(con->v2.server_cookie);
148762306a36Sopenharmony_ci	WARN_ON(con->v2.connect_seq);
148862306a36Sopenharmony_ci	WARN_ON(con->v2.peer_global_seq);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	if (!con->v2.client_cookie) {
149162306a36Sopenharmony_ci		do {
149262306a36Sopenharmony_ci			get_random_bytes(&con->v2.client_cookie,
149362306a36Sopenharmony_ci					 sizeof(con->v2.client_cookie));
149462306a36Sopenharmony_ci		} while (!con->v2.client_cookie);
149562306a36Sopenharmony_ci		dout("%s con %p generated cookie 0x%llx\n", __func__, con,
149662306a36Sopenharmony_ci		     con->v2.client_cookie);
149762306a36Sopenharmony_ci	} else {
149862306a36Sopenharmony_ci		dout("%s con %p cookie already set 0x%llx\n", __func__, con,
149962306a36Sopenharmony_ci		     con->v2.client_cookie);
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	dout("%s con %p my_addr %s/%u peer_addr %s/%u global_id %llu global_seq %llu features 0x%llx required_features 0x%llx cookie 0x%llx\n",
150362306a36Sopenharmony_ci	     __func__, con, ceph_pr_addr(my_addr), le32_to_cpu(my_addr->nonce),
150462306a36Sopenharmony_ci	     ceph_pr_addr(&con->peer_addr), le32_to_cpu(con->peer_addr.nonce),
150562306a36Sopenharmony_ci	     global_id, con->v2.global_seq, client->supported_features,
150662306a36Sopenharmony_ci	     client->required_features, con->v2.client_cookie);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	ctrl_len = 1 + 4 + ceph_entity_addr_encoding_len(my_addr) +
150962306a36Sopenharmony_ci		   ceph_entity_addr_encoding_len(&con->peer_addr) + 6 * 8;
151062306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, con_secure(con)));
151162306a36Sopenharmony_ci	if (!buf)
151262306a36Sopenharmony_ci		return -ENOMEM;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	p = CTRL_BODY(buf);
151562306a36Sopenharmony_ci	ceph_encode_8(&p, 2);  /* addrvec marker */
151662306a36Sopenharmony_ci	ceph_encode_32(&p, 1);  /* addr_cnt */
151762306a36Sopenharmony_ci	ceph_encode_entity_addr(&p, my_addr);
151862306a36Sopenharmony_ci	ceph_encode_entity_addr(&p, &con->peer_addr);
151962306a36Sopenharmony_ci	ceph_encode_64(&p, global_id);
152062306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.global_seq);
152162306a36Sopenharmony_ci	ceph_encode_64(&p, client->supported_features);
152262306a36Sopenharmony_ci	ceph_encode_64(&p, client->required_features);
152362306a36Sopenharmony_ci	ceph_encode_64(&p, 0);  /* flags */
152462306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.client_cookie);
152562306a36Sopenharmony_ci	WARN_ON(p != CTRL_BODY(buf) + ctrl_len);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	return prepare_control(con, FRAME_TAG_CLIENT_IDENT, buf, ctrl_len);
152862306a36Sopenharmony_ci}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_cistatic int prepare_session_reconnect(struct ceph_connection *con)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	struct ceph_entity_addr *my_addr = &con->msgr->inst.addr;
153362306a36Sopenharmony_ci	void *buf, *p;
153462306a36Sopenharmony_ci	int ctrl_len;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	WARN_ON(!con->v2.client_cookie);
153762306a36Sopenharmony_ci	WARN_ON(!con->v2.server_cookie);
153862306a36Sopenharmony_ci	WARN_ON(!con->v2.connect_seq);
153962306a36Sopenharmony_ci	WARN_ON(!con->v2.peer_global_seq);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	dout("%s con %p my_addr %s/%u client_cookie 0x%llx server_cookie 0x%llx global_seq %llu connect_seq %llu in_seq %llu\n",
154262306a36Sopenharmony_ci	     __func__, con, ceph_pr_addr(my_addr), le32_to_cpu(my_addr->nonce),
154362306a36Sopenharmony_ci	     con->v2.client_cookie, con->v2.server_cookie, con->v2.global_seq,
154462306a36Sopenharmony_ci	     con->v2.connect_seq, con->in_seq);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	ctrl_len = 1 + 4 + ceph_entity_addr_encoding_len(my_addr) + 5 * 8;
154762306a36Sopenharmony_ci	buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, con_secure(con)));
154862306a36Sopenharmony_ci	if (!buf)
154962306a36Sopenharmony_ci		return -ENOMEM;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	p = CTRL_BODY(buf);
155262306a36Sopenharmony_ci	ceph_encode_8(&p, 2);  /* entity_addrvec_t marker */
155362306a36Sopenharmony_ci	ceph_encode_32(&p, 1);  /* my_addrs len */
155462306a36Sopenharmony_ci	ceph_encode_entity_addr(&p, my_addr);
155562306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.client_cookie);
155662306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.server_cookie);
155762306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.global_seq);
155862306a36Sopenharmony_ci	ceph_encode_64(&p, con->v2.connect_seq);
155962306a36Sopenharmony_ci	ceph_encode_64(&p, con->in_seq);
156062306a36Sopenharmony_ci	WARN_ON(p != CTRL_BODY(buf) + ctrl_len);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	return prepare_control(con, FRAME_TAG_SESSION_RECONNECT, buf, ctrl_len);
156362306a36Sopenharmony_ci}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_cistatic int prepare_keepalive2(struct ceph_connection *con)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct ceph_timespec *ts = CTRL_BODY(con->v2.out_buf);
156862306a36Sopenharmony_ci	struct timespec64 now;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	ktime_get_real_ts64(&now);
157162306a36Sopenharmony_ci	dout("%s con %p timestamp %lld.%09ld\n", __func__, con, now.tv_sec,
157262306a36Sopenharmony_ci	     now.tv_nsec);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	ceph_encode_timespec64(ts, &now);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	reset_out_kvecs(con);
157762306a36Sopenharmony_ci	return prepare_control(con, FRAME_TAG_KEEPALIVE2, con->v2.out_buf,
157862306a36Sopenharmony_ci			       sizeof(struct ceph_timespec));
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cistatic int prepare_ack(struct ceph_connection *con)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	void *p;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	dout("%s con %p in_seq_acked %llu -> %llu\n", __func__, con,
158662306a36Sopenharmony_ci	     con->in_seq_acked, con->in_seq);
158762306a36Sopenharmony_ci	con->in_seq_acked = con->in_seq;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	p = CTRL_BODY(con->v2.out_buf);
159062306a36Sopenharmony_ci	ceph_encode_64(&p, con->in_seq_acked);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	reset_out_kvecs(con);
159362306a36Sopenharmony_ci	return prepare_control(con, FRAME_TAG_ACK, con->v2.out_buf, 8);
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic void prepare_epilogue_plain(struct ceph_connection *con, bool aborted)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	dout("%s con %p msg %p aborted %d crcs %u %u %u\n", __func__, con,
159962306a36Sopenharmony_ci	     con->out_msg, aborted, con->v2.out_epil.front_crc,
160062306a36Sopenharmony_ci	     con->v2.out_epil.middle_crc, con->v2.out_epil.data_crc);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	encode_epilogue_plain(con, aborted);
160362306a36Sopenharmony_ci	add_out_kvec(con, &con->v2.out_epil, CEPH_EPILOGUE_PLAIN_LEN);
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci/*
160762306a36Sopenharmony_ci * For "used" empty segments, crc is -1.  For unused (trailing)
160862306a36Sopenharmony_ci * segments, crc is 0.
160962306a36Sopenharmony_ci */
161062306a36Sopenharmony_cistatic void prepare_message_plain(struct ceph_connection *con)
161162306a36Sopenharmony_ci{
161262306a36Sopenharmony_ci	struct ceph_msg *msg = con->out_msg;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	prepare_head_plain(con, con->v2.out_buf,
161562306a36Sopenharmony_ci			   sizeof(struct ceph_msg_header2), NULL, 0, false);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (!front_len(msg) && !middle_len(msg)) {
161862306a36Sopenharmony_ci		if (!data_len(msg)) {
161962306a36Sopenharmony_ci			/*
162062306a36Sopenharmony_ci			 * Empty message: once the head is written,
162162306a36Sopenharmony_ci			 * we are done -- there is no epilogue.
162262306a36Sopenharmony_ci			 */
162362306a36Sopenharmony_ci			con->v2.out_state = OUT_S_FINISH_MESSAGE;
162462306a36Sopenharmony_ci			return;
162562306a36Sopenharmony_ci		}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci		con->v2.out_epil.front_crc = -1;
162862306a36Sopenharmony_ci		con->v2.out_epil.middle_crc = -1;
162962306a36Sopenharmony_ci		con->v2.out_state = OUT_S_QUEUE_DATA;
163062306a36Sopenharmony_ci		return;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	if (front_len(msg)) {
163462306a36Sopenharmony_ci		con->v2.out_epil.front_crc = crc32c(-1, msg->front.iov_base,
163562306a36Sopenharmony_ci						    front_len(msg));
163662306a36Sopenharmony_ci		add_out_kvec(con, msg->front.iov_base, front_len(msg));
163762306a36Sopenharmony_ci	} else {
163862306a36Sopenharmony_ci		/* middle (at least) is there, checked above */
163962306a36Sopenharmony_ci		con->v2.out_epil.front_crc = -1;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	if (middle_len(msg)) {
164362306a36Sopenharmony_ci		con->v2.out_epil.middle_crc =
164462306a36Sopenharmony_ci			crc32c(-1, msg->middle->vec.iov_base, middle_len(msg));
164562306a36Sopenharmony_ci		add_out_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
164662306a36Sopenharmony_ci	} else {
164762306a36Sopenharmony_ci		con->v2.out_epil.middle_crc = data_len(msg) ? -1 : 0;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (data_len(msg)) {
165162306a36Sopenharmony_ci		con->v2.out_state = OUT_S_QUEUE_DATA;
165262306a36Sopenharmony_ci	} else {
165362306a36Sopenharmony_ci		con->v2.out_epil.data_crc = 0;
165462306a36Sopenharmony_ci		prepare_epilogue_plain(con, false);
165562306a36Sopenharmony_ci		con->v2.out_state = OUT_S_FINISH_MESSAGE;
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci/*
166062306a36Sopenharmony_ci * Unfortunately the kernel crypto API doesn't support streaming
166162306a36Sopenharmony_ci * (piecewise) operation for AEAD algorithms, so we can't get away
166262306a36Sopenharmony_ci * with a fixed size buffer and a couple sgs.  Instead, we have to
166362306a36Sopenharmony_ci * allocate pages for the entire tail of the message (currently up
166462306a36Sopenharmony_ci * to ~32M) and two sgs arrays (up to ~256K each)...
166562306a36Sopenharmony_ci */
166662306a36Sopenharmony_cistatic int prepare_message_secure(struct ceph_connection *con)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	void *zerop = page_address(ceph_zero_page);
166962306a36Sopenharmony_ci	struct sg_table enc_sgt = {};
167062306a36Sopenharmony_ci	struct sg_table sgt = {};
167162306a36Sopenharmony_ci	struct page **enc_pages;
167262306a36Sopenharmony_ci	int enc_page_cnt;
167362306a36Sopenharmony_ci	int tail_len;
167462306a36Sopenharmony_ci	int ret;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	ret = prepare_head_secure_small(con, con->v2.out_buf,
167762306a36Sopenharmony_ci					sizeof(struct ceph_msg_header2));
167862306a36Sopenharmony_ci	if (ret)
167962306a36Sopenharmony_ci		return ret;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	tail_len = tail_onwire_len(con->out_msg, true);
168262306a36Sopenharmony_ci	if (!tail_len) {
168362306a36Sopenharmony_ci		/*
168462306a36Sopenharmony_ci		 * Empty message: once the head is written,
168562306a36Sopenharmony_ci		 * we are done -- there is no epilogue.
168662306a36Sopenharmony_ci		 */
168762306a36Sopenharmony_ci		con->v2.out_state = OUT_S_FINISH_MESSAGE;
168862306a36Sopenharmony_ci		return 0;
168962306a36Sopenharmony_ci	}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	encode_epilogue_secure(con, false);
169262306a36Sopenharmony_ci	ret = setup_message_sgs(&sgt, con->out_msg, zerop, zerop, zerop,
169362306a36Sopenharmony_ci				&con->v2.out_epil, NULL, 0, false);
169462306a36Sopenharmony_ci	if (ret)
169562306a36Sopenharmony_ci		goto out;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	enc_page_cnt = calc_pages_for(0, tail_len);
169862306a36Sopenharmony_ci	enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
169962306a36Sopenharmony_ci	if (IS_ERR(enc_pages)) {
170062306a36Sopenharmony_ci		ret = PTR_ERR(enc_pages);
170162306a36Sopenharmony_ci		goto out;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	WARN_ON(con->v2.out_enc_pages || con->v2.out_enc_page_cnt);
170562306a36Sopenharmony_ci	con->v2.out_enc_pages = enc_pages;
170662306a36Sopenharmony_ci	con->v2.out_enc_page_cnt = enc_page_cnt;
170762306a36Sopenharmony_ci	con->v2.out_enc_resid = tail_len;
170862306a36Sopenharmony_ci	con->v2.out_enc_i = 0;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	ret = sg_alloc_table_from_pages(&enc_sgt, enc_pages, enc_page_cnt,
171162306a36Sopenharmony_ci					0, tail_len, GFP_NOIO);
171262306a36Sopenharmony_ci	if (ret)
171362306a36Sopenharmony_ci		goto out;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	ret = gcm_crypt(con, true, sgt.sgl, enc_sgt.sgl,
171662306a36Sopenharmony_ci			tail_len - CEPH_GCM_TAG_LEN);
171762306a36Sopenharmony_ci	if (ret)
171862306a36Sopenharmony_ci		goto out;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	dout("%s con %p msg %p sg_cnt %d enc_page_cnt %d\n", __func__, con,
172162306a36Sopenharmony_ci	     con->out_msg, sgt.orig_nents, enc_page_cnt);
172262306a36Sopenharmony_ci	con->v2.out_state = OUT_S_QUEUE_ENC_PAGE;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ciout:
172562306a36Sopenharmony_ci	sg_free_table(&sgt);
172662306a36Sopenharmony_ci	sg_free_table(&enc_sgt);
172762306a36Sopenharmony_ci	return ret;
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_cistatic int prepare_message(struct ceph_connection *con)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	int lens[] = {
173362306a36Sopenharmony_ci		sizeof(struct ceph_msg_header2),
173462306a36Sopenharmony_ci		front_len(con->out_msg),
173562306a36Sopenharmony_ci		middle_len(con->out_msg),
173662306a36Sopenharmony_ci		data_len(con->out_msg)
173762306a36Sopenharmony_ci	};
173862306a36Sopenharmony_ci	struct ceph_frame_desc desc;
173962306a36Sopenharmony_ci	int ret;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	dout("%s con %p msg %p logical %d+%d+%d+%d\n", __func__, con,
174262306a36Sopenharmony_ci	     con->out_msg, lens[0], lens[1], lens[2], lens[3]);
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	if (con->in_seq > con->in_seq_acked) {
174562306a36Sopenharmony_ci		dout("%s con %p in_seq_acked %llu -> %llu\n", __func__, con,
174662306a36Sopenharmony_ci		     con->in_seq_acked, con->in_seq);
174762306a36Sopenharmony_ci		con->in_seq_acked = con->in_seq;
174862306a36Sopenharmony_ci	}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	reset_out_kvecs(con);
175162306a36Sopenharmony_ci	init_frame_desc(&desc, FRAME_TAG_MESSAGE, lens, 4);
175262306a36Sopenharmony_ci	encode_preamble(&desc, con->v2.out_buf);
175362306a36Sopenharmony_ci	fill_header2(CTRL_BODY(con->v2.out_buf), &con->out_msg->hdr,
175462306a36Sopenharmony_ci		     con->in_seq_acked);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	if (con_secure(con)) {
175762306a36Sopenharmony_ci		ret = prepare_message_secure(con);
175862306a36Sopenharmony_ci		if (ret)
175962306a36Sopenharmony_ci			return ret;
176062306a36Sopenharmony_ci	} else {
176162306a36Sopenharmony_ci		prepare_message_plain(con);
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING);
176562306a36Sopenharmony_ci	return 0;
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic int prepare_read_banner_prefix(struct ceph_connection *con)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	void *buf;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	buf = alloc_conn_buf(con, CEPH_BANNER_V2_PREFIX_LEN);
177362306a36Sopenharmony_ci	if (!buf)
177462306a36Sopenharmony_ci		return -ENOMEM;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	reset_in_kvecs(con);
177762306a36Sopenharmony_ci	add_in_kvec(con, buf, CEPH_BANNER_V2_PREFIX_LEN);
177862306a36Sopenharmony_ci	add_in_sign_kvec(con, buf, CEPH_BANNER_V2_PREFIX_LEN);
177962306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_BANNER_PREFIX;
178062306a36Sopenharmony_ci	return 0;
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_cistatic int prepare_read_banner_payload(struct ceph_connection *con,
178462306a36Sopenharmony_ci				       int payload_len)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	void *buf;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	buf = alloc_conn_buf(con, payload_len);
178962306a36Sopenharmony_ci	if (!buf)
179062306a36Sopenharmony_ci		return -ENOMEM;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	reset_in_kvecs(con);
179362306a36Sopenharmony_ci	add_in_kvec(con, buf, payload_len);
179462306a36Sopenharmony_ci	add_in_sign_kvec(con, buf, payload_len);
179562306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_BANNER_PAYLOAD;
179662306a36Sopenharmony_ci	return 0;
179762306a36Sopenharmony_ci}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_cistatic void prepare_read_preamble(struct ceph_connection *con)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	reset_in_kvecs(con);
180262306a36Sopenharmony_ci	add_in_kvec(con, con->v2.in_buf,
180362306a36Sopenharmony_ci		    con_secure(con) ? CEPH_PREAMBLE_SECURE_LEN :
180462306a36Sopenharmony_ci				      CEPH_PREAMBLE_PLAIN_LEN);
180562306a36Sopenharmony_ci	con->v2.in_state = IN_S_HANDLE_PREAMBLE;
180662306a36Sopenharmony_ci}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_cistatic int prepare_read_control(struct ceph_connection *con)
180962306a36Sopenharmony_ci{
181062306a36Sopenharmony_ci	int ctrl_len = con->v2.in_desc.fd_lens[0];
181162306a36Sopenharmony_ci	int head_len;
181262306a36Sopenharmony_ci	void *buf;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	reset_in_kvecs(con);
181562306a36Sopenharmony_ci	if (con->state == CEPH_CON_S_V2_HELLO ||
181662306a36Sopenharmony_ci	    con->state == CEPH_CON_S_V2_AUTH) {
181762306a36Sopenharmony_ci		head_len = head_onwire_len(ctrl_len, false);
181862306a36Sopenharmony_ci		buf = alloc_conn_buf(con, head_len);
181962306a36Sopenharmony_ci		if (!buf)
182062306a36Sopenharmony_ci			return -ENOMEM;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci		/* preserve preamble */
182362306a36Sopenharmony_ci		memcpy(buf, con->v2.in_buf, CEPH_PREAMBLE_LEN);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		add_in_kvec(con, CTRL_BODY(buf), ctrl_len);
182662306a36Sopenharmony_ci		add_in_kvec(con, CTRL_BODY(buf) + ctrl_len, CEPH_CRC_LEN);
182762306a36Sopenharmony_ci		add_in_sign_kvec(con, buf, head_len);
182862306a36Sopenharmony_ci	} else {
182962306a36Sopenharmony_ci		if (ctrl_len > CEPH_PREAMBLE_INLINE_LEN) {
183062306a36Sopenharmony_ci			buf = alloc_conn_buf(con, ctrl_len);
183162306a36Sopenharmony_ci			if (!buf)
183262306a36Sopenharmony_ci				return -ENOMEM;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci			add_in_kvec(con, buf, ctrl_len);
183562306a36Sopenharmony_ci		} else {
183662306a36Sopenharmony_ci			add_in_kvec(con, CTRL_BODY(con->v2.in_buf), ctrl_len);
183762306a36Sopenharmony_ci		}
183862306a36Sopenharmony_ci		add_in_kvec(con, con->v2.in_buf, CEPH_CRC_LEN);
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci	con->v2.in_state = IN_S_HANDLE_CONTROL;
184162306a36Sopenharmony_ci	return 0;
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_cistatic int prepare_read_control_remainder(struct ceph_connection *con)
184562306a36Sopenharmony_ci{
184662306a36Sopenharmony_ci	int ctrl_len = con->v2.in_desc.fd_lens[0];
184762306a36Sopenharmony_ci	int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN;
184862306a36Sopenharmony_ci	void *buf;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	buf = alloc_conn_buf(con, ctrl_len);
185162306a36Sopenharmony_ci	if (!buf)
185262306a36Sopenharmony_ci		return -ENOMEM;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	memcpy(buf, CTRL_BODY(con->v2.in_buf), CEPH_PREAMBLE_INLINE_LEN);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	reset_in_kvecs(con);
185762306a36Sopenharmony_ci	add_in_kvec(con, buf + CEPH_PREAMBLE_INLINE_LEN, rem_len);
185862306a36Sopenharmony_ci	add_in_kvec(con, con->v2.in_buf,
185962306a36Sopenharmony_ci		    padding_len(rem_len) + CEPH_GCM_TAG_LEN);
186062306a36Sopenharmony_ci	con->v2.in_state = IN_S_HANDLE_CONTROL_REMAINDER;
186162306a36Sopenharmony_ci	return 0;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic int prepare_read_data(struct ceph_connection *con)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct bio_vec bv;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	con->in_data_crc = -1;
186962306a36Sopenharmony_ci	ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
187062306a36Sopenharmony_ci				  data_len(con->in_msg));
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	get_bvec_at(&con->v2.in_cursor, &bv);
187362306a36Sopenharmony_ci	if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
187462306a36Sopenharmony_ci		if (unlikely(!con->bounce_page)) {
187562306a36Sopenharmony_ci			con->bounce_page = alloc_page(GFP_NOIO);
187662306a36Sopenharmony_ci			if (!con->bounce_page) {
187762306a36Sopenharmony_ci				pr_err("failed to allocate bounce page\n");
187862306a36Sopenharmony_ci				return -ENOMEM;
187962306a36Sopenharmony_ci			}
188062306a36Sopenharmony_ci		}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci		bv.bv_page = con->bounce_page;
188362306a36Sopenharmony_ci		bv.bv_offset = 0;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci	set_in_bvec(con, &bv);
188662306a36Sopenharmony_ci	con->v2.in_state = IN_S_PREPARE_READ_DATA_CONT;
188762306a36Sopenharmony_ci	return 0;
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_cistatic void prepare_read_data_cont(struct ceph_connection *con)
189162306a36Sopenharmony_ci{
189262306a36Sopenharmony_ci	struct bio_vec bv;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
189562306a36Sopenharmony_ci		con->in_data_crc = crc32c(con->in_data_crc,
189662306a36Sopenharmony_ci					  page_address(con->bounce_page),
189762306a36Sopenharmony_ci					  con->v2.in_bvec.bv_len);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		get_bvec_at(&con->v2.in_cursor, &bv);
190062306a36Sopenharmony_ci		memcpy_to_page(bv.bv_page, bv.bv_offset,
190162306a36Sopenharmony_ci			       page_address(con->bounce_page),
190262306a36Sopenharmony_ci			       con->v2.in_bvec.bv_len);
190362306a36Sopenharmony_ci	} else {
190462306a36Sopenharmony_ci		con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
190562306a36Sopenharmony_ci						    con->v2.in_bvec.bv_page,
190662306a36Sopenharmony_ci						    con->v2.in_bvec.bv_offset,
190762306a36Sopenharmony_ci						    con->v2.in_bvec.bv_len);
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
191162306a36Sopenharmony_ci	if (con->v2.in_cursor.total_resid) {
191262306a36Sopenharmony_ci		get_bvec_at(&con->v2.in_cursor, &bv);
191362306a36Sopenharmony_ci		if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
191462306a36Sopenharmony_ci			bv.bv_page = con->bounce_page;
191562306a36Sopenharmony_ci			bv.bv_offset = 0;
191662306a36Sopenharmony_ci		}
191762306a36Sopenharmony_ci		set_in_bvec(con, &bv);
191862306a36Sopenharmony_ci		WARN_ON(con->v2.in_state != IN_S_PREPARE_READ_DATA_CONT);
191962306a36Sopenharmony_ci		return;
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/*
192362306a36Sopenharmony_ci	 * We've read all data.  Prepare to read epilogue.
192462306a36Sopenharmony_ci	 */
192562306a36Sopenharmony_ci	reset_in_kvecs(con);
192662306a36Sopenharmony_ci	add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
192762306a36Sopenharmony_ci	con->v2.in_state = IN_S_HANDLE_EPILOGUE;
192862306a36Sopenharmony_ci}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_cistatic int prepare_sparse_read_cont(struct ceph_connection *con)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	int ret;
193362306a36Sopenharmony_ci	struct bio_vec bv;
193462306a36Sopenharmony_ci	char *buf = NULL;
193562306a36Sopenharmony_ci	struct ceph_msg_data_cursor *cursor = &con->v2.in_cursor;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	WARN_ON(con->v2.in_state != IN_S_PREPARE_SPARSE_DATA_CONT);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (iov_iter_is_bvec(&con->v2.in_iter)) {
194062306a36Sopenharmony_ci		if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
194162306a36Sopenharmony_ci			con->in_data_crc = crc32c(con->in_data_crc,
194262306a36Sopenharmony_ci						  page_address(con->bounce_page),
194362306a36Sopenharmony_ci						  con->v2.in_bvec.bv_len);
194462306a36Sopenharmony_ci			get_bvec_at(cursor, &bv);
194562306a36Sopenharmony_ci			memcpy_to_page(bv.bv_page, bv.bv_offset,
194662306a36Sopenharmony_ci				       page_address(con->bounce_page),
194762306a36Sopenharmony_ci				       con->v2.in_bvec.bv_len);
194862306a36Sopenharmony_ci		} else {
194962306a36Sopenharmony_ci			con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
195062306a36Sopenharmony_ci							    con->v2.in_bvec.bv_page,
195162306a36Sopenharmony_ci							    con->v2.in_bvec.bv_offset,
195262306a36Sopenharmony_ci							    con->v2.in_bvec.bv_len);
195362306a36Sopenharmony_ci		}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		ceph_msg_data_advance(cursor, con->v2.in_bvec.bv_len);
195662306a36Sopenharmony_ci		cursor->sr_resid -= con->v2.in_bvec.bv_len;
195762306a36Sopenharmony_ci		dout("%s: advance by 0x%x sr_resid 0x%x\n", __func__,
195862306a36Sopenharmony_ci		     con->v2.in_bvec.bv_len, cursor->sr_resid);
195962306a36Sopenharmony_ci		WARN_ON_ONCE(cursor->sr_resid > cursor->total_resid);
196062306a36Sopenharmony_ci		if (cursor->sr_resid) {
196162306a36Sopenharmony_ci			get_bvec_at(cursor, &bv);
196262306a36Sopenharmony_ci			if (bv.bv_len > cursor->sr_resid)
196362306a36Sopenharmony_ci				bv.bv_len = cursor->sr_resid;
196462306a36Sopenharmony_ci			if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
196562306a36Sopenharmony_ci				bv.bv_page = con->bounce_page;
196662306a36Sopenharmony_ci				bv.bv_offset = 0;
196762306a36Sopenharmony_ci			}
196862306a36Sopenharmony_ci			set_in_bvec(con, &bv);
196962306a36Sopenharmony_ci			con->v2.data_len_remain -= bv.bv_len;
197062306a36Sopenharmony_ci			return 0;
197162306a36Sopenharmony_ci		}
197262306a36Sopenharmony_ci	} else if (iov_iter_is_kvec(&con->v2.in_iter)) {
197362306a36Sopenharmony_ci		/* On first call, we have no kvec so don't compute crc */
197462306a36Sopenharmony_ci		if (con->v2.in_kvec_cnt) {
197562306a36Sopenharmony_ci			WARN_ON_ONCE(con->v2.in_kvec_cnt > 1);
197662306a36Sopenharmony_ci			con->in_data_crc = crc32c(con->in_data_crc,
197762306a36Sopenharmony_ci						  con->v2.in_kvecs[0].iov_base,
197862306a36Sopenharmony_ci						  con->v2.in_kvecs[0].iov_len);
197962306a36Sopenharmony_ci		}
198062306a36Sopenharmony_ci	} else {
198162306a36Sopenharmony_ci		return -EIO;
198262306a36Sopenharmony_ci	}
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	/* get next extent */
198562306a36Sopenharmony_ci	ret = con->ops->sparse_read(con, cursor, &buf);
198662306a36Sopenharmony_ci	if (ret <= 0) {
198762306a36Sopenharmony_ci		if (ret < 0)
198862306a36Sopenharmony_ci			return ret;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci		reset_in_kvecs(con);
199162306a36Sopenharmony_ci		add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
199262306a36Sopenharmony_ci		con->v2.in_state = IN_S_HANDLE_EPILOGUE;
199362306a36Sopenharmony_ci		return 0;
199462306a36Sopenharmony_ci	}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (buf) {
199762306a36Sopenharmony_ci		/* receive into buffer */
199862306a36Sopenharmony_ci		reset_in_kvecs(con);
199962306a36Sopenharmony_ci		add_in_kvec(con, buf, ret);
200062306a36Sopenharmony_ci		con->v2.data_len_remain -= ret;
200162306a36Sopenharmony_ci		return 0;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (ret > cursor->total_resid) {
200562306a36Sopenharmony_ci		pr_warn("%s: ret 0x%x total_resid 0x%zx resid 0x%zx\n",
200662306a36Sopenharmony_ci			__func__, ret, cursor->total_resid, cursor->resid);
200762306a36Sopenharmony_ci		return -EIO;
200862306a36Sopenharmony_ci	}
200962306a36Sopenharmony_ci	get_bvec_at(cursor, &bv);
201062306a36Sopenharmony_ci	if (bv.bv_len > cursor->sr_resid)
201162306a36Sopenharmony_ci		bv.bv_len = cursor->sr_resid;
201262306a36Sopenharmony_ci	if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
201362306a36Sopenharmony_ci		if (unlikely(!con->bounce_page)) {
201462306a36Sopenharmony_ci			con->bounce_page = alloc_page(GFP_NOIO);
201562306a36Sopenharmony_ci			if (!con->bounce_page) {
201662306a36Sopenharmony_ci				pr_err("failed to allocate bounce page\n");
201762306a36Sopenharmony_ci				return -ENOMEM;
201862306a36Sopenharmony_ci			}
201962306a36Sopenharmony_ci		}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci		bv.bv_page = con->bounce_page;
202262306a36Sopenharmony_ci		bv.bv_offset = 0;
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci	set_in_bvec(con, &bv);
202562306a36Sopenharmony_ci	con->v2.data_len_remain -= ret;
202662306a36Sopenharmony_ci	return ret;
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic int prepare_sparse_read_data(struct ceph_connection *con)
203062306a36Sopenharmony_ci{
203162306a36Sopenharmony_ci	struct ceph_msg *msg = con->in_msg;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	dout("%s: starting sparse read\n", __func__);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	if (WARN_ON_ONCE(!con->ops->sparse_read))
203662306a36Sopenharmony_ci		return -EOPNOTSUPP;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	if (!con_secure(con))
203962306a36Sopenharmony_ci		con->in_data_crc = -1;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	reset_in_kvecs(con);
204262306a36Sopenharmony_ci	con->v2.in_state = IN_S_PREPARE_SPARSE_DATA_CONT;
204362306a36Sopenharmony_ci	con->v2.data_len_remain = data_len(msg);
204462306a36Sopenharmony_ci	return prepare_sparse_read_cont(con);
204562306a36Sopenharmony_ci}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_cistatic int prepare_read_tail_plain(struct ceph_connection *con)
204862306a36Sopenharmony_ci{
204962306a36Sopenharmony_ci	struct ceph_msg *msg = con->in_msg;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	if (!front_len(msg) && !middle_len(msg)) {
205262306a36Sopenharmony_ci		WARN_ON(!data_len(msg));
205362306a36Sopenharmony_ci		return prepare_read_data(con);
205462306a36Sopenharmony_ci	}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	reset_in_kvecs(con);
205762306a36Sopenharmony_ci	if (front_len(msg)) {
205862306a36Sopenharmony_ci		add_in_kvec(con, msg->front.iov_base, front_len(msg));
205962306a36Sopenharmony_ci		WARN_ON(msg->front.iov_len != front_len(msg));
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci	if (middle_len(msg)) {
206262306a36Sopenharmony_ci		add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
206362306a36Sopenharmony_ci		WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
206462306a36Sopenharmony_ci	}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	if (data_len(msg)) {
206762306a36Sopenharmony_ci		if (msg->sparse_read_total)
206862306a36Sopenharmony_ci			con->v2.in_state = IN_S_PREPARE_SPARSE_DATA;
206962306a36Sopenharmony_ci		else
207062306a36Sopenharmony_ci			con->v2.in_state = IN_S_PREPARE_READ_DATA;
207162306a36Sopenharmony_ci	} else {
207262306a36Sopenharmony_ci		add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
207362306a36Sopenharmony_ci		con->v2.in_state = IN_S_HANDLE_EPILOGUE;
207462306a36Sopenharmony_ci	}
207562306a36Sopenharmony_ci	return 0;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic void prepare_read_enc_page(struct ceph_connection *con)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	struct bio_vec bv;
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
208362306a36Sopenharmony_ci	     con->v2.in_enc_resid);
208462306a36Sopenharmony_ci	WARN_ON(!con->v2.in_enc_resid);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	bvec_set_page(&bv, con->v2.in_enc_pages[con->v2.in_enc_i],
208762306a36Sopenharmony_ci		      min(con->v2.in_enc_resid, (int)PAGE_SIZE), 0);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	set_in_bvec(con, &bv);
209062306a36Sopenharmony_ci	con->v2.in_enc_i++;
209162306a36Sopenharmony_ci	con->v2.in_enc_resid -= bv.bv_len;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	if (con->v2.in_enc_resid) {
209462306a36Sopenharmony_ci		con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
209562306a36Sopenharmony_ci		return;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	/*
209962306a36Sopenharmony_ci	 * We are set to read the last piece of ciphertext (ending
210062306a36Sopenharmony_ci	 * with epilogue) + auth tag.
210162306a36Sopenharmony_ci	 */
210262306a36Sopenharmony_ci	WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
210362306a36Sopenharmony_ci	con->v2.in_state = IN_S_HANDLE_EPILOGUE;
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_cistatic int prepare_read_tail_secure(struct ceph_connection *con)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	struct page **enc_pages;
210962306a36Sopenharmony_ci	int enc_page_cnt;
211062306a36Sopenharmony_ci	int tail_len;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	tail_len = tail_onwire_len(con->in_msg, true);
211362306a36Sopenharmony_ci	WARN_ON(!tail_len);
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	enc_page_cnt = calc_pages_for(0, tail_len);
211662306a36Sopenharmony_ci	enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
211762306a36Sopenharmony_ci	if (IS_ERR(enc_pages))
211862306a36Sopenharmony_ci		return PTR_ERR(enc_pages);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
212162306a36Sopenharmony_ci	con->v2.in_enc_pages = enc_pages;
212262306a36Sopenharmony_ci	con->v2.in_enc_page_cnt = enc_page_cnt;
212362306a36Sopenharmony_ci	con->v2.in_enc_resid = tail_len;
212462306a36Sopenharmony_ci	con->v2.in_enc_i = 0;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	prepare_read_enc_page(con);
212762306a36Sopenharmony_ci	return 0;
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_cistatic void __finish_skip(struct ceph_connection *con)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	con->in_seq++;
213362306a36Sopenharmony_ci	prepare_read_preamble(con);
213462306a36Sopenharmony_ci}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic void prepare_skip_message(struct ceph_connection *con)
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	struct ceph_frame_desc *desc = &con->v2.in_desc;
213962306a36Sopenharmony_ci	int tail_len;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	dout("%s con %p %d+%d+%d\n", __func__, con, desc->fd_lens[1],
214262306a36Sopenharmony_ci	     desc->fd_lens[2], desc->fd_lens[3]);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	tail_len = __tail_onwire_len(desc->fd_lens[1], desc->fd_lens[2],
214562306a36Sopenharmony_ci				     desc->fd_lens[3], con_secure(con));
214662306a36Sopenharmony_ci	if (!tail_len) {
214762306a36Sopenharmony_ci		__finish_skip(con);
214862306a36Sopenharmony_ci	} else {
214962306a36Sopenharmony_ci		set_in_skip(con, tail_len);
215062306a36Sopenharmony_ci		con->v2.in_state = IN_S_FINISH_SKIP;
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_cistatic int process_banner_prefix(struct ceph_connection *con)
215562306a36Sopenharmony_ci{
215662306a36Sopenharmony_ci	int payload_len;
215762306a36Sopenharmony_ci	void *p;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	WARN_ON(con->v2.in_kvecs[0].iov_len != CEPH_BANNER_V2_PREFIX_LEN);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	p = con->v2.in_kvecs[0].iov_base;
216262306a36Sopenharmony_ci	if (memcmp(p, CEPH_BANNER_V2, CEPH_BANNER_V2_LEN)) {
216362306a36Sopenharmony_ci		if (!memcmp(p, CEPH_BANNER, CEPH_BANNER_LEN))
216462306a36Sopenharmony_ci			con->error_msg = "server is speaking msgr1 protocol";
216562306a36Sopenharmony_ci		else
216662306a36Sopenharmony_ci			con->error_msg = "protocol error, bad banner";
216762306a36Sopenharmony_ci		return -EINVAL;
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	p += CEPH_BANNER_V2_LEN;
217162306a36Sopenharmony_ci	payload_len = ceph_decode_16(&p);
217262306a36Sopenharmony_ci	dout("%s con %p payload_len %d\n", __func__, con, payload_len);
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	return prepare_read_banner_payload(con, payload_len);
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic int process_banner_payload(struct ceph_connection *con)
217862306a36Sopenharmony_ci{
217962306a36Sopenharmony_ci	void *end = con->v2.in_kvecs[0].iov_base + con->v2.in_kvecs[0].iov_len;
218062306a36Sopenharmony_ci	u64 feat = CEPH_MSGR2_SUPPORTED_FEATURES;
218162306a36Sopenharmony_ci	u64 req_feat = CEPH_MSGR2_REQUIRED_FEATURES;
218262306a36Sopenharmony_ci	u64 server_feat, server_req_feat;
218362306a36Sopenharmony_ci	void *p;
218462306a36Sopenharmony_ci	int ret;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	p = con->v2.in_kvecs[0].iov_base;
218762306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, server_feat, bad);
218862306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, server_req_feat, bad);
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	dout("%s con %p server_feat 0x%llx server_req_feat 0x%llx\n",
219162306a36Sopenharmony_ci	     __func__, con, server_feat, server_req_feat);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	if (req_feat & ~server_feat) {
219462306a36Sopenharmony_ci		pr_err("msgr2 feature set mismatch: my required > server's supported 0x%llx, need 0x%llx\n",
219562306a36Sopenharmony_ci		       server_feat, req_feat & ~server_feat);
219662306a36Sopenharmony_ci		con->error_msg = "missing required protocol features";
219762306a36Sopenharmony_ci		return -EINVAL;
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci	if (server_req_feat & ~feat) {
220062306a36Sopenharmony_ci		pr_err("msgr2 feature set mismatch: server's required > my supported 0x%llx, missing 0x%llx\n",
220162306a36Sopenharmony_ci		       feat, server_req_feat & ~feat);
220262306a36Sopenharmony_ci		con->error_msg = "missing required protocol features";
220362306a36Sopenharmony_ci		return -EINVAL;
220462306a36Sopenharmony_ci	}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/* no reset_out_kvecs() as our banner may still be pending */
220762306a36Sopenharmony_ci	ret = prepare_hello(con);
220862306a36Sopenharmony_ci	if (ret) {
220962306a36Sopenharmony_ci		pr_err("prepare_hello failed: %d\n", ret);
221062306a36Sopenharmony_ci		return ret;
221162306a36Sopenharmony_ci	}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_HELLO;
221462306a36Sopenharmony_ci	prepare_read_preamble(con);
221562306a36Sopenharmony_ci	return 0;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_cibad:
221862306a36Sopenharmony_ci	pr_err("failed to decode banner payload\n");
221962306a36Sopenharmony_ci	return -EINVAL;
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_cistatic int process_hello(struct ceph_connection *con, void *p, void *end)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	struct ceph_entity_addr *my_addr = &con->msgr->inst.addr;
222562306a36Sopenharmony_ci	struct ceph_entity_addr addr_for_me;
222662306a36Sopenharmony_ci	u8 entity_type;
222762306a36Sopenharmony_ci	int ret;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_HELLO) {
223062306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected hello";
223162306a36Sopenharmony_ci		return -EINVAL;
223262306a36Sopenharmony_ci	}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	ceph_decode_8_safe(&p, end, entity_type, bad);
223562306a36Sopenharmony_ci	ret = ceph_decode_entity_addr(&p, end, &addr_for_me);
223662306a36Sopenharmony_ci	if (ret) {
223762306a36Sopenharmony_ci		pr_err("failed to decode addr_for_me: %d\n", ret);
223862306a36Sopenharmony_ci		return ret;
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	dout("%s con %p entity_type %d addr_for_me %s\n", __func__, con,
224262306a36Sopenharmony_ci	     entity_type, ceph_pr_addr(&addr_for_me));
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	if (entity_type != con->peer_name.type) {
224562306a36Sopenharmony_ci		pr_err("bad peer type, want %d, got %d\n",
224662306a36Sopenharmony_ci		       con->peer_name.type, entity_type);
224762306a36Sopenharmony_ci		con->error_msg = "wrong peer at address";
224862306a36Sopenharmony_ci		return -EINVAL;
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	/*
225262306a36Sopenharmony_ci	 * Set our address to the address our first peer (i.e. monitor)
225362306a36Sopenharmony_ci	 * sees that we are connecting from.  If we are behind some sort
225462306a36Sopenharmony_ci	 * of NAT and want to be identified by some private (not NATed)
225562306a36Sopenharmony_ci	 * address, ip option should be used.
225662306a36Sopenharmony_ci	 */
225762306a36Sopenharmony_ci	if (ceph_addr_is_blank(my_addr)) {
225862306a36Sopenharmony_ci		memcpy(&my_addr->in_addr, &addr_for_me.in_addr,
225962306a36Sopenharmony_ci		       sizeof(my_addr->in_addr));
226062306a36Sopenharmony_ci		ceph_addr_set_port(my_addr, 0);
226162306a36Sopenharmony_ci		dout("%s con %p set my addr %s, as seen by peer %s\n",
226262306a36Sopenharmony_ci		     __func__, con, ceph_pr_addr(my_addr),
226362306a36Sopenharmony_ci		     ceph_pr_addr(&con->peer_addr));
226462306a36Sopenharmony_ci	} else {
226562306a36Sopenharmony_ci		dout("%s con %p my addr already set %s\n",
226662306a36Sopenharmony_ci		     __func__, con, ceph_pr_addr(my_addr));
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	WARN_ON(ceph_addr_is_blank(my_addr) || ceph_addr_port(my_addr));
227062306a36Sopenharmony_ci	WARN_ON(my_addr->type != CEPH_ENTITY_ADDR_TYPE_ANY);
227162306a36Sopenharmony_ci	WARN_ON(!my_addr->nonce);
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	/* no reset_out_kvecs() as our hello may still be pending */
227462306a36Sopenharmony_ci	ret = prepare_auth_request(con);
227562306a36Sopenharmony_ci	if (ret) {
227662306a36Sopenharmony_ci		if (ret != -EAGAIN)
227762306a36Sopenharmony_ci			pr_err("prepare_auth_request failed: %d\n", ret);
227862306a36Sopenharmony_ci		return ret;
227962306a36Sopenharmony_ci	}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_AUTH;
228262306a36Sopenharmony_ci	return 0;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_cibad:
228562306a36Sopenharmony_ci	pr_err("failed to decode hello\n");
228662306a36Sopenharmony_ci	return -EINVAL;
228762306a36Sopenharmony_ci}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_cistatic int process_auth_bad_method(struct ceph_connection *con,
229062306a36Sopenharmony_ci				   void *p, void *end)
229162306a36Sopenharmony_ci{
229262306a36Sopenharmony_ci	int allowed_protos[8], allowed_modes[8];
229362306a36Sopenharmony_ci	int allowed_proto_cnt, allowed_mode_cnt;
229462306a36Sopenharmony_ci	int used_proto, result;
229562306a36Sopenharmony_ci	int ret;
229662306a36Sopenharmony_ci	int i;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
229962306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected auth_bad_method";
230062306a36Sopenharmony_ci		return -EINVAL;
230162306a36Sopenharmony_ci	}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, used_proto, bad);
230462306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, result, bad);
230562306a36Sopenharmony_ci	dout("%s con %p used_proto %d result %d\n", __func__, con, used_proto,
230662306a36Sopenharmony_ci	     result);
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, allowed_proto_cnt, bad);
230962306a36Sopenharmony_ci	if (allowed_proto_cnt > ARRAY_SIZE(allowed_protos)) {
231062306a36Sopenharmony_ci		pr_err("allowed_protos too big %d\n", allowed_proto_cnt);
231162306a36Sopenharmony_ci		return -EINVAL;
231262306a36Sopenharmony_ci	}
231362306a36Sopenharmony_ci	for (i = 0; i < allowed_proto_cnt; i++) {
231462306a36Sopenharmony_ci		ceph_decode_32_safe(&p, end, allowed_protos[i], bad);
231562306a36Sopenharmony_ci		dout("%s con %p allowed_protos[%d] %d\n", __func__, con,
231662306a36Sopenharmony_ci		     i, allowed_protos[i]);
231762306a36Sopenharmony_ci	}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, allowed_mode_cnt, bad);
232062306a36Sopenharmony_ci	if (allowed_mode_cnt > ARRAY_SIZE(allowed_modes)) {
232162306a36Sopenharmony_ci		pr_err("allowed_modes too big %d\n", allowed_mode_cnt);
232262306a36Sopenharmony_ci		return -EINVAL;
232362306a36Sopenharmony_ci	}
232462306a36Sopenharmony_ci	for (i = 0; i < allowed_mode_cnt; i++) {
232562306a36Sopenharmony_ci		ceph_decode_32_safe(&p, end, allowed_modes[i], bad);
232662306a36Sopenharmony_ci		dout("%s con %p allowed_modes[%d] %d\n", __func__, con,
232762306a36Sopenharmony_ci		     i, allowed_modes[i]);
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	mutex_unlock(&con->mutex);
233162306a36Sopenharmony_ci	ret = con->ops->handle_auth_bad_method(con, used_proto, result,
233262306a36Sopenharmony_ci					       allowed_protos,
233362306a36Sopenharmony_ci					       allowed_proto_cnt,
233462306a36Sopenharmony_ci					       allowed_modes,
233562306a36Sopenharmony_ci					       allowed_mode_cnt);
233662306a36Sopenharmony_ci	mutex_lock(&con->mutex);
233762306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
233862306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
233962306a36Sopenharmony_ci		     con->state);
234062306a36Sopenharmony_ci		return -EAGAIN;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	dout("%s con %p handle_auth_bad_method ret %d\n", __func__, con, ret);
234462306a36Sopenharmony_ci	return ret;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_cibad:
234762306a36Sopenharmony_ci	pr_err("failed to decode auth_bad_method\n");
234862306a36Sopenharmony_ci	return -EINVAL;
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_cistatic int process_auth_reply_more(struct ceph_connection *con,
235262306a36Sopenharmony_ci				   void *p, void *end)
235362306a36Sopenharmony_ci{
235462306a36Sopenharmony_ci	int payload_len;
235562306a36Sopenharmony_ci	int ret;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
235862306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected auth_reply_more";
235962306a36Sopenharmony_ci		return -EINVAL;
236062306a36Sopenharmony_ci	}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, payload_len, bad);
236362306a36Sopenharmony_ci	ceph_decode_need(&p, end, payload_len, bad);
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	dout("%s con %p payload_len %d\n", __func__, con, payload_len);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	reset_out_kvecs(con);
236862306a36Sopenharmony_ci	ret = prepare_auth_request_more(con, p, payload_len);
236962306a36Sopenharmony_ci	if (ret) {
237062306a36Sopenharmony_ci		if (ret != -EAGAIN)
237162306a36Sopenharmony_ci			pr_err("prepare_auth_request_more failed: %d\n", ret);
237262306a36Sopenharmony_ci		return ret;
237362306a36Sopenharmony_ci	}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	return 0;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_cibad:
237862306a36Sopenharmony_ci	pr_err("failed to decode auth_reply_more\n");
237962306a36Sopenharmony_ci	return -EINVAL;
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci/*
238362306a36Sopenharmony_ci * Align session_key and con_secret to avoid GFP_ATOMIC allocation
238462306a36Sopenharmony_ci * inside crypto_shash_setkey() and crypto_aead_setkey() called from
238562306a36Sopenharmony_ci * setup_crypto().  __aligned(16) isn't guaranteed to work for stack
238662306a36Sopenharmony_ci * objects, so do it by hand.
238762306a36Sopenharmony_ci */
238862306a36Sopenharmony_cistatic int process_auth_done(struct ceph_connection *con, void *p, void *end)
238962306a36Sopenharmony_ci{
239062306a36Sopenharmony_ci	u8 session_key_buf[CEPH_KEY_LEN + 16];
239162306a36Sopenharmony_ci	u8 con_secret_buf[CEPH_MAX_CON_SECRET_LEN + 16];
239262306a36Sopenharmony_ci	u8 *session_key = PTR_ALIGN(&session_key_buf[0], 16);
239362306a36Sopenharmony_ci	u8 *con_secret = PTR_ALIGN(&con_secret_buf[0], 16);
239462306a36Sopenharmony_ci	int session_key_len, con_secret_len;
239562306a36Sopenharmony_ci	int payload_len;
239662306a36Sopenharmony_ci	u64 global_id;
239762306a36Sopenharmony_ci	int ret;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
240062306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected auth_done";
240162306a36Sopenharmony_ci		return -EINVAL;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, global_id, bad);
240562306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, con->v2.con_mode, bad);
240662306a36Sopenharmony_ci	ceph_decode_32_safe(&p, end, payload_len, bad);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	dout("%s con %p global_id %llu con_mode %d payload_len %d\n",
240962306a36Sopenharmony_ci	     __func__, con, global_id, con->v2.con_mode, payload_len);
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	mutex_unlock(&con->mutex);
241262306a36Sopenharmony_ci	session_key_len = 0;
241362306a36Sopenharmony_ci	con_secret_len = 0;
241462306a36Sopenharmony_ci	ret = con->ops->handle_auth_done(con, global_id, p, payload_len,
241562306a36Sopenharmony_ci					 session_key, &session_key_len,
241662306a36Sopenharmony_ci					 con_secret, &con_secret_len);
241762306a36Sopenharmony_ci	mutex_lock(&con->mutex);
241862306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH) {
241962306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
242062306a36Sopenharmony_ci		     con->state);
242162306a36Sopenharmony_ci		ret = -EAGAIN;
242262306a36Sopenharmony_ci		goto out;
242362306a36Sopenharmony_ci	}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	dout("%s con %p handle_auth_done ret %d\n", __func__, con, ret);
242662306a36Sopenharmony_ci	if (ret)
242762306a36Sopenharmony_ci		goto out;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	ret = setup_crypto(con, session_key, session_key_len, con_secret,
243062306a36Sopenharmony_ci			   con_secret_len);
243162306a36Sopenharmony_ci	if (ret)
243262306a36Sopenharmony_ci		goto out;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	reset_out_kvecs(con);
243562306a36Sopenharmony_ci	ret = prepare_auth_signature(con);
243662306a36Sopenharmony_ci	if (ret) {
243762306a36Sopenharmony_ci		pr_err("prepare_auth_signature failed: %d\n", ret);
243862306a36Sopenharmony_ci		goto out;
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_AUTH_SIGNATURE;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ciout:
244462306a36Sopenharmony_ci	memzero_explicit(session_key_buf, sizeof(session_key_buf));
244562306a36Sopenharmony_ci	memzero_explicit(con_secret_buf, sizeof(con_secret_buf));
244662306a36Sopenharmony_ci	return ret;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cibad:
244962306a36Sopenharmony_ci	pr_err("failed to decode auth_done\n");
245062306a36Sopenharmony_ci	return -EINVAL;
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cistatic int process_auth_signature(struct ceph_connection *con,
245462306a36Sopenharmony_ci				  void *p, void *end)
245562306a36Sopenharmony_ci{
245662306a36Sopenharmony_ci	u8 hmac[SHA256_DIGEST_SIZE];
245762306a36Sopenharmony_ci	int ret;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_AUTH_SIGNATURE) {
246062306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected auth_signature";
246162306a36Sopenharmony_ci		return -EINVAL;
246262306a36Sopenharmony_ci	}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	ret = hmac_sha256(con, con->v2.out_sign_kvecs,
246562306a36Sopenharmony_ci			  con->v2.out_sign_kvec_cnt, hmac);
246662306a36Sopenharmony_ci	if (ret)
246762306a36Sopenharmony_ci		return ret;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	ceph_decode_need(&p, end, SHA256_DIGEST_SIZE, bad);
247062306a36Sopenharmony_ci	if (crypto_memneq(p, hmac, SHA256_DIGEST_SIZE)) {
247162306a36Sopenharmony_ci		con->error_msg = "integrity error, bad auth signature";
247262306a36Sopenharmony_ci		return -EBADMSG;
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	dout("%s con %p auth signature ok\n", __func__, con);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	/* no reset_out_kvecs() as our auth_signature may still be pending */
247862306a36Sopenharmony_ci	if (!con->v2.server_cookie) {
247962306a36Sopenharmony_ci		ret = prepare_client_ident(con);
248062306a36Sopenharmony_ci		if (ret) {
248162306a36Sopenharmony_ci			pr_err("prepare_client_ident failed: %d\n", ret);
248262306a36Sopenharmony_ci			return ret;
248362306a36Sopenharmony_ci		}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci		con->state = CEPH_CON_S_V2_SESSION_CONNECT;
248662306a36Sopenharmony_ci	} else {
248762306a36Sopenharmony_ci		ret = prepare_session_reconnect(con);
248862306a36Sopenharmony_ci		if (ret) {
248962306a36Sopenharmony_ci			pr_err("prepare_session_reconnect failed: %d\n", ret);
249062306a36Sopenharmony_ci			return ret;
249162306a36Sopenharmony_ci		}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci		con->state = CEPH_CON_S_V2_SESSION_RECONNECT;
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	return 0;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_cibad:
249962306a36Sopenharmony_ci	pr_err("failed to decode auth_signature\n");
250062306a36Sopenharmony_ci	return -EINVAL;
250162306a36Sopenharmony_ci}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_cistatic int process_server_ident(struct ceph_connection *con,
250462306a36Sopenharmony_ci				void *p, void *end)
250562306a36Sopenharmony_ci{
250662306a36Sopenharmony_ci	struct ceph_client *client = from_msgr(con->msgr);
250762306a36Sopenharmony_ci	u64 features, required_features;
250862306a36Sopenharmony_ci	struct ceph_entity_addr addr;
250962306a36Sopenharmony_ci	u64 global_seq;
251062306a36Sopenharmony_ci	u64 global_id;
251162306a36Sopenharmony_ci	u64 cookie;
251262306a36Sopenharmony_ci	u64 flags;
251362306a36Sopenharmony_ci	int ret;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_CONNECT) {
251662306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected server_ident";
251762306a36Sopenharmony_ci		return -EINVAL;
251862306a36Sopenharmony_ci	}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	ret = ceph_decode_entity_addrvec(&p, end, true, &addr);
252162306a36Sopenharmony_ci	if (ret) {
252262306a36Sopenharmony_ci		pr_err("failed to decode server addrs: %d\n", ret);
252362306a36Sopenharmony_ci		return ret;
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, global_id, bad);
252762306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, global_seq, bad);
252862306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, features, bad);
252962306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, required_features, bad);
253062306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, flags, bad);
253162306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, cookie, bad);
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	dout("%s con %p addr %s/%u global_id %llu global_seq %llu features 0x%llx required_features 0x%llx flags 0x%llx cookie 0x%llx\n",
253462306a36Sopenharmony_ci	     __func__, con, ceph_pr_addr(&addr), le32_to_cpu(addr.nonce),
253562306a36Sopenharmony_ci	     global_id, global_seq, features, required_features, flags, cookie);
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	/* is this who we intended to talk to? */
253862306a36Sopenharmony_ci	if (memcmp(&addr, &con->peer_addr, sizeof(con->peer_addr))) {
253962306a36Sopenharmony_ci		pr_err("bad peer addr/nonce, want %s/%u, got %s/%u\n",
254062306a36Sopenharmony_ci		       ceph_pr_addr(&con->peer_addr),
254162306a36Sopenharmony_ci		       le32_to_cpu(con->peer_addr.nonce),
254262306a36Sopenharmony_ci		       ceph_pr_addr(&addr), le32_to_cpu(addr.nonce));
254362306a36Sopenharmony_ci		con->error_msg = "wrong peer at address";
254462306a36Sopenharmony_ci		return -EINVAL;
254562306a36Sopenharmony_ci	}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	if (client->required_features & ~features) {
254862306a36Sopenharmony_ci		pr_err("RADOS feature set mismatch: my required > server's supported 0x%llx, need 0x%llx\n",
254962306a36Sopenharmony_ci		       features, client->required_features & ~features);
255062306a36Sopenharmony_ci		con->error_msg = "missing required protocol features";
255162306a36Sopenharmony_ci		return -EINVAL;
255262306a36Sopenharmony_ci	}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	/*
255562306a36Sopenharmony_ci	 * Both name->type and name->num are set in ceph_con_open() but
255662306a36Sopenharmony_ci	 * name->num may be bogus in the initial monmap.  name->type is
255762306a36Sopenharmony_ci	 * verified in handle_hello().
255862306a36Sopenharmony_ci	 */
255962306a36Sopenharmony_ci	WARN_ON(!con->peer_name.type);
256062306a36Sopenharmony_ci	con->peer_name.num = cpu_to_le64(global_id);
256162306a36Sopenharmony_ci	con->v2.peer_global_seq = global_seq;
256262306a36Sopenharmony_ci	con->peer_features = features;
256362306a36Sopenharmony_ci	WARN_ON(required_features & ~client->supported_features);
256462306a36Sopenharmony_ci	con->v2.server_cookie = cookie;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	if (flags & CEPH_MSG_CONNECT_LOSSY) {
256762306a36Sopenharmony_ci		ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX);
256862306a36Sopenharmony_ci		WARN_ON(con->v2.server_cookie);
256962306a36Sopenharmony_ci	} else {
257062306a36Sopenharmony_ci		WARN_ON(!con->v2.server_cookie);
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	clear_in_sign_kvecs(con);
257462306a36Sopenharmony_ci	clear_out_sign_kvecs(con);
257562306a36Sopenharmony_ci	free_conn_bufs(con);
257662306a36Sopenharmony_ci	con->delay = 0;  /* reset backoff memory */
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	con->state = CEPH_CON_S_OPEN;
257962306a36Sopenharmony_ci	con->v2.out_state = OUT_S_GET_NEXT;
258062306a36Sopenharmony_ci	return 0;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_cibad:
258362306a36Sopenharmony_ci	pr_err("failed to decode server_ident\n");
258462306a36Sopenharmony_ci	return -EINVAL;
258562306a36Sopenharmony_ci}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_cistatic int process_ident_missing_features(struct ceph_connection *con,
258862306a36Sopenharmony_ci					  void *p, void *end)
258962306a36Sopenharmony_ci{
259062306a36Sopenharmony_ci	struct ceph_client *client = from_msgr(con->msgr);
259162306a36Sopenharmony_ci	u64 missing_features;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_CONNECT) {
259462306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected ident_missing_features";
259562306a36Sopenharmony_ci		return -EINVAL;
259662306a36Sopenharmony_ci	}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, missing_features, bad);
259962306a36Sopenharmony_ci	pr_err("RADOS feature set mismatch: server's required > my supported 0x%llx, missing 0x%llx\n",
260062306a36Sopenharmony_ci	       client->supported_features, missing_features);
260162306a36Sopenharmony_ci	con->error_msg = "missing required protocol features";
260262306a36Sopenharmony_ci	return -EINVAL;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_cibad:
260562306a36Sopenharmony_ci	pr_err("failed to decode ident_missing_features\n");
260662306a36Sopenharmony_ci	return -EINVAL;
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_cistatic int process_session_reconnect_ok(struct ceph_connection *con,
261062306a36Sopenharmony_ci					void *p, void *end)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	u64 seq;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) {
261562306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected session_reconnect_ok";
261662306a36Sopenharmony_ci		return -EINVAL;
261762306a36Sopenharmony_ci	}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, seq, bad);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	dout("%s con %p seq %llu\n", __func__, con, seq);
262262306a36Sopenharmony_ci	ceph_con_discard_requeued(con, seq);
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	clear_in_sign_kvecs(con);
262562306a36Sopenharmony_ci	clear_out_sign_kvecs(con);
262662306a36Sopenharmony_ci	free_conn_bufs(con);
262762306a36Sopenharmony_ci	con->delay = 0;  /* reset backoff memory */
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	con->state = CEPH_CON_S_OPEN;
263062306a36Sopenharmony_ci	con->v2.out_state = OUT_S_GET_NEXT;
263162306a36Sopenharmony_ci	return 0;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_cibad:
263462306a36Sopenharmony_ci	pr_err("failed to decode session_reconnect_ok\n");
263562306a36Sopenharmony_ci	return -EINVAL;
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_cistatic int process_session_retry(struct ceph_connection *con,
263962306a36Sopenharmony_ci				 void *p, void *end)
264062306a36Sopenharmony_ci{
264162306a36Sopenharmony_ci	u64 connect_seq;
264262306a36Sopenharmony_ci	int ret;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) {
264562306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected session_retry";
264662306a36Sopenharmony_ci		return -EINVAL;
264762306a36Sopenharmony_ci	}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, connect_seq, bad);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	dout("%s con %p connect_seq %llu\n", __func__, con, connect_seq);
265262306a36Sopenharmony_ci	WARN_ON(connect_seq <= con->v2.connect_seq);
265362306a36Sopenharmony_ci	con->v2.connect_seq = connect_seq + 1;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	free_conn_bufs(con);
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	reset_out_kvecs(con);
265862306a36Sopenharmony_ci	ret = prepare_session_reconnect(con);
265962306a36Sopenharmony_ci	if (ret) {
266062306a36Sopenharmony_ci		pr_err("prepare_session_reconnect (cseq) failed: %d\n", ret);
266162306a36Sopenharmony_ci		return ret;
266262306a36Sopenharmony_ci	}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	return 0;
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_cibad:
266762306a36Sopenharmony_ci	pr_err("failed to decode session_retry\n");
266862306a36Sopenharmony_ci	return -EINVAL;
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_cistatic int process_session_retry_global(struct ceph_connection *con,
267262306a36Sopenharmony_ci					void *p, void *end)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	u64 global_seq;
267562306a36Sopenharmony_ci	int ret;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) {
267862306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected session_retry_global";
267962306a36Sopenharmony_ci		return -EINVAL;
268062306a36Sopenharmony_ci	}
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, global_seq, bad);
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	dout("%s con %p global_seq %llu\n", __func__, con, global_seq);
268562306a36Sopenharmony_ci	WARN_ON(global_seq <= con->v2.global_seq);
268662306a36Sopenharmony_ci	con->v2.global_seq = ceph_get_global_seq(con->msgr, global_seq);
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	free_conn_bufs(con);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	reset_out_kvecs(con);
269162306a36Sopenharmony_ci	ret = prepare_session_reconnect(con);
269262306a36Sopenharmony_ci	if (ret) {
269362306a36Sopenharmony_ci		pr_err("prepare_session_reconnect (gseq) failed: %d\n", ret);
269462306a36Sopenharmony_ci		return ret;
269562306a36Sopenharmony_ci	}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	return 0;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_cibad:
270062306a36Sopenharmony_ci	pr_err("failed to decode session_retry_global\n");
270162306a36Sopenharmony_ci	return -EINVAL;
270262306a36Sopenharmony_ci}
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_cistatic int process_session_reset(struct ceph_connection *con,
270562306a36Sopenharmony_ci				 void *p, void *end)
270662306a36Sopenharmony_ci{
270762306a36Sopenharmony_ci	bool full;
270862306a36Sopenharmony_ci	int ret;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) {
271162306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected session_reset";
271262306a36Sopenharmony_ci		return -EINVAL;
271362306a36Sopenharmony_ci	}
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	ceph_decode_8_safe(&p, end, full, bad);
271662306a36Sopenharmony_ci	if (!full) {
271762306a36Sopenharmony_ci		con->error_msg = "protocol error, bad session_reset";
271862306a36Sopenharmony_ci		return -EINVAL;
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	pr_info("%s%lld %s session reset\n", ENTITY_NAME(con->peer_name),
272262306a36Sopenharmony_ci		ceph_pr_addr(&con->peer_addr));
272362306a36Sopenharmony_ci	ceph_con_reset_session(con);
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	mutex_unlock(&con->mutex);
272662306a36Sopenharmony_ci	if (con->ops->peer_reset)
272762306a36Sopenharmony_ci		con->ops->peer_reset(con);
272862306a36Sopenharmony_ci	mutex_lock(&con->mutex);
272962306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) {
273062306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
273162306a36Sopenharmony_ci		     con->state);
273262306a36Sopenharmony_ci		return -EAGAIN;
273362306a36Sopenharmony_ci	}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	free_conn_bufs(con);
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	reset_out_kvecs(con);
273862306a36Sopenharmony_ci	ret = prepare_client_ident(con);
273962306a36Sopenharmony_ci	if (ret) {
274062306a36Sopenharmony_ci		pr_err("prepare_client_ident (rst) failed: %d\n", ret);
274162306a36Sopenharmony_ci		return ret;
274262306a36Sopenharmony_ci	}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	con->state = CEPH_CON_S_V2_SESSION_CONNECT;
274562306a36Sopenharmony_ci	return 0;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_cibad:
274862306a36Sopenharmony_ci	pr_err("failed to decode session_reset\n");
274962306a36Sopenharmony_ci	return -EINVAL;
275062306a36Sopenharmony_ci}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_cistatic int process_keepalive2_ack(struct ceph_connection *con,
275362306a36Sopenharmony_ci				  void *p, void *end)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_OPEN) {
275662306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected keepalive2_ack";
275762306a36Sopenharmony_ci		return -EINVAL;
275862306a36Sopenharmony_ci	}
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	ceph_decode_need(&p, end, sizeof(struct ceph_timespec), bad);
276162306a36Sopenharmony_ci	ceph_decode_timespec64(&con->last_keepalive_ack, p);
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	dout("%s con %p timestamp %lld.%09ld\n", __func__, con,
276462306a36Sopenharmony_ci	     con->last_keepalive_ack.tv_sec, con->last_keepalive_ack.tv_nsec);
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	return 0;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_cibad:
276962306a36Sopenharmony_ci	pr_err("failed to decode keepalive2_ack\n");
277062306a36Sopenharmony_ci	return -EINVAL;
277162306a36Sopenharmony_ci}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_cistatic int process_ack(struct ceph_connection *con, void *p, void *end)
277462306a36Sopenharmony_ci{
277562306a36Sopenharmony_ci	u64 seq;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_OPEN) {
277862306a36Sopenharmony_ci		con->error_msg = "protocol error, unexpected ack";
277962306a36Sopenharmony_ci		return -EINVAL;
278062306a36Sopenharmony_ci	}
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	ceph_decode_64_safe(&p, end, seq, bad);
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	dout("%s con %p seq %llu\n", __func__, con, seq);
278562306a36Sopenharmony_ci	ceph_con_discard_sent(con, seq);
278662306a36Sopenharmony_ci	return 0;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_cibad:
278962306a36Sopenharmony_ci	pr_err("failed to decode ack\n");
279062306a36Sopenharmony_ci	return -EINVAL;
279162306a36Sopenharmony_ci}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_cistatic int process_control(struct ceph_connection *con, void *p, void *end)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	int tag = con->v2.in_desc.fd_tag;
279662306a36Sopenharmony_ci	int ret;
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci	dout("%s con %p tag %d len %d\n", __func__, con, tag, (int)(end - p));
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	switch (tag) {
280162306a36Sopenharmony_ci	case FRAME_TAG_HELLO:
280262306a36Sopenharmony_ci		ret = process_hello(con, p, end);
280362306a36Sopenharmony_ci		break;
280462306a36Sopenharmony_ci	case FRAME_TAG_AUTH_BAD_METHOD:
280562306a36Sopenharmony_ci		ret = process_auth_bad_method(con, p, end);
280662306a36Sopenharmony_ci		break;
280762306a36Sopenharmony_ci	case FRAME_TAG_AUTH_REPLY_MORE:
280862306a36Sopenharmony_ci		ret = process_auth_reply_more(con, p, end);
280962306a36Sopenharmony_ci		break;
281062306a36Sopenharmony_ci	case FRAME_TAG_AUTH_DONE:
281162306a36Sopenharmony_ci		ret = process_auth_done(con, p, end);
281262306a36Sopenharmony_ci		break;
281362306a36Sopenharmony_ci	case FRAME_TAG_AUTH_SIGNATURE:
281462306a36Sopenharmony_ci		ret = process_auth_signature(con, p, end);
281562306a36Sopenharmony_ci		break;
281662306a36Sopenharmony_ci	case FRAME_TAG_SERVER_IDENT:
281762306a36Sopenharmony_ci		ret = process_server_ident(con, p, end);
281862306a36Sopenharmony_ci		break;
281962306a36Sopenharmony_ci	case FRAME_TAG_IDENT_MISSING_FEATURES:
282062306a36Sopenharmony_ci		ret = process_ident_missing_features(con, p, end);
282162306a36Sopenharmony_ci		break;
282262306a36Sopenharmony_ci	case FRAME_TAG_SESSION_RECONNECT_OK:
282362306a36Sopenharmony_ci		ret = process_session_reconnect_ok(con, p, end);
282462306a36Sopenharmony_ci		break;
282562306a36Sopenharmony_ci	case FRAME_TAG_SESSION_RETRY:
282662306a36Sopenharmony_ci		ret = process_session_retry(con, p, end);
282762306a36Sopenharmony_ci		break;
282862306a36Sopenharmony_ci	case FRAME_TAG_SESSION_RETRY_GLOBAL:
282962306a36Sopenharmony_ci		ret = process_session_retry_global(con, p, end);
283062306a36Sopenharmony_ci		break;
283162306a36Sopenharmony_ci	case FRAME_TAG_SESSION_RESET:
283262306a36Sopenharmony_ci		ret = process_session_reset(con, p, end);
283362306a36Sopenharmony_ci		break;
283462306a36Sopenharmony_ci	case FRAME_TAG_KEEPALIVE2_ACK:
283562306a36Sopenharmony_ci		ret = process_keepalive2_ack(con, p, end);
283662306a36Sopenharmony_ci		break;
283762306a36Sopenharmony_ci	case FRAME_TAG_ACK:
283862306a36Sopenharmony_ci		ret = process_ack(con, p, end);
283962306a36Sopenharmony_ci		break;
284062306a36Sopenharmony_ci	default:
284162306a36Sopenharmony_ci		pr_err("bad tag %d\n", tag);
284262306a36Sopenharmony_ci		con->error_msg = "protocol error, bad tag";
284362306a36Sopenharmony_ci		return -EINVAL;
284462306a36Sopenharmony_ci	}
284562306a36Sopenharmony_ci	if (ret) {
284662306a36Sopenharmony_ci		dout("%s con %p error %d\n", __func__, con, ret);
284762306a36Sopenharmony_ci		return ret;
284862306a36Sopenharmony_ci	}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	prepare_read_preamble(con);
285162306a36Sopenharmony_ci	return 0;
285262306a36Sopenharmony_ci}
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci/*
285562306a36Sopenharmony_ci * Return:
285662306a36Sopenharmony_ci *   1 - con->in_msg set, read message
285762306a36Sopenharmony_ci *   0 - skip message
285862306a36Sopenharmony_ci *  <0 - error
285962306a36Sopenharmony_ci */
286062306a36Sopenharmony_cistatic int process_message_header(struct ceph_connection *con,
286162306a36Sopenharmony_ci				  void *p, void *end)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	struct ceph_frame_desc *desc = &con->v2.in_desc;
286462306a36Sopenharmony_ci	struct ceph_msg_header2 *hdr2 = p;
286562306a36Sopenharmony_ci	struct ceph_msg_header hdr;
286662306a36Sopenharmony_ci	int skip;
286762306a36Sopenharmony_ci	int ret;
286862306a36Sopenharmony_ci	u64 seq;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	/* verify seq# */
287162306a36Sopenharmony_ci	seq = le64_to_cpu(hdr2->seq);
287262306a36Sopenharmony_ci	if ((s64)seq - (s64)con->in_seq < 1) {
287362306a36Sopenharmony_ci		pr_info("%s%lld %s skipping old message: seq %llu, expected %llu\n",
287462306a36Sopenharmony_ci			ENTITY_NAME(con->peer_name),
287562306a36Sopenharmony_ci			ceph_pr_addr(&con->peer_addr),
287662306a36Sopenharmony_ci			seq, con->in_seq + 1);
287762306a36Sopenharmony_ci		return 0;
287862306a36Sopenharmony_ci	}
287962306a36Sopenharmony_ci	if ((s64)seq - (s64)con->in_seq > 1) {
288062306a36Sopenharmony_ci		pr_err("bad seq %llu, expected %llu\n", seq, con->in_seq + 1);
288162306a36Sopenharmony_ci		con->error_msg = "bad message sequence # for incoming message";
288262306a36Sopenharmony_ci		return -EBADE;
288362306a36Sopenharmony_ci	}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	ceph_con_discard_sent(con, le64_to_cpu(hdr2->ack_seq));
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	fill_header(&hdr, hdr2, desc->fd_lens[1], desc->fd_lens[2],
288862306a36Sopenharmony_ci		    desc->fd_lens[3], &con->peer_name);
288962306a36Sopenharmony_ci	ret = ceph_con_in_msg_alloc(con, &hdr, &skip);
289062306a36Sopenharmony_ci	if (ret)
289162306a36Sopenharmony_ci		return ret;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	WARN_ON(!con->in_msg ^ skip);
289462306a36Sopenharmony_ci	if (skip)
289562306a36Sopenharmony_ci		return 0;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	WARN_ON(!con->in_msg);
289862306a36Sopenharmony_ci	WARN_ON(con->in_msg->con != con);
289962306a36Sopenharmony_ci	return 1;
290062306a36Sopenharmony_ci}
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_cistatic int process_message(struct ceph_connection *con)
290362306a36Sopenharmony_ci{
290462306a36Sopenharmony_ci	ceph_con_process_message(con);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	/*
290762306a36Sopenharmony_ci	 * We could have been closed by ceph_con_close() because
290862306a36Sopenharmony_ci	 * ceph_con_process_message() temporarily drops con->mutex.
290962306a36Sopenharmony_ci	 */
291062306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_OPEN) {
291162306a36Sopenharmony_ci		dout("%s con %p state changed to %d\n", __func__, con,
291262306a36Sopenharmony_ci		     con->state);
291362306a36Sopenharmony_ci		return -EAGAIN;
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	prepare_read_preamble(con);
291762306a36Sopenharmony_ci	return 0;
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_cistatic int __handle_control(struct ceph_connection *con, void *p)
292162306a36Sopenharmony_ci{
292262306a36Sopenharmony_ci	void *end = p + con->v2.in_desc.fd_lens[0];
292362306a36Sopenharmony_ci	struct ceph_msg *msg;
292462306a36Sopenharmony_ci	int ret;
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	if (con->v2.in_desc.fd_tag != FRAME_TAG_MESSAGE)
292762306a36Sopenharmony_ci		return process_control(con, p, end);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	ret = process_message_header(con, p, end);
293062306a36Sopenharmony_ci	if (ret < 0)
293162306a36Sopenharmony_ci		return ret;
293262306a36Sopenharmony_ci	if (ret == 0) {
293362306a36Sopenharmony_ci		prepare_skip_message(con);
293462306a36Sopenharmony_ci		return 0;
293562306a36Sopenharmony_ci	}
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	msg = con->in_msg;  /* set in process_message_header() */
293862306a36Sopenharmony_ci	if (front_len(msg)) {
293962306a36Sopenharmony_ci		WARN_ON(front_len(msg) > msg->front_alloc_len);
294062306a36Sopenharmony_ci		msg->front.iov_len = front_len(msg);
294162306a36Sopenharmony_ci	} else {
294262306a36Sopenharmony_ci		msg->front.iov_len = 0;
294362306a36Sopenharmony_ci	}
294462306a36Sopenharmony_ci	if (middle_len(msg)) {
294562306a36Sopenharmony_ci		WARN_ON(middle_len(msg) > msg->middle->alloc_len);
294662306a36Sopenharmony_ci		msg->middle->vec.iov_len = middle_len(msg);
294762306a36Sopenharmony_ci	} else if (msg->middle) {
294862306a36Sopenharmony_ci		msg->middle->vec.iov_len = 0;
294962306a36Sopenharmony_ci	}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
295262306a36Sopenharmony_ci		return process_message(con);
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	if (con_secure(con))
295562306a36Sopenharmony_ci		return prepare_read_tail_secure(con);
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	return prepare_read_tail_plain(con);
295862306a36Sopenharmony_ci}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_cistatic int handle_preamble(struct ceph_connection *con)
296162306a36Sopenharmony_ci{
296262306a36Sopenharmony_ci	struct ceph_frame_desc *desc = &con->v2.in_desc;
296362306a36Sopenharmony_ci	int ret;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	if (con_secure(con)) {
296662306a36Sopenharmony_ci		ret = decrypt_preamble(con);
296762306a36Sopenharmony_ci		if (ret) {
296862306a36Sopenharmony_ci			if (ret == -EBADMSG)
296962306a36Sopenharmony_ci				con->error_msg = "integrity error, bad preamble auth tag";
297062306a36Sopenharmony_ci			return ret;
297162306a36Sopenharmony_ci		}
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	ret = decode_preamble(con->v2.in_buf, desc);
297562306a36Sopenharmony_ci	if (ret) {
297662306a36Sopenharmony_ci		if (ret == -EBADMSG)
297762306a36Sopenharmony_ci			con->error_msg = "integrity error, bad crc";
297862306a36Sopenharmony_ci		else
297962306a36Sopenharmony_ci			con->error_msg = "protocol error, bad preamble";
298062306a36Sopenharmony_ci		return ret;
298162306a36Sopenharmony_ci	}
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	dout("%s con %p tag %d seg_cnt %d %d+%d+%d+%d\n", __func__,
298462306a36Sopenharmony_ci	     con, desc->fd_tag, desc->fd_seg_cnt, desc->fd_lens[0],
298562306a36Sopenharmony_ci	     desc->fd_lens[1], desc->fd_lens[2], desc->fd_lens[3]);
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	if (!con_secure(con))
298862306a36Sopenharmony_ci		return prepare_read_control(con);
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	if (desc->fd_lens[0] > CEPH_PREAMBLE_INLINE_LEN)
299162306a36Sopenharmony_ci		return prepare_read_control_remainder(con);
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	return __handle_control(con, CTRL_BODY(con->v2.in_buf));
299462306a36Sopenharmony_ci}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_cistatic int handle_control(struct ceph_connection *con)
299762306a36Sopenharmony_ci{
299862306a36Sopenharmony_ci	int ctrl_len = con->v2.in_desc.fd_lens[0];
299962306a36Sopenharmony_ci	void *buf;
300062306a36Sopenharmony_ci	int ret;
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	WARN_ON(con_secure(con));
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	ret = verify_control_crc(con);
300562306a36Sopenharmony_ci	if (ret) {
300662306a36Sopenharmony_ci		con->error_msg = "integrity error, bad crc";
300762306a36Sopenharmony_ci		return ret;
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	if (con->state == CEPH_CON_S_V2_AUTH) {
301162306a36Sopenharmony_ci		buf = alloc_conn_buf(con, ctrl_len);
301262306a36Sopenharmony_ci		if (!buf)
301362306a36Sopenharmony_ci			return -ENOMEM;
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci		memcpy(buf, con->v2.in_kvecs[0].iov_base, ctrl_len);
301662306a36Sopenharmony_ci		return __handle_control(con, buf);
301762306a36Sopenharmony_ci	}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	return __handle_control(con, con->v2.in_kvecs[0].iov_base);
302062306a36Sopenharmony_ci}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_cistatic int handle_control_remainder(struct ceph_connection *con)
302362306a36Sopenharmony_ci{
302462306a36Sopenharmony_ci	int ret;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	WARN_ON(!con_secure(con));
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	ret = decrypt_control_remainder(con);
302962306a36Sopenharmony_ci	if (ret) {
303062306a36Sopenharmony_ci		if (ret == -EBADMSG)
303162306a36Sopenharmony_ci			con->error_msg = "integrity error, bad control remainder auth tag";
303262306a36Sopenharmony_ci		return ret;
303362306a36Sopenharmony_ci	}
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	return __handle_control(con, con->v2.in_kvecs[0].iov_base -
303662306a36Sopenharmony_ci				     CEPH_PREAMBLE_INLINE_LEN);
303762306a36Sopenharmony_ci}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_cistatic int handle_epilogue(struct ceph_connection *con)
304062306a36Sopenharmony_ci{
304162306a36Sopenharmony_ci	u32 front_crc, middle_crc, data_crc;
304262306a36Sopenharmony_ci	int ret;
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (con_secure(con)) {
304562306a36Sopenharmony_ci		ret = decrypt_tail(con);
304662306a36Sopenharmony_ci		if (ret) {
304762306a36Sopenharmony_ci			if (ret == -EBADMSG)
304862306a36Sopenharmony_ci				con->error_msg = "integrity error, bad epilogue auth tag";
304962306a36Sopenharmony_ci			return ret;
305062306a36Sopenharmony_ci		}
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		/* just late_status */
305362306a36Sopenharmony_ci		ret = decode_epilogue(con->v2.in_buf, NULL, NULL, NULL);
305462306a36Sopenharmony_ci		if (ret) {
305562306a36Sopenharmony_ci			con->error_msg = "protocol error, bad epilogue";
305662306a36Sopenharmony_ci			return ret;
305762306a36Sopenharmony_ci		}
305862306a36Sopenharmony_ci	} else {
305962306a36Sopenharmony_ci		ret = decode_epilogue(con->v2.in_buf, &front_crc,
306062306a36Sopenharmony_ci				      &middle_crc, &data_crc);
306162306a36Sopenharmony_ci		if (ret) {
306262306a36Sopenharmony_ci			con->error_msg = "protocol error, bad epilogue";
306362306a36Sopenharmony_ci			return ret;
306462306a36Sopenharmony_ci		}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci		ret = verify_epilogue_crcs(con, front_crc, middle_crc,
306762306a36Sopenharmony_ci					   data_crc);
306862306a36Sopenharmony_ci		if (ret) {
306962306a36Sopenharmony_ci			con->error_msg = "integrity error, bad crc";
307062306a36Sopenharmony_ci			return ret;
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci	}
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	return process_message(con);
307562306a36Sopenharmony_ci}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_cistatic void finish_skip(struct ceph_connection *con)
307862306a36Sopenharmony_ci{
307962306a36Sopenharmony_ci	dout("%s con %p\n", __func__, con);
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	if (con_secure(con))
308262306a36Sopenharmony_ci		gcm_inc_nonce(&con->v2.in_gcm_nonce);
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	__finish_skip(con);
308562306a36Sopenharmony_ci}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_cistatic int populate_in_iter(struct ceph_connection *con)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	int ret;
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci	dout("%s con %p state %d in_state %d\n", __func__, con, con->state,
309262306a36Sopenharmony_ci	     con->v2.in_state);
309362306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.in_iter));
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	if (con->state == CEPH_CON_S_V2_BANNER_PREFIX) {
309662306a36Sopenharmony_ci		ret = process_banner_prefix(con);
309762306a36Sopenharmony_ci	} else if (con->state == CEPH_CON_S_V2_BANNER_PAYLOAD) {
309862306a36Sopenharmony_ci		ret = process_banner_payload(con);
309962306a36Sopenharmony_ci	} else if ((con->state >= CEPH_CON_S_V2_HELLO &&
310062306a36Sopenharmony_ci		    con->state <= CEPH_CON_S_V2_SESSION_RECONNECT) ||
310162306a36Sopenharmony_ci		   con->state == CEPH_CON_S_OPEN) {
310262306a36Sopenharmony_ci		switch (con->v2.in_state) {
310362306a36Sopenharmony_ci		case IN_S_HANDLE_PREAMBLE:
310462306a36Sopenharmony_ci			ret = handle_preamble(con);
310562306a36Sopenharmony_ci			break;
310662306a36Sopenharmony_ci		case IN_S_HANDLE_CONTROL:
310762306a36Sopenharmony_ci			ret = handle_control(con);
310862306a36Sopenharmony_ci			break;
310962306a36Sopenharmony_ci		case IN_S_HANDLE_CONTROL_REMAINDER:
311062306a36Sopenharmony_ci			ret = handle_control_remainder(con);
311162306a36Sopenharmony_ci			break;
311262306a36Sopenharmony_ci		case IN_S_PREPARE_READ_DATA:
311362306a36Sopenharmony_ci			ret = prepare_read_data(con);
311462306a36Sopenharmony_ci			break;
311562306a36Sopenharmony_ci		case IN_S_PREPARE_READ_DATA_CONT:
311662306a36Sopenharmony_ci			prepare_read_data_cont(con);
311762306a36Sopenharmony_ci			ret = 0;
311862306a36Sopenharmony_ci			break;
311962306a36Sopenharmony_ci		case IN_S_PREPARE_READ_ENC_PAGE:
312062306a36Sopenharmony_ci			prepare_read_enc_page(con);
312162306a36Sopenharmony_ci			ret = 0;
312262306a36Sopenharmony_ci			break;
312362306a36Sopenharmony_ci		case IN_S_PREPARE_SPARSE_DATA:
312462306a36Sopenharmony_ci			ret = prepare_sparse_read_data(con);
312562306a36Sopenharmony_ci			break;
312662306a36Sopenharmony_ci		case IN_S_PREPARE_SPARSE_DATA_CONT:
312762306a36Sopenharmony_ci			ret = prepare_sparse_read_cont(con);
312862306a36Sopenharmony_ci			break;
312962306a36Sopenharmony_ci		case IN_S_HANDLE_EPILOGUE:
313062306a36Sopenharmony_ci			ret = handle_epilogue(con);
313162306a36Sopenharmony_ci			break;
313262306a36Sopenharmony_ci		case IN_S_FINISH_SKIP:
313362306a36Sopenharmony_ci			finish_skip(con);
313462306a36Sopenharmony_ci			ret = 0;
313562306a36Sopenharmony_ci			break;
313662306a36Sopenharmony_ci		default:
313762306a36Sopenharmony_ci			WARN(1, "bad in_state %d", con->v2.in_state);
313862306a36Sopenharmony_ci			return -EINVAL;
313962306a36Sopenharmony_ci		}
314062306a36Sopenharmony_ci	} else {
314162306a36Sopenharmony_ci		WARN(1, "bad state %d", con->state);
314262306a36Sopenharmony_ci		return -EINVAL;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci	if (ret) {
314562306a36Sopenharmony_ci		dout("%s con %p error %d\n", __func__, con, ret);
314662306a36Sopenharmony_ci		return ret;
314762306a36Sopenharmony_ci	}
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	if (WARN_ON(!iov_iter_count(&con->v2.in_iter)))
315062306a36Sopenharmony_ci		return -ENODATA;
315162306a36Sopenharmony_ci	dout("%s con %p populated %zu\n", __func__, con,
315262306a36Sopenharmony_ci	     iov_iter_count(&con->v2.in_iter));
315362306a36Sopenharmony_ci	return 1;
315462306a36Sopenharmony_ci}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ciint ceph_con_v2_try_read(struct ceph_connection *con)
315762306a36Sopenharmony_ci{
315862306a36Sopenharmony_ci	int ret;
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	dout("%s con %p state %d need %zu\n", __func__, con, con->state,
316162306a36Sopenharmony_ci	     iov_iter_count(&con->v2.in_iter));
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	if (con->state == CEPH_CON_S_PREOPEN)
316462306a36Sopenharmony_ci		return 0;
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	/*
316762306a36Sopenharmony_ci	 * We should always have something pending here.  If not,
316862306a36Sopenharmony_ci	 * avoid calling populate_in_iter() as if we read something
316962306a36Sopenharmony_ci	 * (ceph_tcp_recv() would immediately return 1).
317062306a36Sopenharmony_ci	 */
317162306a36Sopenharmony_ci	if (WARN_ON(!iov_iter_count(&con->v2.in_iter)))
317262306a36Sopenharmony_ci		return -ENODATA;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	for (;;) {
317562306a36Sopenharmony_ci		ret = ceph_tcp_recv(con);
317662306a36Sopenharmony_ci		if (ret <= 0)
317762306a36Sopenharmony_ci			return ret;
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci		ret = populate_in_iter(con);
318062306a36Sopenharmony_ci		if (ret <= 0) {
318162306a36Sopenharmony_ci			if (ret && ret != -EAGAIN && !con->error_msg)
318262306a36Sopenharmony_ci				con->error_msg = "read processing error";
318362306a36Sopenharmony_ci			return ret;
318462306a36Sopenharmony_ci		}
318562306a36Sopenharmony_ci	}
318662306a36Sopenharmony_ci}
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_cistatic void queue_data(struct ceph_connection *con)
318962306a36Sopenharmony_ci{
319062306a36Sopenharmony_ci	struct bio_vec bv;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	con->v2.out_epil.data_crc = -1;
319362306a36Sopenharmony_ci	ceph_msg_data_cursor_init(&con->v2.out_cursor, con->out_msg,
319462306a36Sopenharmony_ci				  data_len(con->out_msg));
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	get_bvec_at(&con->v2.out_cursor, &bv);
319762306a36Sopenharmony_ci	set_out_bvec(con, &bv, true);
319862306a36Sopenharmony_ci	con->v2.out_state = OUT_S_QUEUE_DATA_CONT;
319962306a36Sopenharmony_ci}
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_cistatic void queue_data_cont(struct ceph_connection *con)
320262306a36Sopenharmony_ci{
320362306a36Sopenharmony_ci	struct bio_vec bv;
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	con->v2.out_epil.data_crc = ceph_crc32c_page(
320662306a36Sopenharmony_ci		con->v2.out_epil.data_crc, con->v2.out_bvec.bv_page,
320762306a36Sopenharmony_ci		con->v2.out_bvec.bv_offset, con->v2.out_bvec.bv_len);
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	ceph_msg_data_advance(&con->v2.out_cursor, con->v2.out_bvec.bv_len);
321062306a36Sopenharmony_ci	if (con->v2.out_cursor.total_resid) {
321162306a36Sopenharmony_ci		get_bvec_at(&con->v2.out_cursor, &bv);
321262306a36Sopenharmony_ci		set_out_bvec(con, &bv, true);
321362306a36Sopenharmony_ci		WARN_ON(con->v2.out_state != OUT_S_QUEUE_DATA_CONT);
321462306a36Sopenharmony_ci		return;
321562306a36Sopenharmony_ci	}
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	/*
321862306a36Sopenharmony_ci	 * We've written all data.  Queue epilogue.  Once it's written,
321962306a36Sopenharmony_ci	 * we are done.
322062306a36Sopenharmony_ci	 */
322162306a36Sopenharmony_ci	reset_out_kvecs(con);
322262306a36Sopenharmony_ci	prepare_epilogue_plain(con, false);
322362306a36Sopenharmony_ci	con->v2.out_state = OUT_S_FINISH_MESSAGE;
322462306a36Sopenharmony_ci}
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_cistatic void queue_enc_page(struct ceph_connection *con)
322762306a36Sopenharmony_ci{
322862306a36Sopenharmony_ci	struct bio_vec bv;
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	dout("%s con %p i %d resid %d\n", __func__, con, con->v2.out_enc_i,
323162306a36Sopenharmony_ci	     con->v2.out_enc_resid);
323262306a36Sopenharmony_ci	WARN_ON(!con->v2.out_enc_resid);
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	bvec_set_page(&bv, con->v2.out_enc_pages[con->v2.out_enc_i],
323562306a36Sopenharmony_ci		      min(con->v2.out_enc_resid, (int)PAGE_SIZE), 0);
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci	set_out_bvec(con, &bv, false);
323862306a36Sopenharmony_ci	con->v2.out_enc_i++;
323962306a36Sopenharmony_ci	con->v2.out_enc_resid -= bv.bv_len;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	if (con->v2.out_enc_resid) {
324262306a36Sopenharmony_ci		WARN_ON(con->v2.out_state != OUT_S_QUEUE_ENC_PAGE);
324362306a36Sopenharmony_ci		return;
324462306a36Sopenharmony_ci	}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	/*
324762306a36Sopenharmony_ci	 * We've queued the last piece of ciphertext (ending with
324862306a36Sopenharmony_ci	 * epilogue) + auth tag.  Once it's written, we are done.
324962306a36Sopenharmony_ci	 */
325062306a36Sopenharmony_ci	WARN_ON(con->v2.out_enc_i != con->v2.out_enc_page_cnt);
325162306a36Sopenharmony_ci	con->v2.out_state = OUT_S_FINISH_MESSAGE;
325262306a36Sopenharmony_ci}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_cistatic void queue_zeros(struct ceph_connection *con)
325562306a36Sopenharmony_ci{
325662306a36Sopenharmony_ci	dout("%s con %p out_zero %d\n", __func__, con, con->v2.out_zero);
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci	if (con->v2.out_zero) {
325962306a36Sopenharmony_ci		set_out_bvec_zero(con);
326062306a36Sopenharmony_ci		con->v2.out_zero -= con->v2.out_bvec.bv_len;
326162306a36Sopenharmony_ci		con->v2.out_state = OUT_S_QUEUE_ZEROS;
326262306a36Sopenharmony_ci		return;
326362306a36Sopenharmony_ci	}
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	/*
326662306a36Sopenharmony_ci	 * We've zero-filled everything up to epilogue.  Queue epilogue
326762306a36Sopenharmony_ci	 * with late_status set to ABORTED and crcs adjusted for zeros.
326862306a36Sopenharmony_ci	 * Once it's written, we are done patching up for the revoke.
326962306a36Sopenharmony_ci	 */
327062306a36Sopenharmony_ci	reset_out_kvecs(con);
327162306a36Sopenharmony_ci	prepare_epilogue_plain(con, true);
327262306a36Sopenharmony_ci	con->v2.out_state = OUT_S_FINISH_MESSAGE;
327362306a36Sopenharmony_ci}
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_cistatic void finish_message(struct ceph_connection *con)
327662306a36Sopenharmony_ci{
327762306a36Sopenharmony_ci	dout("%s con %p msg %p\n", __func__, con, con->out_msg);
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	/* we end up here both plain and secure modes */
328062306a36Sopenharmony_ci	if (con->v2.out_enc_pages) {
328162306a36Sopenharmony_ci		WARN_ON(!con->v2.out_enc_page_cnt);
328262306a36Sopenharmony_ci		ceph_release_page_vector(con->v2.out_enc_pages,
328362306a36Sopenharmony_ci					 con->v2.out_enc_page_cnt);
328462306a36Sopenharmony_ci		con->v2.out_enc_pages = NULL;
328562306a36Sopenharmony_ci		con->v2.out_enc_page_cnt = 0;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci	/* message may have been revoked */
328862306a36Sopenharmony_ci	if (con->out_msg) {
328962306a36Sopenharmony_ci		ceph_msg_put(con->out_msg);
329062306a36Sopenharmony_ci		con->out_msg = NULL;
329162306a36Sopenharmony_ci	}
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci	con->v2.out_state = OUT_S_GET_NEXT;
329462306a36Sopenharmony_ci}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_cistatic int populate_out_iter(struct ceph_connection *con)
329762306a36Sopenharmony_ci{
329862306a36Sopenharmony_ci	int ret;
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	dout("%s con %p state %d out_state %d\n", __func__, con, con->state,
330162306a36Sopenharmony_ci	     con->v2.out_state);
330262306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.out_iter));
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	if (con->state != CEPH_CON_S_OPEN) {
330562306a36Sopenharmony_ci		WARN_ON(con->state < CEPH_CON_S_V2_BANNER_PREFIX ||
330662306a36Sopenharmony_ci			con->state > CEPH_CON_S_V2_SESSION_RECONNECT);
330762306a36Sopenharmony_ci		goto nothing_pending;
330862306a36Sopenharmony_ci	}
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci	switch (con->v2.out_state) {
331162306a36Sopenharmony_ci	case OUT_S_QUEUE_DATA:
331262306a36Sopenharmony_ci		WARN_ON(!con->out_msg);
331362306a36Sopenharmony_ci		queue_data(con);
331462306a36Sopenharmony_ci		goto populated;
331562306a36Sopenharmony_ci	case OUT_S_QUEUE_DATA_CONT:
331662306a36Sopenharmony_ci		WARN_ON(!con->out_msg);
331762306a36Sopenharmony_ci		queue_data_cont(con);
331862306a36Sopenharmony_ci		goto populated;
331962306a36Sopenharmony_ci	case OUT_S_QUEUE_ENC_PAGE:
332062306a36Sopenharmony_ci		queue_enc_page(con);
332162306a36Sopenharmony_ci		goto populated;
332262306a36Sopenharmony_ci	case OUT_S_QUEUE_ZEROS:
332362306a36Sopenharmony_ci		WARN_ON(con->out_msg);  /* revoked */
332462306a36Sopenharmony_ci		queue_zeros(con);
332562306a36Sopenharmony_ci		goto populated;
332662306a36Sopenharmony_ci	case OUT_S_FINISH_MESSAGE:
332762306a36Sopenharmony_ci		finish_message(con);
332862306a36Sopenharmony_ci		break;
332962306a36Sopenharmony_ci	case OUT_S_GET_NEXT:
333062306a36Sopenharmony_ci		break;
333162306a36Sopenharmony_ci	default:
333262306a36Sopenharmony_ci		WARN(1, "bad out_state %d", con->v2.out_state);
333362306a36Sopenharmony_ci		return -EINVAL;
333462306a36Sopenharmony_ci	}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	WARN_ON(con->v2.out_state != OUT_S_GET_NEXT);
333762306a36Sopenharmony_ci	if (ceph_con_flag_test_and_clear(con, CEPH_CON_F_KEEPALIVE_PENDING)) {
333862306a36Sopenharmony_ci		ret = prepare_keepalive2(con);
333962306a36Sopenharmony_ci		if (ret) {
334062306a36Sopenharmony_ci			pr_err("prepare_keepalive2 failed: %d\n", ret);
334162306a36Sopenharmony_ci			return ret;
334262306a36Sopenharmony_ci		}
334362306a36Sopenharmony_ci	} else if (!list_empty(&con->out_queue)) {
334462306a36Sopenharmony_ci		ceph_con_get_out_msg(con);
334562306a36Sopenharmony_ci		ret = prepare_message(con);
334662306a36Sopenharmony_ci		if (ret) {
334762306a36Sopenharmony_ci			pr_err("prepare_message failed: %d\n", ret);
334862306a36Sopenharmony_ci			return ret;
334962306a36Sopenharmony_ci		}
335062306a36Sopenharmony_ci	} else if (con->in_seq > con->in_seq_acked) {
335162306a36Sopenharmony_ci		ret = prepare_ack(con);
335262306a36Sopenharmony_ci		if (ret) {
335362306a36Sopenharmony_ci			pr_err("prepare_ack failed: %d\n", ret);
335462306a36Sopenharmony_ci			return ret;
335562306a36Sopenharmony_ci		}
335662306a36Sopenharmony_ci	} else {
335762306a36Sopenharmony_ci		goto nothing_pending;
335862306a36Sopenharmony_ci	}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_cipopulated:
336162306a36Sopenharmony_ci	if (WARN_ON(!iov_iter_count(&con->v2.out_iter)))
336262306a36Sopenharmony_ci		return -ENODATA;
336362306a36Sopenharmony_ci	dout("%s con %p populated %zu\n", __func__, con,
336462306a36Sopenharmony_ci	     iov_iter_count(&con->v2.out_iter));
336562306a36Sopenharmony_ci	return 1;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_cinothing_pending:
336862306a36Sopenharmony_ci	WARN_ON(iov_iter_count(&con->v2.out_iter));
336962306a36Sopenharmony_ci	dout("%s con %p nothing pending\n", __func__, con);
337062306a36Sopenharmony_ci	ceph_con_flag_clear(con, CEPH_CON_F_WRITE_PENDING);
337162306a36Sopenharmony_ci	return 0;
337262306a36Sopenharmony_ci}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ciint ceph_con_v2_try_write(struct ceph_connection *con)
337562306a36Sopenharmony_ci{
337662306a36Sopenharmony_ci	int ret;
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	dout("%s con %p state %d have %zu\n", __func__, con, con->state,
337962306a36Sopenharmony_ci	     iov_iter_count(&con->v2.out_iter));
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	/* open the socket first? */
338262306a36Sopenharmony_ci	if (con->state == CEPH_CON_S_PREOPEN) {
338362306a36Sopenharmony_ci		WARN_ON(con->peer_addr.type != CEPH_ENTITY_ADDR_TYPE_MSGR2);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci		/*
338662306a36Sopenharmony_ci		 * Always bump global_seq.  Bump connect_seq only if
338762306a36Sopenharmony_ci		 * there is a session (i.e. we are reconnecting and will
338862306a36Sopenharmony_ci		 * send session_reconnect instead of client_ident).
338962306a36Sopenharmony_ci		 */
339062306a36Sopenharmony_ci		con->v2.global_seq = ceph_get_global_seq(con->msgr, 0);
339162306a36Sopenharmony_ci		if (con->v2.server_cookie)
339262306a36Sopenharmony_ci			con->v2.connect_seq++;
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci		ret = prepare_read_banner_prefix(con);
339562306a36Sopenharmony_ci		if (ret) {
339662306a36Sopenharmony_ci			pr_err("prepare_read_banner_prefix failed: %d\n", ret);
339762306a36Sopenharmony_ci			con->error_msg = "connect error";
339862306a36Sopenharmony_ci			return ret;
339962306a36Sopenharmony_ci		}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci		reset_out_kvecs(con);
340262306a36Sopenharmony_ci		ret = prepare_banner(con);
340362306a36Sopenharmony_ci		if (ret) {
340462306a36Sopenharmony_ci			pr_err("prepare_banner failed: %d\n", ret);
340562306a36Sopenharmony_ci			con->error_msg = "connect error";
340662306a36Sopenharmony_ci			return ret;
340762306a36Sopenharmony_ci		}
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci		ret = ceph_tcp_connect(con);
341062306a36Sopenharmony_ci		if (ret) {
341162306a36Sopenharmony_ci			pr_err("ceph_tcp_connect failed: %d\n", ret);
341262306a36Sopenharmony_ci			con->error_msg = "connect error";
341362306a36Sopenharmony_ci			return ret;
341462306a36Sopenharmony_ci		}
341562306a36Sopenharmony_ci	}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	if (!iov_iter_count(&con->v2.out_iter)) {
341862306a36Sopenharmony_ci		ret = populate_out_iter(con);
341962306a36Sopenharmony_ci		if (ret <= 0) {
342062306a36Sopenharmony_ci			if (ret && ret != -EAGAIN && !con->error_msg)
342162306a36Sopenharmony_ci				con->error_msg = "write processing error";
342262306a36Sopenharmony_ci			return ret;
342362306a36Sopenharmony_ci		}
342462306a36Sopenharmony_ci	}
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	tcp_sock_set_cork(con->sock->sk, true);
342762306a36Sopenharmony_ci	for (;;) {
342862306a36Sopenharmony_ci		ret = ceph_tcp_send(con);
342962306a36Sopenharmony_ci		if (ret <= 0)
343062306a36Sopenharmony_ci			break;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci		ret = populate_out_iter(con);
343362306a36Sopenharmony_ci		if (ret <= 0) {
343462306a36Sopenharmony_ci			if (ret && ret != -EAGAIN && !con->error_msg)
343562306a36Sopenharmony_ci				con->error_msg = "write processing error";
343662306a36Sopenharmony_ci			break;
343762306a36Sopenharmony_ci		}
343862306a36Sopenharmony_ci	}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	tcp_sock_set_cork(con->sock->sk, false);
344162306a36Sopenharmony_ci	return ret;
344262306a36Sopenharmony_ci}
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_cistatic u32 crc32c_zeros(u32 crc, int zero_len)
344562306a36Sopenharmony_ci{
344662306a36Sopenharmony_ci	int len;
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	while (zero_len) {
344962306a36Sopenharmony_ci		len = min(zero_len, (int)PAGE_SIZE);
345062306a36Sopenharmony_ci		crc = crc32c(crc, page_address(ceph_zero_page), len);
345162306a36Sopenharmony_ci		zero_len -= len;
345262306a36Sopenharmony_ci	}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	return crc;
345562306a36Sopenharmony_ci}
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_cistatic void prepare_zero_front(struct ceph_connection *con, int resid)
345862306a36Sopenharmony_ci{
345962306a36Sopenharmony_ci	int sent;
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	WARN_ON(!resid || resid > front_len(con->out_msg));
346262306a36Sopenharmony_ci	sent = front_len(con->out_msg) - resid;
346362306a36Sopenharmony_ci	dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid);
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	if (sent) {
346662306a36Sopenharmony_ci		con->v2.out_epil.front_crc =
346762306a36Sopenharmony_ci			crc32c(-1, con->out_msg->front.iov_base, sent);
346862306a36Sopenharmony_ci		con->v2.out_epil.front_crc =
346962306a36Sopenharmony_ci			crc32c_zeros(con->v2.out_epil.front_crc, resid);
347062306a36Sopenharmony_ci	} else {
347162306a36Sopenharmony_ci		con->v2.out_epil.front_crc = crc32c_zeros(-1, resid);
347262306a36Sopenharmony_ci	}
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	con->v2.out_iter.count -= resid;
347562306a36Sopenharmony_ci	out_zero_add(con, resid);
347662306a36Sopenharmony_ci}
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_cistatic void prepare_zero_middle(struct ceph_connection *con, int resid)
347962306a36Sopenharmony_ci{
348062306a36Sopenharmony_ci	int sent;
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	WARN_ON(!resid || resid > middle_len(con->out_msg));
348362306a36Sopenharmony_ci	sent = middle_len(con->out_msg) - resid;
348462306a36Sopenharmony_ci	dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid);
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	if (sent) {
348762306a36Sopenharmony_ci		con->v2.out_epil.middle_crc =
348862306a36Sopenharmony_ci			crc32c(-1, con->out_msg->middle->vec.iov_base, sent);
348962306a36Sopenharmony_ci		con->v2.out_epil.middle_crc =
349062306a36Sopenharmony_ci			crc32c_zeros(con->v2.out_epil.middle_crc, resid);
349162306a36Sopenharmony_ci	} else {
349262306a36Sopenharmony_ci		con->v2.out_epil.middle_crc = crc32c_zeros(-1, resid);
349362306a36Sopenharmony_ci	}
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	con->v2.out_iter.count -= resid;
349662306a36Sopenharmony_ci	out_zero_add(con, resid);
349762306a36Sopenharmony_ci}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_cistatic void prepare_zero_data(struct ceph_connection *con)
350062306a36Sopenharmony_ci{
350162306a36Sopenharmony_ci	dout("%s con %p\n", __func__, con);
350262306a36Sopenharmony_ci	con->v2.out_epil.data_crc = crc32c_zeros(-1, data_len(con->out_msg));
350362306a36Sopenharmony_ci	out_zero_add(con, data_len(con->out_msg));
350462306a36Sopenharmony_ci}
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_cistatic void revoke_at_queue_data(struct ceph_connection *con)
350762306a36Sopenharmony_ci{
350862306a36Sopenharmony_ci	int boundary;
350962306a36Sopenharmony_ci	int resid;
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	WARN_ON(!data_len(con->out_msg));
351262306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter));
351362306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.out_iter);
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	boundary = front_len(con->out_msg) + middle_len(con->out_msg);
351662306a36Sopenharmony_ci	if (resid > boundary) {
351762306a36Sopenharmony_ci		resid -= boundary;
351862306a36Sopenharmony_ci		WARN_ON(resid > MESSAGE_HEAD_PLAIN_LEN);
351962306a36Sopenharmony_ci		dout("%s con %p was sending head\n", __func__, con);
352062306a36Sopenharmony_ci		if (front_len(con->out_msg))
352162306a36Sopenharmony_ci			prepare_zero_front(con, front_len(con->out_msg));
352262306a36Sopenharmony_ci		if (middle_len(con->out_msg))
352362306a36Sopenharmony_ci			prepare_zero_middle(con, middle_len(con->out_msg));
352462306a36Sopenharmony_ci		prepare_zero_data(con);
352562306a36Sopenharmony_ci		WARN_ON(iov_iter_count(&con->v2.out_iter) != resid);
352662306a36Sopenharmony_ci		con->v2.out_state = OUT_S_QUEUE_ZEROS;
352762306a36Sopenharmony_ci		return;
352862306a36Sopenharmony_ci	}
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	boundary = middle_len(con->out_msg);
353162306a36Sopenharmony_ci	if (resid > boundary) {
353262306a36Sopenharmony_ci		resid -= boundary;
353362306a36Sopenharmony_ci		dout("%s con %p was sending front\n", __func__, con);
353462306a36Sopenharmony_ci		prepare_zero_front(con, resid);
353562306a36Sopenharmony_ci		if (middle_len(con->out_msg))
353662306a36Sopenharmony_ci			prepare_zero_middle(con, middle_len(con->out_msg));
353762306a36Sopenharmony_ci		prepare_zero_data(con);
353862306a36Sopenharmony_ci		queue_zeros(con);
353962306a36Sopenharmony_ci		return;
354062306a36Sopenharmony_ci	}
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	WARN_ON(!resid);
354362306a36Sopenharmony_ci	dout("%s con %p was sending middle\n", __func__, con);
354462306a36Sopenharmony_ci	prepare_zero_middle(con, resid);
354562306a36Sopenharmony_ci	prepare_zero_data(con);
354662306a36Sopenharmony_ci	queue_zeros(con);
354762306a36Sopenharmony_ci}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_cistatic void revoke_at_queue_data_cont(struct ceph_connection *con)
355062306a36Sopenharmony_ci{
355162306a36Sopenharmony_ci	int sent, resid;  /* current piece of data */
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	WARN_ON(!data_len(con->out_msg));
355462306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_bvec(&con->v2.out_iter));
355562306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.out_iter);
355662306a36Sopenharmony_ci	WARN_ON(!resid || resid > con->v2.out_bvec.bv_len);
355762306a36Sopenharmony_ci	sent = con->v2.out_bvec.bv_len - resid;
355862306a36Sopenharmony_ci	dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid);
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	if (sent) {
356162306a36Sopenharmony_ci		con->v2.out_epil.data_crc = ceph_crc32c_page(
356262306a36Sopenharmony_ci			con->v2.out_epil.data_crc, con->v2.out_bvec.bv_page,
356362306a36Sopenharmony_ci			con->v2.out_bvec.bv_offset, sent);
356462306a36Sopenharmony_ci		ceph_msg_data_advance(&con->v2.out_cursor, sent);
356562306a36Sopenharmony_ci	}
356662306a36Sopenharmony_ci	WARN_ON(resid > con->v2.out_cursor.total_resid);
356762306a36Sopenharmony_ci	con->v2.out_epil.data_crc = crc32c_zeros(con->v2.out_epil.data_crc,
356862306a36Sopenharmony_ci						con->v2.out_cursor.total_resid);
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	con->v2.out_iter.count -= resid;
357162306a36Sopenharmony_ci	out_zero_add(con, con->v2.out_cursor.total_resid);
357262306a36Sopenharmony_ci	queue_zeros(con);
357362306a36Sopenharmony_ci}
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_cistatic void revoke_at_finish_message(struct ceph_connection *con)
357662306a36Sopenharmony_ci{
357762306a36Sopenharmony_ci	int boundary;
357862306a36Sopenharmony_ci	int resid;
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter));
358162306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.out_iter);
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	if (!front_len(con->out_msg) && !middle_len(con->out_msg) &&
358462306a36Sopenharmony_ci	    !data_len(con->out_msg)) {
358562306a36Sopenharmony_ci		WARN_ON(!resid || resid > MESSAGE_HEAD_PLAIN_LEN);
358662306a36Sopenharmony_ci		dout("%s con %p was sending head (empty message) - noop\n",
358762306a36Sopenharmony_ci		     __func__, con);
358862306a36Sopenharmony_ci		return;
358962306a36Sopenharmony_ci	}
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	boundary = front_len(con->out_msg) + middle_len(con->out_msg) +
359262306a36Sopenharmony_ci		   CEPH_EPILOGUE_PLAIN_LEN;
359362306a36Sopenharmony_ci	if (resid > boundary) {
359462306a36Sopenharmony_ci		resid -= boundary;
359562306a36Sopenharmony_ci		WARN_ON(resid > MESSAGE_HEAD_PLAIN_LEN);
359662306a36Sopenharmony_ci		dout("%s con %p was sending head\n", __func__, con);
359762306a36Sopenharmony_ci		if (front_len(con->out_msg))
359862306a36Sopenharmony_ci			prepare_zero_front(con, front_len(con->out_msg));
359962306a36Sopenharmony_ci		if (middle_len(con->out_msg))
360062306a36Sopenharmony_ci			prepare_zero_middle(con, middle_len(con->out_msg));
360162306a36Sopenharmony_ci		con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN;
360262306a36Sopenharmony_ci		WARN_ON(iov_iter_count(&con->v2.out_iter) != resid);
360362306a36Sopenharmony_ci		con->v2.out_state = OUT_S_QUEUE_ZEROS;
360462306a36Sopenharmony_ci		return;
360562306a36Sopenharmony_ci	}
360662306a36Sopenharmony_ci
360762306a36Sopenharmony_ci	boundary = middle_len(con->out_msg) + CEPH_EPILOGUE_PLAIN_LEN;
360862306a36Sopenharmony_ci	if (resid > boundary) {
360962306a36Sopenharmony_ci		resid -= boundary;
361062306a36Sopenharmony_ci		dout("%s con %p was sending front\n", __func__, con);
361162306a36Sopenharmony_ci		prepare_zero_front(con, resid);
361262306a36Sopenharmony_ci		if (middle_len(con->out_msg))
361362306a36Sopenharmony_ci			prepare_zero_middle(con, middle_len(con->out_msg));
361462306a36Sopenharmony_ci		con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN;
361562306a36Sopenharmony_ci		queue_zeros(con);
361662306a36Sopenharmony_ci		return;
361762306a36Sopenharmony_ci	}
361862306a36Sopenharmony_ci
361962306a36Sopenharmony_ci	boundary = CEPH_EPILOGUE_PLAIN_LEN;
362062306a36Sopenharmony_ci	if (resid > boundary) {
362162306a36Sopenharmony_ci		resid -= boundary;
362262306a36Sopenharmony_ci		dout("%s con %p was sending middle\n", __func__, con);
362362306a36Sopenharmony_ci		prepare_zero_middle(con, resid);
362462306a36Sopenharmony_ci		con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN;
362562306a36Sopenharmony_ci		queue_zeros(con);
362662306a36Sopenharmony_ci		return;
362762306a36Sopenharmony_ci	}
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	WARN_ON(!resid);
363062306a36Sopenharmony_ci	dout("%s con %p was sending epilogue - noop\n", __func__, con);
363162306a36Sopenharmony_ci}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_civoid ceph_con_v2_revoke(struct ceph_connection *con)
363462306a36Sopenharmony_ci{
363562306a36Sopenharmony_ci	WARN_ON(con->v2.out_zero);
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	if (con_secure(con)) {
363862306a36Sopenharmony_ci		WARN_ON(con->v2.out_state != OUT_S_QUEUE_ENC_PAGE &&
363962306a36Sopenharmony_ci			con->v2.out_state != OUT_S_FINISH_MESSAGE);
364062306a36Sopenharmony_ci		dout("%s con %p secure - noop\n", __func__, con);
364162306a36Sopenharmony_ci		return;
364262306a36Sopenharmony_ci	}
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	switch (con->v2.out_state) {
364562306a36Sopenharmony_ci	case OUT_S_QUEUE_DATA:
364662306a36Sopenharmony_ci		revoke_at_queue_data(con);
364762306a36Sopenharmony_ci		break;
364862306a36Sopenharmony_ci	case OUT_S_QUEUE_DATA_CONT:
364962306a36Sopenharmony_ci		revoke_at_queue_data_cont(con);
365062306a36Sopenharmony_ci		break;
365162306a36Sopenharmony_ci	case OUT_S_FINISH_MESSAGE:
365262306a36Sopenharmony_ci		revoke_at_finish_message(con);
365362306a36Sopenharmony_ci		break;
365462306a36Sopenharmony_ci	default:
365562306a36Sopenharmony_ci		WARN(1, "bad out_state %d", con->v2.out_state);
365662306a36Sopenharmony_ci		break;
365762306a36Sopenharmony_ci	}
365862306a36Sopenharmony_ci}
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_cistatic void revoke_at_prepare_read_data(struct ceph_connection *con)
366162306a36Sopenharmony_ci{
366262306a36Sopenharmony_ci	int remaining;
366362306a36Sopenharmony_ci	int resid;
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	WARN_ON(con_secure(con));
366662306a36Sopenharmony_ci	WARN_ON(!data_len(con->in_msg));
366762306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
366862306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.in_iter);
366962306a36Sopenharmony_ci	WARN_ON(!resid);
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci	remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
367262306a36Sopenharmony_ci	dout("%s con %p resid %d remaining %d\n", __func__, con, resid,
367362306a36Sopenharmony_ci	     remaining);
367462306a36Sopenharmony_ci	con->v2.in_iter.count -= resid;
367562306a36Sopenharmony_ci	set_in_skip(con, resid + remaining);
367662306a36Sopenharmony_ci	con->v2.in_state = IN_S_FINISH_SKIP;
367762306a36Sopenharmony_ci}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_cistatic void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
368062306a36Sopenharmony_ci{
368162306a36Sopenharmony_ci	int recved, resid;  /* current piece of data */
368262306a36Sopenharmony_ci	int remaining;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	WARN_ON(con_secure(con));
368562306a36Sopenharmony_ci	WARN_ON(!data_len(con->in_msg));
368662306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
368762306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.in_iter);
368862306a36Sopenharmony_ci	WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
368962306a36Sopenharmony_ci	recved = con->v2.in_bvec.bv_len - resid;
369062306a36Sopenharmony_ci	dout("%s con %p recved %d resid %d\n", __func__, con, recved, resid);
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	if (recved)
369362306a36Sopenharmony_ci		ceph_msg_data_advance(&con->v2.in_cursor, recved);
369462306a36Sopenharmony_ci	WARN_ON(resid > con->v2.in_cursor.total_resid);
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	remaining = CEPH_EPILOGUE_PLAIN_LEN;
369762306a36Sopenharmony_ci	dout("%s con %p total_resid %zu remaining %d\n", __func__, con,
369862306a36Sopenharmony_ci	     con->v2.in_cursor.total_resid, remaining);
369962306a36Sopenharmony_ci	con->v2.in_iter.count -= resid;
370062306a36Sopenharmony_ci	set_in_skip(con, con->v2.in_cursor.total_resid + remaining);
370162306a36Sopenharmony_ci	con->v2.in_state = IN_S_FINISH_SKIP;
370262306a36Sopenharmony_ci}
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_cistatic void revoke_at_prepare_read_enc_page(struct ceph_connection *con)
370562306a36Sopenharmony_ci{
370662306a36Sopenharmony_ci	int resid;  /* current enc page (not necessarily data) */
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	WARN_ON(!con_secure(con));
370962306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
371062306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.in_iter);
371162306a36Sopenharmony_ci	WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid,
371462306a36Sopenharmony_ci	     con->v2.in_enc_resid);
371562306a36Sopenharmony_ci	con->v2.in_iter.count -= resid;
371662306a36Sopenharmony_ci	set_in_skip(con, resid + con->v2.in_enc_resid);
371762306a36Sopenharmony_ci	con->v2.in_state = IN_S_FINISH_SKIP;
371862306a36Sopenharmony_ci}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_cistatic void revoke_at_prepare_sparse_data(struct ceph_connection *con)
372162306a36Sopenharmony_ci{
372262306a36Sopenharmony_ci	int resid;  /* current piece of data */
372362306a36Sopenharmony_ci	int remaining;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	WARN_ON(con_secure(con));
372662306a36Sopenharmony_ci	WARN_ON(!data_len(con->in_msg));
372762306a36Sopenharmony_ci	WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
372862306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.in_iter);
372962306a36Sopenharmony_ci	dout("%s con %p resid %d\n", __func__, con, resid);
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	remaining = CEPH_EPILOGUE_PLAIN_LEN + con->v2.data_len_remain;
373262306a36Sopenharmony_ci	con->v2.in_iter.count -= resid;
373362306a36Sopenharmony_ci	set_in_skip(con, resid + remaining);
373462306a36Sopenharmony_ci	con->v2.in_state = IN_S_FINISH_SKIP;
373562306a36Sopenharmony_ci}
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_cistatic void revoke_at_handle_epilogue(struct ceph_connection *con)
373862306a36Sopenharmony_ci{
373962306a36Sopenharmony_ci	int resid;
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	resid = iov_iter_count(&con->v2.in_iter);
374262306a36Sopenharmony_ci	WARN_ON(!resid);
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	dout("%s con %p resid %d\n", __func__, con, resid);
374562306a36Sopenharmony_ci	con->v2.in_iter.count -= resid;
374662306a36Sopenharmony_ci	set_in_skip(con, resid);
374762306a36Sopenharmony_ci	con->v2.in_state = IN_S_FINISH_SKIP;
374862306a36Sopenharmony_ci}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_civoid ceph_con_v2_revoke_incoming(struct ceph_connection *con)
375162306a36Sopenharmony_ci{
375262306a36Sopenharmony_ci	switch (con->v2.in_state) {
375362306a36Sopenharmony_ci	case IN_S_PREPARE_SPARSE_DATA:
375462306a36Sopenharmony_ci	case IN_S_PREPARE_READ_DATA:
375562306a36Sopenharmony_ci		revoke_at_prepare_read_data(con);
375662306a36Sopenharmony_ci		break;
375762306a36Sopenharmony_ci	case IN_S_PREPARE_READ_DATA_CONT:
375862306a36Sopenharmony_ci		revoke_at_prepare_read_data_cont(con);
375962306a36Sopenharmony_ci		break;
376062306a36Sopenharmony_ci	case IN_S_PREPARE_READ_ENC_PAGE:
376162306a36Sopenharmony_ci		revoke_at_prepare_read_enc_page(con);
376262306a36Sopenharmony_ci		break;
376362306a36Sopenharmony_ci	case IN_S_PREPARE_SPARSE_DATA_CONT:
376462306a36Sopenharmony_ci		revoke_at_prepare_sparse_data(con);
376562306a36Sopenharmony_ci		break;
376662306a36Sopenharmony_ci	case IN_S_HANDLE_EPILOGUE:
376762306a36Sopenharmony_ci		revoke_at_handle_epilogue(con);
376862306a36Sopenharmony_ci		break;
376962306a36Sopenharmony_ci	default:
377062306a36Sopenharmony_ci		WARN(1, "bad in_state %d", con->v2.in_state);
377162306a36Sopenharmony_ci		break;
377262306a36Sopenharmony_ci	}
377362306a36Sopenharmony_ci}
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_cibool ceph_con_v2_opened(struct ceph_connection *con)
377662306a36Sopenharmony_ci{
377762306a36Sopenharmony_ci	return con->v2.peer_global_seq;
377862306a36Sopenharmony_ci}
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_civoid ceph_con_v2_reset_session(struct ceph_connection *con)
378162306a36Sopenharmony_ci{
378262306a36Sopenharmony_ci	con->v2.client_cookie = 0;
378362306a36Sopenharmony_ci	con->v2.server_cookie = 0;
378462306a36Sopenharmony_ci	con->v2.global_seq = 0;
378562306a36Sopenharmony_ci	con->v2.connect_seq = 0;
378662306a36Sopenharmony_ci	con->v2.peer_global_seq = 0;
378762306a36Sopenharmony_ci}
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_civoid ceph_con_v2_reset_protocol(struct ceph_connection *con)
379062306a36Sopenharmony_ci{
379162306a36Sopenharmony_ci	iov_iter_truncate(&con->v2.in_iter, 0);
379262306a36Sopenharmony_ci	iov_iter_truncate(&con->v2.out_iter, 0);
379362306a36Sopenharmony_ci	con->v2.out_zero = 0;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	clear_in_sign_kvecs(con);
379662306a36Sopenharmony_ci	clear_out_sign_kvecs(con);
379762306a36Sopenharmony_ci	free_conn_bufs(con);
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	if (con->v2.in_enc_pages) {
380062306a36Sopenharmony_ci		WARN_ON(!con->v2.in_enc_page_cnt);
380162306a36Sopenharmony_ci		ceph_release_page_vector(con->v2.in_enc_pages,
380262306a36Sopenharmony_ci					 con->v2.in_enc_page_cnt);
380362306a36Sopenharmony_ci		con->v2.in_enc_pages = NULL;
380462306a36Sopenharmony_ci		con->v2.in_enc_page_cnt = 0;
380562306a36Sopenharmony_ci	}
380662306a36Sopenharmony_ci	if (con->v2.out_enc_pages) {
380762306a36Sopenharmony_ci		WARN_ON(!con->v2.out_enc_page_cnt);
380862306a36Sopenharmony_ci		ceph_release_page_vector(con->v2.out_enc_pages,
380962306a36Sopenharmony_ci					 con->v2.out_enc_page_cnt);
381062306a36Sopenharmony_ci		con->v2.out_enc_pages = NULL;
381162306a36Sopenharmony_ci		con->v2.out_enc_page_cnt = 0;
381262306a36Sopenharmony_ci	}
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ci	con->v2.con_mode = CEPH_CON_MODE_UNKNOWN;
381562306a36Sopenharmony_ci	memzero_explicit(&con->v2.in_gcm_nonce, CEPH_GCM_IV_LEN);
381662306a36Sopenharmony_ci	memzero_explicit(&con->v2.out_gcm_nonce, CEPH_GCM_IV_LEN);
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	if (con->v2.hmac_tfm) {
381962306a36Sopenharmony_ci		crypto_free_shash(con->v2.hmac_tfm);
382062306a36Sopenharmony_ci		con->v2.hmac_tfm = NULL;
382162306a36Sopenharmony_ci	}
382262306a36Sopenharmony_ci	if (con->v2.gcm_req) {
382362306a36Sopenharmony_ci		aead_request_free(con->v2.gcm_req);
382462306a36Sopenharmony_ci		con->v2.gcm_req = NULL;
382562306a36Sopenharmony_ci	}
382662306a36Sopenharmony_ci	if (con->v2.gcm_tfm) {
382762306a36Sopenharmony_ci		crypto_free_aead(con->v2.gcm_tfm);
382862306a36Sopenharmony_ci		con->v2.gcm_tfm = NULL;
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci}
3831