1cd1a677cSIlya Dryomov // SPDX-License-Identifier: GPL-2.0 2cd1a677cSIlya Dryomov /* 3cd1a677cSIlya Dryomov * Ceph msgr2 protocol implementation 4cd1a677cSIlya Dryomov * 5cd1a677cSIlya Dryomov * Copyright (C) 2020 Ilya Dryomov <idryomov@gmail.com> 6cd1a677cSIlya Dryomov */ 7cd1a677cSIlya Dryomov 8cd1a677cSIlya Dryomov #include <linux/ceph/ceph_debug.h> 9cd1a677cSIlya Dryomov 10cd1a677cSIlya Dryomov #include <crypto/aead.h> 11cd1a677cSIlya Dryomov #include <crypto/algapi.h> /* for crypto_memneq() */ 12cd1a677cSIlya Dryomov #include <crypto/hash.h> 13be695ee2SLinus Torvalds #include <crypto/sha2.h> 14cd1a677cSIlya Dryomov #include <linux/bvec.h> 15cd1a677cSIlya Dryomov #include <linux/crc32c.h> 16cd1a677cSIlya Dryomov #include <linux/net.h> 17cd1a677cSIlya Dryomov #include <linux/scatterlist.h> 18cd1a677cSIlya Dryomov #include <linux/socket.h> 19cd1a677cSIlya Dryomov #include <linux/sched/mm.h> 20cd1a677cSIlya Dryomov #include <net/sock.h> 21cd1a677cSIlya Dryomov #include <net/tcp.h> 22cd1a677cSIlya Dryomov 23cd1a677cSIlya Dryomov #include <linux/ceph/ceph_features.h> 24cd1a677cSIlya Dryomov #include <linux/ceph/decode.h> 25cd1a677cSIlya Dryomov #include <linux/ceph/libceph.h> 26cd1a677cSIlya Dryomov #include <linux/ceph/messenger.h> 27cd1a677cSIlya Dryomov 28cd1a677cSIlya Dryomov #include "crypto.h" /* for CEPH_KEY_LEN and CEPH_MAX_CON_SECRET_LEN */ 29cd1a677cSIlya Dryomov 30cd1a677cSIlya Dryomov #define FRAME_TAG_HELLO 1 31cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_REQUEST 2 32cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_BAD_METHOD 3 33cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_REPLY_MORE 4 34cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_REQUEST_MORE 5 35cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_DONE 6 36cd1a677cSIlya Dryomov #define FRAME_TAG_AUTH_SIGNATURE 7 37cd1a677cSIlya Dryomov #define FRAME_TAG_CLIENT_IDENT 8 38cd1a677cSIlya Dryomov #define FRAME_TAG_SERVER_IDENT 9 39cd1a677cSIlya Dryomov #define FRAME_TAG_IDENT_MISSING_FEATURES 10 40cd1a677cSIlya Dryomov #define FRAME_TAG_SESSION_RECONNECT 11 41cd1a677cSIlya Dryomov #define FRAME_TAG_SESSION_RESET 12 42cd1a677cSIlya Dryomov #define FRAME_TAG_SESSION_RETRY 13 43cd1a677cSIlya Dryomov #define FRAME_TAG_SESSION_RETRY_GLOBAL 14 44cd1a677cSIlya Dryomov #define FRAME_TAG_SESSION_RECONNECT_OK 15 45cd1a677cSIlya Dryomov #define FRAME_TAG_WAIT 16 46cd1a677cSIlya Dryomov #define FRAME_TAG_MESSAGE 17 47cd1a677cSIlya Dryomov #define FRAME_TAG_KEEPALIVE2 18 48cd1a677cSIlya Dryomov #define FRAME_TAG_KEEPALIVE2_ACK 19 49cd1a677cSIlya Dryomov #define FRAME_TAG_ACK 20 50cd1a677cSIlya Dryomov 51cd1a677cSIlya Dryomov #define FRAME_LATE_STATUS_ABORTED 0x1 52cd1a677cSIlya Dryomov #define FRAME_LATE_STATUS_COMPLETE 0xe 53cd1a677cSIlya Dryomov #define FRAME_LATE_STATUS_ABORTED_MASK 0xf 54cd1a677cSIlya Dryomov 55cd1a677cSIlya Dryomov #define IN_S_HANDLE_PREAMBLE 1 56cd1a677cSIlya Dryomov #define IN_S_HANDLE_CONTROL 2 57cd1a677cSIlya Dryomov #define IN_S_HANDLE_CONTROL_REMAINDER 3 58cd1a677cSIlya Dryomov #define IN_S_PREPARE_READ_DATA 4 59cd1a677cSIlya Dryomov #define IN_S_PREPARE_READ_DATA_CONT 5 602ea88716SIlya Dryomov #define IN_S_PREPARE_READ_ENC_PAGE 6 612ea88716SIlya Dryomov #define IN_S_HANDLE_EPILOGUE 7 622ea88716SIlya Dryomov #define IN_S_FINISH_SKIP 8 63cd1a677cSIlya Dryomov 64cd1a677cSIlya Dryomov #define OUT_S_QUEUE_DATA 1 65cd1a677cSIlya Dryomov #define OUT_S_QUEUE_DATA_CONT 2 66cd1a677cSIlya Dryomov #define OUT_S_QUEUE_ENC_PAGE 3 67cd1a677cSIlya Dryomov #define OUT_S_QUEUE_ZEROS 4 68cd1a677cSIlya Dryomov #define OUT_S_FINISH_MESSAGE 5 69cd1a677cSIlya Dryomov #define OUT_S_GET_NEXT 6 70cd1a677cSIlya Dryomov 71cd1a677cSIlya Dryomov #define CTRL_BODY(p) ((void *)(p) + CEPH_PREAMBLE_LEN) 72cd1a677cSIlya Dryomov #define FRONT_PAD(p) ((void *)(p) + CEPH_EPILOGUE_SECURE_LEN) 73cd1a677cSIlya Dryomov #define MIDDLE_PAD(p) (FRONT_PAD(p) + CEPH_GCM_BLOCK_LEN) 74cd1a677cSIlya Dryomov #define DATA_PAD(p) (MIDDLE_PAD(p) + CEPH_GCM_BLOCK_LEN) 75cd1a677cSIlya Dryomov 76cd1a677cSIlya Dryomov #define CEPH_MSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) 77cd1a677cSIlya Dryomov 78cd1a677cSIlya Dryomov static int do_recvmsg(struct socket *sock, struct iov_iter *it) 79cd1a677cSIlya Dryomov { 80cd1a677cSIlya Dryomov struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; 81cd1a677cSIlya Dryomov int ret; 82cd1a677cSIlya Dryomov 83cd1a677cSIlya Dryomov msg.msg_iter = *it; 84cd1a677cSIlya Dryomov while (iov_iter_count(it)) { 85cd1a677cSIlya Dryomov ret = sock_recvmsg(sock, &msg, msg.msg_flags); 86cd1a677cSIlya Dryomov if (ret <= 0) { 87cd1a677cSIlya Dryomov if (ret == -EAGAIN) 88cd1a677cSIlya Dryomov ret = 0; 89cd1a677cSIlya Dryomov return ret; 90cd1a677cSIlya Dryomov } 91cd1a677cSIlya Dryomov 92cd1a677cSIlya Dryomov iov_iter_advance(it, ret); 93cd1a677cSIlya Dryomov } 94cd1a677cSIlya Dryomov 95cd1a677cSIlya Dryomov WARN_ON(msg_data_left(&msg)); 96cd1a677cSIlya Dryomov return 1; 97cd1a677cSIlya Dryomov } 98cd1a677cSIlya Dryomov 99cd1a677cSIlya Dryomov /* 100cd1a677cSIlya Dryomov * Read as much as possible. 101cd1a677cSIlya Dryomov * 102cd1a677cSIlya Dryomov * Return: 103cd1a677cSIlya Dryomov * 1 - done, nothing (else) to read 104cd1a677cSIlya Dryomov * 0 - socket is empty, need to wait 105cd1a677cSIlya Dryomov * <0 - error 106cd1a677cSIlya Dryomov */ 107cd1a677cSIlya Dryomov static int ceph_tcp_recv(struct ceph_connection *con) 108cd1a677cSIlya Dryomov { 109cd1a677cSIlya Dryomov int ret; 110cd1a677cSIlya Dryomov 111cd1a677cSIlya Dryomov dout("%s con %p %s %zu\n", __func__, con, 112cd1a677cSIlya Dryomov iov_iter_is_discard(&con->v2.in_iter) ? "discard" : "need", 113cd1a677cSIlya Dryomov iov_iter_count(&con->v2.in_iter)); 114cd1a677cSIlya Dryomov ret = do_recvmsg(con->sock, &con->v2.in_iter); 115cd1a677cSIlya Dryomov dout("%s con %p ret %d left %zu\n", __func__, con, ret, 116cd1a677cSIlya Dryomov iov_iter_count(&con->v2.in_iter)); 117cd1a677cSIlya Dryomov return ret; 118cd1a677cSIlya Dryomov } 119cd1a677cSIlya Dryomov 120cd1a677cSIlya Dryomov static int do_sendmsg(struct socket *sock, struct iov_iter *it) 121cd1a677cSIlya Dryomov { 122cd1a677cSIlya Dryomov struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; 123cd1a677cSIlya Dryomov int ret; 124cd1a677cSIlya Dryomov 125cd1a677cSIlya Dryomov msg.msg_iter = *it; 126cd1a677cSIlya Dryomov while (iov_iter_count(it)) { 127cd1a677cSIlya Dryomov ret = sock_sendmsg(sock, &msg); 128cd1a677cSIlya Dryomov if (ret <= 0) { 129cd1a677cSIlya Dryomov if (ret == -EAGAIN) 130cd1a677cSIlya Dryomov ret = 0; 131cd1a677cSIlya Dryomov return ret; 132cd1a677cSIlya Dryomov } 133cd1a677cSIlya Dryomov 134cd1a677cSIlya Dryomov iov_iter_advance(it, ret); 135cd1a677cSIlya Dryomov } 136cd1a677cSIlya Dryomov 137cd1a677cSIlya Dryomov WARN_ON(msg_data_left(&msg)); 138cd1a677cSIlya Dryomov return 1; 139cd1a677cSIlya Dryomov } 140cd1a677cSIlya Dryomov 141cd1a677cSIlya Dryomov static int do_try_sendpage(struct socket *sock, struct iov_iter *it) 142cd1a677cSIlya Dryomov { 143cd1a677cSIlya Dryomov struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; 144cd1a677cSIlya Dryomov struct bio_vec bv; 145cd1a677cSIlya Dryomov int ret; 146cd1a677cSIlya Dryomov 147cd1a677cSIlya Dryomov if (WARN_ON(!iov_iter_is_bvec(it))) 148cd1a677cSIlya Dryomov return -EINVAL; 149cd1a677cSIlya Dryomov 150cd1a677cSIlya Dryomov while (iov_iter_count(it)) { 151cd1a677cSIlya Dryomov /* iov_iter_iovec() for ITER_BVEC */ 152cd1a677cSIlya Dryomov bv.bv_page = it->bvec->bv_page; 153cd1a677cSIlya Dryomov bv.bv_offset = it->bvec->bv_offset + it->iov_offset; 154cd1a677cSIlya Dryomov bv.bv_len = min(iov_iter_count(it), 155cd1a677cSIlya Dryomov it->bvec->bv_len - it->iov_offset); 156cd1a677cSIlya Dryomov 157cd1a677cSIlya Dryomov /* 158cd1a677cSIlya Dryomov * sendpage cannot properly handle pages with 159cd1a677cSIlya Dryomov * page_count == 0, we need to fall back to sendmsg if 160cd1a677cSIlya Dryomov * that's the case. 161cd1a677cSIlya Dryomov * 162cd1a677cSIlya Dryomov * Same goes for slab pages: skb_can_coalesce() allows 163cd1a677cSIlya Dryomov * coalescing neighboring slab objects into a single frag 164cd1a677cSIlya Dryomov * which triggers one of hardened usercopy checks. 165cd1a677cSIlya Dryomov */ 166cd1a677cSIlya Dryomov if (sendpage_ok(bv.bv_page)) { 167cd1a677cSIlya Dryomov ret = sock->ops->sendpage(sock, bv.bv_page, 168cd1a677cSIlya Dryomov bv.bv_offset, bv.bv_len, 169cd1a677cSIlya Dryomov CEPH_MSG_FLAGS); 170cd1a677cSIlya Dryomov } else { 171cd1a677cSIlya Dryomov iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, bv.bv_len); 172cd1a677cSIlya Dryomov ret = sock_sendmsg(sock, &msg); 173cd1a677cSIlya Dryomov } 174cd1a677cSIlya Dryomov if (ret <= 0) { 175cd1a677cSIlya Dryomov if (ret == -EAGAIN) 176cd1a677cSIlya Dryomov ret = 0; 177cd1a677cSIlya Dryomov return ret; 178cd1a677cSIlya Dryomov } 179cd1a677cSIlya Dryomov 180cd1a677cSIlya Dryomov iov_iter_advance(it, ret); 181cd1a677cSIlya Dryomov } 182cd1a677cSIlya Dryomov 183cd1a677cSIlya Dryomov return 1; 184cd1a677cSIlya Dryomov } 185cd1a677cSIlya Dryomov 186cd1a677cSIlya Dryomov /* 187cd1a677cSIlya Dryomov * Write as much as possible. The socket is expected to be corked, 188cd1a677cSIlya Dryomov * so we don't bother with MSG_MORE/MSG_SENDPAGE_NOTLAST here. 189cd1a677cSIlya Dryomov * 190cd1a677cSIlya Dryomov * Return: 191cd1a677cSIlya Dryomov * 1 - done, nothing (else) to write 192cd1a677cSIlya Dryomov * 0 - socket is full, need to wait 193cd1a677cSIlya Dryomov * <0 - error 194cd1a677cSIlya Dryomov */ 195cd1a677cSIlya Dryomov static int ceph_tcp_send(struct ceph_connection *con) 196cd1a677cSIlya Dryomov { 197cd1a677cSIlya Dryomov int ret; 198cd1a677cSIlya Dryomov 199cd1a677cSIlya Dryomov dout("%s con %p have %zu try_sendpage %d\n", __func__, con, 200cd1a677cSIlya Dryomov iov_iter_count(&con->v2.out_iter), con->v2.out_iter_sendpage); 201cd1a677cSIlya Dryomov if (con->v2.out_iter_sendpage) 202cd1a677cSIlya Dryomov ret = do_try_sendpage(con->sock, &con->v2.out_iter); 203cd1a677cSIlya Dryomov else 204cd1a677cSIlya Dryomov ret = do_sendmsg(con->sock, &con->v2.out_iter); 205cd1a677cSIlya Dryomov dout("%s con %p ret %d left %zu\n", __func__, con, ret, 206cd1a677cSIlya Dryomov iov_iter_count(&con->v2.out_iter)); 207cd1a677cSIlya Dryomov return ret; 208cd1a677cSIlya Dryomov } 209cd1a677cSIlya Dryomov 210cd1a677cSIlya Dryomov static void add_in_kvec(struct ceph_connection *con, void *buf, int len) 211cd1a677cSIlya Dryomov { 212cd1a677cSIlya Dryomov BUG_ON(con->v2.in_kvec_cnt >= ARRAY_SIZE(con->v2.in_kvecs)); 213cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter)); 214cd1a677cSIlya Dryomov 215cd1a677cSIlya Dryomov con->v2.in_kvecs[con->v2.in_kvec_cnt].iov_base = buf; 216cd1a677cSIlya Dryomov con->v2.in_kvecs[con->v2.in_kvec_cnt].iov_len = len; 217cd1a677cSIlya Dryomov con->v2.in_kvec_cnt++; 218cd1a677cSIlya Dryomov 219cd1a677cSIlya Dryomov con->v2.in_iter.nr_segs++; 220cd1a677cSIlya Dryomov con->v2.in_iter.count += len; 221cd1a677cSIlya Dryomov } 222cd1a677cSIlya Dryomov 223cd1a677cSIlya Dryomov static void reset_in_kvecs(struct ceph_connection *con) 224cd1a677cSIlya Dryomov { 225cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.in_iter)); 226cd1a677cSIlya Dryomov 227cd1a677cSIlya Dryomov con->v2.in_kvec_cnt = 0; 228cd1a677cSIlya Dryomov iov_iter_kvec(&con->v2.in_iter, READ, con->v2.in_kvecs, 0, 0); 229cd1a677cSIlya Dryomov } 230cd1a677cSIlya Dryomov 231cd1a677cSIlya Dryomov static void set_in_bvec(struct ceph_connection *con, const struct bio_vec *bv) 232cd1a677cSIlya Dryomov { 233cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.in_iter)); 234cd1a677cSIlya Dryomov 235cd1a677cSIlya Dryomov con->v2.in_bvec = *bv; 236cd1a677cSIlya Dryomov iov_iter_bvec(&con->v2.in_iter, READ, &con->v2.in_bvec, 1, bv->bv_len); 237cd1a677cSIlya Dryomov } 238cd1a677cSIlya Dryomov 239cd1a677cSIlya Dryomov static void set_in_skip(struct ceph_connection *con, int len) 240cd1a677cSIlya Dryomov { 241cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.in_iter)); 242cd1a677cSIlya Dryomov 243cd1a677cSIlya Dryomov dout("%s con %p len %d\n", __func__, con, len); 244cd1a677cSIlya Dryomov iov_iter_discard(&con->v2.in_iter, READ, len); 245cd1a677cSIlya Dryomov } 246cd1a677cSIlya Dryomov 247cd1a677cSIlya Dryomov static void add_out_kvec(struct ceph_connection *con, void *buf, int len) 248cd1a677cSIlya Dryomov { 249cd1a677cSIlya Dryomov BUG_ON(con->v2.out_kvec_cnt >= ARRAY_SIZE(con->v2.out_kvecs)); 250cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter)); 251cd1a677cSIlya Dryomov WARN_ON(con->v2.out_zero); 252cd1a677cSIlya Dryomov 253cd1a677cSIlya Dryomov con->v2.out_kvecs[con->v2.out_kvec_cnt].iov_base = buf; 254cd1a677cSIlya Dryomov con->v2.out_kvecs[con->v2.out_kvec_cnt].iov_len = len; 255cd1a677cSIlya Dryomov con->v2.out_kvec_cnt++; 256cd1a677cSIlya Dryomov 257cd1a677cSIlya Dryomov con->v2.out_iter.nr_segs++; 258cd1a677cSIlya Dryomov con->v2.out_iter.count += len; 259cd1a677cSIlya Dryomov } 260cd1a677cSIlya Dryomov 261cd1a677cSIlya Dryomov static void reset_out_kvecs(struct ceph_connection *con) 262cd1a677cSIlya Dryomov { 263cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter)); 264cd1a677cSIlya Dryomov WARN_ON(con->v2.out_zero); 265cd1a677cSIlya Dryomov 266cd1a677cSIlya Dryomov con->v2.out_kvec_cnt = 0; 267cd1a677cSIlya Dryomov 268cd1a677cSIlya Dryomov iov_iter_kvec(&con->v2.out_iter, WRITE, con->v2.out_kvecs, 0, 0); 269cd1a677cSIlya Dryomov con->v2.out_iter_sendpage = false; 270cd1a677cSIlya Dryomov } 271cd1a677cSIlya Dryomov 272cd1a677cSIlya Dryomov static void set_out_bvec(struct ceph_connection *con, const struct bio_vec *bv, 273cd1a677cSIlya Dryomov bool zerocopy) 274cd1a677cSIlya Dryomov { 275cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter)); 276cd1a677cSIlya Dryomov WARN_ON(con->v2.out_zero); 277cd1a677cSIlya Dryomov 278cd1a677cSIlya Dryomov con->v2.out_bvec = *bv; 279cd1a677cSIlya Dryomov con->v2.out_iter_sendpage = zerocopy; 280cd1a677cSIlya Dryomov iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1, 281cd1a677cSIlya Dryomov con->v2.out_bvec.bv_len); 282cd1a677cSIlya Dryomov } 283cd1a677cSIlya Dryomov 284cd1a677cSIlya Dryomov static void set_out_bvec_zero(struct ceph_connection *con) 285cd1a677cSIlya Dryomov { 286cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter)); 287cd1a677cSIlya Dryomov WARN_ON(!con->v2.out_zero); 288cd1a677cSIlya Dryomov 289cd1a677cSIlya Dryomov con->v2.out_bvec.bv_page = ceph_zero_page; 290cd1a677cSIlya Dryomov con->v2.out_bvec.bv_offset = 0; 291cd1a677cSIlya Dryomov con->v2.out_bvec.bv_len = min(con->v2.out_zero, (int)PAGE_SIZE); 292cd1a677cSIlya Dryomov con->v2.out_iter_sendpage = true; 293cd1a677cSIlya Dryomov iov_iter_bvec(&con->v2.out_iter, WRITE, &con->v2.out_bvec, 1, 294cd1a677cSIlya Dryomov con->v2.out_bvec.bv_len); 295cd1a677cSIlya Dryomov } 296cd1a677cSIlya Dryomov 297cd1a677cSIlya Dryomov static void out_zero_add(struct ceph_connection *con, int len) 298cd1a677cSIlya Dryomov { 299cd1a677cSIlya Dryomov dout("%s con %p len %d\n", __func__, con, len); 300cd1a677cSIlya Dryomov con->v2.out_zero += len; 301cd1a677cSIlya Dryomov } 302cd1a677cSIlya Dryomov 303cd1a677cSIlya Dryomov static void *alloc_conn_buf(struct ceph_connection *con, int len) 304cd1a677cSIlya Dryomov { 305cd1a677cSIlya Dryomov void *buf; 306cd1a677cSIlya Dryomov 307cd1a677cSIlya Dryomov dout("%s con %p len %d\n", __func__, con, len); 308cd1a677cSIlya Dryomov 309cd1a677cSIlya Dryomov if (WARN_ON(con->v2.conn_buf_cnt >= ARRAY_SIZE(con->v2.conn_bufs))) 310cd1a677cSIlya Dryomov return NULL; 311cd1a677cSIlya Dryomov 312a421ef30SMichal Hocko buf = kvmalloc(len, GFP_NOIO); 313cd1a677cSIlya Dryomov if (!buf) 314cd1a677cSIlya Dryomov return NULL; 315cd1a677cSIlya Dryomov 316cd1a677cSIlya Dryomov con->v2.conn_bufs[con->v2.conn_buf_cnt++] = buf; 317cd1a677cSIlya Dryomov return buf; 318cd1a677cSIlya Dryomov } 319cd1a677cSIlya Dryomov 320cd1a677cSIlya Dryomov static void free_conn_bufs(struct ceph_connection *con) 321cd1a677cSIlya Dryomov { 322cd1a677cSIlya Dryomov while (con->v2.conn_buf_cnt) 323cd1a677cSIlya Dryomov kvfree(con->v2.conn_bufs[--con->v2.conn_buf_cnt]); 324cd1a677cSIlya Dryomov } 325cd1a677cSIlya Dryomov 326cd1a677cSIlya Dryomov static void add_in_sign_kvec(struct ceph_connection *con, void *buf, int len) 327cd1a677cSIlya Dryomov { 328cd1a677cSIlya Dryomov BUG_ON(con->v2.in_sign_kvec_cnt >= ARRAY_SIZE(con->v2.in_sign_kvecs)); 329cd1a677cSIlya Dryomov 330cd1a677cSIlya Dryomov con->v2.in_sign_kvecs[con->v2.in_sign_kvec_cnt].iov_base = buf; 331cd1a677cSIlya Dryomov con->v2.in_sign_kvecs[con->v2.in_sign_kvec_cnt].iov_len = len; 332cd1a677cSIlya Dryomov con->v2.in_sign_kvec_cnt++; 333cd1a677cSIlya Dryomov } 334cd1a677cSIlya Dryomov 335cd1a677cSIlya Dryomov static void clear_in_sign_kvecs(struct ceph_connection *con) 336cd1a677cSIlya Dryomov { 337cd1a677cSIlya Dryomov con->v2.in_sign_kvec_cnt = 0; 338cd1a677cSIlya Dryomov } 339cd1a677cSIlya Dryomov 340cd1a677cSIlya Dryomov static void add_out_sign_kvec(struct ceph_connection *con, void *buf, int len) 341cd1a677cSIlya Dryomov { 342cd1a677cSIlya Dryomov BUG_ON(con->v2.out_sign_kvec_cnt >= ARRAY_SIZE(con->v2.out_sign_kvecs)); 343cd1a677cSIlya Dryomov 344cd1a677cSIlya Dryomov con->v2.out_sign_kvecs[con->v2.out_sign_kvec_cnt].iov_base = buf; 345cd1a677cSIlya Dryomov con->v2.out_sign_kvecs[con->v2.out_sign_kvec_cnt].iov_len = len; 346cd1a677cSIlya Dryomov con->v2.out_sign_kvec_cnt++; 347cd1a677cSIlya Dryomov } 348cd1a677cSIlya Dryomov 349cd1a677cSIlya Dryomov static void clear_out_sign_kvecs(struct ceph_connection *con) 350cd1a677cSIlya Dryomov { 351cd1a677cSIlya Dryomov con->v2.out_sign_kvec_cnt = 0; 352cd1a677cSIlya Dryomov } 353cd1a677cSIlya Dryomov 354cd1a677cSIlya Dryomov static bool con_secure(struct ceph_connection *con) 355cd1a677cSIlya Dryomov { 356cd1a677cSIlya Dryomov return con->v2.con_mode == CEPH_CON_MODE_SECURE; 357cd1a677cSIlya Dryomov } 358cd1a677cSIlya Dryomov 359cd1a677cSIlya Dryomov static int front_len(const struct ceph_msg *msg) 360cd1a677cSIlya Dryomov { 361cd1a677cSIlya Dryomov return le32_to_cpu(msg->hdr.front_len); 362cd1a677cSIlya Dryomov } 363cd1a677cSIlya Dryomov 364cd1a677cSIlya Dryomov static int middle_len(const struct ceph_msg *msg) 365cd1a677cSIlya Dryomov { 366cd1a677cSIlya Dryomov return le32_to_cpu(msg->hdr.middle_len); 367cd1a677cSIlya Dryomov } 368cd1a677cSIlya Dryomov 369cd1a677cSIlya Dryomov static int data_len(const struct ceph_msg *msg) 370cd1a677cSIlya Dryomov { 371cd1a677cSIlya Dryomov return le32_to_cpu(msg->hdr.data_len); 372cd1a677cSIlya Dryomov } 373cd1a677cSIlya Dryomov 374cd1a677cSIlya Dryomov static bool need_padding(int len) 375cd1a677cSIlya Dryomov { 376cd1a677cSIlya Dryomov return !IS_ALIGNED(len, CEPH_GCM_BLOCK_LEN); 377cd1a677cSIlya Dryomov } 378cd1a677cSIlya Dryomov 379cd1a677cSIlya Dryomov static int padded_len(int len) 380cd1a677cSIlya Dryomov { 381cd1a677cSIlya Dryomov return ALIGN(len, CEPH_GCM_BLOCK_LEN); 382cd1a677cSIlya Dryomov } 383cd1a677cSIlya Dryomov 384cd1a677cSIlya Dryomov static int padding_len(int len) 385cd1a677cSIlya Dryomov { 386cd1a677cSIlya Dryomov return padded_len(len) - len; 387cd1a677cSIlya Dryomov } 388cd1a677cSIlya Dryomov 389cd1a677cSIlya Dryomov /* preamble + control segment */ 390cd1a677cSIlya Dryomov static int head_onwire_len(int ctrl_len, bool secure) 391cd1a677cSIlya Dryomov { 392cd1a677cSIlya Dryomov int head_len; 393cd1a677cSIlya Dryomov int rem_len; 394cd1a677cSIlya Dryomov 395cd1a677cSIlya Dryomov if (secure) { 396cd1a677cSIlya Dryomov head_len = CEPH_PREAMBLE_SECURE_LEN; 397cd1a677cSIlya Dryomov if (ctrl_len > CEPH_PREAMBLE_INLINE_LEN) { 398cd1a677cSIlya Dryomov rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN; 399cd1a677cSIlya Dryomov head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN; 400cd1a677cSIlya Dryomov } 401cd1a677cSIlya Dryomov } else { 402cd1a677cSIlya Dryomov head_len = CEPH_PREAMBLE_PLAIN_LEN; 403cd1a677cSIlya Dryomov if (ctrl_len) 404cd1a677cSIlya Dryomov head_len += ctrl_len + CEPH_CRC_LEN; 405cd1a677cSIlya Dryomov } 406cd1a677cSIlya Dryomov return head_len; 407cd1a677cSIlya Dryomov } 408cd1a677cSIlya Dryomov 409cd1a677cSIlya Dryomov /* front, middle and data segments + epilogue */ 410cd1a677cSIlya Dryomov static int __tail_onwire_len(int front_len, int middle_len, int data_len, 411cd1a677cSIlya Dryomov bool secure) 412cd1a677cSIlya Dryomov { 413cd1a677cSIlya Dryomov if (!front_len && !middle_len && !data_len) 414cd1a677cSIlya Dryomov return 0; 415cd1a677cSIlya Dryomov 416cd1a677cSIlya Dryomov if (!secure) 417cd1a677cSIlya Dryomov return front_len + middle_len + data_len + 418cd1a677cSIlya Dryomov CEPH_EPILOGUE_PLAIN_LEN; 419cd1a677cSIlya Dryomov 420cd1a677cSIlya Dryomov return padded_len(front_len) + padded_len(middle_len) + 421cd1a677cSIlya Dryomov padded_len(data_len) + CEPH_EPILOGUE_SECURE_LEN; 422cd1a677cSIlya Dryomov } 423cd1a677cSIlya Dryomov 424cd1a677cSIlya Dryomov static int tail_onwire_len(const struct ceph_msg *msg, bool secure) 425cd1a677cSIlya Dryomov { 426cd1a677cSIlya Dryomov return __tail_onwire_len(front_len(msg), middle_len(msg), 427cd1a677cSIlya Dryomov data_len(msg), secure); 428cd1a677cSIlya Dryomov } 429cd1a677cSIlya Dryomov 430cd1a677cSIlya Dryomov /* head_onwire_len(sizeof(struct ceph_msg_header2), false) */ 431cd1a677cSIlya Dryomov #define MESSAGE_HEAD_PLAIN_LEN (CEPH_PREAMBLE_PLAIN_LEN + \ 432cd1a677cSIlya Dryomov sizeof(struct ceph_msg_header2) + \ 433cd1a677cSIlya Dryomov CEPH_CRC_LEN) 434cd1a677cSIlya Dryomov 435cd1a677cSIlya Dryomov static const int frame_aligns[] = { 436cd1a677cSIlya Dryomov sizeof(void *), 437cd1a677cSIlya Dryomov sizeof(void *), 438cd1a677cSIlya Dryomov sizeof(void *), 439cd1a677cSIlya Dryomov PAGE_SIZE 440cd1a677cSIlya Dryomov }; 441cd1a677cSIlya Dryomov 442cd1a677cSIlya Dryomov /* 443cd1a677cSIlya Dryomov * Discards trailing empty segments, unless there is just one segment. 444cd1a677cSIlya Dryomov * A frame always has at least one (possibly empty) segment. 445cd1a677cSIlya Dryomov */ 446cd1a677cSIlya Dryomov static int calc_segment_count(const int *lens, int len_cnt) 447cd1a677cSIlya Dryomov { 448cd1a677cSIlya Dryomov int i; 449cd1a677cSIlya Dryomov 450cd1a677cSIlya Dryomov for (i = len_cnt - 1; i >= 0; i--) { 451cd1a677cSIlya Dryomov if (lens[i]) 452cd1a677cSIlya Dryomov return i + 1; 453cd1a677cSIlya Dryomov } 454cd1a677cSIlya Dryomov 455cd1a677cSIlya Dryomov return 1; 456cd1a677cSIlya Dryomov } 457cd1a677cSIlya Dryomov 458cd1a677cSIlya Dryomov static void init_frame_desc(struct ceph_frame_desc *desc, int tag, 459cd1a677cSIlya Dryomov const int *lens, int len_cnt) 460cd1a677cSIlya Dryomov { 461cd1a677cSIlya Dryomov int i; 462cd1a677cSIlya Dryomov 463cd1a677cSIlya Dryomov memset(desc, 0, sizeof(*desc)); 464cd1a677cSIlya Dryomov 465cd1a677cSIlya Dryomov desc->fd_tag = tag; 466cd1a677cSIlya Dryomov desc->fd_seg_cnt = calc_segment_count(lens, len_cnt); 467cd1a677cSIlya Dryomov BUG_ON(desc->fd_seg_cnt > CEPH_FRAME_MAX_SEGMENT_COUNT); 468cd1a677cSIlya Dryomov for (i = 0; i < desc->fd_seg_cnt; i++) { 469cd1a677cSIlya Dryomov desc->fd_lens[i] = lens[i]; 470cd1a677cSIlya Dryomov desc->fd_aligns[i] = frame_aligns[i]; 471cd1a677cSIlya Dryomov } 472cd1a677cSIlya Dryomov } 473cd1a677cSIlya Dryomov 474cd1a677cSIlya Dryomov /* 475cd1a677cSIlya Dryomov * Preamble crc covers everything up to itself (28 bytes) and 476cd1a677cSIlya Dryomov * is calculated and verified irrespective of the connection mode 477cd1a677cSIlya Dryomov * (i.e. even if the frame is encrypted). 478cd1a677cSIlya Dryomov */ 479cd1a677cSIlya Dryomov static void encode_preamble(const struct ceph_frame_desc *desc, void *p) 480cd1a677cSIlya Dryomov { 481cd1a677cSIlya Dryomov void *crcp = p + CEPH_PREAMBLE_LEN - CEPH_CRC_LEN; 482cd1a677cSIlya Dryomov void *start = p; 483cd1a677cSIlya Dryomov int i; 484cd1a677cSIlya Dryomov 485cd1a677cSIlya Dryomov memset(p, 0, CEPH_PREAMBLE_LEN); 486cd1a677cSIlya Dryomov 487cd1a677cSIlya Dryomov ceph_encode_8(&p, desc->fd_tag); 488cd1a677cSIlya Dryomov ceph_encode_8(&p, desc->fd_seg_cnt); 489cd1a677cSIlya Dryomov for (i = 0; i < desc->fd_seg_cnt; i++) { 490cd1a677cSIlya Dryomov ceph_encode_32(&p, desc->fd_lens[i]); 491cd1a677cSIlya Dryomov ceph_encode_16(&p, desc->fd_aligns[i]); 492cd1a677cSIlya Dryomov } 493cd1a677cSIlya Dryomov 494cd1a677cSIlya Dryomov put_unaligned_le32(crc32c(0, start, crcp - start), crcp); 495cd1a677cSIlya Dryomov } 496cd1a677cSIlya Dryomov 497cd1a677cSIlya Dryomov static int decode_preamble(void *p, struct ceph_frame_desc *desc) 498cd1a677cSIlya Dryomov { 499cd1a677cSIlya Dryomov void *crcp = p + CEPH_PREAMBLE_LEN - CEPH_CRC_LEN; 500cd1a677cSIlya Dryomov u32 crc, expected_crc; 501cd1a677cSIlya Dryomov int i; 502cd1a677cSIlya Dryomov 503cd1a677cSIlya Dryomov crc = crc32c(0, p, crcp - p); 504cd1a677cSIlya Dryomov expected_crc = get_unaligned_le32(crcp); 505cd1a677cSIlya Dryomov if (crc != expected_crc) { 506cd1a677cSIlya Dryomov pr_err("bad preamble crc, calculated %u, expected %u\n", 507cd1a677cSIlya Dryomov crc, expected_crc); 508cd1a677cSIlya Dryomov return -EBADMSG; 509cd1a677cSIlya Dryomov } 510cd1a677cSIlya Dryomov 511cd1a677cSIlya Dryomov memset(desc, 0, sizeof(*desc)); 512cd1a677cSIlya Dryomov 513cd1a677cSIlya Dryomov desc->fd_tag = ceph_decode_8(&p); 514cd1a677cSIlya Dryomov desc->fd_seg_cnt = ceph_decode_8(&p); 515cd1a677cSIlya Dryomov if (desc->fd_seg_cnt < 1 || 516cd1a677cSIlya Dryomov desc->fd_seg_cnt > CEPH_FRAME_MAX_SEGMENT_COUNT) { 517cd1a677cSIlya Dryomov pr_err("bad segment count %d\n", desc->fd_seg_cnt); 518cd1a677cSIlya Dryomov return -EINVAL; 519cd1a677cSIlya Dryomov } 520cd1a677cSIlya Dryomov for (i = 0; i < desc->fd_seg_cnt; i++) { 521cd1a677cSIlya Dryomov desc->fd_lens[i] = ceph_decode_32(&p); 522cd1a677cSIlya Dryomov desc->fd_aligns[i] = ceph_decode_16(&p); 523cd1a677cSIlya Dryomov } 524cd1a677cSIlya Dryomov 525cd1a677cSIlya Dryomov /* 526cd1a677cSIlya Dryomov * This would fire for FRAME_TAG_WAIT (it has one empty 527cd1a677cSIlya Dryomov * segment), but we should never get it as client. 528cd1a677cSIlya Dryomov */ 529cd1a677cSIlya Dryomov if (!desc->fd_lens[desc->fd_seg_cnt - 1]) { 530cd1a677cSIlya Dryomov pr_err("last segment empty\n"); 531cd1a677cSIlya Dryomov return -EINVAL; 532cd1a677cSIlya Dryomov } 533cd1a677cSIlya Dryomov 534cd1a677cSIlya Dryomov if (desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) { 535cd1a677cSIlya Dryomov pr_err("control segment too big %d\n", desc->fd_lens[0]); 536cd1a677cSIlya Dryomov return -EINVAL; 537cd1a677cSIlya Dryomov } 538cd1a677cSIlya Dryomov if (desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) { 539cd1a677cSIlya Dryomov pr_err("front segment too big %d\n", desc->fd_lens[1]); 540cd1a677cSIlya Dryomov return -EINVAL; 541cd1a677cSIlya Dryomov } 542cd1a677cSIlya Dryomov if (desc->fd_lens[2] > CEPH_MSG_MAX_MIDDLE_LEN) { 543cd1a677cSIlya Dryomov pr_err("middle segment too big %d\n", desc->fd_lens[2]); 544cd1a677cSIlya Dryomov return -EINVAL; 545cd1a677cSIlya Dryomov } 546cd1a677cSIlya Dryomov if (desc->fd_lens[3] > CEPH_MSG_MAX_DATA_LEN) { 547cd1a677cSIlya Dryomov pr_err("data segment too big %d\n", desc->fd_lens[3]); 548cd1a677cSIlya Dryomov return -EINVAL; 549cd1a677cSIlya Dryomov } 550cd1a677cSIlya Dryomov 551cd1a677cSIlya Dryomov return 0; 552cd1a677cSIlya Dryomov } 553cd1a677cSIlya Dryomov 554cd1a677cSIlya Dryomov static void encode_epilogue_plain(struct ceph_connection *con, bool aborted) 555cd1a677cSIlya Dryomov { 556cd1a677cSIlya Dryomov con->v2.out_epil.late_status = aborted ? FRAME_LATE_STATUS_ABORTED : 557cd1a677cSIlya Dryomov FRAME_LATE_STATUS_COMPLETE; 558cd1a677cSIlya Dryomov cpu_to_le32s(&con->v2.out_epil.front_crc); 559cd1a677cSIlya Dryomov cpu_to_le32s(&con->v2.out_epil.middle_crc); 560cd1a677cSIlya Dryomov cpu_to_le32s(&con->v2.out_epil.data_crc); 561cd1a677cSIlya Dryomov } 562cd1a677cSIlya Dryomov 563cd1a677cSIlya Dryomov static void encode_epilogue_secure(struct ceph_connection *con, bool aborted) 564cd1a677cSIlya Dryomov { 565cd1a677cSIlya Dryomov memset(&con->v2.out_epil, 0, sizeof(con->v2.out_epil)); 566cd1a677cSIlya Dryomov con->v2.out_epil.late_status = aborted ? FRAME_LATE_STATUS_ABORTED : 567cd1a677cSIlya Dryomov FRAME_LATE_STATUS_COMPLETE; 568cd1a677cSIlya Dryomov } 569cd1a677cSIlya Dryomov 570cd1a677cSIlya Dryomov static int decode_epilogue(void *p, u32 *front_crc, u32 *middle_crc, 571cd1a677cSIlya Dryomov u32 *data_crc) 572cd1a677cSIlya Dryomov { 573cd1a677cSIlya Dryomov u8 late_status; 574cd1a677cSIlya Dryomov 575cd1a677cSIlya Dryomov late_status = ceph_decode_8(&p); 576cd1a677cSIlya Dryomov if ((late_status & FRAME_LATE_STATUS_ABORTED_MASK) != 577cd1a677cSIlya Dryomov FRAME_LATE_STATUS_COMPLETE) { 578cd1a677cSIlya Dryomov /* we should never get an aborted message as client */ 579cd1a677cSIlya Dryomov pr_err("bad late_status 0x%x\n", late_status); 580cd1a677cSIlya Dryomov return -EINVAL; 581cd1a677cSIlya Dryomov } 582cd1a677cSIlya Dryomov 583cd1a677cSIlya Dryomov if (front_crc && middle_crc && data_crc) { 584cd1a677cSIlya Dryomov *front_crc = ceph_decode_32(&p); 585cd1a677cSIlya Dryomov *middle_crc = ceph_decode_32(&p); 586cd1a677cSIlya Dryomov *data_crc = ceph_decode_32(&p); 587cd1a677cSIlya Dryomov } 588cd1a677cSIlya Dryomov 589cd1a677cSIlya Dryomov return 0; 590cd1a677cSIlya Dryomov } 591cd1a677cSIlya Dryomov 592cd1a677cSIlya Dryomov static void fill_header(struct ceph_msg_header *hdr, 593cd1a677cSIlya Dryomov const struct ceph_msg_header2 *hdr2, 594cd1a677cSIlya Dryomov int front_len, int middle_len, int data_len, 595cd1a677cSIlya Dryomov const struct ceph_entity_name *peer_name) 596cd1a677cSIlya Dryomov { 597cd1a677cSIlya Dryomov hdr->seq = hdr2->seq; 598cd1a677cSIlya Dryomov hdr->tid = hdr2->tid; 599cd1a677cSIlya Dryomov hdr->type = hdr2->type; 600cd1a677cSIlya Dryomov hdr->priority = hdr2->priority; 601cd1a677cSIlya Dryomov hdr->version = hdr2->version; 602cd1a677cSIlya Dryomov hdr->front_len = cpu_to_le32(front_len); 603cd1a677cSIlya Dryomov hdr->middle_len = cpu_to_le32(middle_len); 604cd1a677cSIlya Dryomov hdr->data_len = cpu_to_le32(data_len); 605cd1a677cSIlya Dryomov hdr->data_off = hdr2->data_off; 606cd1a677cSIlya Dryomov hdr->src = *peer_name; 607cd1a677cSIlya Dryomov hdr->compat_version = hdr2->compat_version; 608cd1a677cSIlya Dryomov hdr->reserved = 0; 609cd1a677cSIlya Dryomov hdr->crc = 0; 610cd1a677cSIlya Dryomov } 611cd1a677cSIlya Dryomov 612cd1a677cSIlya Dryomov static void fill_header2(struct ceph_msg_header2 *hdr2, 613cd1a677cSIlya Dryomov const struct ceph_msg_header *hdr, u64 ack_seq) 614cd1a677cSIlya Dryomov { 615cd1a677cSIlya Dryomov hdr2->seq = hdr->seq; 616cd1a677cSIlya Dryomov hdr2->tid = hdr->tid; 617cd1a677cSIlya Dryomov hdr2->type = hdr->type; 618cd1a677cSIlya Dryomov hdr2->priority = hdr->priority; 619cd1a677cSIlya Dryomov hdr2->version = hdr->version; 620cd1a677cSIlya Dryomov hdr2->data_pre_padding_len = 0; 621cd1a677cSIlya Dryomov hdr2->data_off = hdr->data_off; 622cd1a677cSIlya Dryomov hdr2->ack_seq = cpu_to_le64(ack_seq); 623cd1a677cSIlya Dryomov hdr2->flags = 0; 624cd1a677cSIlya Dryomov hdr2->compat_version = hdr->compat_version; 625cd1a677cSIlya Dryomov hdr2->reserved = 0; 626cd1a677cSIlya Dryomov } 627cd1a677cSIlya Dryomov 628cd1a677cSIlya Dryomov static int verify_control_crc(struct ceph_connection *con) 629cd1a677cSIlya Dryomov { 630cd1a677cSIlya Dryomov int ctrl_len = con->v2.in_desc.fd_lens[0]; 631cd1a677cSIlya Dryomov u32 crc, expected_crc; 632cd1a677cSIlya Dryomov 633cd1a677cSIlya Dryomov WARN_ON(con->v2.in_kvecs[0].iov_len != ctrl_len); 634cd1a677cSIlya Dryomov WARN_ON(con->v2.in_kvecs[1].iov_len != CEPH_CRC_LEN); 635cd1a677cSIlya Dryomov 636cd1a677cSIlya Dryomov crc = crc32c(-1, con->v2.in_kvecs[0].iov_base, ctrl_len); 637cd1a677cSIlya Dryomov expected_crc = get_unaligned_le32(con->v2.in_kvecs[1].iov_base); 638cd1a677cSIlya Dryomov if (crc != expected_crc) { 639cd1a677cSIlya Dryomov pr_err("bad control crc, calculated %u, expected %u\n", 640cd1a677cSIlya Dryomov crc, expected_crc); 641cd1a677cSIlya Dryomov return -EBADMSG; 642cd1a677cSIlya Dryomov } 643cd1a677cSIlya Dryomov 644cd1a677cSIlya Dryomov return 0; 645cd1a677cSIlya Dryomov } 646cd1a677cSIlya Dryomov 647cd1a677cSIlya Dryomov static int verify_epilogue_crcs(struct ceph_connection *con, u32 front_crc, 648cd1a677cSIlya Dryomov u32 middle_crc, u32 data_crc) 649cd1a677cSIlya Dryomov { 650cd1a677cSIlya Dryomov if (front_len(con->in_msg)) { 651cd1a677cSIlya Dryomov con->in_front_crc = crc32c(-1, con->in_msg->front.iov_base, 652cd1a677cSIlya Dryomov front_len(con->in_msg)); 653cd1a677cSIlya Dryomov } else { 654cd1a677cSIlya Dryomov WARN_ON(!middle_len(con->in_msg) && !data_len(con->in_msg)); 655cd1a677cSIlya Dryomov con->in_front_crc = -1; 656cd1a677cSIlya Dryomov } 657cd1a677cSIlya Dryomov 658cd1a677cSIlya Dryomov if (middle_len(con->in_msg)) 659cd1a677cSIlya Dryomov con->in_middle_crc = crc32c(-1, 660cd1a677cSIlya Dryomov con->in_msg->middle->vec.iov_base, 661cd1a677cSIlya Dryomov middle_len(con->in_msg)); 662cd1a677cSIlya Dryomov else if (data_len(con->in_msg)) 663cd1a677cSIlya Dryomov con->in_middle_crc = -1; 664cd1a677cSIlya Dryomov else 665cd1a677cSIlya Dryomov con->in_middle_crc = 0; 666cd1a677cSIlya Dryomov 667cd1a677cSIlya Dryomov if (!data_len(con->in_msg)) 668cd1a677cSIlya Dryomov con->in_data_crc = 0; 669cd1a677cSIlya Dryomov 670cd1a677cSIlya Dryomov dout("%s con %p msg %p crcs %u %u %u\n", __func__, con, con->in_msg, 671cd1a677cSIlya Dryomov con->in_front_crc, con->in_middle_crc, con->in_data_crc); 672cd1a677cSIlya Dryomov 673cd1a677cSIlya Dryomov if (con->in_front_crc != front_crc) { 674cd1a677cSIlya Dryomov pr_err("bad front crc, calculated %u, expected %u\n", 675cd1a677cSIlya Dryomov con->in_front_crc, front_crc); 676cd1a677cSIlya Dryomov return -EBADMSG; 677cd1a677cSIlya Dryomov } 678cd1a677cSIlya Dryomov if (con->in_middle_crc != middle_crc) { 679cd1a677cSIlya Dryomov pr_err("bad middle crc, calculated %u, expected %u\n", 680cd1a677cSIlya Dryomov con->in_middle_crc, middle_crc); 681cd1a677cSIlya Dryomov return -EBADMSG; 682cd1a677cSIlya Dryomov } 683cd1a677cSIlya Dryomov if (con->in_data_crc != data_crc) { 684cd1a677cSIlya Dryomov pr_err("bad data crc, calculated %u, expected %u\n", 685cd1a677cSIlya Dryomov con->in_data_crc, data_crc); 686cd1a677cSIlya Dryomov return -EBADMSG; 687cd1a677cSIlya Dryomov } 688cd1a677cSIlya Dryomov 689cd1a677cSIlya Dryomov return 0; 690cd1a677cSIlya Dryomov } 691cd1a677cSIlya Dryomov 692cd1a677cSIlya Dryomov static int setup_crypto(struct ceph_connection *con, 69310f42b3eSIlya Dryomov const u8 *session_key, int session_key_len, 69410f42b3eSIlya Dryomov const u8 *con_secret, int con_secret_len) 695cd1a677cSIlya Dryomov { 696cd1a677cSIlya Dryomov unsigned int noio_flag; 697cd1a677cSIlya Dryomov int ret; 698cd1a677cSIlya Dryomov 699cd1a677cSIlya Dryomov dout("%s con %p con_mode %d session_key_len %d con_secret_len %d\n", 700cd1a677cSIlya Dryomov __func__, con, con->v2.con_mode, session_key_len, con_secret_len); 701cd1a677cSIlya Dryomov WARN_ON(con->v2.hmac_tfm || con->v2.gcm_tfm || con->v2.gcm_req); 702cd1a677cSIlya Dryomov 703cd1a677cSIlya Dryomov if (con->v2.con_mode != CEPH_CON_MODE_CRC && 704cd1a677cSIlya Dryomov con->v2.con_mode != CEPH_CON_MODE_SECURE) { 705cd1a677cSIlya Dryomov pr_err("bad con_mode %d\n", con->v2.con_mode); 706cd1a677cSIlya Dryomov return -EINVAL; 707cd1a677cSIlya Dryomov } 708cd1a677cSIlya Dryomov 709cd1a677cSIlya Dryomov if (!session_key_len) { 710cd1a677cSIlya Dryomov WARN_ON(con->v2.con_mode != CEPH_CON_MODE_CRC); 711cd1a677cSIlya Dryomov WARN_ON(con_secret_len); 712cd1a677cSIlya Dryomov return 0; /* auth_none */ 713cd1a677cSIlya Dryomov } 714cd1a677cSIlya Dryomov 715cd1a677cSIlya Dryomov noio_flag = memalloc_noio_save(); 716cd1a677cSIlya Dryomov con->v2.hmac_tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); 717cd1a677cSIlya Dryomov memalloc_noio_restore(noio_flag); 718cd1a677cSIlya Dryomov if (IS_ERR(con->v2.hmac_tfm)) { 719cd1a677cSIlya Dryomov ret = PTR_ERR(con->v2.hmac_tfm); 720cd1a677cSIlya Dryomov con->v2.hmac_tfm = NULL; 721cd1a677cSIlya Dryomov pr_err("failed to allocate hmac tfm context: %d\n", ret); 722cd1a677cSIlya Dryomov return ret; 723cd1a677cSIlya Dryomov } 724cd1a677cSIlya Dryomov 725cd1a677cSIlya Dryomov WARN_ON((unsigned long)session_key & 726cd1a677cSIlya Dryomov crypto_shash_alignmask(con->v2.hmac_tfm)); 727cd1a677cSIlya Dryomov ret = crypto_shash_setkey(con->v2.hmac_tfm, session_key, 728cd1a677cSIlya Dryomov session_key_len); 729cd1a677cSIlya Dryomov if (ret) { 730cd1a677cSIlya Dryomov pr_err("failed to set hmac key: %d\n", ret); 731cd1a677cSIlya Dryomov return ret; 732cd1a677cSIlya Dryomov } 733cd1a677cSIlya Dryomov 734cd1a677cSIlya Dryomov if (con->v2.con_mode == CEPH_CON_MODE_CRC) { 735cd1a677cSIlya Dryomov WARN_ON(con_secret_len); 736cd1a677cSIlya Dryomov return 0; /* auth_x, plain mode */ 737cd1a677cSIlya Dryomov } 738cd1a677cSIlya Dryomov 739cd1a677cSIlya Dryomov if (con_secret_len < CEPH_GCM_KEY_LEN + 2 * CEPH_GCM_IV_LEN) { 740cd1a677cSIlya Dryomov pr_err("con_secret too small %d\n", con_secret_len); 741cd1a677cSIlya Dryomov return -EINVAL; 742cd1a677cSIlya Dryomov } 743cd1a677cSIlya Dryomov 744cd1a677cSIlya Dryomov noio_flag = memalloc_noio_save(); 745cd1a677cSIlya Dryomov con->v2.gcm_tfm = crypto_alloc_aead("gcm(aes)", 0, 0); 746cd1a677cSIlya Dryomov memalloc_noio_restore(noio_flag); 747cd1a677cSIlya Dryomov if (IS_ERR(con->v2.gcm_tfm)) { 748cd1a677cSIlya Dryomov ret = PTR_ERR(con->v2.gcm_tfm); 749cd1a677cSIlya Dryomov con->v2.gcm_tfm = NULL; 750cd1a677cSIlya Dryomov pr_err("failed to allocate gcm tfm context: %d\n", ret); 751cd1a677cSIlya Dryomov return ret; 752cd1a677cSIlya Dryomov } 753cd1a677cSIlya Dryomov 75410f42b3eSIlya Dryomov WARN_ON((unsigned long)con_secret & 75510f42b3eSIlya Dryomov crypto_aead_alignmask(con->v2.gcm_tfm)); 75610f42b3eSIlya Dryomov ret = crypto_aead_setkey(con->v2.gcm_tfm, con_secret, CEPH_GCM_KEY_LEN); 757cd1a677cSIlya Dryomov if (ret) { 758cd1a677cSIlya Dryomov pr_err("failed to set gcm key: %d\n", ret); 759cd1a677cSIlya Dryomov return ret; 760cd1a677cSIlya Dryomov } 761cd1a677cSIlya Dryomov 762cd1a677cSIlya Dryomov WARN_ON(crypto_aead_ivsize(con->v2.gcm_tfm) != CEPH_GCM_IV_LEN); 763cd1a677cSIlya Dryomov ret = crypto_aead_setauthsize(con->v2.gcm_tfm, CEPH_GCM_TAG_LEN); 764cd1a677cSIlya Dryomov if (ret) { 765cd1a677cSIlya Dryomov pr_err("failed to set gcm tag size: %d\n", ret); 766cd1a677cSIlya Dryomov return ret; 767cd1a677cSIlya Dryomov } 768cd1a677cSIlya Dryomov 769cd1a677cSIlya Dryomov con->v2.gcm_req = aead_request_alloc(con->v2.gcm_tfm, GFP_NOIO); 770cd1a677cSIlya Dryomov if (!con->v2.gcm_req) { 771cd1a677cSIlya Dryomov pr_err("failed to allocate gcm request\n"); 772cd1a677cSIlya Dryomov return -ENOMEM; 773cd1a677cSIlya Dryomov } 774cd1a677cSIlya Dryomov 775cd1a677cSIlya Dryomov crypto_init_wait(&con->v2.gcm_wait); 776cd1a677cSIlya Dryomov aead_request_set_callback(con->v2.gcm_req, CRYPTO_TFM_REQ_MAY_BACKLOG, 777cd1a677cSIlya Dryomov crypto_req_done, &con->v2.gcm_wait); 778cd1a677cSIlya Dryomov 77910f42b3eSIlya Dryomov memcpy(&con->v2.in_gcm_nonce, con_secret + CEPH_GCM_KEY_LEN, 78010f42b3eSIlya Dryomov CEPH_GCM_IV_LEN); 78110f42b3eSIlya Dryomov memcpy(&con->v2.out_gcm_nonce, 78210f42b3eSIlya Dryomov con_secret + CEPH_GCM_KEY_LEN + CEPH_GCM_IV_LEN, 78310f42b3eSIlya Dryomov CEPH_GCM_IV_LEN); 784cd1a677cSIlya Dryomov return 0; /* auth_x, secure mode */ 785cd1a677cSIlya Dryomov } 786cd1a677cSIlya Dryomov 787cd1a677cSIlya Dryomov static int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs, 788cd1a677cSIlya Dryomov int kvec_cnt, u8 *hmac) 789cd1a677cSIlya Dryomov { 790cd1a677cSIlya Dryomov SHASH_DESC_ON_STACK(desc, con->v2.hmac_tfm); /* tfm arg is ignored */ 791cd1a677cSIlya Dryomov int ret; 792cd1a677cSIlya Dryomov int i; 793cd1a677cSIlya Dryomov 794cd1a677cSIlya Dryomov dout("%s con %p hmac_tfm %p kvec_cnt %d\n", __func__, con, 795cd1a677cSIlya Dryomov con->v2.hmac_tfm, kvec_cnt); 796cd1a677cSIlya Dryomov 797cd1a677cSIlya Dryomov if (!con->v2.hmac_tfm) { 798cd1a677cSIlya Dryomov memset(hmac, 0, SHA256_DIGEST_SIZE); 799cd1a677cSIlya Dryomov return 0; /* auth_none */ 800cd1a677cSIlya Dryomov } 801cd1a677cSIlya Dryomov 802cd1a677cSIlya Dryomov desc->tfm = con->v2.hmac_tfm; 803cd1a677cSIlya Dryomov ret = crypto_shash_init(desc); 804cd1a677cSIlya Dryomov if (ret) 80510f42b3eSIlya Dryomov goto out; 806cd1a677cSIlya Dryomov 807cd1a677cSIlya Dryomov for (i = 0; i < kvec_cnt; i++) { 808cd1a677cSIlya Dryomov WARN_ON((unsigned long)kvecs[i].iov_base & 809cd1a677cSIlya Dryomov crypto_shash_alignmask(con->v2.hmac_tfm)); 810cd1a677cSIlya Dryomov ret = crypto_shash_update(desc, kvecs[i].iov_base, 811cd1a677cSIlya Dryomov kvecs[i].iov_len); 812cd1a677cSIlya Dryomov if (ret) 81310f42b3eSIlya Dryomov goto out; 814cd1a677cSIlya Dryomov } 815cd1a677cSIlya Dryomov 816cd1a677cSIlya Dryomov ret = crypto_shash_final(desc, hmac); 817cd1a677cSIlya Dryomov 81810f42b3eSIlya Dryomov out: 819cd1a677cSIlya Dryomov shash_desc_zero(desc); 82010f42b3eSIlya Dryomov return ret; /* auth_x, both plain and secure modes */ 821cd1a677cSIlya Dryomov } 822cd1a677cSIlya Dryomov 823cd1a677cSIlya Dryomov static void gcm_inc_nonce(struct ceph_gcm_nonce *nonce) 824cd1a677cSIlya Dryomov { 825cd1a677cSIlya Dryomov u64 counter; 826cd1a677cSIlya Dryomov 827cd1a677cSIlya Dryomov counter = le64_to_cpu(nonce->counter); 828cd1a677cSIlya Dryomov nonce->counter = cpu_to_le64(counter + 1); 829cd1a677cSIlya Dryomov } 830cd1a677cSIlya Dryomov 831cd1a677cSIlya Dryomov static int gcm_crypt(struct ceph_connection *con, bool encrypt, 832cd1a677cSIlya Dryomov struct scatterlist *src, struct scatterlist *dst, 833cd1a677cSIlya Dryomov int src_len) 834cd1a677cSIlya Dryomov { 835cd1a677cSIlya Dryomov struct ceph_gcm_nonce *nonce; 836cd1a677cSIlya Dryomov int ret; 837cd1a677cSIlya Dryomov 838cd1a677cSIlya Dryomov nonce = encrypt ? &con->v2.out_gcm_nonce : &con->v2.in_gcm_nonce; 839cd1a677cSIlya Dryomov 840cd1a677cSIlya Dryomov aead_request_set_ad(con->v2.gcm_req, 0); /* no AAD */ 841cd1a677cSIlya Dryomov aead_request_set_crypt(con->v2.gcm_req, src, dst, src_len, (u8 *)nonce); 842cd1a677cSIlya Dryomov ret = crypto_wait_req(encrypt ? crypto_aead_encrypt(con->v2.gcm_req) : 843cd1a677cSIlya Dryomov crypto_aead_decrypt(con->v2.gcm_req), 844cd1a677cSIlya Dryomov &con->v2.gcm_wait); 845cd1a677cSIlya Dryomov if (ret) 846cd1a677cSIlya Dryomov return ret; 847cd1a677cSIlya Dryomov 848cd1a677cSIlya Dryomov gcm_inc_nonce(nonce); 849cd1a677cSIlya Dryomov return 0; 850cd1a677cSIlya Dryomov } 851cd1a677cSIlya Dryomov 852cd1a677cSIlya Dryomov static void get_bvec_at(struct ceph_msg_data_cursor *cursor, 853cd1a677cSIlya Dryomov struct bio_vec *bv) 854cd1a677cSIlya Dryomov { 855cd1a677cSIlya Dryomov struct page *page; 856cd1a677cSIlya Dryomov size_t off, len; 857cd1a677cSIlya Dryomov 858cd1a677cSIlya Dryomov WARN_ON(!cursor->total_resid); 859cd1a677cSIlya Dryomov 860cd1a677cSIlya Dryomov /* skip zero-length data items */ 861cd1a677cSIlya Dryomov while (!cursor->resid) 862cd1a677cSIlya Dryomov ceph_msg_data_advance(cursor, 0); 863cd1a677cSIlya Dryomov 864cd1a677cSIlya Dryomov /* get a piece of data, cursor isn't advanced */ 865cd1a677cSIlya Dryomov page = ceph_msg_data_next(cursor, &off, &len, NULL); 866cd1a677cSIlya Dryomov 867cd1a677cSIlya Dryomov bv->bv_page = page; 868cd1a677cSIlya Dryomov bv->bv_offset = off; 869cd1a677cSIlya Dryomov bv->bv_len = len; 870cd1a677cSIlya Dryomov } 871cd1a677cSIlya Dryomov 872cd1a677cSIlya Dryomov static int calc_sg_cnt(void *buf, int buf_len) 873cd1a677cSIlya Dryomov { 874cd1a677cSIlya Dryomov int sg_cnt; 875cd1a677cSIlya Dryomov 876cd1a677cSIlya Dryomov if (!buf_len) 877cd1a677cSIlya Dryomov return 0; 878cd1a677cSIlya Dryomov 879cd1a677cSIlya Dryomov sg_cnt = need_padding(buf_len) ? 1 : 0; 880cd1a677cSIlya Dryomov if (is_vmalloc_addr(buf)) { 881cd1a677cSIlya Dryomov WARN_ON(offset_in_page(buf)); 882cd1a677cSIlya Dryomov sg_cnt += PAGE_ALIGN(buf_len) >> PAGE_SHIFT; 883cd1a677cSIlya Dryomov } else { 884cd1a677cSIlya Dryomov sg_cnt++; 885cd1a677cSIlya Dryomov } 886cd1a677cSIlya Dryomov 887cd1a677cSIlya Dryomov return sg_cnt; 888cd1a677cSIlya Dryomov } 889cd1a677cSIlya Dryomov 890cd1a677cSIlya Dryomov static int calc_sg_cnt_cursor(struct ceph_msg_data_cursor *cursor) 891cd1a677cSIlya Dryomov { 892cd1a677cSIlya Dryomov int data_len = cursor->total_resid; 893cd1a677cSIlya Dryomov struct bio_vec bv; 894cd1a677cSIlya Dryomov int sg_cnt; 895cd1a677cSIlya Dryomov 896cd1a677cSIlya Dryomov if (!data_len) 897cd1a677cSIlya Dryomov return 0; 898cd1a677cSIlya Dryomov 899cd1a677cSIlya Dryomov sg_cnt = need_padding(data_len) ? 1 : 0; 900cd1a677cSIlya Dryomov do { 901cd1a677cSIlya Dryomov get_bvec_at(cursor, &bv); 902cd1a677cSIlya Dryomov sg_cnt++; 903cd1a677cSIlya Dryomov 904cd1a677cSIlya Dryomov ceph_msg_data_advance(cursor, bv.bv_len); 905cd1a677cSIlya Dryomov } while (cursor->total_resid); 906cd1a677cSIlya Dryomov 907cd1a677cSIlya Dryomov return sg_cnt; 908cd1a677cSIlya Dryomov } 909cd1a677cSIlya Dryomov 910cd1a677cSIlya Dryomov static void init_sgs(struct scatterlist **sg, void *buf, int buf_len, u8 *pad) 911cd1a677cSIlya Dryomov { 912cd1a677cSIlya Dryomov void *end = buf + buf_len; 913cd1a677cSIlya Dryomov struct page *page; 914cd1a677cSIlya Dryomov int len; 915cd1a677cSIlya Dryomov void *p; 916cd1a677cSIlya Dryomov 917cd1a677cSIlya Dryomov if (!buf_len) 918cd1a677cSIlya Dryomov return; 919cd1a677cSIlya Dryomov 920cd1a677cSIlya Dryomov if (is_vmalloc_addr(buf)) { 921cd1a677cSIlya Dryomov p = buf; 922cd1a677cSIlya Dryomov do { 923cd1a677cSIlya Dryomov page = vmalloc_to_page(p); 924cd1a677cSIlya Dryomov len = min_t(int, end - p, PAGE_SIZE); 925cd1a677cSIlya Dryomov WARN_ON(!page || !len || offset_in_page(p)); 926cd1a677cSIlya Dryomov sg_set_page(*sg, page, len, 0); 927cd1a677cSIlya Dryomov *sg = sg_next(*sg); 928cd1a677cSIlya Dryomov p += len; 929cd1a677cSIlya Dryomov } while (p != end); 930cd1a677cSIlya Dryomov } else { 931cd1a677cSIlya Dryomov sg_set_buf(*sg, buf, buf_len); 932cd1a677cSIlya Dryomov *sg = sg_next(*sg); 933cd1a677cSIlya Dryomov } 934cd1a677cSIlya Dryomov 935cd1a677cSIlya Dryomov if (need_padding(buf_len)) { 936cd1a677cSIlya Dryomov sg_set_buf(*sg, pad, padding_len(buf_len)); 937cd1a677cSIlya Dryomov *sg = sg_next(*sg); 938cd1a677cSIlya Dryomov } 939cd1a677cSIlya Dryomov } 940cd1a677cSIlya Dryomov 941cd1a677cSIlya Dryomov static void init_sgs_cursor(struct scatterlist **sg, 942cd1a677cSIlya Dryomov struct ceph_msg_data_cursor *cursor, u8 *pad) 943cd1a677cSIlya Dryomov { 944cd1a677cSIlya Dryomov int data_len = cursor->total_resid; 945cd1a677cSIlya Dryomov struct bio_vec bv; 946cd1a677cSIlya Dryomov 947cd1a677cSIlya Dryomov if (!data_len) 948cd1a677cSIlya Dryomov return; 949cd1a677cSIlya Dryomov 950cd1a677cSIlya Dryomov do { 951cd1a677cSIlya Dryomov get_bvec_at(cursor, &bv); 952cd1a677cSIlya Dryomov sg_set_page(*sg, bv.bv_page, bv.bv_len, bv.bv_offset); 953cd1a677cSIlya Dryomov *sg = sg_next(*sg); 954cd1a677cSIlya Dryomov 955cd1a677cSIlya Dryomov ceph_msg_data_advance(cursor, bv.bv_len); 956cd1a677cSIlya Dryomov } while (cursor->total_resid); 957cd1a677cSIlya Dryomov 958cd1a677cSIlya Dryomov if (need_padding(data_len)) { 959cd1a677cSIlya Dryomov sg_set_buf(*sg, pad, padding_len(data_len)); 960cd1a677cSIlya Dryomov *sg = sg_next(*sg); 961cd1a677cSIlya Dryomov } 962cd1a677cSIlya Dryomov } 963cd1a677cSIlya Dryomov 964cd1a677cSIlya Dryomov static int setup_message_sgs(struct sg_table *sgt, struct ceph_msg *msg, 965cd1a677cSIlya Dryomov u8 *front_pad, u8 *middle_pad, u8 *data_pad, 966cd1a677cSIlya Dryomov void *epilogue, bool add_tag) 967cd1a677cSIlya Dryomov { 968cd1a677cSIlya Dryomov struct ceph_msg_data_cursor cursor; 969cd1a677cSIlya Dryomov struct scatterlist *cur_sg; 970cd1a677cSIlya Dryomov int sg_cnt; 971cd1a677cSIlya Dryomov int ret; 972cd1a677cSIlya Dryomov 973cd1a677cSIlya Dryomov if (!front_len(msg) && !middle_len(msg) && !data_len(msg)) 974cd1a677cSIlya Dryomov return 0; 975cd1a677cSIlya Dryomov 976cd1a677cSIlya Dryomov sg_cnt = 1; /* epilogue + [auth tag] */ 977cd1a677cSIlya Dryomov if (front_len(msg)) 978cd1a677cSIlya Dryomov sg_cnt += calc_sg_cnt(msg->front.iov_base, 979cd1a677cSIlya Dryomov front_len(msg)); 980cd1a677cSIlya Dryomov if (middle_len(msg)) 981cd1a677cSIlya Dryomov sg_cnt += calc_sg_cnt(msg->middle->vec.iov_base, 982cd1a677cSIlya Dryomov middle_len(msg)); 983cd1a677cSIlya Dryomov if (data_len(msg)) { 984cd1a677cSIlya Dryomov ceph_msg_data_cursor_init(&cursor, msg, data_len(msg)); 985cd1a677cSIlya Dryomov sg_cnt += calc_sg_cnt_cursor(&cursor); 986cd1a677cSIlya Dryomov } 987cd1a677cSIlya Dryomov 988cd1a677cSIlya Dryomov ret = sg_alloc_table(sgt, sg_cnt, GFP_NOIO); 989cd1a677cSIlya Dryomov if (ret) 990cd1a677cSIlya Dryomov return ret; 991cd1a677cSIlya Dryomov 992cd1a677cSIlya Dryomov cur_sg = sgt->sgl; 993cd1a677cSIlya Dryomov if (front_len(msg)) 994cd1a677cSIlya Dryomov init_sgs(&cur_sg, msg->front.iov_base, front_len(msg), 995cd1a677cSIlya Dryomov front_pad); 996cd1a677cSIlya Dryomov if (middle_len(msg)) 997cd1a677cSIlya Dryomov init_sgs(&cur_sg, msg->middle->vec.iov_base, middle_len(msg), 998cd1a677cSIlya Dryomov middle_pad); 999cd1a677cSIlya Dryomov if (data_len(msg)) { 1000cd1a677cSIlya Dryomov ceph_msg_data_cursor_init(&cursor, msg, data_len(msg)); 1001cd1a677cSIlya Dryomov init_sgs_cursor(&cur_sg, &cursor, data_pad); 1002cd1a677cSIlya Dryomov } 1003cd1a677cSIlya Dryomov 1004cd1a677cSIlya Dryomov WARN_ON(!sg_is_last(cur_sg)); 1005cd1a677cSIlya Dryomov sg_set_buf(cur_sg, epilogue, 1006cd1a677cSIlya Dryomov CEPH_GCM_BLOCK_LEN + (add_tag ? CEPH_GCM_TAG_LEN : 0)); 1007cd1a677cSIlya Dryomov return 0; 1008cd1a677cSIlya Dryomov } 1009cd1a677cSIlya Dryomov 1010cd1a677cSIlya Dryomov static int decrypt_preamble(struct ceph_connection *con) 1011cd1a677cSIlya Dryomov { 1012cd1a677cSIlya Dryomov struct scatterlist sg; 1013cd1a677cSIlya Dryomov 1014cd1a677cSIlya Dryomov sg_init_one(&sg, con->v2.in_buf, CEPH_PREAMBLE_SECURE_LEN); 1015cd1a677cSIlya Dryomov return gcm_crypt(con, false, &sg, &sg, CEPH_PREAMBLE_SECURE_LEN); 1016cd1a677cSIlya Dryomov } 1017cd1a677cSIlya Dryomov 1018cd1a677cSIlya Dryomov static int decrypt_control_remainder(struct ceph_connection *con) 1019cd1a677cSIlya Dryomov { 1020cd1a677cSIlya Dryomov int ctrl_len = con->v2.in_desc.fd_lens[0]; 1021cd1a677cSIlya Dryomov int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN; 1022cd1a677cSIlya Dryomov int pt_len = padding_len(rem_len) + CEPH_GCM_TAG_LEN; 1023cd1a677cSIlya Dryomov struct scatterlist sgs[2]; 1024cd1a677cSIlya Dryomov 1025cd1a677cSIlya Dryomov WARN_ON(con->v2.in_kvecs[0].iov_len != rem_len); 1026cd1a677cSIlya Dryomov WARN_ON(con->v2.in_kvecs[1].iov_len != pt_len); 1027cd1a677cSIlya Dryomov 1028cd1a677cSIlya Dryomov sg_init_table(sgs, 2); 1029cd1a677cSIlya Dryomov sg_set_buf(&sgs[0], con->v2.in_kvecs[0].iov_base, rem_len); 1030cd1a677cSIlya Dryomov sg_set_buf(&sgs[1], con->v2.in_buf, pt_len); 1031cd1a677cSIlya Dryomov 1032cd1a677cSIlya Dryomov return gcm_crypt(con, false, sgs, sgs, 1033cd1a677cSIlya Dryomov padded_len(rem_len) + CEPH_GCM_TAG_LEN); 1034cd1a677cSIlya Dryomov } 1035cd1a677cSIlya Dryomov 10362ea88716SIlya Dryomov static int decrypt_tail(struct ceph_connection *con) 1037cd1a677cSIlya Dryomov { 10382ea88716SIlya Dryomov struct sg_table enc_sgt = {}; 1039cd1a677cSIlya Dryomov struct sg_table sgt = {}; 10402ea88716SIlya Dryomov int tail_len; 1041cd1a677cSIlya Dryomov int ret; 1042cd1a677cSIlya Dryomov 10432ea88716SIlya Dryomov tail_len = tail_onwire_len(con->in_msg, true); 10442ea88716SIlya Dryomov ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages, 10452ea88716SIlya Dryomov con->v2.in_enc_page_cnt, 0, tail_len, 10462ea88716SIlya Dryomov GFP_NOIO); 10472ea88716SIlya Dryomov if (ret) 10482ea88716SIlya Dryomov goto out; 10492ea88716SIlya Dryomov 1050cd1a677cSIlya Dryomov ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf), 1051cd1a677cSIlya Dryomov MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf), 1052cd1a677cSIlya Dryomov con->v2.in_buf, true); 1053cd1a677cSIlya Dryomov if (ret) 1054cd1a677cSIlya Dryomov goto out; 1055cd1a677cSIlya Dryomov 10562ea88716SIlya Dryomov dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con, 10572ea88716SIlya Dryomov con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents); 10582ea88716SIlya Dryomov ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len); 10592ea88716SIlya Dryomov if (ret) 10602ea88716SIlya Dryomov goto out; 10612ea88716SIlya Dryomov 10622ea88716SIlya Dryomov WARN_ON(!con->v2.in_enc_page_cnt); 10632ea88716SIlya Dryomov ceph_release_page_vector(con->v2.in_enc_pages, 10642ea88716SIlya Dryomov con->v2.in_enc_page_cnt); 10652ea88716SIlya Dryomov con->v2.in_enc_pages = NULL; 10662ea88716SIlya Dryomov con->v2.in_enc_page_cnt = 0; 1067cd1a677cSIlya Dryomov 1068cd1a677cSIlya Dryomov out: 1069cd1a677cSIlya Dryomov sg_free_table(&sgt); 10702ea88716SIlya Dryomov sg_free_table(&enc_sgt); 1071cd1a677cSIlya Dryomov return ret; 1072cd1a677cSIlya Dryomov } 1073cd1a677cSIlya Dryomov 1074cd1a677cSIlya Dryomov static int prepare_banner(struct ceph_connection *con) 1075cd1a677cSIlya Dryomov { 1076cd1a677cSIlya Dryomov int buf_len = CEPH_BANNER_V2_LEN + 2 + 8 + 8; 1077cd1a677cSIlya Dryomov void *buf, *p; 1078cd1a677cSIlya Dryomov 1079cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, buf_len); 1080cd1a677cSIlya Dryomov if (!buf) 1081cd1a677cSIlya Dryomov return -ENOMEM; 1082cd1a677cSIlya Dryomov 1083cd1a677cSIlya Dryomov p = buf; 1084cd1a677cSIlya Dryomov ceph_encode_copy(&p, CEPH_BANNER_V2, CEPH_BANNER_V2_LEN); 1085cd1a677cSIlya Dryomov ceph_encode_16(&p, sizeof(u64) + sizeof(u64)); 1086cd1a677cSIlya Dryomov ceph_encode_64(&p, CEPH_MSGR2_SUPPORTED_FEATURES); 1087cd1a677cSIlya Dryomov ceph_encode_64(&p, CEPH_MSGR2_REQUIRED_FEATURES); 1088cd1a677cSIlya Dryomov WARN_ON(p != buf + buf_len); 1089cd1a677cSIlya Dryomov 1090cd1a677cSIlya Dryomov add_out_kvec(con, buf, buf_len); 1091cd1a677cSIlya Dryomov add_out_sign_kvec(con, buf, buf_len); 1092cd1a677cSIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 1093cd1a677cSIlya Dryomov return 0; 1094cd1a677cSIlya Dryomov } 1095cd1a677cSIlya Dryomov 1096cd1a677cSIlya Dryomov /* 1097cd1a677cSIlya Dryomov * base: 1098cd1a677cSIlya Dryomov * preamble 1099cd1a677cSIlya Dryomov * control body (ctrl_len bytes) 1100cd1a677cSIlya Dryomov * space for control crc 1101cd1a677cSIlya Dryomov * 1102cd1a677cSIlya Dryomov * extdata (optional): 1103cd1a677cSIlya Dryomov * control body (extdata_len bytes) 1104cd1a677cSIlya Dryomov * 1105cd1a677cSIlya Dryomov * Compute control crc and gather base and extdata into: 1106cd1a677cSIlya Dryomov * 1107cd1a677cSIlya Dryomov * preamble 1108cd1a677cSIlya Dryomov * control body (ctrl_len + extdata_len bytes) 1109cd1a677cSIlya Dryomov * control crc 1110cd1a677cSIlya Dryomov * 1111cd1a677cSIlya Dryomov * Preamble should already be encoded at the start of base. 1112cd1a677cSIlya Dryomov */ 1113cd1a677cSIlya Dryomov static void prepare_head_plain(struct ceph_connection *con, void *base, 1114cd1a677cSIlya Dryomov int ctrl_len, void *extdata, int extdata_len, 1115cd1a677cSIlya Dryomov bool to_be_signed) 1116cd1a677cSIlya Dryomov { 1117cd1a677cSIlya Dryomov int base_len = CEPH_PREAMBLE_LEN + ctrl_len + CEPH_CRC_LEN; 1118cd1a677cSIlya Dryomov void *crcp = base + base_len - CEPH_CRC_LEN; 1119cd1a677cSIlya Dryomov u32 crc; 1120cd1a677cSIlya Dryomov 1121cd1a677cSIlya Dryomov crc = crc32c(-1, CTRL_BODY(base), ctrl_len); 1122cd1a677cSIlya Dryomov if (extdata_len) 1123cd1a677cSIlya Dryomov crc = crc32c(crc, extdata, extdata_len); 1124cd1a677cSIlya Dryomov put_unaligned_le32(crc, crcp); 1125cd1a677cSIlya Dryomov 1126cd1a677cSIlya Dryomov if (!extdata_len) { 1127cd1a677cSIlya Dryomov add_out_kvec(con, base, base_len); 1128cd1a677cSIlya Dryomov if (to_be_signed) 1129cd1a677cSIlya Dryomov add_out_sign_kvec(con, base, base_len); 1130cd1a677cSIlya Dryomov return; 1131cd1a677cSIlya Dryomov } 1132cd1a677cSIlya Dryomov 1133cd1a677cSIlya Dryomov add_out_kvec(con, base, crcp - base); 1134cd1a677cSIlya Dryomov add_out_kvec(con, extdata, extdata_len); 1135cd1a677cSIlya Dryomov add_out_kvec(con, crcp, CEPH_CRC_LEN); 1136cd1a677cSIlya Dryomov if (to_be_signed) { 1137cd1a677cSIlya Dryomov add_out_sign_kvec(con, base, crcp - base); 1138cd1a677cSIlya Dryomov add_out_sign_kvec(con, extdata, extdata_len); 1139cd1a677cSIlya Dryomov add_out_sign_kvec(con, crcp, CEPH_CRC_LEN); 1140cd1a677cSIlya Dryomov } 1141cd1a677cSIlya Dryomov } 1142cd1a677cSIlya Dryomov 1143cd1a677cSIlya Dryomov static int prepare_head_secure_small(struct ceph_connection *con, 1144cd1a677cSIlya Dryomov void *base, int ctrl_len) 1145cd1a677cSIlya Dryomov { 1146cd1a677cSIlya Dryomov struct scatterlist sg; 1147cd1a677cSIlya Dryomov int ret; 1148cd1a677cSIlya Dryomov 1149cd1a677cSIlya Dryomov /* inline buffer padding? */ 1150cd1a677cSIlya Dryomov if (ctrl_len < CEPH_PREAMBLE_INLINE_LEN) 1151cd1a677cSIlya Dryomov memset(CTRL_BODY(base) + ctrl_len, 0, 1152cd1a677cSIlya Dryomov CEPH_PREAMBLE_INLINE_LEN - ctrl_len); 1153cd1a677cSIlya Dryomov 1154cd1a677cSIlya Dryomov sg_init_one(&sg, base, CEPH_PREAMBLE_SECURE_LEN); 1155cd1a677cSIlya Dryomov ret = gcm_crypt(con, true, &sg, &sg, 1156cd1a677cSIlya Dryomov CEPH_PREAMBLE_SECURE_LEN - CEPH_GCM_TAG_LEN); 1157cd1a677cSIlya Dryomov if (ret) 1158cd1a677cSIlya Dryomov return ret; 1159cd1a677cSIlya Dryomov 1160cd1a677cSIlya Dryomov add_out_kvec(con, base, CEPH_PREAMBLE_SECURE_LEN); 1161cd1a677cSIlya Dryomov return 0; 1162cd1a677cSIlya Dryomov } 1163cd1a677cSIlya Dryomov 1164cd1a677cSIlya Dryomov /* 1165cd1a677cSIlya Dryomov * base: 1166cd1a677cSIlya Dryomov * preamble 1167cd1a677cSIlya Dryomov * control body (ctrl_len bytes) 1168cd1a677cSIlya Dryomov * space for padding, if needed 1169cd1a677cSIlya Dryomov * space for control remainder auth tag 1170cd1a677cSIlya Dryomov * space for preamble auth tag 1171cd1a677cSIlya Dryomov * 1172cd1a677cSIlya Dryomov * Encrypt preamble and the inline portion, then encrypt the remainder 1173cd1a677cSIlya Dryomov * and gather into: 1174cd1a677cSIlya Dryomov * 1175cd1a677cSIlya Dryomov * preamble 1176cd1a677cSIlya Dryomov * control body (48 bytes) 1177cd1a677cSIlya Dryomov * preamble auth tag 1178cd1a677cSIlya Dryomov * control body (ctrl_len - 48 bytes) 1179cd1a677cSIlya Dryomov * zero padding, if needed 1180cd1a677cSIlya Dryomov * control remainder auth tag 1181cd1a677cSIlya Dryomov * 1182cd1a677cSIlya Dryomov * Preamble should already be encoded at the start of base. 1183cd1a677cSIlya Dryomov */ 1184cd1a677cSIlya Dryomov static int prepare_head_secure_big(struct ceph_connection *con, 1185cd1a677cSIlya Dryomov void *base, int ctrl_len) 1186cd1a677cSIlya Dryomov { 1187cd1a677cSIlya Dryomov int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN; 1188cd1a677cSIlya Dryomov void *rem = CTRL_BODY(base) + CEPH_PREAMBLE_INLINE_LEN; 1189cd1a677cSIlya Dryomov void *rem_tag = rem + padded_len(rem_len); 1190cd1a677cSIlya Dryomov void *pmbl_tag = rem_tag + CEPH_GCM_TAG_LEN; 1191cd1a677cSIlya Dryomov struct scatterlist sgs[2]; 1192cd1a677cSIlya Dryomov int ret; 1193cd1a677cSIlya Dryomov 1194cd1a677cSIlya Dryomov sg_init_table(sgs, 2); 1195cd1a677cSIlya Dryomov sg_set_buf(&sgs[0], base, rem - base); 1196cd1a677cSIlya Dryomov sg_set_buf(&sgs[1], pmbl_tag, CEPH_GCM_TAG_LEN); 1197cd1a677cSIlya Dryomov ret = gcm_crypt(con, true, sgs, sgs, rem - base); 1198cd1a677cSIlya Dryomov if (ret) 1199cd1a677cSIlya Dryomov return ret; 1200cd1a677cSIlya Dryomov 1201cd1a677cSIlya Dryomov /* control remainder padding? */ 1202cd1a677cSIlya Dryomov if (need_padding(rem_len)) 1203cd1a677cSIlya Dryomov memset(rem + rem_len, 0, padding_len(rem_len)); 1204cd1a677cSIlya Dryomov 1205cd1a677cSIlya Dryomov sg_init_one(&sgs[0], rem, pmbl_tag - rem); 1206cd1a677cSIlya Dryomov ret = gcm_crypt(con, true, sgs, sgs, rem_tag - rem); 1207cd1a677cSIlya Dryomov if (ret) 1208cd1a677cSIlya Dryomov return ret; 1209cd1a677cSIlya Dryomov 1210cd1a677cSIlya Dryomov add_out_kvec(con, base, rem - base); 1211cd1a677cSIlya Dryomov add_out_kvec(con, pmbl_tag, CEPH_GCM_TAG_LEN); 1212cd1a677cSIlya Dryomov add_out_kvec(con, rem, pmbl_tag - rem); 1213cd1a677cSIlya Dryomov return 0; 1214cd1a677cSIlya Dryomov } 1215cd1a677cSIlya Dryomov 1216cd1a677cSIlya Dryomov static int __prepare_control(struct ceph_connection *con, int tag, 1217cd1a677cSIlya Dryomov void *base, int ctrl_len, void *extdata, 1218cd1a677cSIlya Dryomov int extdata_len, bool to_be_signed) 1219cd1a677cSIlya Dryomov { 1220cd1a677cSIlya Dryomov int total_len = ctrl_len + extdata_len; 1221cd1a677cSIlya Dryomov struct ceph_frame_desc desc; 1222cd1a677cSIlya Dryomov int ret; 1223cd1a677cSIlya Dryomov 1224cd1a677cSIlya Dryomov dout("%s con %p tag %d len %d (%d+%d)\n", __func__, con, tag, 1225cd1a677cSIlya Dryomov total_len, ctrl_len, extdata_len); 1226cd1a677cSIlya Dryomov 1227cd1a677cSIlya Dryomov /* extdata may be vmalloc'ed but not base */ 1228cd1a677cSIlya Dryomov if (WARN_ON(is_vmalloc_addr(base) || !ctrl_len)) 1229cd1a677cSIlya Dryomov return -EINVAL; 1230cd1a677cSIlya Dryomov 1231cd1a677cSIlya Dryomov init_frame_desc(&desc, tag, &total_len, 1); 1232cd1a677cSIlya Dryomov encode_preamble(&desc, base); 1233cd1a677cSIlya Dryomov 1234cd1a677cSIlya Dryomov if (con_secure(con)) { 1235cd1a677cSIlya Dryomov if (WARN_ON(extdata_len || to_be_signed)) 1236cd1a677cSIlya Dryomov return -EINVAL; 1237cd1a677cSIlya Dryomov 1238cd1a677cSIlya Dryomov if (ctrl_len <= CEPH_PREAMBLE_INLINE_LEN) 1239cd1a677cSIlya Dryomov /* fully inlined, inline buffer may need padding */ 1240cd1a677cSIlya Dryomov ret = prepare_head_secure_small(con, base, ctrl_len); 1241cd1a677cSIlya Dryomov else 1242cd1a677cSIlya Dryomov /* partially inlined, inline buffer is full */ 1243cd1a677cSIlya Dryomov ret = prepare_head_secure_big(con, base, ctrl_len); 1244cd1a677cSIlya Dryomov if (ret) 1245cd1a677cSIlya Dryomov return ret; 1246cd1a677cSIlya Dryomov } else { 1247cd1a677cSIlya Dryomov prepare_head_plain(con, base, ctrl_len, extdata, extdata_len, 1248cd1a677cSIlya Dryomov to_be_signed); 1249cd1a677cSIlya Dryomov } 1250cd1a677cSIlya Dryomov 1251cd1a677cSIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 1252cd1a677cSIlya Dryomov return 0; 1253cd1a677cSIlya Dryomov } 1254cd1a677cSIlya Dryomov 1255cd1a677cSIlya Dryomov static int prepare_control(struct ceph_connection *con, int tag, 1256cd1a677cSIlya Dryomov void *base, int ctrl_len) 1257cd1a677cSIlya Dryomov { 1258cd1a677cSIlya Dryomov return __prepare_control(con, tag, base, ctrl_len, NULL, 0, false); 1259cd1a677cSIlya Dryomov } 1260cd1a677cSIlya Dryomov 1261cd1a677cSIlya Dryomov static int prepare_hello(struct ceph_connection *con) 1262cd1a677cSIlya Dryomov { 1263cd1a677cSIlya Dryomov void *buf, *p; 1264cd1a677cSIlya Dryomov int ctrl_len; 1265cd1a677cSIlya Dryomov 1266cd1a677cSIlya Dryomov ctrl_len = 1 + ceph_entity_addr_encoding_len(&con->peer_addr); 1267cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false)); 1268cd1a677cSIlya Dryomov if (!buf) 1269cd1a677cSIlya Dryomov return -ENOMEM; 1270cd1a677cSIlya Dryomov 1271cd1a677cSIlya Dryomov p = CTRL_BODY(buf); 1272cd1a677cSIlya Dryomov ceph_encode_8(&p, CEPH_ENTITY_TYPE_CLIENT); 1273cd1a677cSIlya Dryomov ceph_encode_entity_addr(&p, &con->peer_addr); 1274cd1a677cSIlya Dryomov WARN_ON(p != CTRL_BODY(buf) + ctrl_len); 1275cd1a677cSIlya Dryomov 1276cd1a677cSIlya Dryomov return __prepare_control(con, FRAME_TAG_HELLO, buf, ctrl_len, 1277cd1a677cSIlya Dryomov NULL, 0, true); 1278cd1a677cSIlya Dryomov } 1279cd1a677cSIlya Dryomov 1280cd1a677cSIlya Dryomov /* so that head_onwire_len(AUTH_BUF_LEN, false) is 512 */ 1281cd1a677cSIlya Dryomov #define AUTH_BUF_LEN (512 - CEPH_CRC_LEN - CEPH_PREAMBLE_PLAIN_LEN) 1282cd1a677cSIlya Dryomov 1283cd1a677cSIlya Dryomov static int prepare_auth_request(struct ceph_connection *con) 1284cd1a677cSIlya Dryomov { 1285cd1a677cSIlya Dryomov void *authorizer, *authorizer_copy; 1286cd1a677cSIlya Dryomov int ctrl_len, authorizer_len; 1287cd1a677cSIlya Dryomov void *buf; 1288cd1a677cSIlya Dryomov int ret; 1289cd1a677cSIlya Dryomov 1290cd1a677cSIlya Dryomov ctrl_len = AUTH_BUF_LEN; 1291cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false)); 1292cd1a677cSIlya Dryomov if (!buf) 1293cd1a677cSIlya Dryomov return -ENOMEM; 1294cd1a677cSIlya Dryomov 1295cd1a677cSIlya Dryomov mutex_unlock(&con->mutex); 1296cd1a677cSIlya Dryomov ret = con->ops->get_auth_request(con, CTRL_BODY(buf), &ctrl_len, 1297cd1a677cSIlya Dryomov &authorizer, &authorizer_len); 1298cd1a677cSIlya Dryomov mutex_lock(&con->mutex); 1299cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_HELLO) { 1300cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 1301cd1a677cSIlya Dryomov con->state); 1302cd1a677cSIlya Dryomov return -EAGAIN; 1303cd1a677cSIlya Dryomov } 1304cd1a677cSIlya Dryomov 1305cd1a677cSIlya Dryomov dout("%s con %p get_auth_request ret %d\n", __func__, con, ret); 1306cd1a677cSIlya Dryomov if (ret) 1307cd1a677cSIlya Dryomov return ret; 1308cd1a677cSIlya Dryomov 1309cd1a677cSIlya Dryomov authorizer_copy = alloc_conn_buf(con, authorizer_len); 1310cd1a677cSIlya Dryomov if (!authorizer_copy) 1311cd1a677cSIlya Dryomov return -ENOMEM; 1312cd1a677cSIlya Dryomov 1313cd1a677cSIlya Dryomov memcpy(authorizer_copy, authorizer, authorizer_len); 1314cd1a677cSIlya Dryomov 1315cd1a677cSIlya Dryomov return __prepare_control(con, FRAME_TAG_AUTH_REQUEST, buf, ctrl_len, 1316cd1a677cSIlya Dryomov authorizer_copy, authorizer_len, true); 1317cd1a677cSIlya Dryomov } 1318cd1a677cSIlya Dryomov 1319cd1a677cSIlya Dryomov static int prepare_auth_request_more(struct ceph_connection *con, 1320cd1a677cSIlya Dryomov void *reply, int reply_len) 1321cd1a677cSIlya Dryomov { 1322cd1a677cSIlya Dryomov int ctrl_len, authorizer_len; 1323cd1a677cSIlya Dryomov void *authorizer; 1324cd1a677cSIlya Dryomov void *buf; 1325cd1a677cSIlya Dryomov int ret; 1326cd1a677cSIlya Dryomov 1327cd1a677cSIlya Dryomov ctrl_len = AUTH_BUF_LEN; 1328cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, false)); 1329cd1a677cSIlya Dryomov if (!buf) 1330cd1a677cSIlya Dryomov return -ENOMEM; 1331cd1a677cSIlya Dryomov 1332cd1a677cSIlya Dryomov mutex_unlock(&con->mutex); 1333cd1a677cSIlya Dryomov ret = con->ops->handle_auth_reply_more(con, reply, reply_len, 1334cd1a677cSIlya Dryomov CTRL_BODY(buf), &ctrl_len, 1335cd1a677cSIlya Dryomov &authorizer, &authorizer_len); 1336cd1a677cSIlya Dryomov mutex_lock(&con->mutex); 1337cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 1338cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 1339cd1a677cSIlya Dryomov con->state); 1340cd1a677cSIlya Dryomov return -EAGAIN; 1341cd1a677cSIlya Dryomov } 1342cd1a677cSIlya Dryomov 1343cd1a677cSIlya Dryomov dout("%s con %p handle_auth_reply_more ret %d\n", __func__, con, ret); 1344cd1a677cSIlya Dryomov if (ret) 1345cd1a677cSIlya Dryomov return ret; 1346cd1a677cSIlya Dryomov 1347cd1a677cSIlya Dryomov return __prepare_control(con, FRAME_TAG_AUTH_REQUEST_MORE, buf, 1348cd1a677cSIlya Dryomov ctrl_len, authorizer, authorizer_len, true); 1349cd1a677cSIlya Dryomov } 1350cd1a677cSIlya Dryomov 1351cd1a677cSIlya Dryomov static int prepare_auth_signature(struct ceph_connection *con) 1352cd1a677cSIlya Dryomov { 1353cd1a677cSIlya Dryomov void *buf; 1354cd1a677cSIlya Dryomov int ret; 1355cd1a677cSIlya Dryomov 1356ad32fe88SIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(SHA256_DIGEST_SIZE, 1357ad32fe88SIlya Dryomov con_secure(con))); 1358cd1a677cSIlya Dryomov if (!buf) 1359cd1a677cSIlya Dryomov return -ENOMEM; 1360cd1a677cSIlya Dryomov 1361cd1a677cSIlya Dryomov ret = hmac_sha256(con, con->v2.in_sign_kvecs, con->v2.in_sign_kvec_cnt, 1362cd1a677cSIlya Dryomov CTRL_BODY(buf)); 1363cd1a677cSIlya Dryomov if (ret) 1364cd1a677cSIlya Dryomov return ret; 1365cd1a677cSIlya Dryomov 1366cd1a677cSIlya Dryomov return prepare_control(con, FRAME_TAG_AUTH_SIGNATURE, buf, 1367cd1a677cSIlya Dryomov SHA256_DIGEST_SIZE); 1368cd1a677cSIlya Dryomov } 1369cd1a677cSIlya Dryomov 1370cd1a677cSIlya Dryomov static int prepare_client_ident(struct ceph_connection *con) 1371cd1a677cSIlya Dryomov { 1372cd1a677cSIlya Dryomov struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 1373cd1a677cSIlya Dryomov struct ceph_client *client = from_msgr(con->msgr); 1374cd1a677cSIlya Dryomov u64 global_id = ceph_client_gid(client); 1375cd1a677cSIlya Dryomov void *buf, *p; 1376cd1a677cSIlya Dryomov int ctrl_len; 1377cd1a677cSIlya Dryomov 1378cd1a677cSIlya Dryomov WARN_ON(con->v2.server_cookie); 1379cd1a677cSIlya Dryomov WARN_ON(con->v2.connect_seq); 1380cd1a677cSIlya Dryomov WARN_ON(con->v2.peer_global_seq); 1381cd1a677cSIlya Dryomov 1382cd1a677cSIlya Dryomov if (!con->v2.client_cookie) { 1383cd1a677cSIlya Dryomov do { 1384cd1a677cSIlya Dryomov get_random_bytes(&con->v2.client_cookie, 1385cd1a677cSIlya Dryomov sizeof(con->v2.client_cookie)); 1386cd1a677cSIlya Dryomov } while (!con->v2.client_cookie); 1387cd1a677cSIlya Dryomov dout("%s con %p generated cookie 0x%llx\n", __func__, con, 1388cd1a677cSIlya Dryomov con->v2.client_cookie); 1389cd1a677cSIlya Dryomov } else { 1390cd1a677cSIlya Dryomov dout("%s con %p cookie already set 0x%llx\n", __func__, con, 1391cd1a677cSIlya Dryomov con->v2.client_cookie); 1392cd1a677cSIlya Dryomov } 1393cd1a677cSIlya Dryomov 1394cd1a677cSIlya Dryomov 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", 1395cd1a677cSIlya Dryomov __func__, con, ceph_pr_addr(my_addr), le32_to_cpu(my_addr->nonce), 1396cd1a677cSIlya Dryomov ceph_pr_addr(&con->peer_addr), le32_to_cpu(con->peer_addr.nonce), 1397cd1a677cSIlya Dryomov global_id, con->v2.global_seq, client->supported_features, 1398cd1a677cSIlya Dryomov client->required_features, con->v2.client_cookie); 1399cd1a677cSIlya Dryomov 1400cd1a677cSIlya Dryomov ctrl_len = 1 + 4 + ceph_entity_addr_encoding_len(my_addr) + 1401cd1a677cSIlya Dryomov ceph_entity_addr_encoding_len(&con->peer_addr) + 6 * 8; 1402cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, con_secure(con))); 1403cd1a677cSIlya Dryomov if (!buf) 1404cd1a677cSIlya Dryomov return -ENOMEM; 1405cd1a677cSIlya Dryomov 1406cd1a677cSIlya Dryomov p = CTRL_BODY(buf); 1407cd1a677cSIlya Dryomov ceph_encode_8(&p, 2); /* addrvec marker */ 1408cd1a677cSIlya Dryomov ceph_encode_32(&p, 1); /* addr_cnt */ 1409cd1a677cSIlya Dryomov ceph_encode_entity_addr(&p, my_addr); 1410cd1a677cSIlya Dryomov ceph_encode_entity_addr(&p, &con->peer_addr); 1411cd1a677cSIlya Dryomov ceph_encode_64(&p, global_id); 1412cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.global_seq); 1413cd1a677cSIlya Dryomov ceph_encode_64(&p, client->supported_features); 1414cd1a677cSIlya Dryomov ceph_encode_64(&p, client->required_features); 1415cd1a677cSIlya Dryomov ceph_encode_64(&p, 0); /* flags */ 1416cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.client_cookie); 1417cd1a677cSIlya Dryomov WARN_ON(p != CTRL_BODY(buf) + ctrl_len); 1418cd1a677cSIlya Dryomov 1419cd1a677cSIlya Dryomov return prepare_control(con, FRAME_TAG_CLIENT_IDENT, buf, ctrl_len); 1420cd1a677cSIlya Dryomov } 1421cd1a677cSIlya Dryomov 1422cd1a677cSIlya Dryomov static int prepare_session_reconnect(struct ceph_connection *con) 1423cd1a677cSIlya Dryomov { 1424cd1a677cSIlya Dryomov struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 1425cd1a677cSIlya Dryomov void *buf, *p; 1426cd1a677cSIlya Dryomov int ctrl_len; 1427cd1a677cSIlya Dryomov 1428cd1a677cSIlya Dryomov WARN_ON(!con->v2.client_cookie); 1429cd1a677cSIlya Dryomov WARN_ON(!con->v2.server_cookie); 1430cd1a677cSIlya Dryomov WARN_ON(!con->v2.connect_seq); 1431cd1a677cSIlya Dryomov WARN_ON(!con->v2.peer_global_seq); 1432cd1a677cSIlya Dryomov 1433cd1a677cSIlya Dryomov 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", 1434cd1a677cSIlya Dryomov __func__, con, ceph_pr_addr(my_addr), le32_to_cpu(my_addr->nonce), 1435cd1a677cSIlya Dryomov con->v2.client_cookie, con->v2.server_cookie, con->v2.global_seq, 1436cd1a677cSIlya Dryomov con->v2.connect_seq, con->in_seq); 1437cd1a677cSIlya Dryomov 1438cd1a677cSIlya Dryomov ctrl_len = 1 + 4 + ceph_entity_addr_encoding_len(my_addr) + 5 * 8; 1439cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_onwire_len(ctrl_len, con_secure(con))); 1440cd1a677cSIlya Dryomov if (!buf) 1441cd1a677cSIlya Dryomov return -ENOMEM; 1442cd1a677cSIlya Dryomov 1443cd1a677cSIlya Dryomov p = CTRL_BODY(buf); 1444cd1a677cSIlya Dryomov ceph_encode_8(&p, 2); /* entity_addrvec_t marker */ 1445cd1a677cSIlya Dryomov ceph_encode_32(&p, 1); /* my_addrs len */ 1446cd1a677cSIlya Dryomov ceph_encode_entity_addr(&p, my_addr); 1447cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.client_cookie); 1448cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.server_cookie); 1449cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.global_seq); 1450cd1a677cSIlya Dryomov ceph_encode_64(&p, con->v2.connect_seq); 1451cd1a677cSIlya Dryomov ceph_encode_64(&p, con->in_seq); 1452cd1a677cSIlya Dryomov WARN_ON(p != CTRL_BODY(buf) + ctrl_len); 1453cd1a677cSIlya Dryomov 1454cd1a677cSIlya Dryomov return prepare_control(con, FRAME_TAG_SESSION_RECONNECT, buf, ctrl_len); 1455cd1a677cSIlya Dryomov } 1456cd1a677cSIlya Dryomov 1457cd1a677cSIlya Dryomov static int prepare_keepalive2(struct ceph_connection *con) 1458cd1a677cSIlya Dryomov { 1459cd1a677cSIlya Dryomov struct ceph_timespec *ts = CTRL_BODY(con->v2.out_buf); 1460cd1a677cSIlya Dryomov struct timespec64 now; 1461cd1a677cSIlya Dryomov 1462cd1a677cSIlya Dryomov ktime_get_real_ts64(&now); 1463cd1a677cSIlya Dryomov dout("%s con %p timestamp %lld.%09ld\n", __func__, con, now.tv_sec, 1464cd1a677cSIlya Dryomov now.tv_nsec); 1465cd1a677cSIlya Dryomov 1466cd1a677cSIlya Dryomov ceph_encode_timespec64(ts, &now); 1467cd1a677cSIlya Dryomov 1468cd1a677cSIlya Dryomov reset_out_kvecs(con); 1469cd1a677cSIlya Dryomov return prepare_control(con, FRAME_TAG_KEEPALIVE2, con->v2.out_buf, 1470cd1a677cSIlya Dryomov sizeof(struct ceph_timespec)); 1471cd1a677cSIlya Dryomov } 1472cd1a677cSIlya Dryomov 1473cd1a677cSIlya Dryomov static int prepare_ack(struct ceph_connection *con) 1474cd1a677cSIlya Dryomov { 1475cd1a677cSIlya Dryomov void *p; 1476cd1a677cSIlya Dryomov 1477cd1a677cSIlya Dryomov dout("%s con %p in_seq_acked %llu -> %llu\n", __func__, con, 1478cd1a677cSIlya Dryomov con->in_seq_acked, con->in_seq); 1479cd1a677cSIlya Dryomov con->in_seq_acked = con->in_seq; 1480cd1a677cSIlya Dryomov 1481cd1a677cSIlya Dryomov p = CTRL_BODY(con->v2.out_buf); 1482cd1a677cSIlya Dryomov ceph_encode_64(&p, con->in_seq_acked); 1483cd1a677cSIlya Dryomov 1484cd1a677cSIlya Dryomov reset_out_kvecs(con); 1485cd1a677cSIlya Dryomov return prepare_control(con, FRAME_TAG_ACK, con->v2.out_buf, 8); 1486cd1a677cSIlya Dryomov } 1487cd1a677cSIlya Dryomov 1488cd1a677cSIlya Dryomov static void prepare_epilogue_plain(struct ceph_connection *con, bool aborted) 1489cd1a677cSIlya Dryomov { 1490cd1a677cSIlya Dryomov dout("%s con %p msg %p aborted %d crcs %u %u %u\n", __func__, con, 1491cd1a677cSIlya Dryomov con->out_msg, aborted, con->v2.out_epil.front_crc, 1492cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc, con->v2.out_epil.data_crc); 1493cd1a677cSIlya Dryomov 1494cd1a677cSIlya Dryomov encode_epilogue_plain(con, aborted); 1495cd1a677cSIlya Dryomov add_out_kvec(con, &con->v2.out_epil, CEPH_EPILOGUE_PLAIN_LEN); 1496cd1a677cSIlya Dryomov } 1497cd1a677cSIlya Dryomov 1498cd1a677cSIlya Dryomov /* 1499cd1a677cSIlya Dryomov * For "used" empty segments, crc is -1. For unused (trailing) 1500cd1a677cSIlya Dryomov * segments, crc is 0. 1501cd1a677cSIlya Dryomov */ 1502cd1a677cSIlya Dryomov static void prepare_message_plain(struct ceph_connection *con) 1503cd1a677cSIlya Dryomov { 1504cd1a677cSIlya Dryomov struct ceph_msg *msg = con->out_msg; 1505cd1a677cSIlya Dryomov 1506cd1a677cSIlya Dryomov prepare_head_plain(con, con->v2.out_buf, 1507cd1a677cSIlya Dryomov sizeof(struct ceph_msg_header2), NULL, 0, false); 1508cd1a677cSIlya Dryomov 1509cd1a677cSIlya Dryomov if (!front_len(msg) && !middle_len(msg)) { 1510cd1a677cSIlya Dryomov if (!data_len(msg)) { 1511cd1a677cSIlya Dryomov /* 1512cd1a677cSIlya Dryomov * Empty message: once the head is written, 1513cd1a677cSIlya Dryomov * we are done -- there is no epilogue. 1514cd1a677cSIlya Dryomov */ 1515cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 1516cd1a677cSIlya Dryomov return; 1517cd1a677cSIlya Dryomov } 1518cd1a677cSIlya Dryomov 1519cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = -1; 1520cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = -1; 1521cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_DATA; 1522cd1a677cSIlya Dryomov return; 1523cd1a677cSIlya Dryomov } 1524cd1a677cSIlya Dryomov 1525cd1a677cSIlya Dryomov if (front_len(msg)) { 1526cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = crc32c(-1, msg->front.iov_base, 1527cd1a677cSIlya Dryomov front_len(msg)); 1528cd1a677cSIlya Dryomov add_out_kvec(con, msg->front.iov_base, front_len(msg)); 1529cd1a677cSIlya Dryomov } else { 1530cd1a677cSIlya Dryomov /* middle (at least) is there, checked above */ 1531cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = -1; 1532cd1a677cSIlya Dryomov } 1533cd1a677cSIlya Dryomov 1534cd1a677cSIlya Dryomov if (middle_len(msg)) { 1535cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = 1536cd1a677cSIlya Dryomov crc32c(-1, msg->middle->vec.iov_base, middle_len(msg)); 1537cd1a677cSIlya Dryomov add_out_kvec(con, msg->middle->vec.iov_base, middle_len(msg)); 1538cd1a677cSIlya Dryomov } else { 1539cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = data_len(msg) ? -1 : 0; 1540cd1a677cSIlya Dryomov } 1541cd1a677cSIlya Dryomov 1542cd1a677cSIlya Dryomov if (data_len(msg)) { 1543cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_DATA; 1544cd1a677cSIlya Dryomov } else { 1545cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = 0; 1546cd1a677cSIlya Dryomov prepare_epilogue_plain(con, false); 1547cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 1548cd1a677cSIlya Dryomov } 1549cd1a677cSIlya Dryomov } 1550cd1a677cSIlya Dryomov 1551cd1a677cSIlya Dryomov /* 1552cd1a677cSIlya Dryomov * Unfortunately the kernel crypto API doesn't support streaming 1553cd1a677cSIlya Dryomov * (piecewise) operation for AEAD algorithms, so we can't get away 1554cd1a677cSIlya Dryomov * with a fixed size buffer and a couple sgs. Instead, we have to 1555cd1a677cSIlya Dryomov * allocate pages for the entire tail of the message (currently up 1556cd1a677cSIlya Dryomov * to ~32M) and two sgs arrays (up to ~256K each)... 1557cd1a677cSIlya Dryomov */ 1558cd1a677cSIlya Dryomov static int prepare_message_secure(struct ceph_connection *con) 1559cd1a677cSIlya Dryomov { 1560cd1a677cSIlya Dryomov void *zerop = page_address(ceph_zero_page); 1561cd1a677cSIlya Dryomov struct sg_table enc_sgt = {}; 1562cd1a677cSIlya Dryomov struct sg_table sgt = {}; 1563cd1a677cSIlya Dryomov struct page **enc_pages; 1564cd1a677cSIlya Dryomov int enc_page_cnt; 1565cd1a677cSIlya Dryomov int tail_len; 1566cd1a677cSIlya Dryomov int ret; 1567cd1a677cSIlya Dryomov 1568cd1a677cSIlya Dryomov ret = prepare_head_secure_small(con, con->v2.out_buf, 1569cd1a677cSIlya Dryomov sizeof(struct ceph_msg_header2)); 1570cd1a677cSIlya Dryomov if (ret) 1571cd1a677cSIlya Dryomov return ret; 1572cd1a677cSIlya Dryomov 1573cd1a677cSIlya Dryomov tail_len = tail_onwire_len(con->out_msg, true); 1574cd1a677cSIlya Dryomov if (!tail_len) { 1575cd1a677cSIlya Dryomov /* 1576cd1a677cSIlya Dryomov * Empty message: once the head is written, 1577cd1a677cSIlya Dryomov * we are done -- there is no epilogue. 1578cd1a677cSIlya Dryomov */ 1579cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 1580cd1a677cSIlya Dryomov return 0; 1581cd1a677cSIlya Dryomov } 1582cd1a677cSIlya Dryomov 1583cd1a677cSIlya Dryomov encode_epilogue_secure(con, false); 1584cd1a677cSIlya Dryomov ret = setup_message_sgs(&sgt, con->out_msg, zerop, zerop, zerop, 1585cd1a677cSIlya Dryomov &con->v2.out_epil, false); 1586cd1a677cSIlya Dryomov if (ret) 1587cd1a677cSIlya Dryomov goto out; 1588cd1a677cSIlya Dryomov 1589cd1a677cSIlya Dryomov enc_page_cnt = calc_pages_for(0, tail_len); 1590cd1a677cSIlya Dryomov enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO); 1591cd1a677cSIlya Dryomov if (IS_ERR(enc_pages)) { 1592cd1a677cSIlya Dryomov ret = PTR_ERR(enc_pages); 1593cd1a677cSIlya Dryomov goto out; 1594cd1a677cSIlya Dryomov } 1595cd1a677cSIlya Dryomov 1596cd1a677cSIlya Dryomov WARN_ON(con->v2.out_enc_pages || con->v2.out_enc_page_cnt); 1597cd1a677cSIlya Dryomov con->v2.out_enc_pages = enc_pages; 1598cd1a677cSIlya Dryomov con->v2.out_enc_page_cnt = enc_page_cnt; 1599cd1a677cSIlya Dryomov con->v2.out_enc_resid = tail_len; 1600cd1a677cSIlya Dryomov con->v2.out_enc_i = 0; 1601cd1a677cSIlya Dryomov 1602cd1a677cSIlya Dryomov ret = sg_alloc_table_from_pages(&enc_sgt, enc_pages, enc_page_cnt, 1603cd1a677cSIlya Dryomov 0, tail_len, GFP_NOIO); 1604cd1a677cSIlya Dryomov if (ret) 1605cd1a677cSIlya Dryomov goto out; 1606cd1a677cSIlya Dryomov 1607cd1a677cSIlya Dryomov ret = gcm_crypt(con, true, sgt.sgl, enc_sgt.sgl, 1608cd1a677cSIlya Dryomov tail_len - CEPH_GCM_TAG_LEN); 1609cd1a677cSIlya Dryomov if (ret) 1610cd1a677cSIlya Dryomov goto out; 1611cd1a677cSIlya Dryomov 1612cd1a677cSIlya Dryomov dout("%s con %p msg %p sg_cnt %d enc_page_cnt %d\n", __func__, con, 1613cd1a677cSIlya Dryomov con->out_msg, sgt.orig_nents, enc_page_cnt); 1614cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_ENC_PAGE; 1615cd1a677cSIlya Dryomov 1616cd1a677cSIlya Dryomov out: 1617cd1a677cSIlya Dryomov sg_free_table(&sgt); 1618cd1a677cSIlya Dryomov sg_free_table(&enc_sgt); 1619cd1a677cSIlya Dryomov return ret; 1620cd1a677cSIlya Dryomov } 1621cd1a677cSIlya Dryomov 1622cd1a677cSIlya Dryomov static int prepare_message(struct ceph_connection *con) 1623cd1a677cSIlya Dryomov { 1624cd1a677cSIlya Dryomov int lens[] = { 1625cd1a677cSIlya Dryomov sizeof(struct ceph_msg_header2), 1626cd1a677cSIlya Dryomov front_len(con->out_msg), 1627cd1a677cSIlya Dryomov middle_len(con->out_msg), 1628cd1a677cSIlya Dryomov data_len(con->out_msg) 1629cd1a677cSIlya Dryomov }; 1630cd1a677cSIlya Dryomov struct ceph_frame_desc desc; 1631cd1a677cSIlya Dryomov int ret; 1632cd1a677cSIlya Dryomov 1633cd1a677cSIlya Dryomov dout("%s con %p msg %p logical %d+%d+%d+%d\n", __func__, con, 1634cd1a677cSIlya Dryomov con->out_msg, lens[0], lens[1], lens[2], lens[3]); 1635cd1a677cSIlya Dryomov 1636cd1a677cSIlya Dryomov if (con->in_seq > con->in_seq_acked) { 1637cd1a677cSIlya Dryomov dout("%s con %p in_seq_acked %llu -> %llu\n", __func__, con, 1638cd1a677cSIlya Dryomov con->in_seq_acked, con->in_seq); 1639cd1a677cSIlya Dryomov con->in_seq_acked = con->in_seq; 1640cd1a677cSIlya Dryomov } 1641cd1a677cSIlya Dryomov 1642cd1a677cSIlya Dryomov reset_out_kvecs(con); 1643cd1a677cSIlya Dryomov init_frame_desc(&desc, FRAME_TAG_MESSAGE, lens, 4); 1644cd1a677cSIlya Dryomov encode_preamble(&desc, con->v2.out_buf); 1645cd1a677cSIlya Dryomov fill_header2(CTRL_BODY(con->v2.out_buf), &con->out_msg->hdr, 1646cd1a677cSIlya Dryomov con->in_seq_acked); 1647cd1a677cSIlya Dryomov 1648cd1a677cSIlya Dryomov if (con_secure(con)) { 1649cd1a677cSIlya Dryomov ret = prepare_message_secure(con); 1650cd1a677cSIlya Dryomov if (ret) 1651cd1a677cSIlya Dryomov return ret; 1652cd1a677cSIlya Dryomov } else { 1653cd1a677cSIlya Dryomov prepare_message_plain(con); 1654cd1a677cSIlya Dryomov } 1655cd1a677cSIlya Dryomov 1656cd1a677cSIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 1657cd1a677cSIlya Dryomov return 0; 1658cd1a677cSIlya Dryomov } 1659cd1a677cSIlya Dryomov 1660cd1a677cSIlya Dryomov static int prepare_read_banner_prefix(struct ceph_connection *con) 1661cd1a677cSIlya Dryomov { 1662cd1a677cSIlya Dryomov void *buf; 1663cd1a677cSIlya Dryomov 1664cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, CEPH_BANNER_V2_PREFIX_LEN); 1665cd1a677cSIlya Dryomov if (!buf) 1666cd1a677cSIlya Dryomov return -ENOMEM; 1667cd1a677cSIlya Dryomov 1668cd1a677cSIlya Dryomov reset_in_kvecs(con); 1669cd1a677cSIlya Dryomov add_in_kvec(con, buf, CEPH_BANNER_V2_PREFIX_LEN); 1670cd1a677cSIlya Dryomov add_in_sign_kvec(con, buf, CEPH_BANNER_V2_PREFIX_LEN); 1671cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_BANNER_PREFIX; 1672cd1a677cSIlya Dryomov return 0; 1673cd1a677cSIlya Dryomov } 1674cd1a677cSIlya Dryomov 1675cd1a677cSIlya Dryomov static int prepare_read_banner_payload(struct ceph_connection *con, 1676cd1a677cSIlya Dryomov int payload_len) 1677cd1a677cSIlya Dryomov { 1678cd1a677cSIlya Dryomov void *buf; 1679cd1a677cSIlya Dryomov 1680cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, payload_len); 1681cd1a677cSIlya Dryomov if (!buf) 1682cd1a677cSIlya Dryomov return -ENOMEM; 1683cd1a677cSIlya Dryomov 1684cd1a677cSIlya Dryomov reset_in_kvecs(con); 1685cd1a677cSIlya Dryomov add_in_kvec(con, buf, payload_len); 1686cd1a677cSIlya Dryomov add_in_sign_kvec(con, buf, payload_len); 1687cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_BANNER_PAYLOAD; 1688cd1a677cSIlya Dryomov return 0; 1689cd1a677cSIlya Dryomov } 1690cd1a677cSIlya Dryomov 1691cd1a677cSIlya Dryomov static void prepare_read_preamble(struct ceph_connection *con) 1692cd1a677cSIlya Dryomov { 1693cd1a677cSIlya Dryomov reset_in_kvecs(con); 1694cd1a677cSIlya Dryomov add_in_kvec(con, con->v2.in_buf, 1695cd1a677cSIlya Dryomov con_secure(con) ? CEPH_PREAMBLE_SECURE_LEN : 1696cd1a677cSIlya Dryomov CEPH_PREAMBLE_PLAIN_LEN); 1697cd1a677cSIlya Dryomov con->v2.in_state = IN_S_HANDLE_PREAMBLE; 1698cd1a677cSIlya Dryomov } 1699cd1a677cSIlya Dryomov 1700cd1a677cSIlya Dryomov static int prepare_read_control(struct ceph_connection *con) 1701cd1a677cSIlya Dryomov { 1702cd1a677cSIlya Dryomov int ctrl_len = con->v2.in_desc.fd_lens[0]; 1703cd1a677cSIlya Dryomov int head_len; 1704cd1a677cSIlya Dryomov void *buf; 1705cd1a677cSIlya Dryomov 1706cd1a677cSIlya Dryomov reset_in_kvecs(con); 1707cd1a677cSIlya Dryomov if (con->state == CEPH_CON_S_V2_HELLO || 1708cd1a677cSIlya Dryomov con->state == CEPH_CON_S_V2_AUTH) { 1709cd1a677cSIlya Dryomov head_len = head_onwire_len(ctrl_len, false); 1710cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, head_len); 1711cd1a677cSIlya Dryomov if (!buf) 1712cd1a677cSIlya Dryomov return -ENOMEM; 1713cd1a677cSIlya Dryomov 1714cd1a677cSIlya Dryomov /* preserve preamble */ 1715cd1a677cSIlya Dryomov memcpy(buf, con->v2.in_buf, CEPH_PREAMBLE_LEN); 1716cd1a677cSIlya Dryomov 1717cd1a677cSIlya Dryomov add_in_kvec(con, CTRL_BODY(buf), ctrl_len); 1718cd1a677cSIlya Dryomov add_in_kvec(con, CTRL_BODY(buf) + ctrl_len, CEPH_CRC_LEN); 1719cd1a677cSIlya Dryomov add_in_sign_kvec(con, buf, head_len); 1720cd1a677cSIlya Dryomov } else { 1721cd1a677cSIlya Dryomov if (ctrl_len > CEPH_PREAMBLE_INLINE_LEN) { 1722cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, ctrl_len); 1723cd1a677cSIlya Dryomov if (!buf) 1724cd1a677cSIlya Dryomov return -ENOMEM; 1725cd1a677cSIlya Dryomov 1726cd1a677cSIlya Dryomov add_in_kvec(con, buf, ctrl_len); 1727cd1a677cSIlya Dryomov } else { 1728cd1a677cSIlya Dryomov add_in_kvec(con, CTRL_BODY(con->v2.in_buf), ctrl_len); 1729cd1a677cSIlya Dryomov } 1730cd1a677cSIlya Dryomov add_in_kvec(con, con->v2.in_buf, CEPH_CRC_LEN); 1731cd1a677cSIlya Dryomov } 1732cd1a677cSIlya Dryomov con->v2.in_state = IN_S_HANDLE_CONTROL; 1733cd1a677cSIlya Dryomov return 0; 1734cd1a677cSIlya Dryomov } 1735cd1a677cSIlya Dryomov 1736cd1a677cSIlya Dryomov static int prepare_read_control_remainder(struct ceph_connection *con) 1737cd1a677cSIlya Dryomov { 1738cd1a677cSIlya Dryomov int ctrl_len = con->v2.in_desc.fd_lens[0]; 1739cd1a677cSIlya Dryomov int rem_len = ctrl_len - CEPH_PREAMBLE_INLINE_LEN; 1740cd1a677cSIlya Dryomov void *buf; 1741cd1a677cSIlya Dryomov 1742cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, ctrl_len); 1743cd1a677cSIlya Dryomov if (!buf) 1744cd1a677cSIlya Dryomov return -ENOMEM; 1745cd1a677cSIlya Dryomov 1746cd1a677cSIlya Dryomov memcpy(buf, CTRL_BODY(con->v2.in_buf), CEPH_PREAMBLE_INLINE_LEN); 1747cd1a677cSIlya Dryomov 1748cd1a677cSIlya Dryomov reset_in_kvecs(con); 1749cd1a677cSIlya Dryomov add_in_kvec(con, buf + CEPH_PREAMBLE_INLINE_LEN, rem_len); 1750cd1a677cSIlya Dryomov add_in_kvec(con, con->v2.in_buf, 1751cd1a677cSIlya Dryomov padding_len(rem_len) + CEPH_GCM_TAG_LEN); 1752cd1a677cSIlya Dryomov con->v2.in_state = IN_S_HANDLE_CONTROL_REMAINDER; 1753cd1a677cSIlya Dryomov return 0; 1754cd1a677cSIlya Dryomov } 1755cd1a677cSIlya Dryomov 1756*038b8d1dSIlya Dryomov static int prepare_read_data(struct ceph_connection *con) 1757cd1a677cSIlya Dryomov { 1758cd1a677cSIlya Dryomov struct bio_vec bv; 1759cd1a677cSIlya Dryomov 1760cd1a677cSIlya Dryomov con->in_data_crc = -1; 1761cd1a677cSIlya Dryomov ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg, 1762cd1a677cSIlya Dryomov data_len(con->in_msg)); 1763cd1a677cSIlya Dryomov 1764cd1a677cSIlya Dryomov get_bvec_at(&con->v2.in_cursor, &bv); 1765*038b8d1dSIlya Dryomov if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) { 1766*038b8d1dSIlya Dryomov if (unlikely(!con->bounce_page)) { 1767*038b8d1dSIlya Dryomov con->bounce_page = alloc_page(GFP_NOIO); 1768*038b8d1dSIlya Dryomov if (!con->bounce_page) { 1769*038b8d1dSIlya Dryomov pr_err("failed to allocate bounce page\n"); 1770*038b8d1dSIlya Dryomov return -ENOMEM; 1771*038b8d1dSIlya Dryomov } 1772*038b8d1dSIlya Dryomov } 1773*038b8d1dSIlya Dryomov 1774*038b8d1dSIlya Dryomov bv.bv_page = con->bounce_page; 1775*038b8d1dSIlya Dryomov bv.bv_offset = 0; 1776cd1a677cSIlya Dryomov set_in_bvec(con, &bv); 1777*038b8d1dSIlya Dryomov } else { 1778*038b8d1dSIlya Dryomov set_in_bvec(con, &bv); 1779*038b8d1dSIlya Dryomov } 1780cd1a677cSIlya Dryomov con->v2.in_state = IN_S_PREPARE_READ_DATA_CONT; 1781*038b8d1dSIlya Dryomov return 0; 1782cd1a677cSIlya Dryomov } 1783cd1a677cSIlya Dryomov 1784cd1a677cSIlya Dryomov static void prepare_read_data_cont(struct ceph_connection *con) 1785cd1a677cSIlya Dryomov { 1786cd1a677cSIlya Dryomov struct bio_vec bv; 1787cd1a677cSIlya Dryomov 1788*038b8d1dSIlya Dryomov if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) { 1789*038b8d1dSIlya Dryomov con->in_data_crc = crc32c(con->in_data_crc, 1790*038b8d1dSIlya Dryomov page_address(con->bounce_page), 1791*038b8d1dSIlya Dryomov con->v2.in_bvec.bv_len); 1792*038b8d1dSIlya Dryomov 1793*038b8d1dSIlya Dryomov get_bvec_at(&con->v2.in_cursor, &bv); 1794*038b8d1dSIlya Dryomov memcpy_to_page(bv.bv_page, bv.bv_offset, 1795*038b8d1dSIlya Dryomov page_address(con->bounce_page), 1796*038b8d1dSIlya Dryomov con->v2.in_bvec.bv_len); 1797*038b8d1dSIlya Dryomov } else { 1798cd1a677cSIlya Dryomov con->in_data_crc = ceph_crc32c_page(con->in_data_crc, 1799cd1a677cSIlya Dryomov con->v2.in_bvec.bv_page, 1800cd1a677cSIlya Dryomov con->v2.in_bvec.bv_offset, 1801cd1a677cSIlya Dryomov con->v2.in_bvec.bv_len); 1802*038b8d1dSIlya Dryomov } 1803cd1a677cSIlya Dryomov 1804cd1a677cSIlya Dryomov ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len); 1805cd1a677cSIlya Dryomov if (con->v2.in_cursor.total_resid) { 1806cd1a677cSIlya Dryomov get_bvec_at(&con->v2.in_cursor, &bv); 1807*038b8d1dSIlya Dryomov if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) { 1808*038b8d1dSIlya Dryomov bv.bv_page = con->bounce_page; 1809*038b8d1dSIlya Dryomov bv.bv_offset = 0; 1810cd1a677cSIlya Dryomov set_in_bvec(con, &bv); 1811*038b8d1dSIlya Dryomov } else { 1812*038b8d1dSIlya Dryomov set_in_bvec(con, &bv); 1813*038b8d1dSIlya Dryomov } 1814cd1a677cSIlya Dryomov WARN_ON(con->v2.in_state != IN_S_PREPARE_READ_DATA_CONT); 1815cd1a677cSIlya Dryomov return; 1816cd1a677cSIlya Dryomov } 1817cd1a677cSIlya Dryomov 1818cd1a677cSIlya Dryomov /* 18192ea88716SIlya Dryomov * We've read all data. Prepare to read epilogue. 1820cd1a677cSIlya Dryomov */ 1821cd1a677cSIlya Dryomov reset_in_kvecs(con); 18222ea88716SIlya Dryomov add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN); 18232ea88716SIlya Dryomov con->v2.in_state = IN_S_HANDLE_EPILOGUE; 18242ea88716SIlya Dryomov } 18252ea88716SIlya Dryomov 1826*038b8d1dSIlya Dryomov static int prepare_read_tail_plain(struct ceph_connection *con) 18272ea88716SIlya Dryomov { 18282ea88716SIlya Dryomov struct ceph_msg *msg = con->in_msg; 18292ea88716SIlya Dryomov 18302ea88716SIlya Dryomov if (!front_len(msg) && !middle_len(msg)) { 18312ea88716SIlya Dryomov WARN_ON(!data_len(msg)); 1832*038b8d1dSIlya Dryomov return prepare_read_data(con); 18332ea88716SIlya Dryomov } 18342ea88716SIlya Dryomov 18352ea88716SIlya Dryomov reset_in_kvecs(con); 18362ea88716SIlya Dryomov if (front_len(msg)) { 18372ea88716SIlya Dryomov add_in_kvec(con, msg->front.iov_base, front_len(msg)); 18382ea88716SIlya Dryomov WARN_ON(msg->front.iov_len != front_len(msg)); 18392ea88716SIlya Dryomov } 18402ea88716SIlya Dryomov if (middle_len(msg)) { 18412ea88716SIlya Dryomov add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg)); 18422ea88716SIlya Dryomov WARN_ON(msg->middle->vec.iov_len != middle_len(msg)); 18432ea88716SIlya Dryomov } 18442ea88716SIlya Dryomov 18452ea88716SIlya Dryomov if (data_len(msg)) { 18462ea88716SIlya Dryomov con->v2.in_state = IN_S_PREPARE_READ_DATA; 1847cd1a677cSIlya Dryomov } else { 1848cd1a677cSIlya Dryomov add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN); 1849cd1a677cSIlya Dryomov con->v2.in_state = IN_S_HANDLE_EPILOGUE; 1850cd1a677cSIlya Dryomov } 1851*038b8d1dSIlya Dryomov return 0; 18522ea88716SIlya Dryomov } 18532ea88716SIlya Dryomov 18542ea88716SIlya Dryomov static void prepare_read_enc_page(struct ceph_connection *con) 18552ea88716SIlya Dryomov { 18562ea88716SIlya Dryomov struct bio_vec bv; 18572ea88716SIlya Dryomov 18582ea88716SIlya Dryomov dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i, 18592ea88716SIlya Dryomov con->v2.in_enc_resid); 18602ea88716SIlya Dryomov WARN_ON(!con->v2.in_enc_resid); 18612ea88716SIlya Dryomov 18622ea88716SIlya Dryomov bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i]; 18632ea88716SIlya Dryomov bv.bv_offset = 0; 18642ea88716SIlya Dryomov bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE); 18652ea88716SIlya Dryomov 18662ea88716SIlya Dryomov set_in_bvec(con, &bv); 18672ea88716SIlya Dryomov con->v2.in_enc_i++; 18682ea88716SIlya Dryomov con->v2.in_enc_resid -= bv.bv_len; 18692ea88716SIlya Dryomov 18702ea88716SIlya Dryomov if (con->v2.in_enc_resid) { 18712ea88716SIlya Dryomov con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE; 18722ea88716SIlya Dryomov return; 18732ea88716SIlya Dryomov } 18742ea88716SIlya Dryomov 18752ea88716SIlya Dryomov /* 18762ea88716SIlya Dryomov * We are set to read the last piece of ciphertext (ending 18772ea88716SIlya Dryomov * with epilogue) + auth tag. 18782ea88716SIlya Dryomov */ 18792ea88716SIlya Dryomov WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt); 18802ea88716SIlya Dryomov con->v2.in_state = IN_S_HANDLE_EPILOGUE; 18812ea88716SIlya Dryomov } 18822ea88716SIlya Dryomov 18832ea88716SIlya Dryomov static int prepare_read_tail_secure(struct ceph_connection *con) 18842ea88716SIlya Dryomov { 18852ea88716SIlya Dryomov struct page **enc_pages; 18862ea88716SIlya Dryomov int enc_page_cnt; 18872ea88716SIlya Dryomov int tail_len; 18882ea88716SIlya Dryomov 18892ea88716SIlya Dryomov tail_len = tail_onwire_len(con->in_msg, true); 18902ea88716SIlya Dryomov WARN_ON(!tail_len); 18912ea88716SIlya Dryomov 18922ea88716SIlya Dryomov enc_page_cnt = calc_pages_for(0, tail_len); 18932ea88716SIlya Dryomov enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO); 18942ea88716SIlya Dryomov if (IS_ERR(enc_pages)) 18952ea88716SIlya Dryomov return PTR_ERR(enc_pages); 18962ea88716SIlya Dryomov 18972ea88716SIlya Dryomov WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt); 18982ea88716SIlya Dryomov con->v2.in_enc_pages = enc_pages; 18992ea88716SIlya Dryomov con->v2.in_enc_page_cnt = enc_page_cnt; 19002ea88716SIlya Dryomov con->v2.in_enc_resid = tail_len; 19012ea88716SIlya Dryomov con->v2.in_enc_i = 0; 19022ea88716SIlya Dryomov 19032ea88716SIlya Dryomov prepare_read_enc_page(con); 19042ea88716SIlya Dryomov return 0; 19052ea88716SIlya Dryomov } 1906cd1a677cSIlya Dryomov 1907cd1a677cSIlya Dryomov static void __finish_skip(struct ceph_connection *con) 1908cd1a677cSIlya Dryomov { 1909cd1a677cSIlya Dryomov con->in_seq++; 1910cd1a677cSIlya Dryomov prepare_read_preamble(con); 1911cd1a677cSIlya Dryomov } 1912cd1a677cSIlya Dryomov 1913cd1a677cSIlya Dryomov static void prepare_skip_message(struct ceph_connection *con) 1914cd1a677cSIlya Dryomov { 1915cd1a677cSIlya Dryomov struct ceph_frame_desc *desc = &con->v2.in_desc; 1916cd1a677cSIlya Dryomov int tail_len; 1917cd1a677cSIlya Dryomov 1918cd1a677cSIlya Dryomov dout("%s con %p %d+%d+%d\n", __func__, con, desc->fd_lens[1], 1919cd1a677cSIlya Dryomov desc->fd_lens[2], desc->fd_lens[3]); 1920cd1a677cSIlya Dryomov 1921cd1a677cSIlya Dryomov tail_len = __tail_onwire_len(desc->fd_lens[1], desc->fd_lens[2], 1922cd1a677cSIlya Dryomov desc->fd_lens[3], con_secure(con)); 1923cd1a677cSIlya Dryomov if (!tail_len) { 1924cd1a677cSIlya Dryomov __finish_skip(con); 1925cd1a677cSIlya Dryomov } else { 1926cd1a677cSIlya Dryomov set_in_skip(con, tail_len); 1927cd1a677cSIlya Dryomov con->v2.in_state = IN_S_FINISH_SKIP; 1928cd1a677cSIlya Dryomov } 1929cd1a677cSIlya Dryomov } 1930cd1a677cSIlya Dryomov 1931cd1a677cSIlya Dryomov static int process_banner_prefix(struct ceph_connection *con) 1932cd1a677cSIlya Dryomov { 1933cd1a677cSIlya Dryomov int payload_len; 1934cd1a677cSIlya Dryomov void *p; 1935cd1a677cSIlya Dryomov 1936cd1a677cSIlya Dryomov WARN_ON(con->v2.in_kvecs[0].iov_len != CEPH_BANNER_V2_PREFIX_LEN); 1937cd1a677cSIlya Dryomov 1938cd1a677cSIlya Dryomov p = con->v2.in_kvecs[0].iov_base; 1939cd1a677cSIlya Dryomov if (memcmp(p, CEPH_BANNER_V2, CEPH_BANNER_V2_LEN)) { 1940cd1a677cSIlya Dryomov if (!memcmp(p, CEPH_BANNER, CEPH_BANNER_LEN)) 1941cd1a677cSIlya Dryomov con->error_msg = "server is speaking msgr1 protocol"; 1942cd1a677cSIlya Dryomov else 1943cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad banner"; 1944cd1a677cSIlya Dryomov return -EINVAL; 1945cd1a677cSIlya Dryomov } 1946cd1a677cSIlya Dryomov 1947cd1a677cSIlya Dryomov p += CEPH_BANNER_V2_LEN; 1948cd1a677cSIlya Dryomov payload_len = ceph_decode_16(&p); 1949cd1a677cSIlya Dryomov dout("%s con %p payload_len %d\n", __func__, con, payload_len); 1950cd1a677cSIlya Dryomov 1951cd1a677cSIlya Dryomov return prepare_read_banner_payload(con, payload_len); 1952cd1a677cSIlya Dryomov } 1953cd1a677cSIlya Dryomov 1954cd1a677cSIlya Dryomov static int process_banner_payload(struct ceph_connection *con) 1955cd1a677cSIlya Dryomov { 1956cd1a677cSIlya Dryomov void *end = con->v2.in_kvecs[0].iov_base + con->v2.in_kvecs[0].iov_len; 1957cd1a677cSIlya Dryomov u64 feat = CEPH_MSGR2_SUPPORTED_FEATURES; 1958cd1a677cSIlya Dryomov u64 req_feat = CEPH_MSGR2_REQUIRED_FEATURES; 1959cd1a677cSIlya Dryomov u64 server_feat, server_req_feat; 1960cd1a677cSIlya Dryomov void *p; 1961cd1a677cSIlya Dryomov int ret; 1962cd1a677cSIlya Dryomov 1963cd1a677cSIlya Dryomov p = con->v2.in_kvecs[0].iov_base; 1964cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, server_feat, bad); 1965cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, server_req_feat, bad); 1966cd1a677cSIlya Dryomov 1967cd1a677cSIlya Dryomov dout("%s con %p server_feat 0x%llx server_req_feat 0x%llx\n", 1968cd1a677cSIlya Dryomov __func__, con, server_feat, server_req_feat); 1969cd1a677cSIlya Dryomov 1970cd1a677cSIlya Dryomov if (req_feat & ~server_feat) { 1971cd1a677cSIlya Dryomov pr_err("msgr2 feature set mismatch: my required > server's supported 0x%llx, need 0x%llx\n", 1972cd1a677cSIlya Dryomov server_feat, req_feat & ~server_feat); 1973cd1a677cSIlya Dryomov con->error_msg = "missing required protocol features"; 1974cd1a677cSIlya Dryomov return -EINVAL; 1975cd1a677cSIlya Dryomov } 1976cd1a677cSIlya Dryomov if (server_req_feat & ~feat) { 1977cd1a677cSIlya Dryomov pr_err("msgr2 feature set mismatch: server's required > my supported 0x%llx, missing 0x%llx\n", 1978cd1a677cSIlya Dryomov feat, server_req_feat & ~feat); 1979cd1a677cSIlya Dryomov con->error_msg = "missing required protocol features"; 1980cd1a677cSIlya Dryomov return -EINVAL; 1981cd1a677cSIlya Dryomov } 1982cd1a677cSIlya Dryomov 1983cd1a677cSIlya Dryomov /* no reset_out_kvecs() as our banner may still be pending */ 1984cd1a677cSIlya Dryomov ret = prepare_hello(con); 1985cd1a677cSIlya Dryomov if (ret) { 1986cd1a677cSIlya Dryomov pr_err("prepare_hello failed: %d\n", ret); 1987cd1a677cSIlya Dryomov return ret; 1988cd1a677cSIlya Dryomov } 1989cd1a677cSIlya Dryomov 1990cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_HELLO; 1991cd1a677cSIlya Dryomov prepare_read_preamble(con); 1992cd1a677cSIlya Dryomov return 0; 1993cd1a677cSIlya Dryomov 1994cd1a677cSIlya Dryomov bad: 1995cd1a677cSIlya Dryomov pr_err("failed to decode banner payload\n"); 1996cd1a677cSIlya Dryomov return -EINVAL; 1997cd1a677cSIlya Dryomov } 1998cd1a677cSIlya Dryomov 1999cd1a677cSIlya Dryomov static int process_hello(struct ceph_connection *con, void *p, void *end) 2000cd1a677cSIlya Dryomov { 2001cd1a677cSIlya Dryomov struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 2002cd1a677cSIlya Dryomov struct ceph_entity_addr addr_for_me; 2003cd1a677cSIlya Dryomov u8 entity_type; 2004cd1a677cSIlya Dryomov int ret; 2005cd1a677cSIlya Dryomov 2006cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_HELLO) { 2007cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected hello"; 2008cd1a677cSIlya Dryomov return -EINVAL; 2009cd1a677cSIlya Dryomov } 2010cd1a677cSIlya Dryomov 2011cd1a677cSIlya Dryomov ceph_decode_8_safe(&p, end, entity_type, bad); 2012cd1a677cSIlya Dryomov ret = ceph_decode_entity_addr(&p, end, &addr_for_me); 2013cd1a677cSIlya Dryomov if (ret) { 2014cd1a677cSIlya Dryomov pr_err("failed to decode addr_for_me: %d\n", ret); 2015cd1a677cSIlya Dryomov return ret; 2016cd1a677cSIlya Dryomov } 2017cd1a677cSIlya Dryomov 2018cd1a677cSIlya Dryomov dout("%s con %p entity_type %d addr_for_me %s\n", __func__, con, 2019cd1a677cSIlya Dryomov entity_type, ceph_pr_addr(&addr_for_me)); 2020cd1a677cSIlya Dryomov 2021cd1a677cSIlya Dryomov if (entity_type != con->peer_name.type) { 2022cd1a677cSIlya Dryomov pr_err("bad peer type, want %d, got %d\n", 2023cd1a677cSIlya Dryomov con->peer_name.type, entity_type); 2024cd1a677cSIlya Dryomov con->error_msg = "wrong peer at address"; 2025cd1a677cSIlya Dryomov return -EINVAL; 2026cd1a677cSIlya Dryomov } 2027cd1a677cSIlya Dryomov 2028cd1a677cSIlya Dryomov /* 2029cd1a677cSIlya Dryomov * Set our address to the address our first peer (i.e. monitor) 2030cd1a677cSIlya Dryomov * sees that we are connecting from. If we are behind some sort 2031cd1a677cSIlya Dryomov * of NAT and want to be identified by some private (not NATed) 2032cd1a677cSIlya Dryomov * address, ip option should be used. 2033cd1a677cSIlya Dryomov */ 2034cd1a677cSIlya Dryomov if (ceph_addr_is_blank(my_addr)) { 2035cd1a677cSIlya Dryomov memcpy(&my_addr->in_addr, &addr_for_me.in_addr, 2036cd1a677cSIlya Dryomov sizeof(my_addr->in_addr)); 2037cd1a677cSIlya Dryomov ceph_addr_set_port(my_addr, 0); 2038cd1a677cSIlya Dryomov dout("%s con %p set my addr %s, as seen by peer %s\n", 2039cd1a677cSIlya Dryomov __func__, con, ceph_pr_addr(my_addr), 2040cd1a677cSIlya Dryomov ceph_pr_addr(&con->peer_addr)); 2041cd1a677cSIlya Dryomov } else { 2042cd1a677cSIlya Dryomov dout("%s con %p my addr already set %s\n", 2043cd1a677cSIlya Dryomov __func__, con, ceph_pr_addr(my_addr)); 2044cd1a677cSIlya Dryomov } 2045cd1a677cSIlya Dryomov 2046cd1a677cSIlya Dryomov WARN_ON(ceph_addr_is_blank(my_addr) || ceph_addr_port(my_addr)); 2047cd1a677cSIlya Dryomov WARN_ON(my_addr->type != CEPH_ENTITY_ADDR_TYPE_ANY); 2048cd1a677cSIlya Dryomov WARN_ON(!my_addr->nonce); 2049cd1a677cSIlya Dryomov 2050cd1a677cSIlya Dryomov /* no reset_out_kvecs() as our hello may still be pending */ 2051cd1a677cSIlya Dryomov ret = prepare_auth_request(con); 2052cd1a677cSIlya Dryomov if (ret) { 2053cd1a677cSIlya Dryomov if (ret != -EAGAIN) 2054cd1a677cSIlya Dryomov pr_err("prepare_auth_request failed: %d\n", ret); 2055cd1a677cSIlya Dryomov return ret; 2056cd1a677cSIlya Dryomov } 2057cd1a677cSIlya Dryomov 2058cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_AUTH; 2059cd1a677cSIlya Dryomov return 0; 2060cd1a677cSIlya Dryomov 2061cd1a677cSIlya Dryomov bad: 2062cd1a677cSIlya Dryomov pr_err("failed to decode hello\n"); 2063cd1a677cSIlya Dryomov return -EINVAL; 2064cd1a677cSIlya Dryomov } 2065cd1a677cSIlya Dryomov 2066cd1a677cSIlya Dryomov static int process_auth_bad_method(struct ceph_connection *con, 2067cd1a677cSIlya Dryomov void *p, void *end) 2068cd1a677cSIlya Dryomov { 2069cd1a677cSIlya Dryomov int allowed_protos[8], allowed_modes[8]; 2070cd1a677cSIlya Dryomov int allowed_proto_cnt, allowed_mode_cnt; 2071cd1a677cSIlya Dryomov int used_proto, result; 2072cd1a677cSIlya Dryomov int ret; 2073cd1a677cSIlya Dryomov int i; 2074cd1a677cSIlya Dryomov 2075cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 2076cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected auth_bad_method"; 2077cd1a677cSIlya Dryomov return -EINVAL; 2078cd1a677cSIlya Dryomov } 2079cd1a677cSIlya Dryomov 2080cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, used_proto, bad); 2081cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, result, bad); 2082cd1a677cSIlya Dryomov dout("%s con %p used_proto %d result %d\n", __func__, con, used_proto, 2083cd1a677cSIlya Dryomov result); 2084cd1a677cSIlya Dryomov 2085cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, allowed_proto_cnt, bad); 2086cd1a677cSIlya Dryomov if (allowed_proto_cnt > ARRAY_SIZE(allowed_protos)) { 2087cd1a677cSIlya Dryomov pr_err("allowed_protos too big %d\n", allowed_proto_cnt); 2088cd1a677cSIlya Dryomov return -EINVAL; 2089cd1a677cSIlya Dryomov } 2090cd1a677cSIlya Dryomov for (i = 0; i < allowed_proto_cnt; i++) { 2091cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, allowed_protos[i], bad); 2092cd1a677cSIlya Dryomov dout("%s con %p allowed_protos[%d] %d\n", __func__, con, 2093cd1a677cSIlya Dryomov i, allowed_protos[i]); 2094cd1a677cSIlya Dryomov } 2095cd1a677cSIlya Dryomov 2096cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, allowed_mode_cnt, bad); 2097cd1a677cSIlya Dryomov if (allowed_mode_cnt > ARRAY_SIZE(allowed_modes)) { 2098cd1a677cSIlya Dryomov pr_err("allowed_modes too big %d\n", allowed_mode_cnt); 2099cd1a677cSIlya Dryomov return -EINVAL; 2100cd1a677cSIlya Dryomov } 2101cd1a677cSIlya Dryomov for (i = 0; i < allowed_mode_cnt; i++) { 2102cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, allowed_modes[i], bad); 2103cd1a677cSIlya Dryomov dout("%s con %p allowed_modes[%d] %d\n", __func__, con, 2104cd1a677cSIlya Dryomov i, allowed_modes[i]); 2105cd1a677cSIlya Dryomov } 2106cd1a677cSIlya Dryomov 2107cd1a677cSIlya Dryomov mutex_unlock(&con->mutex); 2108cd1a677cSIlya Dryomov ret = con->ops->handle_auth_bad_method(con, used_proto, result, 2109cd1a677cSIlya Dryomov allowed_protos, 2110cd1a677cSIlya Dryomov allowed_proto_cnt, 2111cd1a677cSIlya Dryomov allowed_modes, 2112cd1a677cSIlya Dryomov allowed_mode_cnt); 2113cd1a677cSIlya Dryomov mutex_lock(&con->mutex); 2114cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 2115cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 2116cd1a677cSIlya Dryomov con->state); 2117cd1a677cSIlya Dryomov return -EAGAIN; 2118cd1a677cSIlya Dryomov } 2119cd1a677cSIlya Dryomov 2120cd1a677cSIlya Dryomov dout("%s con %p handle_auth_bad_method ret %d\n", __func__, con, ret); 2121cd1a677cSIlya Dryomov return ret; 2122cd1a677cSIlya Dryomov 2123cd1a677cSIlya Dryomov bad: 2124cd1a677cSIlya Dryomov pr_err("failed to decode auth_bad_method\n"); 2125cd1a677cSIlya Dryomov return -EINVAL; 2126cd1a677cSIlya Dryomov } 2127cd1a677cSIlya Dryomov 2128cd1a677cSIlya Dryomov static int process_auth_reply_more(struct ceph_connection *con, 2129cd1a677cSIlya Dryomov void *p, void *end) 2130cd1a677cSIlya Dryomov { 2131cd1a677cSIlya Dryomov int payload_len; 2132cd1a677cSIlya Dryomov int ret; 2133cd1a677cSIlya Dryomov 2134cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 2135cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected auth_reply_more"; 2136cd1a677cSIlya Dryomov return -EINVAL; 2137cd1a677cSIlya Dryomov } 2138cd1a677cSIlya Dryomov 2139cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, payload_len, bad); 2140cd1a677cSIlya Dryomov ceph_decode_need(&p, end, payload_len, bad); 2141cd1a677cSIlya Dryomov 2142cd1a677cSIlya Dryomov dout("%s con %p payload_len %d\n", __func__, con, payload_len); 2143cd1a677cSIlya Dryomov 2144cd1a677cSIlya Dryomov reset_out_kvecs(con); 2145cd1a677cSIlya Dryomov ret = prepare_auth_request_more(con, p, payload_len); 2146cd1a677cSIlya Dryomov if (ret) { 2147cd1a677cSIlya Dryomov if (ret != -EAGAIN) 2148cd1a677cSIlya Dryomov pr_err("prepare_auth_request_more failed: %d\n", ret); 2149cd1a677cSIlya Dryomov return ret; 2150cd1a677cSIlya Dryomov } 2151cd1a677cSIlya Dryomov 2152cd1a677cSIlya Dryomov return 0; 2153cd1a677cSIlya Dryomov 2154cd1a677cSIlya Dryomov bad: 2155cd1a677cSIlya Dryomov pr_err("failed to decode auth_reply_more\n"); 2156cd1a677cSIlya Dryomov return -EINVAL; 2157cd1a677cSIlya Dryomov } 2158cd1a677cSIlya Dryomov 2159f5f2c9a0SIlya Dryomov /* 2160f5f2c9a0SIlya Dryomov * Align session_key and con_secret to avoid GFP_ATOMIC allocation 2161f5f2c9a0SIlya Dryomov * inside crypto_shash_setkey() and crypto_aead_setkey() called from 2162f5f2c9a0SIlya Dryomov * setup_crypto(). __aligned(16) isn't guaranteed to work for stack 2163f5f2c9a0SIlya Dryomov * objects, so do it by hand. 2164f5f2c9a0SIlya Dryomov */ 2165cd1a677cSIlya Dryomov static int process_auth_done(struct ceph_connection *con, void *p, void *end) 2166cd1a677cSIlya Dryomov { 2167f5f2c9a0SIlya Dryomov u8 session_key_buf[CEPH_KEY_LEN + 16]; 2168f5f2c9a0SIlya Dryomov u8 con_secret_buf[CEPH_MAX_CON_SECRET_LEN + 16]; 2169f5f2c9a0SIlya Dryomov u8 *session_key = PTR_ALIGN(&session_key_buf[0], 16); 2170f5f2c9a0SIlya Dryomov u8 *con_secret = PTR_ALIGN(&con_secret_buf[0], 16); 2171cd1a677cSIlya Dryomov int session_key_len, con_secret_len; 2172cd1a677cSIlya Dryomov int payload_len; 2173cd1a677cSIlya Dryomov u64 global_id; 2174cd1a677cSIlya Dryomov int ret; 2175cd1a677cSIlya Dryomov 2176cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 2177cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected auth_done"; 2178cd1a677cSIlya Dryomov return -EINVAL; 2179cd1a677cSIlya Dryomov } 2180cd1a677cSIlya Dryomov 2181cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, global_id, bad); 2182cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, con->v2.con_mode, bad); 2183cd1a677cSIlya Dryomov ceph_decode_32_safe(&p, end, payload_len, bad); 2184cd1a677cSIlya Dryomov 2185cd1a677cSIlya Dryomov dout("%s con %p global_id %llu con_mode %d payload_len %d\n", 2186cd1a677cSIlya Dryomov __func__, con, global_id, con->v2.con_mode, payload_len); 2187cd1a677cSIlya Dryomov 2188cd1a677cSIlya Dryomov mutex_unlock(&con->mutex); 2189cd1a677cSIlya Dryomov session_key_len = 0; 2190cd1a677cSIlya Dryomov con_secret_len = 0; 2191cd1a677cSIlya Dryomov ret = con->ops->handle_auth_done(con, global_id, p, payload_len, 2192cd1a677cSIlya Dryomov session_key, &session_key_len, 2193cd1a677cSIlya Dryomov con_secret, &con_secret_len); 2194cd1a677cSIlya Dryomov mutex_lock(&con->mutex); 2195cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH) { 2196cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 2197cd1a677cSIlya Dryomov con->state); 219810f42b3eSIlya Dryomov ret = -EAGAIN; 219910f42b3eSIlya Dryomov goto out; 2200cd1a677cSIlya Dryomov } 2201cd1a677cSIlya Dryomov 2202cd1a677cSIlya Dryomov dout("%s con %p handle_auth_done ret %d\n", __func__, con, ret); 2203cd1a677cSIlya Dryomov if (ret) 220410f42b3eSIlya Dryomov goto out; 2205cd1a677cSIlya Dryomov 2206cd1a677cSIlya Dryomov ret = setup_crypto(con, session_key, session_key_len, con_secret, 2207cd1a677cSIlya Dryomov con_secret_len); 2208cd1a677cSIlya Dryomov if (ret) 220910f42b3eSIlya Dryomov goto out; 2210cd1a677cSIlya Dryomov 2211cd1a677cSIlya Dryomov reset_out_kvecs(con); 2212cd1a677cSIlya Dryomov ret = prepare_auth_signature(con); 2213cd1a677cSIlya Dryomov if (ret) { 2214cd1a677cSIlya Dryomov pr_err("prepare_auth_signature failed: %d\n", ret); 221510f42b3eSIlya Dryomov goto out; 2216cd1a677cSIlya Dryomov } 2217cd1a677cSIlya Dryomov 2218cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_AUTH_SIGNATURE; 221910f42b3eSIlya Dryomov 222010f42b3eSIlya Dryomov out: 222110f42b3eSIlya Dryomov memzero_explicit(session_key_buf, sizeof(session_key_buf)); 222210f42b3eSIlya Dryomov memzero_explicit(con_secret_buf, sizeof(con_secret_buf)); 222310f42b3eSIlya Dryomov return ret; 2224cd1a677cSIlya Dryomov 2225cd1a677cSIlya Dryomov bad: 2226cd1a677cSIlya Dryomov pr_err("failed to decode auth_done\n"); 2227cd1a677cSIlya Dryomov return -EINVAL; 2228cd1a677cSIlya Dryomov } 2229cd1a677cSIlya Dryomov 2230cd1a677cSIlya Dryomov static int process_auth_signature(struct ceph_connection *con, 2231cd1a677cSIlya Dryomov void *p, void *end) 2232cd1a677cSIlya Dryomov { 2233cd1a677cSIlya Dryomov u8 hmac[SHA256_DIGEST_SIZE]; 2234cd1a677cSIlya Dryomov int ret; 2235cd1a677cSIlya Dryomov 2236cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_AUTH_SIGNATURE) { 2237cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected auth_signature"; 2238cd1a677cSIlya Dryomov return -EINVAL; 2239cd1a677cSIlya Dryomov } 2240cd1a677cSIlya Dryomov 2241cd1a677cSIlya Dryomov ret = hmac_sha256(con, con->v2.out_sign_kvecs, 2242cd1a677cSIlya Dryomov con->v2.out_sign_kvec_cnt, hmac); 2243cd1a677cSIlya Dryomov if (ret) 2244cd1a677cSIlya Dryomov return ret; 2245cd1a677cSIlya Dryomov 2246cd1a677cSIlya Dryomov ceph_decode_need(&p, end, SHA256_DIGEST_SIZE, bad); 2247cd1a677cSIlya Dryomov if (crypto_memneq(p, hmac, SHA256_DIGEST_SIZE)) { 2248cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad auth signature"; 2249cd1a677cSIlya Dryomov return -EBADMSG; 2250cd1a677cSIlya Dryomov } 2251cd1a677cSIlya Dryomov 2252cd1a677cSIlya Dryomov dout("%s con %p auth signature ok\n", __func__, con); 2253cd1a677cSIlya Dryomov 2254cd1a677cSIlya Dryomov /* no reset_out_kvecs() as our auth_signature may still be pending */ 2255cd1a677cSIlya Dryomov if (!con->v2.server_cookie) { 2256cd1a677cSIlya Dryomov ret = prepare_client_ident(con); 2257cd1a677cSIlya Dryomov if (ret) { 2258cd1a677cSIlya Dryomov pr_err("prepare_client_ident failed: %d\n", ret); 2259cd1a677cSIlya Dryomov return ret; 2260cd1a677cSIlya Dryomov } 2261cd1a677cSIlya Dryomov 2262cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_SESSION_CONNECT; 2263cd1a677cSIlya Dryomov } else { 2264cd1a677cSIlya Dryomov ret = prepare_session_reconnect(con); 2265cd1a677cSIlya Dryomov if (ret) { 2266cd1a677cSIlya Dryomov pr_err("prepare_session_reconnect failed: %d\n", ret); 2267cd1a677cSIlya Dryomov return ret; 2268cd1a677cSIlya Dryomov } 2269cd1a677cSIlya Dryomov 2270cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_SESSION_RECONNECT; 2271cd1a677cSIlya Dryomov } 2272cd1a677cSIlya Dryomov 2273cd1a677cSIlya Dryomov return 0; 2274cd1a677cSIlya Dryomov 2275cd1a677cSIlya Dryomov bad: 2276cd1a677cSIlya Dryomov pr_err("failed to decode auth_signature\n"); 2277cd1a677cSIlya Dryomov return -EINVAL; 2278cd1a677cSIlya Dryomov } 2279cd1a677cSIlya Dryomov 2280cd1a677cSIlya Dryomov static int process_server_ident(struct ceph_connection *con, 2281cd1a677cSIlya Dryomov void *p, void *end) 2282cd1a677cSIlya Dryomov { 2283cd1a677cSIlya Dryomov struct ceph_client *client = from_msgr(con->msgr); 2284cd1a677cSIlya Dryomov u64 features, required_features; 2285cd1a677cSIlya Dryomov struct ceph_entity_addr addr; 2286cd1a677cSIlya Dryomov u64 global_seq; 2287cd1a677cSIlya Dryomov u64 global_id; 2288cd1a677cSIlya Dryomov u64 cookie; 2289cd1a677cSIlya Dryomov u64 flags; 2290cd1a677cSIlya Dryomov int ret; 2291cd1a677cSIlya Dryomov 2292cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_CONNECT) { 2293cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected server_ident"; 2294cd1a677cSIlya Dryomov return -EINVAL; 2295cd1a677cSIlya Dryomov } 2296cd1a677cSIlya Dryomov 2297cd1a677cSIlya Dryomov ret = ceph_decode_entity_addrvec(&p, end, true, &addr); 2298cd1a677cSIlya Dryomov if (ret) { 2299cd1a677cSIlya Dryomov pr_err("failed to decode server addrs: %d\n", ret); 2300cd1a677cSIlya Dryomov return ret; 2301cd1a677cSIlya Dryomov } 2302cd1a677cSIlya Dryomov 2303cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, global_id, bad); 2304cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, global_seq, bad); 2305cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, features, bad); 2306cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, required_features, bad); 2307cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, flags, bad); 2308cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, cookie, bad); 2309cd1a677cSIlya Dryomov 2310cd1a677cSIlya Dryomov 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", 2311cd1a677cSIlya Dryomov __func__, con, ceph_pr_addr(&addr), le32_to_cpu(addr.nonce), 2312cd1a677cSIlya Dryomov global_id, global_seq, features, required_features, flags, cookie); 2313cd1a677cSIlya Dryomov 2314cd1a677cSIlya Dryomov /* is this who we intended to talk to? */ 2315cd1a677cSIlya Dryomov if (memcmp(&addr, &con->peer_addr, sizeof(con->peer_addr))) { 2316cd1a677cSIlya Dryomov pr_err("bad peer addr/nonce, want %s/%u, got %s/%u\n", 2317cd1a677cSIlya Dryomov ceph_pr_addr(&con->peer_addr), 2318cd1a677cSIlya Dryomov le32_to_cpu(con->peer_addr.nonce), 2319cd1a677cSIlya Dryomov ceph_pr_addr(&addr), le32_to_cpu(addr.nonce)); 2320cd1a677cSIlya Dryomov con->error_msg = "wrong peer at address"; 2321cd1a677cSIlya Dryomov return -EINVAL; 2322cd1a677cSIlya Dryomov } 2323cd1a677cSIlya Dryomov 2324cd1a677cSIlya Dryomov if (client->required_features & ~features) { 2325cd1a677cSIlya Dryomov pr_err("RADOS feature set mismatch: my required > server's supported 0x%llx, need 0x%llx\n", 2326cd1a677cSIlya Dryomov features, client->required_features & ~features); 2327cd1a677cSIlya Dryomov con->error_msg = "missing required protocol features"; 2328cd1a677cSIlya Dryomov return -EINVAL; 2329cd1a677cSIlya Dryomov } 2330cd1a677cSIlya Dryomov 2331cd1a677cSIlya Dryomov /* 2332cd1a677cSIlya Dryomov * Both name->type and name->num are set in ceph_con_open() but 2333cd1a677cSIlya Dryomov * name->num may be bogus in the initial monmap. name->type is 2334cd1a677cSIlya Dryomov * verified in handle_hello(). 2335cd1a677cSIlya Dryomov */ 2336cd1a677cSIlya Dryomov WARN_ON(!con->peer_name.type); 2337cd1a677cSIlya Dryomov con->peer_name.num = cpu_to_le64(global_id); 2338cd1a677cSIlya Dryomov con->v2.peer_global_seq = global_seq; 2339cd1a677cSIlya Dryomov con->peer_features = features; 2340cd1a677cSIlya Dryomov WARN_ON(required_features & ~client->supported_features); 2341cd1a677cSIlya Dryomov con->v2.server_cookie = cookie; 2342cd1a677cSIlya Dryomov 2343cd1a677cSIlya Dryomov if (flags & CEPH_MSG_CONNECT_LOSSY) { 2344cd1a677cSIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); 2345cd1a677cSIlya Dryomov WARN_ON(con->v2.server_cookie); 2346cd1a677cSIlya Dryomov } else { 2347cd1a677cSIlya Dryomov WARN_ON(!con->v2.server_cookie); 2348cd1a677cSIlya Dryomov } 2349cd1a677cSIlya Dryomov 2350cd1a677cSIlya Dryomov clear_in_sign_kvecs(con); 2351cd1a677cSIlya Dryomov clear_out_sign_kvecs(con); 2352cd1a677cSIlya Dryomov free_conn_bufs(con); 2353cd1a677cSIlya Dryomov con->delay = 0; /* reset backoff memory */ 2354cd1a677cSIlya Dryomov 2355cd1a677cSIlya Dryomov con->state = CEPH_CON_S_OPEN; 2356cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_GET_NEXT; 2357cd1a677cSIlya Dryomov return 0; 2358cd1a677cSIlya Dryomov 2359cd1a677cSIlya Dryomov bad: 2360cd1a677cSIlya Dryomov pr_err("failed to decode server_ident\n"); 2361cd1a677cSIlya Dryomov return -EINVAL; 2362cd1a677cSIlya Dryomov } 2363cd1a677cSIlya Dryomov 2364cd1a677cSIlya Dryomov static int process_ident_missing_features(struct ceph_connection *con, 2365cd1a677cSIlya Dryomov void *p, void *end) 2366cd1a677cSIlya Dryomov { 2367cd1a677cSIlya Dryomov struct ceph_client *client = from_msgr(con->msgr); 2368cd1a677cSIlya Dryomov u64 missing_features; 2369cd1a677cSIlya Dryomov 2370cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_CONNECT) { 2371cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected ident_missing_features"; 2372cd1a677cSIlya Dryomov return -EINVAL; 2373cd1a677cSIlya Dryomov } 2374cd1a677cSIlya Dryomov 2375cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, missing_features, bad); 2376cd1a677cSIlya Dryomov pr_err("RADOS feature set mismatch: server's required > my supported 0x%llx, missing 0x%llx\n", 2377cd1a677cSIlya Dryomov client->supported_features, missing_features); 2378cd1a677cSIlya Dryomov con->error_msg = "missing required protocol features"; 2379cd1a677cSIlya Dryomov return -EINVAL; 2380cd1a677cSIlya Dryomov 2381cd1a677cSIlya Dryomov bad: 2382cd1a677cSIlya Dryomov pr_err("failed to decode ident_missing_features\n"); 2383cd1a677cSIlya Dryomov return -EINVAL; 2384cd1a677cSIlya Dryomov } 2385cd1a677cSIlya Dryomov 2386cd1a677cSIlya Dryomov static int process_session_reconnect_ok(struct ceph_connection *con, 2387cd1a677cSIlya Dryomov void *p, void *end) 2388cd1a677cSIlya Dryomov { 2389cd1a677cSIlya Dryomov u64 seq; 2390cd1a677cSIlya Dryomov 2391cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) { 2392cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected session_reconnect_ok"; 2393cd1a677cSIlya Dryomov return -EINVAL; 2394cd1a677cSIlya Dryomov } 2395cd1a677cSIlya Dryomov 2396cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, seq, bad); 2397cd1a677cSIlya Dryomov 2398cd1a677cSIlya Dryomov dout("%s con %p seq %llu\n", __func__, con, seq); 2399cd1a677cSIlya Dryomov ceph_con_discard_requeued(con, seq); 2400cd1a677cSIlya Dryomov 2401cd1a677cSIlya Dryomov clear_in_sign_kvecs(con); 2402cd1a677cSIlya Dryomov clear_out_sign_kvecs(con); 2403cd1a677cSIlya Dryomov free_conn_bufs(con); 2404cd1a677cSIlya Dryomov con->delay = 0; /* reset backoff memory */ 2405cd1a677cSIlya Dryomov 2406cd1a677cSIlya Dryomov con->state = CEPH_CON_S_OPEN; 2407cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_GET_NEXT; 2408cd1a677cSIlya Dryomov return 0; 2409cd1a677cSIlya Dryomov 2410cd1a677cSIlya Dryomov bad: 2411cd1a677cSIlya Dryomov pr_err("failed to decode session_reconnect_ok\n"); 2412cd1a677cSIlya Dryomov return -EINVAL; 2413cd1a677cSIlya Dryomov } 2414cd1a677cSIlya Dryomov 2415cd1a677cSIlya Dryomov static int process_session_retry(struct ceph_connection *con, 2416cd1a677cSIlya Dryomov void *p, void *end) 2417cd1a677cSIlya Dryomov { 2418cd1a677cSIlya Dryomov u64 connect_seq; 2419cd1a677cSIlya Dryomov int ret; 2420cd1a677cSIlya Dryomov 2421cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) { 2422cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected session_retry"; 2423cd1a677cSIlya Dryomov return -EINVAL; 2424cd1a677cSIlya Dryomov } 2425cd1a677cSIlya Dryomov 2426cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, connect_seq, bad); 2427cd1a677cSIlya Dryomov 2428cd1a677cSIlya Dryomov dout("%s con %p connect_seq %llu\n", __func__, con, connect_seq); 2429cd1a677cSIlya Dryomov WARN_ON(connect_seq <= con->v2.connect_seq); 2430cd1a677cSIlya Dryomov con->v2.connect_seq = connect_seq + 1; 2431cd1a677cSIlya Dryomov 2432cd1a677cSIlya Dryomov free_conn_bufs(con); 2433cd1a677cSIlya Dryomov 2434cd1a677cSIlya Dryomov reset_out_kvecs(con); 2435cd1a677cSIlya Dryomov ret = prepare_session_reconnect(con); 2436cd1a677cSIlya Dryomov if (ret) { 2437cd1a677cSIlya Dryomov pr_err("prepare_session_reconnect (cseq) failed: %d\n", ret); 2438cd1a677cSIlya Dryomov return ret; 2439cd1a677cSIlya Dryomov } 2440cd1a677cSIlya Dryomov 2441cd1a677cSIlya Dryomov return 0; 2442cd1a677cSIlya Dryomov 2443cd1a677cSIlya Dryomov bad: 2444cd1a677cSIlya Dryomov pr_err("failed to decode session_retry\n"); 2445cd1a677cSIlya Dryomov return -EINVAL; 2446cd1a677cSIlya Dryomov } 2447cd1a677cSIlya Dryomov 2448cd1a677cSIlya Dryomov static int process_session_retry_global(struct ceph_connection *con, 2449cd1a677cSIlya Dryomov void *p, void *end) 2450cd1a677cSIlya Dryomov { 2451cd1a677cSIlya Dryomov u64 global_seq; 2452cd1a677cSIlya Dryomov int ret; 2453cd1a677cSIlya Dryomov 2454cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) { 2455cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected session_retry_global"; 2456cd1a677cSIlya Dryomov return -EINVAL; 2457cd1a677cSIlya Dryomov } 2458cd1a677cSIlya Dryomov 2459cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, global_seq, bad); 2460cd1a677cSIlya Dryomov 2461cd1a677cSIlya Dryomov dout("%s con %p global_seq %llu\n", __func__, con, global_seq); 2462cd1a677cSIlya Dryomov WARN_ON(global_seq <= con->v2.global_seq); 2463cd1a677cSIlya Dryomov con->v2.global_seq = ceph_get_global_seq(con->msgr, global_seq); 2464cd1a677cSIlya Dryomov 2465cd1a677cSIlya Dryomov free_conn_bufs(con); 2466cd1a677cSIlya Dryomov 2467cd1a677cSIlya Dryomov reset_out_kvecs(con); 2468cd1a677cSIlya Dryomov ret = prepare_session_reconnect(con); 2469cd1a677cSIlya Dryomov if (ret) { 2470cd1a677cSIlya Dryomov pr_err("prepare_session_reconnect (gseq) failed: %d\n", ret); 2471cd1a677cSIlya Dryomov return ret; 2472cd1a677cSIlya Dryomov } 2473cd1a677cSIlya Dryomov 2474cd1a677cSIlya Dryomov return 0; 2475cd1a677cSIlya Dryomov 2476cd1a677cSIlya Dryomov bad: 2477cd1a677cSIlya Dryomov pr_err("failed to decode session_retry_global\n"); 2478cd1a677cSIlya Dryomov return -EINVAL; 2479cd1a677cSIlya Dryomov } 2480cd1a677cSIlya Dryomov 2481cd1a677cSIlya Dryomov static int process_session_reset(struct ceph_connection *con, 2482cd1a677cSIlya Dryomov void *p, void *end) 2483cd1a677cSIlya Dryomov { 2484cd1a677cSIlya Dryomov bool full; 2485cd1a677cSIlya Dryomov int ret; 2486cd1a677cSIlya Dryomov 2487cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) { 2488cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected session_reset"; 2489cd1a677cSIlya Dryomov return -EINVAL; 2490cd1a677cSIlya Dryomov } 2491cd1a677cSIlya Dryomov 2492cd1a677cSIlya Dryomov ceph_decode_8_safe(&p, end, full, bad); 2493cd1a677cSIlya Dryomov if (!full) { 2494cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad session_reset"; 2495cd1a677cSIlya Dryomov return -EINVAL; 2496cd1a677cSIlya Dryomov } 2497cd1a677cSIlya Dryomov 2498cd1a677cSIlya Dryomov pr_info("%s%lld %s session reset\n", ENTITY_NAME(con->peer_name), 2499cd1a677cSIlya Dryomov ceph_pr_addr(&con->peer_addr)); 2500cd1a677cSIlya Dryomov ceph_con_reset_session(con); 2501cd1a677cSIlya Dryomov 2502cd1a677cSIlya Dryomov mutex_unlock(&con->mutex); 2503cd1a677cSIlya Dryomov if (con->ops->peer_reset) 2504cd1a677cSIlya Dryomov con->ops->peer_reset(con); 2505cd1a677cSIlya Dryomov mutex_lock(&con->mutex); 2506cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_V2_SESSION_RECONNECT) { 2507cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 2508cd1a677cSIlya Dryomov con->state); 2509cd1a677cSIlya Dryomov return -EAGAIN; 2510cd1a677cSIlya Dryomov } 2511cd1a677cSIlya Dryomov 2512cd1a677cSIlya Dryomov free_conn_bufs(con); 2513cd1a677cSIlya Dryomov 2514cd1a677cSIlya Dryomov reset_out_kvecs(con); 2515cd1a677cSIlya Dryomov ret = prepare_client_ident(con); 2516cd1a677cSIlya Dryomov if (ret) { 2517cd1a677cSIlya Dryomov pr_err("prepare_client_ident (rst) failed: %d\n", ret); 2518cd1a677cSIlya Dryomov return ret; 2519cd1a677cSIlya Dryomov } 2520cd1a677cSIlya Dryomov 2521cd1a677cSIlya Dryomov con->state = CEPH_CON_S_V2_SESSION_CONNECT; 2522cd1a677cSIlya Dryomov return 0; 2523cd1a677cSIlya Dryomov 2524cd1a677cSIlya Dryomov bad: 2525cd1a677cSIlya Dryomov pr_err("failed to decode session_reset\n"); 2526cd1a677cSIlya Dryomov return -EINVAL; 2527cd1a677cSIlya Dryomov } 2528cd1a677cSIlya Dryomov 2529cd1a677cSIlya Dryomov static int process_keepalive2_ack(struct ceph_connection *con, 2530cd1a677cSIlya Dryomov void *p, void *end) 2531cd1a677cSIlya Dryomov { 2532cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_OPEN) { 2533cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected keepalive2_ack"; 2534cd1a677cSIlya Dryomov return -EINVAL; 2535cd1a677cSIlya Dryomov } 2536cd1a677cSIlya Dryomov 2537cd1a677cSIlya Dryomov ceph_decode_need(&p, end, sizeof(struct ceph_timespec), bad); 2538cd1a677cSIlya Dryomov ceph_decode_timespec64(&con->last_keepalive_ack, p); 2539cd1a677cSIlya Dryomov 2540cd1a677cSIlya Dryomov dout("%s con %p timestamp %lld.%09ld\n", __func__, con, 2541cd1a677cSIlya Dryomov con->last_keepalive_ack.tv_sec, con->last_keepalive_ack.tv_nsec); 2542cd1a677cSIlya Dryomov 2543cd1a677cSIlya Dryomov return 0; 2544cd1a677cSIlya Dryomov 2545cd1a677cSIlya Dryomov bad: 2546cd1a677cSIlya Dryomov pr_err("failed to decode keepalive2_ack\n"); 2547cd1a677cSIlya Dryomov return -EINVAL; 2548cd1a677cSIlya Dryomov } 2549cd1a677cSIlya Dryomov 2550cd1a677cSIlya Dryomov static int process_ack(struct ceph_connection *con, void *p, void *end) 2551cd1a677cSIlya Dryomov { 2552cd1a677cSIlya Dryomov u64 seq; 2553cd1a677cSIlya Dryomov 2554cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_OPEN) { 2555cd1a677cSIlya Dryomov con->error_msg = "protocol error, unexpected ack"; 2556cd1a677cSIlya Dryomov return -EINVAL; 2557cd1a677cSIlya Dryomov } 2558cd1a677cSIlya Dryomov 2559cd1a677cSIlya Dryomov ceph_decode_64_safe(&p, end, seq, bad); 2560cd1a677cSIlya Dryomov 2561cd1a677cSIlya Dryomov dout("%s con %p seq %llu\n", __func__, con, seq); 2562cd1a677cSIlya Dryomov ceph_con_discard_sent(con, seq); 2563cd1a677cSIlya Dryomov return 0; 2564cd1a677cSIlya Dryomov 2565cd1a677cSIlya Dryomov bad: 2566cd1a677cSIlya Dryomov pr_err("failed to decode ack\n"); 2567cd1a677cSIlya Dryomov return -EINVAL; 2568cd1a677cSIlya Dryomov } 2569cd1a677cSIlya Dryomov 2570cd1a677cSIlya Dryomov static int process_control(struct ceph_connection *con, void *p, void *end) 2571cd1a677cSIlya Dryomov { 2572cd1a677cSIlya Dryomov int tag = con->v2.in_desc.fd_tag; 2573cd1a677cSIlya Dryomov int ret; 2574cd1a677cSIlya Dryomov 2575cd1a677cSIlya Dryomov dout("%s con %p tag %d len %d\n", __func__, con, tag, (int)(end - p)); 2576cd1a677cSIlya Dryomov 2577cd1a677cSIlya Dryomov switch (tag) { 2578cd1a677cSIlya Dryomov case FRAME_TAG_HELLO: 2579cd1a677cSIlya Dryomov ret = process_hello(con, p, end); 2580cd1a677cSIlya Dryomov break; 2581cd1a677cSIlya Dryomov case FRAME_TAG_AUTH_BAD_METHOD: 2582cd1a677cSIlya Dryomov ret = process_auth_bad_method(con, p, end); 2583cd1a677cSIlya Dryomov break; 2584cd1a677cSIlya Dryomov case FRAME_TAG_AUTH_REPLY_MORE: 2585cd1a677cSIlya Dryomov ret = process_auth_reply_more(con, p, end); 2586cd1a677cSIlya Dryomov break; 2587cd1a677cSIlya Dryomov case FRAME_TAG_AUTH_DONE: 2588cd1a677cSIlya Dryomov ret = process_auth_done(con, p, end); 2589cd1a677cSIlya Dryomov break; 2590cd1a677cSIlya Dryomov case FRAME_TAG_AUTH_SIGNATURE: 2591cd1a677cSIlya Dryomov ret = process_auth_signature(con, p, end); 2592cd1a677cSIlya Dryomov break; 2593cd1a677cSIlya Dryomov case FRAME_TAG_SERVER_IDENT: 2594cd1a677cSIlya Dryomov ret = process_server_ident(con, p, end); 2595cd1a677cSIlya Dryomov break; 2596cd1a677cSIlya Dryomov case FRAME_TAG_IDENT_MISSING_FEATURES: 2597cd1a677cSIlya Dryomov ret = process_ident_missing_features(con, p, end); 2598cd1a677cSIlya Dryomov break; 2599cd1a677cSIlya Dryomov case FRAME_TAG_SESSION_RECONNECT_OK: 2600cd1a677cSIlya Dryomov ret = process_session_reconnect_ok(con, p, end); 2601cd1a677cSIlya Dryomov break; 2602cd1a677cSIlya Dryomov case FRAME_TAG_SESSION_RETRY: 2603cd1a677cSIlya Dryomov ret = process_session_retry(con, p, end); 2604cd1a677cSIlya Dryomov break; 2605cd1a677cSIlya Dryomov case FRAME_TAG_SESSION_RETRY_GLOBAL: 2606cd1a677cSIlya Dryomov ret = process_session_retry_global(con, p, end); 2607cd1a677cSIlya Dryomov break; 2608cd1a677cSIlya Dryomov case FRAME_TAG_SESSION_RESET: 2609cd1a677cSIlya Dryomov ret = process_session_reset(con, p, end); 2610cd1a677cSIlya Dryomov break; 2611cd1a677cSIlya Dryomov case FRAME_TAG_KEEPALIVE2_ACK: 2612cd1a677cSIlya Dryomov ret = process_keepalive2_ack(con, p, end); 2613cd1a677cSIlya Dryomov break; 2614cd1a677cSIlya Dryomov case FRAME_TAG_ACK: 2615cd1a677cSIlya Dryomov ret = process_ack(con, p, end); 2616cd1a677cSIlya Dryomov break; 2617cd1a677cSIlya Dryomov default: 2618cd1a677cSIlya Dryomov pr_err("bad tag %d\n", tag); 2619cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad tag"; 2620cd1a677cSIlya Dryomov return -EINVAL; 2621cd1a677cSIlya Dryomov } 2622cd1a677cSIlya Dryomov if (ret) { 2623cd1a677cSIlya Dryomov dout("%s con %p error %d\n", __func__, con, ret); 2624cd1a677cSIlya Dryomov return ret; 2625cd1a677cSIlya Dryomov } 2626cd1a677cSIlya Dryomov 2627cd1a677cSIlya Dryomov prepare_read_preamble(con); 2628cd1a677cSIlya Dryomov return 0; 2629cd1a677cSIlya Dryomov } 2630cd1a677cSIlya Dryomov 2631cd1a677cSIlya Dryomov /* 2632cd1a677cSIlya Dryomov * Return: 2633cd1a677cSIlya Dryomov * 1 - con->in_msg set, read message 2634cd1a677cSIlya Dryomov * 0 - skip message 2635cd1a677cSIlya Dryomov * <0 - error 2636cd1a677cSIlya Dryomov */ 2637cd1a677cSIlya Dryomov static int process_message_header(struct ceph_connection *con, 2638cd1a677cSIlya Dryomov void *p, void *end) 2639cd1a677cSIlya Dryomov { 2640cd1a677cSIlya Dryomov struct ceph_frame_desc *desc = &con->v2.in_desc; 2641cd1a677cSIlya Dryomov struct ceph_msg_header2 *hdr2 = p; 2642cd1a677cSIlya Dryomov struct ceph_msg_header hdr; 2643cd1a677cSIlya Dryomov int skip; 2644cd1a677cSIlya Dryomov int ret; 2645cd1a677cSIlya Dryomov u64 seq; 2646cd1a677cSIlya Dryomov 2647cd1a677cSIlya Dryomov /* verify seq# */ 2648cd1a677cSIlya Dryomov seq = le64_to_cpu(hdr2->seq); 2649cd1a677cSIlya Dryomov if ((s64)seq - (s64)con->in_seq < 1) { 2650cd1a677cSIlya Dryomov pr_info("%s%lld %s skipping old message: seq %llu, expected %llu\n", 2651cd1a677cSIlya Dryomov ENTITY_NAME(con->peer_name), 2652cd1a677cSIlya Dryomov ceph_pr_addr(&con->peer_addr), 2653cd1a677cSIlya Dryomov seq, con->in_seq + 1); 2654cd1a677cSIlya Dryomov return 0; 2655cd1a677cSIlya Dryomov } 2656cd1a677cSIlya Dryomov if ((s64)seq - (s64)con->in_seq > 1) { 2657cd1a677cSIlya Dryomov pr_err("bad seq %llu, expected %llu\n", seq, con->in_seq + 1); 2658cd1a677cSIlya Dryomov con->error_msg = "bad message sequence # for incoming message"; 2659cd1a677cSIlya Dryomov return -EBADE; 2660cd1a677cSIlya Dryomov } 2661cd1a677cSIlya Dryomov 2662cd1a677cSIlya Dryomov ceph_con_discard_sent(con, le64_to_cpu(hdr2->ack_seq)); 2663cd1a677cSIlya Dryomov 2664cd1a677cSIlya Dryomov fill_header(&hdr, hdr2, desc->fd_lens[1], desc->fd_lens[2], 2665cd1a677cSIlya Dryomov desc->fd_lens[3], &con->peer_name); 2666cd1a677cSIlya Dryomov ret = ceph_con_in_msg_alloc(con, &hdr, &skip); 2667cd1a677cSIlya Dryomov if (ret) 2668cd1a677cSIlya Dryomov return ret; 2669cd1a677cSIlya Dryomov 2670cd1a677cSIlya Dryomov WARN_ON(!con->in_msg ^ skip); 2671cd1a677cSIlya Dryomov if (skip) 2672cd1a677cSIlya Dryomov return 0; 2673cd1a677cSIlya Dryomov 2674cd1a677cSIlya Dryomov WARN_ON(!con->in_msg); 2675cd1a677cSIlya Dryomov WARN_ON(con->in_msg->con != con); 2676cd1a677cSIlya Dryomov return 1; 2677cd1a677cSIlya Dryomov } 2678cd1a677cSIlya Dryomov 2679cd1a677cSIlya Dryomov static int process_message(struct ceph_connection *con) 2680cd1a677cSIlya Dryomov { 2681cd1a677cSIlya Dryomov ceph_con_process_message(con); 2682cd1a677cSIlya Dryomov 2683cd1a677cSIlya Dryomov /* 2684cd1a677cSIlya Dryomov * We could have been closed by ceph_con_close() because 2685cd1a677cSIlya Dryomov * ceph_con_process_message() temporarily drops con->mutex. 2686cd1a677cSIlya Dryomov */ 2687cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_OPEN) { 2688cd1a677cSIlya Dryomov dout("%s con %p state changed to %d\n", __func__, con, 2689cd1a677cSIlya Dryomov con->state); 2690cd1a677cSIlya Dryomov return -EAGAIN; 2691cd1a677cSIlya Dryomov } 2692cd1a677cSIlya Dryomov 2693cd1a677cSIlya Dryomov prepare_read_preamble(con); 2694cd1a677cSIlya Dryomov return 0; 2695cd1a677cSIlya Dryomov } 2696cd1a677cSIlya Dryomov 2697cd1a677cSIlya Dryomov static int __handle_control(struct ceph_connection *con, void *p) 2698cd1a677cSIlya Dryomov { 2699cd1a677cSIlya Dryomov void *end = p + con->v2.in_desc.fd_lens[0]; 2700cd1a677cSIlya Dryomov struct ceph_msg *msg; 2701cd1a677cSIlya Dryomov int ret; 2702cd1a677cSIlya Dryomov 2703cd1a677cSIlya Dryomov if (con->v2.in_desc.fd_tag != FRAME_TAG_MESSAGE) 2704cd1a677cSIlya Dryomov return process_control(con, p, end); 2705cd1a677cSIlya Dryomov 2706cd1a677cSIlya Dryomov ret = process_message_header(con, p, end); 2707cd1a677cSIlya Dryomov if (ret < 0) 2708cd1a677cSIlya Dryomov return ret; 2709cd1a677cSIlya Dryomov if (ret == 0) { 2710cd1a677cSIlya Dryomov prepare_skip_message(con); 2711cd1a677cSIlya Dryomov return 0; 2712cd1a677cSIlya Dryomov } 2713cd1a677cSIlya Dryomov 2714cd1a677cSIlya Dryomov msg = con->in_msg; /* set in process_message_header() */ 2715cd1a677cSIlya Dryomov if (front_len(msg)) { 2716cd1a677cSIlya Dryomov WARN_ON(front_len(msg) > msg->front_alloc_len); 2717cd1a677cSIlya Dryomov msg->front.iov_len = front_len(msg); 2718cd1a677cSIlya Dryomov } else { 2719cd1a677cSIlya Dryomov msg->front.iov_len = 0; 2720cd1a677cSIlya Dryomov } 2721cd1a677cSIlya Dryomov if (middle_len(msg)) { 2722cd1a677cSIlya Dryomov WARN_ON(middle_len(msg) > msg->middle->alloc_len); 2723cd1a677cSIlya Dryomov msg->middle->vec.iov_len = middle_len(msg); 2724cd1a677cSIlya Dryomov } else if (msg->middle) { 2725cd1a677cSIlya Dryomov msg->middle->vec.iov_len = 0; 2726cd1a677cSIlya Dryomov } 2727cd1a677cSIlya Dryomov 27282ea88716SIlya Dryomov if (!front_len(msg) && !middle_len(msg) && !data_len(msg)) 27292ea88716SIlya Dryomov return process_message(con); 27302ea88716SIlya Dryomov 27312ea88716SIlya Dryomov if (con_secure(con)) 27322ea88716SIlya Dryomov return prepare_read_tail_secure(con); 27332ea88716SIlya Dryomov 2734*038b8d1dSIlya Dryomov return prepare_read_tail_plain(con); 2735cd1a677cSIlya Dryomov } 2736cd1a677cSIlya Dryomov 2737cd1a677cSIlya Dryomov static int handle_preamble(struct ceph_connection *con) 2738cd1a677cSIlya Dryomov { 2739cd1a677cSIlya Dryomov struct ceph_frame_desc *desc = &con->v2.in_desc; 2740cd1a677cSIlya Dryomov int ret; 2741cd1a677cSIlya Dryomov 2742cd1a677cSIlya Dryomov if (con_secure(con)) { 2743cd1a677cSIlya Dryomov ret = decrypt_preamble(con); 2744cd1a677cSIlya Dryomov if (ret) { 2745cd1a677cSIlya Dryomov if (ret == -EBADMSG) 2746cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad preamble auth tag"; 2747cd1a677cSIlya Dryomov return ret; 2748cd1a677cSIlya Dryomov } 2749cd1a677cSIlya Dryomov } 2750cd1a677cSIlya Dryomov 2751cd1a677cSIlya Dryomov ret = decode_preamble(con->v2.in_buf, desc); 2752cd1a677cSIlya Dryomov if (ret) { 2753cd1a677cSIlya Dryomov if (ret == -EBADMSG) 2754cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad crc"; 2755cd1a677cSIlya Dryomov else 2756cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad preamble"; 2757cd1a677cSIlya Dryomov return ret; 2758cd1a677cSIlya Dryomov } 2759cd1a677cSIlya Dryomov 2760cd1a677cSIlya Dryomov dout("%s con %p tag %d seg_cnt %d %d+%d+%d+%d\n", __func__, 2761cd1a677cSIlya Dryomov con, desc->fd_tag, desc->fd_seg_cnt, desc->fd_lens[0], 2762cd1a677cSIlya Dryomov desc->fd_lens[1], desc->fd_lens[2], desc->fd_lens[3]); 2763cd1a677cSIlya Dryomov 2764cd1a677cSIlya Dryomov if (!con_secure(con)) 2765cd1a677cSIlya Dryomov return prepare_read_control(con); 2766cd1a677cSIlya Dryomov 2767cd1a677cSIlya Dryomov if (desc->fd_lens[0] > CEPH_PREAMBLE_INLINE_LEN) 2768cd1a677cSIlya Dryomov return prepare_read_control_remainder(con); 2769cd1a677cSIlya Dryomov 2770cd1a677cSIlya Dryomov return __handle_control(con, CTRL_BODY(con->v2.in_buf)); 2771cd1a677cSIlya Dryomov } 2772cd1a677cSIlya Dryomov 2773cd1a677cSIlya Dryomov static int handle_control(struct ceph_connection *con) 2774cd1a677cSIlya Dryomov { 2775cd1a677cSIlya Dryomov int ctrl_len = con->v2.in_desc.fd_lens[0]; 2776cd1a677cSIlya Dryomov void *buf; 2777cd1a677cSIlya Dryomov int ret; 2778cd1a677cSIlya Dryomov 2779cd1a677cSIlya Dryomov WARN_ON(con_secure(con)); 2780cd1a677cSIlya Dryomov 2781cd1a677cSIlya Dryomov ret = verify_control_crc(con); 2782cd1a677cSIlya Dryomov if (ret) { 2783cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad crc"; 2784cd1a677cSIlya Dryomov return ret; 2785cd1a677cSIlya Dryomov } 2786cd1a677cSIlya Dryomov 2787cd1a677cSIlya Dryomov if (con->state == CEPH_CON_S_V2_AUTH) { 2788cd1a677cSIlya Dryomov buf = alloc_conn_buf(con, ctrl_len); 2789cd1a677cSIlya Dryomov if (!buf) 2790cd1a677cSIlya Dryomov return -ENOMEM; 2791cd1a677cSIlya Dryomov 2792cd1a677cSIlya Dryomov memcpy(buf, con->v2.in_kvecs[0].iov_base, ctrl_len); 2793cd1a677cSIlya Dryomov return __handle_control(con, buf); 2794cd1a677cSIlya Dryomov } 2795cd1a677cSIlya Dryomov 2796cd1a677cSIlya Dryomov return __handle_control(con, con->v2.in_kvecs[0].iov_base); 2797cd1a677cSIlya Dryomov } 2798cd1a677cSIlya Dryomov 2799cd1a677cSIlya Dryomov static int handle_control_remainder(struct ceph_connection *con) 2800cd1a677cSIlya Dryomov { 2801cd1a677cSIlya Dryomov int ret; 2802cd1a677cSIlya Dryomov 2803cd1a677cSIlya Dryomov WARN_ON(!con_secure(con)); 2804cd1a677cSIlya Dryomov 2805cd1a677cSIlya Dryomov ret = decrypt_control_remainder(con); 2806cd1a677cSIlya Dryomov if (ret) { 2807cd1a677cSIlya Dryomov if (ret == -EBADMSG) 2808cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad control remainder auth tag"; 2809cd1a677cSIlya Dryomov return ret; 2810cd1a677cSIlya Dryomov } 2811cd1a677cSIlya Dryomov 2812cd1a677cSIlya Dryomov return __handle_control(con, con->v2.in_kvecs[0].iov_base - 2813cd1a677cSIlya Dryomov CEPH_PREAMBLE_INLINE_LEN); 2814cd1a677cSIlya Dryomov } 2815cd1a677cSIlya Dryomov 2816cd1a677cSIlya Dryomov static int handle_epilogue(struct ceph_connection *con) 2817cd1a677cSIlya Dryomov { 2818cd1a677cSIlya Dryomov u32 front_crc, middle_crc, data_crc; 2819cd1a677cSIlya Dryomov int ret; 2820cd1a677cSIlya Dryomov 2821cd1a677cSIlya Dryomov if (con_secure(con)) { 28222ea88716SIlya Dryomov ret = decrypt_tail(con); 2823cd1a677cSIlya Dryomov if (ret) { 2824cd1a677cSIlya Dryomov if (ret == -EBADMSG) 2825cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad epilogue auth tag"; 2826cd1a677cSIlya Dryomov return ret; 2827cd1a677cSIlya Dryomov } 2828cd1a677cSIlya Dryomov 2829cd1a677cSIlya Dryomov /* just late_status */ 2830cd1a677cSIlya Dryomov ret = decode_epilogue(con->v2.in_buf, NULL, NULL, NULL); 2831cd1a677cSIlya Dryomov if (ret) { 2832cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad epilogue"; 2833cd1a677cSIlya Dryomov return ret; 2834cd1a677cSIlya Dryomov } 2835cd1a677cSIlya Dryomov } else { 2836cd1a677cSIlya Dryomov ret = decode_epilogue(con->v2.in_buf, &front_crc, 2837cd1a677cSIlya Dryomov &middle_crc, &data_crc); 2838cd1a677cSIlya Dryomov if (ret) { 2839cd1a677cSIlya Dryomov con->error_msg = "protocol error, bad epilogue"; 2840cd1a677cSIlya Dryomov return ret; 2841cd1a677cSIlya Dryomov } 2842cd1a677cSIlya Dryomov 2843cd1a677cSIlya Dryomov ret = verify_epilogue_crcs(con, front_crc, middle_crc, 2844cd1a677cSIlya Dryomov data_crc); 2845cd1a677cSIlya Dryomov if (ret) { 2846cd1a677cSIlya Dryomov con->error_msg = "integrity error, bad crc"; 2847cd1a677cSIlya Dryomov return ret; 2848cd1a677cSIlya Dryomov } 2849cd1a677cSIlya Dryomov } 2850cd1a677cSIlya Dryomov 2851cd1a677cSIlya Dryomov return process_message(con); 2852cd1a677cSIlya Dryomov } 2853cd1a677cSIlya Dryomov 2854cd1a677cSIlya Dryomov static void finish_skip(struct ceph_connection *con) 2855cd1a677cSIlya Dryomov { 2856cd1a677cSIlya Dryomov dout("%s con %p\n", __func__, con); 2857cd1a677cSIlya Dryomov 2858cd1a677cSIlya Dryomov if (con_secure(con)) 2859cd1a677cSIlya Dryomov gcm_inc_nonce(&con->v2.in_gcm_nonce); 2860cd1a677cSIlya Dryomov 2861cd1a677cSIlya Dryomov __finish_skip(con); 2862cd1a677cSIlya Dryomov } 2863cd1a677cSIlya Dryomov 2864cd1a677cSIlya Dryomov static int populate_in_iter(struct ceph_connection *con) 2865cd1a677cSIlya Dryomov { 2866cd1a677cSIlya Dryomov int ret; 2867cd1a677cSIlya Dryomov 2868cd1a677cSIlya Dryomov dout("%s con %p state %d in_state %d\n", __func__, con, con->state, 2869cd1a677cSIlya Dryomov con->v2.in_state); 2870cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.in_iter)); 2871cd1a677cSIlya Dryomov 2872cd1a677cSIlya Dryomov if (con->state == CEPH_CON_S_V2_BANNER_PREFIX) { 2873cd1a677cSIlya Dryomov ret = process_banner_prefix(con); 2874cd1a677cSIlya Dryomov } else if (con->state == CEPH_CON_S_V2_BANNER_PAYLOAD) { 2875cd1a677cSIlya Dryomov ret = process_banner_payload(con); 2876cd1a677cSIlya Dryomov } else if ((con->state >= CEPH_CON_S_V2_HELLO && 2877cd1a677cSIlya Dryomov con->state <= CEPH_CON_S_V2_SESSION_RECONNECT) || 2878cd1a677cSIlya Dryomov con->state == CEPH_CON_S_OPEN) { 2879cd1a677cSIlya Dryomov switch (con->v2.in_state) { 2880cd1a677cSIlya Dryomov case IN_S_HANDLE_PREAMBLE: 2881cd1a677cSIlya Dryomov ret = handle_preamble(con); 2882cd1a677cSIlya Dryomov break; 2883cd1a677cSIlya Dryomov case IN_S_HANDLE_CONTROL: 2884cd1a677cSIlya Dryomov ret = handle_control(con); 2885cd1a677cSIlya Dryomov break; 2886cd1a677cSIlya Dryomov case IN_S_HANDLE_CONTROL_REMAINDER: 2887cd1a677cSIlya Dryomov ret = handle_control_remainder(con); 2888cd1a677cSIlya Dryomov break; 2889cd1a677cSIlya Dryomov case IN_S_PREPARE_READ_DATA: 2890*038b8d1dSIlya Dryomov ret = prepare_read_data(con); 2891cd1a677cSIlya Dryomov break; 2892cd1a677cSIlya Dryomov case IN_S_PREPARE_READ_DATA_CONT: 2893cd1a677cSIlya Dryomov prepare_read_data_cont(con); 2894cd1a677cSIlya Dryomov ret = 0; 2895cd1a677cSIlya Dryomov break; 28962ea88716SIlya Dryomov case IN_S_PREPARE_READ_ENC_PAGE: 28972ea88716SIlya Dryomov prepare_read_enc_page(con); 28982ea88716SIlya Dryomov ret = 0; 28992ea88716SIlya Dryomov break; 2900cd1a677cSIlya Dryomov case IN_S_HANDLE_EPILOGUE: 2901cd1a677cSIlya Dryomov ret = handle_epilogue(con); 2902cd1a677cSIlya Dryomov break; 2903cd1a677cSIlya Dryomov case IN_S_FINISH_SKIP: 2904cd1a677cSIlya Dryomov finish_skip(con); 2905cd1a677cSIlya Dryomov ret = 0; 2906cd1a677cSIlya Dryomov break; 2907cd1a677cSIlya Dryomov default: 2908cd1a677cSIlya Dryomov WARN(1, "bad in_state %d", con->v2.in_state); 2909cd1a677cSIlya Dryomov return -EINVAL; 2910cd1a677cSIlya Dryomov } 2911cd1a677cSIlya Dryomov } else { 2912cd1a677cSIlya Dryomov WARN(1, "bad state %d", con->state); 2913cd1a677cSIlya Dryomov return -EINVAL; 2914cd1a677cSIlya Dryomov } 2915cd1a677cSIlya Dryomov if (ret) { 2916cd1a677cSIlya Dryomov dout("%s con %p error %d\n", __func__, con, ret); 2917cd1a677cSIlya Dryomov return ret; 2918cd1a677cSIlya Dryomov } 2919cd1a677cSIlya Dryomov 2920cd1a677cSIlya Dryomov if (WARN_ON(!iov_iter_count(&con->v2.in_iter))) 2921cd1a677cSIlya Dryomov return -ENODATA; 2922cd1a677cSIlya Dryomov dout("%s con %p populated %zu\n", __func__, con, 2923cd1a677cSIlya Dryomov iov_iter_count(&con->v2.in_iter)); 2924cd1a677cSIlya Dryomov return 1; 2925cd1a677cSIlya Dryomov } 2926cd1a677cSIlya Dryomov 2927cd1a677cSIlya Dryomov int ceph_con_v2_try_read(struct ceph_connection *con) 2928cd1a677cSIlya Dryomov { 2929cd1a677cSIlya Dryomov int ret; 2930cd1a677cSIlya Dryomov 2931cd1a677cSIlya Dryomov dout("%s con %p state %d need %zu\n", __func__, con, con->state, 2932cd1a677cSIlya Dryomov iov_iter_count(&con->v2.in_iter)); 2933cd1a677cSIlya Dryomov 2934cd1a677cSIlya Dryomov if (con->state == CEPH_CON_S_PREOPEN) 2935cd1a677cSIlya Dryomov return 0; 2936cd1a677cSIlya Dryomov 2937cd1a677cSIlya Dryomov /* 2938cd1a677cSIlya Dryomov * We should always have something pending here. If not, 2939cd1a677cSIlya Dryomov * avoid calling populate_in_iter() as if we read something 2940cd1a677cSIlya Dryomov * (ceph_tcp_recv() would immediately return 1). 2941cd1a677cSIlya Dryomov */ 2942cd1a677cSIlya Dryomov if (WARN_ON(!iov_iter_count(&con->v2.in_iter))) 2943cd1a677cSIlya Dryomov return -ENODATA; 2944cd1a677cSIlya Dryomov 2945cd1a677cSIlya Dryomov for (;;) { 2946cd1a677cSIlya Dryomov ret = ceph_tcp_recv(con); 2947cd1a677cSIlya Dryomov if (ret <= 0) 2948cd1a677cSIlya Dryomov return ret; 2949cd1a677cSIlya Dryomov 2950cd1a677cSIlya Dryomov ret = populate_in_iter(con); 2951cd1a677cSIlya Dryomov if (ret <= 0) { 2952cd1a677cSIlya Dryomov if (ret && ret != -EAGAIN && !con->error_msg) 2953cd1a677cSIlya Dryomov con->error_msg = "read processing error"; 2954cd1a677cSIlya Dryomov return ret; 2955cd1a677cSIlya Dryomov } 2956cd1a677cSIlya Dryomov } 2957cd1a677cSIlya Dryomov } 2958cd1a677cSIlya Dryomov 2959cd1a677cSIlya Dryomov static void queue_data(struct ceph_connection *con) 2960cd1a677cSIlya Dryomov { 2961cd1a677cSIlya Dryomov struct bio_vec bv; 2962cd1a677cSIlya Dryomov 2963cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = -1; 2964cd1a677cSIlya Dryomov ceph_msg_data_cursor_init(&con->v2.out_cursor, con->out_msg, 2965cd1a677cSIlya Dryomov data_len(con->out_msg)); 2966cd1a677cSIlya Dryomov 2967cd1a677cSIlya Dryomov get_bvec_at(&con->v2.out_cursor, &bv); 2968cd1a677cSIlya Dryomov set_out_bvec(con, &bv, true); 2969cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_DATA_CONT; 2970cd1a677cSIlya Dryomov } 2971cd1a677cSIlya Dryomov 2972cd1a677cSIlya Dryomov static void queue_data_cont(struct ceph_connection *con) 2973cd1a677cSIlya Dryomov { 2974cd1a677cSIlya Dryomov struct bio_vec bv; 2975cd1a677cSIlya Dryomov 2976cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = ceph_crc32c_page( 2977cd1a677cSIlya Dryomov con->v2.out_epil.data_crc, con->v2.out_bvec.bv_page, 2978cd1a677cSIlya Dryomov con->v2.out_bvec.bv_offset, con->v2.out_bvec.bv_len); 2979cd1a677cSIlya Dryomov 2980cd1a677cSIlya Dryomov ceph_msg_data_advance(&con->v2.out_cursor, con->v2.out_bvec.bv_len); 2981cd1a677cSIlya Dryomov if (con->v2.out_cursor.total_resid) { 2982cd1a677cSIlya Dryomov get_bvec_at(&con->v2.out_cursor, &bv); 2983cd1a677cSIlya Dryomov set_out_bvec(con, &bv, true); 2984cd1a677cSIlya Dryomov WARN_ON(con->v2.out_state != OUT_S_QUEUE_DATA_CONT); 2985cd1a677cSIlya Dryomov return; 2986cd1a677cSIlya Dryomov } 2987cd1a677cSIlya Dryomov 2988cd1a677cSIlya Dryomov /* 2989cd1a677cSIlya Dryomov * We've written all data. Queue epilogue. Once it's written, 2990cd1a677cSIlya Dryomov * we are done. 2991cd1a677cSIlya Dryomov */ 2992cd1a677cSIlya Dryomov reset_out_kvecs(con); 2993cd1a677cSIlya Dryomov prepare_epilogue_plain(con, false); 2994cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 2995cd1a677cSIlya Dryomov } 2996cd1a677cSIlya Dryomov 2997cd1a677cSIlya Dryomov static void queue_enc_page(struct ceph_connection *con) 2998cd1a677cSIlya Dryomov { 2999cd1a677cSIlya Dryomov struct bio_vec bv; 3000cd1a677cSIlya Dryomov 3001cd1a677cSIlya Dryomov dout("%s con %p i %d resid %d\n", __func__, con, con->v2.out_enc_i, 3002cd1a677cSIlya Dryomov con->v2.out_enc_resid); 3003cd1a677cSIlya Dryomov WARN_ON(!con->v2.out_enc_resid); 3004cd1a677cSIlya Dryomov 3005cd1a677cSIlya Dryomov bv.bv_page = con->v2.out_enc_pages[con->v2.out_enc_i]; 3006cd1a677cSIlya Dryomov bv.bv_offset = 0; 3007cd1a677cSIlya Dryomov bv.bv_len = min(con->v2.out_enc_resid, (int)PAGE_SIZE); 3008cd1a677cSIlya Dryomov 3009cd1a677cSIlya Dryomov set_out_bvec(con, &bv, false); 3010cd1a677cSIlya Dryomov con->v2.out_enc_i++; 3011cd1a677cSIlya Dryomov con->v2.out_enc_resid -= bv.bv_len; 3012cd1a677cSIlya Dryomov 3013cd1a677cSIlya Dryomov if (con->v2.out_enc_resid) { 3014cd1a677cSIlya Dryomov WARN_ON(con->v2.out_state != OUT_S_QUEUE_ENC_PAGE); 3015cd1a677cSIlya Dryomov return; 3016cd1a677cSIlya Dryomov } 3017cd1a677cSIlya Dryomov 3018cd1a677cSIlya Dryomov /* 3019cd1a677cSIlya Dryomov * We've queued the last piece of ciphertext (ending with 3020cd1a677cSIlya Dryomov * epilogue) + auth tag. Once it's written, we are done. 3021cd1a677cSIlya Dryomov */ 3022cd1a677cSIlya Dryomov WARN_ON(con->v2.out_enc_i != con->v2.out_enc_page_cnt); 3023cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 3024cd1a677cSIlya Dryomov } 3025cd1a677cSIlya Dryomov 3026cd1a677cSIlya Dryomov static void queue_zeros(struct ceph_connection *con) 3027cd1a677cSIlya Dryomov { 3028cd1a677cSIlya Dryomov dout("%s con %p out_zero %d\n", __func__, con, con->v2.out_zero); 3029cd1a677cSIlya Dryomov 3030cd1a677cSIlya Dryomov if (con->v2.out_zero) { 3031cd1a677cSIlya Dryomov set_out_bvec_zero(con); 3032cd1a677cSIlya Dryomov con->v2.out_zero -= con->v2.out_bvec.bv_len; 3033cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_ZEROS; 3034cd1a677cSIlya Dryomov return; 3035cd1a677cSIlya Dryomov } 3036cd1a677cSIlya Dryomov 3037cd1a677cSIlya Dryomov /* 3038cd1a677cSIlya Dryomov * We've zero-filled everything up to epilogue. Queue epilogue 3039cd1a677cSIlya Dryomov * with late_status set to ABORTED and crcs adjusted for zeros. 3040cd1a677cSIlya Dryomov * Once it's written, we are done patching up for the revoke. 3041cd1a677cSIlya Dryomov */ 3042cd1a677cSIlya Dryomov reset_out_kvecs(con); 3043cd1a677cSIlya Dryomov prepare_epilogue_plain(con, true); 3044cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_FINISH_MESSAGE; 3045cd1a677cSIlya Dryomov } 3046cd1a677cSIlya Dryomov 3047cd1a677cSIlya Dryomov static void finish_message(struct ceph_connection *con) 3048cd1a677cSIlya Dryomov { 3049cd1a677cSIlya Dryomov dout("%s con %p msg %p\n", __func__, con, con->out_msg); 3050cd1a677cSIlya Dryomov 3051cd1a677cSIlya Dryomov /* we end up here both plain and secure modes */ 3052cd1a677cSIlya Dryomov if (con->v2.out_enc_pages) { 3053cd1a677cSIlya Dryomov WARN_ON(!con->v2.out_enc_page_cnt); 3054cd1a677cSIlya Dryomov ceph_release_page_vector(con->v2.out_enc_pages, 3055cd1a677cSIlya Dryomov con->v2.out_enc_page_cnt); 3056cd1a677cSIlya Dryomov con->v2.out_enc_pages = NULL; 3057cd1a677cSIlya Dryomov con->v2.out_enc_page_cnt = 0; 3058cd1a677cSIlya Dryomov } 3059cd1a677cSIlya Dryomov /* message may have been revoked */ 3060cd1a677cSIlya Dryomov if (con->out_msg) { 3061cd1a677cSIlya Dryomov ceph_msg_put(con->out_msg); 3062cd1a677cSIlya Dryomov con->out_msg = NULL; 3063cd1a677cSIlya Dryomov } 3064cd1a677cSIlya Dryomov 3065cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_GET_NEXT; 3066cd1a677cSIlya Dryomov } 3067cd1a677cSIlya Dryomov 3068cd1a677cSIlya Dryomov static int populate_out_iter(struct ceph_connection *con) 3069cd1a677cSIlya Dryomov { 3070cd1a677cSIlya Dryomov int ret; 3071cd1a677cSIlya Dryomov 3072cd1a677cSIlya Dryomov dout("%s con %p state %d out_state %d\n", __func__, con, con->state, 3073cd1a677cSIlya Dryomov con->v2.out_state); 3074cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter)); 3075cd1a677cSIlya Dryomov 3076cd1a677cSIlya Dryomov if (con->state != CEPH_CON_S_OPEN) { 3077cd1a677cSIlya Dryomov WARN_ON(con->state < CEPH_CON_S_V2_BANNER_PREFIX || 3078cd1a677cSIlya Dryomov con->state > CEPH_CON_S_V2_SESSION_RECONNECT); 3079cd1a677cSIlya Dryomov goto nothing_pending; 3080cd1a677cSIlya Dryomov } 3081cd1a677cSIlya Dryomov 3082cd1a677cSIlya Dryomov switch (con->v2.out_state) { 3083cd1a677cSIlya Dryomov case OUT_S_QUEUE_DATA: 3084cd1a677cSIlya Dryomov WARN_ON(!con->out_msg); 3085cd1a677cSIlya Dryomov queue_data(con); 3086cd1a677cSIlya Dryomov goto populated; 3087cd1a677cSIlya Dryomov case OUT_S_QUEUE_DATA_CONT: 3088cd1a677cSIlya Dryomov WARN_ON(!con->out_msg); 3089cd1a677cSIlya Dryomov queue_data_cont(con); 3090cd1a677cSIlya Dryomov goto populated; 3091cd1a677cSIlya Dryomov case OUT_S_QUEUE_ENC_PAGE: 3092cd1a677cSIlya Dryomov queue_enc_page(con); 3093cd1a677cSIlya Dryomov goto populated; 3094cd1a677cSIlya Dryomov case OUT_S_QUEUE_ZEROS: 3095cd1a677cSIlya Dryomov WARN_ON(con->out_msg); /* revoked */ 3096cd1a677cSIlya Dryomov queue_zeros(con); 3097cd1a677cSIlya Dryomov goto populated; 3098cd1a677cSIlya Dryomov case OUT_S_FINISH_MESSAGE: 3099cd1a677cSIlya Dryomov finish_message(con); 3100cd1a677cSIlya Dryomov break; 3101cd1a677cSIlya Dryomov case OUT_S_GET_NEXT: 3102cd1a677cSIlya Dryomov break; 3103cd1a677cSIlya Dryomov default: 3104cd1a677cSIlya Dryomov WARN(1, "bad out_state %d", con->v2.out_state); 3105cd1a677cSIlya Dryomov return -EINVAL; 3106cd1a677cSIlya Dryomov } 3107cd1a677cSIlya Dryomov 3108cd1a677cSIlya Dryomov WARN_ON(con->v2.out_state != OUT_S_GET_NEXT); 3109cd1a677cSIlya Dryomov if (ceph_con_flag_test_and_clear(con, CEPH_CON_F_KEEPALIVE_PENDING)) { 3110cd1a677cSIlya Dryomov ret = prepare_keepalive2(con); 3111cd1a677cSIlya Dryomov if (ret) { 3112cd1a677cSIlya Dryomov pr_err("prepare_keepalive2 failed: %d\n", ret); 3113cd1a677cSIlya Dryomov return ret; 3114cd1a677cSIlya Dryomov } 3115cd1a677cSIlya Dryomov } else if (!list_empty(&con->out_queue)) { 3116cd1a677cSIlya Dryomov ceph_con_get_out_msg(con); 3117cd1a677cSIlya Dryomov ret = prepare_message(con); 3118cd1a677cSIlya Dryomov if (ret) { 3119cd1a677cSIlya Dryomov pr_err("prepare_message failed: %d\n", ret); 3120cd1a677cSIlya Dryomov return ret; 3121cd1a677cSIlya Dryomov } 3122cd1a677cSIlya Dryomov } else if (con->in_seq > con->in_seq_acked) { 3123cd1a677cSIlya Dryomov ret = prepare_ack(con); 3124cd1a677cSIlya Dryomov if (ret) { 3125cd1a677cSIlya Dryomov pr_err("prepare_ack failed: %d\n", ret); 3126cd1a677cSIlya Dryomov return ret; 3127cd1a677cSIlya Dryomov } 3128cd1a677cSIlya Dryomov } else { 3129cd1a677cSIlya Dryomov goto nothing_pending; 3130cd1a677cSIlya Dryomov } 3131cd1a677cSIlya Dryomov 3132cd1a677cSIlya Dryomov populated: 3133cd1a677cSIlya Dryomov if (WARN_ON(!iov_iter_count(&con->v2.out_iter))) 3134cd1a677cSIlya Dryomov return -ENODATA; 3135cd1a677cSIlya Dryomov dout("%s con %p populated %zu\n", __func__, con, 3136cd1a677cSIlya Dryomov iov_iter_count(&con->v2.out_iter)); 3137cd1a677cSIlya Dryomov return 1; 3138cd1a677cSIlya Dryomov 3139cd1a677cSIlya Dryomov nothing_pending: 3140cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter)); 3141cd1a677cSIlya Dryomov dout("%s con %p nothing pending\n", __func__, con); 3142cd1a677cSIlya Dryomov ceph_con_flag_clear(con, CEPH_CON_F_WRITE_PENDING); 3143cd1a677cSIlya Dryomov return 0; 3144cd1a677cSIlya Dryomov } 3145cd1a677cSIlya Dryomov 3146cd1a677cSIlya Dryomov int ceph_con_v2_try_write(struct ceph_connection *con) 3147cd1a677cSIlya Dryomov { 3148cd1a677cSIlya Dryomov int ret; 3149cd1a677cSIlya Dryomov 3150cd1a677cSIlya Dryomov dout("%s con %p state %d have %zu\n", __func__, con, con->state, 3151cd1a677cSIlya Dryomov iov_iter_count(&con->v2.out_iter)); 3152cd1a677cSIlya Dryomov 3153cd1a677cSIlya Dryomov /* open the socket first? */ 3154cd1a677cSIlya Dryomov if (con->state == CEPH_CON_S_PREOPEN) { 3155cd1a677cSIlya Dryomov WARN_ON(con->peer_addr.type != CEPH_ENTITY_ADDR_TYPE_MSGR2); 3156cd1a677cSIlya Dryomov 3157cd1a677cSIlya Dryomov /* 3158cd1a677cSIlya Dryomov * Always bump global_seq. Bump connect_seq only if 3159cd1a677cSIlya Dryomov * there is a session (i.e. we are reconnecting and will 3160cd1a677cSIlya Dryomov * send session_reconnect instead of client_ident). 3161cd1a677cSIlya Dryomov */ 3162cd1a677cSIlya Dryomov con->v2.global_seq = ceph_get_global_seq(con->msgr, 0); 3163cd1a677cSIlya Dryomov if (con->v2.server_cookie) 3164cd1a677cSIlya Dryomov con->v2.connect_seq++; 3165cd1a677cSIlya Dryomov 3166cd1a677cSIlya Dryomov ret = prepare_read_banner_prefix(con); 3167cd1a677cSIlya Dryomov if (ret) { 3168cd1a677cSIlya Dryomov pr_err("prepare_read_banner_prefix failed: %d\n", ret); 3169cd1a677cSIlya Dryomov con->error_msg = "connect error"; 3170cd1a677cSIlya Dryomov return ret; 3171cd1a677cSIlya Dryomov } 3172cd1a677cSIlya Dryomov 3173cd1a677cSIlya Dryomov reset_out_kvecs(con); 3174cd1a677cSIlya Dryomov ret = prepare_banner(con); 3175cd1a677cSIlya Dryomov if (ret) { 3176cd1a677cSIlya Dryomov pr_err("prepare_banner failed: %d\n", ret); 3177cd1a677cSIlya Dryomov con->error_msg = "connect error"; 3178cd1a677cSIlya Dryomov return ret; 3179cd1a677cSIlya Dryomov } 3180cd1a677cSIlya Dryomov 3181cd1a677cSIlya Dryomov ret = ceph_tcp_connect(con); 3182cd1a677cSIlya Dryomov if (ret) { 3183cd1a677cSIlya Dryomov pr_err("ceph_tcp_connect failed: %d\n", ret); 3184cd1a677cSIlya Dryomov con->error_msg = "connect error"; 3185cd1a677cSIlya Dryomov return ret; 3186cd1a677cSIlya Dryomov } 3187cd1a677cSIlya Dryomov } 3188cd1a677cSIlya Dryomov 3189cd1a677cSIlya Dryomov if (!iov_iter_count(&con->v2.out_iter)) { 3190cd1a677cSIlya Dryomov ret = populate_out_iter(con); 3191cd1a677cSIlya Dryomov if (ret <= 0) { 3192cd1a677cSIlya Dryomov if (ret && ret != -EAGAIN && !con->error_msg) 3193cd1a677cSIlya Dryomov con->error_msg = "write processing error"; 3194cd1a677cSIlya Dryomov return ret; 3195cd1a677cSIlya Dryomov } 3196cd1a677cSIlya Dryomov } 3197cd1a677cSIlya Dryomov 3198cd1a677cSIlya Dryomov tcp_sock_set_cork(con->sock->sk, true); 3199cd1a677cSIlya Dryomov for (;;) { 3200cd1a677cSIlya Dryomov ret = ceph_tcp_send(con); 3201cd1a677cSIlya Dryomov if (ret <= 0) 3202cd1a677cSIlya Dryomov break; 3203cd1a677cSIlya Dryomov 3204cd1a677cSIlya Dryomov ret = populate_out_iter(con); 3205cd1a677cSIlya Dryomov if (ret <= 0) { 3206cd1a677cSIlya Dryomov if (ret && ret != -EAGAIN && !con->error_msg) 3207cd1a677cSIlya Dryomov con->error_msg = "write processing error"; 3208cd1a677cSIlya Dryomov break; 3209cd1a677cSIlya Dryomov } 3210cd1a677cSIlya Dryomov } 3211cd1a677cSIlya Dryomov 3212cd1a677cSIlya Dryomov tcp_sock_set_cork(con->sock->sk, false); 3213cd1a677cSIlya Dryomov return ret; 3214cd1a677cSIlya Dryomov } 3215cd1a677cSIlya Dryomov 3216cd1a677cSIlya Dryomov static u32 crc32c_zeros(u32 crc, int zero_len) 3217cd1a677cSIlya Dryomov { 3218cd1a677cSIlya Dryomov int len; 3219cd1a677cSIlya Dryomov 3220cd1a677cSIlya Dryomov while (zero_len) { 3221cd1a677cSIlya Dryomov len = min(zero_len, (int)PAGE_SIZE); 3222cd1a677cSIlya Dryomov crc = crc32c(crc, page_address(ceph_zero_page), len); 3223cd1a677cSIlya Dryomov zero_len -= len; 3224cd1a677cSIlya Dryomov } 3225cd1a677cSIlya Dryomov 3226cd1a677cSIlya Dryomov return crc; 3227cd1a677cSIlya Dryomov } 3228cd1a677cSIlya Dryomov 3229cd1a677cSIlya Dryomov static void prepare_zero_front(struct ceph_connection *con, int resid) 3230cd1a677cSIlya Dryomov { 3231cd1a677cSIlya Dryomov int sent; 3232cd1a677cSIlya Dryomov 3233cd1a677cSIlya Dryomov WARN_ON(!resid || resid > front_len(con->out_msg)); 3234cd1a677cSIlya Dryomov sent = front_len(con->out_msg) - resid; 3235cd1a677cSIlya Dryomov dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid); 3236cd1a677cSIlya Dryomov 3237cd1a677cSIlya Dryomov if (sent) { 3238cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = 3239cd1a677cSIlya Dryomov crc32c(-1, con->out_msg->front.iov_base, sent); 3240cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = 3241cd1a677cSIlya Dryomov crc32c_zeros(con->v2.out_epil.front_crc, resid); 3242cd1a677cSIlya Dryomov } else { 3243cd1a677cSIlya Dryomov con->v2.out_epil.front_crc = crc32c_zeros(-1, resid); 3244cd1a677cSIlya Dryomov } 3245cd1a677cSIlya Dryomov 3246cd1a677cSIlya Dryomov con->v2.out_iter.count -= resid; 3247cd1a677cSIlya Dryomov out_zero_add(con, resid); 3248cd1a677cSIlya Dryomov } 3249cd1a677cSIlya Dryomov 3250cd1a677cSIlya Dryomov static void prepare_zero_middle(struct ceph_connection *con, int resid) 3251cd1a677cSIlya Dryomov { 3252cd1a677cSIlya Dryomov int sent; 3253cd1a677cSIlya Dryomov 3254cd1a677cSIlya Dryomov WARN_ON(!resid || resid > middle_len(con->out_msg)); 3255cd1a677cSIlya Dryomov sent = middle_len(con->out_msg) - resid; 3256cd1a677cSIlya Dryomov dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid); 3257cd1a677cSIlya Dryomov 3258cd1a677cSIlya Dryomov if (sent) { 3259cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = 3260cd1a677cSIlya Dryomov crc32c(-1, con->out_msg->middle->vec.iov_base, sent); 3261cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = 3262cd1a677cSIlya Dryomov crc32c_zeros(con->v2.out_epil.middle_crc, resid); 3263cd1a677cSIlya Dryomov } else { 3264cd1a677cSIlya Dryomov con->v2.out_epil.middle_crc = crc32c_zeros(-1, resid); 3265cd1a677cSIlya Dryomov } 3266cd1a677cSIlya Dryomov 3267cd1a677cSIlya Dryomov con->v2.out_iter.count -= resid; 3268cd1a677cSIlya Dryomov out_zero_add(con, resid); 3269cd1a677cSIlya Dryomov } 3270cd1a677cSIlya Dryomov 3271cd1a677cSIlya Dryomov static void prepare_zero_data(struct ceph_connection *con) 3272cd1a677cSIlya Dryomov { 3273cd1a677cSIlya Dryomov dout("%s con %p\n", __func__, con); 3274cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = crc32c_zeros(-1, data_len(con->out_msg)); 3275cd1a677cSIlya Dryomov out_zero_add(con, data_len(con->out_msg)); 3276cd1a677cSIlya Dryomov } 3277cd1a677cSIlya Dryomov 3278cd1a677cSIlya Dryomov static void revoke_at_queue_data(struct ceph_connection *con) 3279cd1a677cSIlya Dryomov { 3280cd1a677cSIlya Dryomov int boundary; 3281cd1a677cSIlya Dryomov int resid; 3282cd1a677cSIlya Dryomov 3283cd1a677cSIlya Dryomov WARN_ON(!data_len(con->out_msg)); 3284cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter)); 3285cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.out_iter); 3286cd1a677cSIlya Dryomov 3287cd1a677cSIlya Dryomov boundary = front_len(con->out_msg) + middle_len(con->out_msg); 3288cd1a677cSIlya Dryomov if (resid > boundary) { 3289cd1a677cSIlya Dryomov resid -= boundary; 3290cd1a677cSIlya Dryomov WARN_ON(resid > MESSAGE_HEAD_PLAIN_LEN); 3291cd1a677cSIlya Dryomov dout("%s con %p was sending head\n", __func__, con); 3292cd1a677cSIlya Dryomov if (front_len(con->out_msg)) 3293cd1a677cSIlya Dryomov prepare_zero_front(con, front_len(con->out_msg)); 3294cd1a677cSIlya Dryomov if (middle_len(con->out_msg)) 3295cd1a677cSIlya Dryomov prepare_zero_middle(con, middle_len(con->out_msg)); 3296cd1a677cSIlya Dryomov prepare_zero_data(con); 3297cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter) != resid); 3298cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_ZEROS; 3299cd1a677cSIlya Dryomov return; 3300cd1a677cSIlya Dryomov } 3301cd1a677cSIlya Dryomov 3302cd1a677cSIlya Dryomov boundary = middle_len(con->out_msg); 3303cd1a677cSIlya Dryomov if (resid > boundary) { 3304cd1a677cSIlya Dryomov resid -= boundary; 3305cd1a677cSIlya Dryomov dout("%s con %p was sending front\n", __func__, con); 3306cd1a677cSIlya Dryomov prepare_zero_front(con, resid); 3307cd1a677cSIlya Dryomov if (middle_len(con->out_msg)) 3308cd1a677cSIlya Dryomov prepare_zero_middle(con, middle_len(con->out_msg)); 3309cd1a677cSIlya Dryomov prepare_zero_data(con); 3310cd1a677cSIlya Dryomov queue_zeros(con); 3311cd1a677cSIlya Dryomov return; 3312cd1a677cSIlya Dryomov } 3313cd1a677cSIlya Dryomov 3314cd1a677cSIlya Dryomov WARN_ON(!resid); 3315cd1a677cSIlya Dryomov dout("%s con %p was sending middle\n", __func__, con); 3316cd1a677cSIlya Dryomov prepare_zero_middle(con, resid); 3317cd1a677cSIlya Dryomov prepare_zero_data(con); 3318cd1a677cSIlya Dryomov queue_zeros(con); 3319cd1a677cSIlya Dryomov } 3320cd1a677cSIlya Dryomov 3321cd1a677cSIlya Dryomov static void revoke_at_queue_data_cont(struct ceph_connection *con) 3322cd1a677cSIlya Dryomov { 3323cd1a677cSIlya Dryomov int sent, resid; /* current piece of data */ 3324cd1a677cSIlya Dryomov 3325cd1a677cSIlya Dryomov WARN_ON(!data_len(con->out_msg)); 3326cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_bvec(&con->v2.out_iter)); 3327cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.out_iter); 3328cd1a677cSIlya Dryomov WARN_ON(!resid || resid > con->v2.out_bvec.bv_len); 3329cd1a677cSIlya Dryomov sent = con->v2.out_bvec.bv_len - resid; 3330cd1a677cSIlya Dryomov dout("%s con %p sent %d resid %d\n", __func__, con, sent, resid); 3331cd1a677cSIlya Dryomov 3332cd1a677cSIlya Dryomov if (sent) { 3333cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = ceph_crc32c_page( 3334cd1a677cSIlya Dryomov con->v2.out_epil.data_crc, con->v2.out_bvec.bv_page, 3335cd1a677cSIlya Dryomov con->v2.out_bvec.bv_offset, sent); 3336cd1a677cSIlya Dryomov ceph_msg_data_advance(&con->v2.out_cursor, sent); 3337cd1a677cSIlya Dryomov } 3338cd1a677cSIlya Dryomov WARN_ON(resid > con->v2.out_cursor.total_resid); 3339cd1a677cSIlya Dryomov con->v2.out_epil.data_crc = crc32c_zeros(con->v2.out_epil.data_crc, 3340cd1a677cSIlya Dryomov con->v2.out_cursor.total_resid); 3341cd1a677cSIlya Dryomov 3342cd1a677cSIlya Dryomov con->v2.out_iter.count -= resid; 3343cd1a677cSIlya Dryomov out_zero_add(con, con->v2.out_cursor.total_resid); 3344cd1a677cSIlya Dryomov queue_zeros(con); 3345cd1a677cSIlya Dryomov } 3346cd1a677cSIlya Dryomov 3347cd1a677cSIlya Dryomov static void revoke_at_finish_message(struct ceph_connection *con) 3348cd1a677cSIlya Dryomov { 3349cd1a677cSIlya Dryomov int boundary; 3350cd1a677cSIlya Dryomov int resid; 3351cd1a677cSIlya Dryomov 3352cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_kvec(&con->v2.out_iter)); 3353cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.out_iter); 3354cd1a677cSIlya Dryomov 3355cd1a677cSIlya Dryomov if (!front_len(con->out_msg) && !middle_len(con->out_msg) && 3356cd1a677cSIlya Dryomov !data_len(con->out_msg)) { 3357cd1a677cSIlya Dryomov WARN_ON(!resid || resid > MESSAGE_HEAD_PLAIN_LEN); 3358cd1a677cSIlya Dryomov dout("%s con %p was sending head (empty message) - noop\n", 3359cd1a677cSIlya Dryomov __func__, con); 3360cd1a677cSIlya Dryomov return; 3361cd1a677cSIlya Dryomov } 3362cd1a677cSIlya Dryomov 3363cd1a677cSIlya Dryomov boundary = front_len(con->out_msg) + middle_len(con->out_msg) + 3364cd1a677cSIlya Dryomov CEPH_EPILOGUE_PLAIN_LEN; 3365cd1a677cSIlya Dryomov if (resid > boundary) { 3366cd1a677cSIlya Dryomov resid -= boundary; 3367cd1a677cSIlya Dryomov WARN_ON(resid > MESSAGE_HEAD_PLAIN_LEN); 3368cd1a677cSIlya Dryomov dout("%s con %p was sending head\n", __func__, con); 3369cd1a677cSIlya Dryomov if (front_len(con->out_msg)) 3370cd1a677cSIlya Dryomov prepare_zero_front(con, front_len(con->out_msg)); 3371cd1a677cSIlya Dryomov if (middle_len(con->out_msg)) 3372cd1a677cSIlya Dryomov prepare_zero_middle(con, middle_len(con->out_msg)); 3373cd1a677cSIlya Dryomov con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN; 3374cd1a677cSIlya Dryomov WARN_ON(iov_iter_count(&con->v2.out_iter) != resid); 3375cd1a677cSIlya Dryomov con->v2.out_state = OUT_S_QUEUE_ZEROS; 3376cd1a677cSIlya Dryomov return; 3377cd1a677cSIlya Dryomov } 3378cd1a677cSIlya Dryomov 3379cd1a677cSIlya Dryomov boundary = middle_len(con->out_msg) + CEPH_EPILOGUE_PLAIN_LEN; 3380cd1a677cSIlya Dryomov if (resid > boundary) { 3381cd1a677cSIlya Dryomov resid -= boundary; 3382cd1a677cSIlya Dryomov dout("%s con %p was sending front\n", __func__, con); 3383cd1a677cSIlya Dryomov prepare_zero_front(con, resid); 3384cd1a677cSIlya Dryomov if (middle_len(con->out_msg)) 3385cd1a677cSIlya Dryomov prepare_zero_middle(con, middle_len(con->out_msg)); 3386cd1a677cSIlya Dryomov con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN; 3387cd1a677cSIlya Dryomov queue_zeros(con); 3388cd1a677cSIlya Dryomov return; 3389cd1a677cSIlya Dryomov } 3390cd1a677cSIlya Dryomov 3391cd1a677cSIlya Dryomov boundary = CEPH_EPILOGUE_PLAIN_LEN; 3392cd1a677cSIlya Dryomov if (resid > boundary) { 3393cd1a677cSIlya Dryomov resid -= boundary; 3394cd1a677cSIlya Dryomov dout("%s con %p was sending middle\n", __func__, con); 3395cd1a677cSIlya Dryomov prepare_zero_middle(con, resid); 3396cd1a677cSIlya Dryomov con->v2.out_iter.count -= CEPH_EPILOGUE_PLAIN_LEN; 3397cd1a677cSIlya Dryomov queue_zeros(con); 3398cd1a677cSIlya Dryomov return; 3399cd1a677cSIlya Dryomov } 3400cd1a677cSIlya Dryomov 3401cd1a677cSIlya Dryomov WARN_ON(!resid); 3402cd1a677cSIlya Dryomov dout("%s con %p was sending epilogue - noop\n", __func__, con); 3403cd1a677cSIlya Dryomov } 3404cd1a677cSIlya Dryomov 3405cd1a677cSIlya Dryomov void ceph_con_v2_revoke(struct ceph_connection *con) 3406cd1a677cSIlya Dryomov { 3407cd1a677cSIlya Dryomov WARN_ON(con->v2.out_zero); 3408cd1a677cSIlya Dryomov 3409cd1a677cSIlya Dryomov if (con_secure(con)) { 3410cd1a677cSIlya Dryomov WARN_ON(con->v2.out_state != OUT_S_QUEUE_ENC_PAGE && 3411cd1a677cSIlya Dryomov con->v2.out_state != OUT_S_FINISH_MESSAGE); 3412cd1a677cSIlya Dryomov dout("%s con %p secure - noop\n", __func__, con); 3413cd1a677cSIlya Dryomov return; 3414cd1a677cSIlya Dryomov } 3415cd1a677cSIlya Dryomov 3416cd1a677cSIlya Dryomov switch (con->v2.out_state) { 3417cd1a677cSIlya Dryomov case OUT_S_QUEUE_DATA: 3418cd1a677cSIlya Dryomov revoke_at_queue_data(con); 3419cd1a677cSIlya Dryomov break; 3420cd1a677cSIlya Dryomov case OUT_S_QUEUE_DATA_CONT: 3421cd1a677cSIlya Dryomov revoke_at_queue_data_cont(con); 3422cd1a677cSIlya Dryomov break; 3423cd1a677cSIlya Dryomov case OUT_S_FINISH_MESSAGE: 3424cd1a677cSIlya Dryomov revoke_at_finish_message(con); 3425cd1a677cSIlya Dryomov break; 3426cd1a677cSIlya Dryomov default: 3427cd1a677cSIlya Dryomov WARN(1, "bad out_state %d", con->v2.out_state); 3428cd1a677cSIlya Dryomov break; 3429cd1a677cSIlya Dryomov } 3430cd1a677cSIlya Dryomov } 3431cd1a677cSIlya Dryomov 3432cd1a677cSIlya Dryomov static void revoke_at_prepare_read_data(struct ceph_connection *con) 3433cd1a677cSIlya Dryomov { 34342ea88716SIlya Dryomov int remaining; 3435cd1a677cSIlya Dryomov int resid; 3436cd1a677cSIlya Dryomov 34372ea88716SIlya Dryomov WARN_ON(con_secure(con)); 3438cd1a677cSIlya Dryomov WARN_ON(!data_len(con->in_msg)); 3439cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter)); 3440cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.in_iter); 3441cd1a677cSIlya Dryomov WARN_ON(!resid); 3442cd1a677cSIlya Dryomov 3443cd1a677cSIlya Dryomov remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN; 3444cd1a677cSIlya Dryomov dout("%s con %p resid %d remaining %d\n", __func__, con, resid, 3445cd1a677cSIlya Dryomov remaining); 3446cd1a677cSIlya Dryomov con->v2.in_iter.count -= resid; 3447cd1a677cSIlya Dryomov set_in_skip(con, resid + remaining); 3448cd1a677cSIlya Dryomov con->v2.in_state = IN_S_FINISH_SKIP; 3449cd1a677cSIlya Dryomov } 3450cd1a677cSIlya Dryomov 3451cd1a677cSIlya Dryomov static void revoke_at_prepare_read_data_cont(struct ceph_connection *con) 3452cd1a677cSIlya Dryomov { 3453cd1a677cSIlya Dryomov int recved, resid; /* current piece of data */ 34542ea88716SIlya Dryomov int remaining; 3455cd1a677cSIlya Dryomov 34562ea88716SIlya Dryomov WARN_ON(con_secure(con)); 3457cd1a677cSIlya Dryomov WARN_ON(!data_len(con->in_msg)); 3458cd1a677cSIlya Dryomov WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter)); 3459cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.in_iter); 3460cd1a677cSIlya Dryomov WARN_ON(!resid || resid > con->v2.in_bvec.bv_len); 3461cd1a677cSIlya Dryomov recved = con->v2.in_bvec.bv_len - resid; 3462cd1a677cSIlya Dryomov dout("%s con %p recved %d resid %d\n", __func__, con, recved, resid); 3463cd1a677cSIlya Dryomov 3464cd1a677cSIlya Dryomov if (recved) 3465cd1a677cSIlya Dryomov ceph_msg_data_advance(&con->v2.in_cursor, recved); 3466cd1a677cSIlya Dryomov WARN_ON(resid > con->v2.in_cursor.total_resid); 3467cd1a677cSIlya Dryomov 3468cd1a677cSIlya Dryomov remaining = CEPH_EPILOGUE_PLAIN_LEN; 3469cd1a677cSIlya Dryomov dout("%s con %p total_resid %zu remaining %d\n", __func__, con, 3470cd1a677cSIlya Dryomov con->v2.in_cursor.total_resid, remaining); 3471cd1a677cSIlya Dryomov con->v2.in_iter.count -= resid; 3472cd1a677cSIlya Dryomov set_in_skip(con, con->v2.in_cursor.total_resid + remaining); 3473cd1a677cSIlya Dryomov con->v2.in_state = IN_S_FINISH_SKIP; 3474cd1a677cSIlya Dryomov } 3475cd1a677cSIlya Dryomov 34762ea88716SIlya Dryomov static void revoke_at_prepare_read_enc_page(struct ceph_connection *con) 34772ea88716SIlya Dryomov { 34782ea88716SIlya Dryomov int resid; /* current enc page (not necessarily data) */ 34792ea88716SIlya Dryomov 34802ea88716SIlya Dryomov WARN_ON(!con_secure(con)); 34812ea88716SIlya Dryomov WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter)); 34822ea88716SIlya Dryomov resid = iov_iter_count(&con->v2.in_iter); 34832ea88716SIlya Dryomov WARN_ON(!resid || resid > con->v2.in_bvec.bv_len); 34842ea88716SIlya Dryomov 34852ea88716SIlya Dryomov dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid, 34862ea88716SIlya Dryomov con->v2.in_enc_resid); 34872ea88716SIlya Dryomov con->v2.in_iter.count -= resid; 34882ea88716SIlya Dryomov set_in_skip(con, resid + con->v2.in_enc_resid); 34892ea88716SIlya Dryomov con->v2.in_state = IN_S_FINISH_SKIP; 34902ea88716SIlya Dryomov } 34912ea88716SIlya Dryomov 3492cd1a677cSIlya Dryomov static void revoke_at_handle_epilogue(struct ceph_connection *con) 3493cd1a677cSIlya Dryomov { 3494cd1a677cSIlya Dryomov int resid; 3495cd1a677cSIlya Dryomov 3496cd1a677cSIlya Dryomov resid = iov_iter_count(&con->v2.in_iter); 3497cd1a677cSIlya Dryomov WARN_ON(!resid); 3498cd1a677cSIlya Dryomov 3499cd1a677cSIlya Dryomov dout("%s con %p resid %d\n", __func__, con, resid); 3500cd1a677cSIlya Dryomov con->v2.in_iter.count -= resid; 3501cd1a677cSIlya Dryomov set_in_skip(con, resid); 3502cd1a677cSIlya Dryomov con->v2.in_state = IN_S_FINISH_SKIP; 3503cd1a677cSIlya Dryomov } 3504cd1a677cSIlya Dryomov 3505cd1a677cSIlya Dryomov void ceph_con_v2_revoke_incoming(struct ceph_connection *con) 3506cd1a677cSIlya Dryomov { 3507cd1a677cSIlya Dryomov switch (con->v2.in_state) { 3508cd1a677cSIlya Dryomov case IN_S_PREPARE_READ_DATA: 3509cd1a677cSIlya Dryomov revoke_at_prepare_read_data(con); 3510cd1a677cSIlya Dryomov break; 3511cd1a677cSIlya Dryomov case IN_S_PREPARE_READ_DATA_CONT: 3512cd1a677cSIlya Dryomov revoke_at_prepare_read_data_cont(con); 3513cd1a677cSIlya Dryomov break; 35142ea88716SIlya Dryomov case IN_S_PREPARE_READ_ENC_PAGE: 35152ea88716SIlya Dryomov revoke_at_prepare_read_enc_page(con); 35162ea88716SIlya Dryomov break; 3517cd1a677cSIlya Dryomov case IN_S_HANDLE_EPILOGUE: 3518cd1a677cSIlya Dryomov revoke_at_handle_epilogue(con); 3519cd1a677cSIlya Dryomov break; 3520cd1a677cSIlya Dryomov default: 3521cd1a677cSIlya Dryomov WARN(1, "bad in_state %d", con->v2.in_state); 3522cd1a677cSIlya Dryomov break; 3523cd1a677cSIlya Dryomov } 3524cd1a677cSIlya Dryomov } 3525cd1a677cSIlya Dryomov 3526cd1a677cSIlya Dryomov bool ceph_con_v2_opened(struct ceph_connection *con) 3527cd1a677cSIlya Dryomov { 3528cd1a677cSIlya Dryomov return con->v2.peer_global_seq; 3529cd1a677cSIlya Dryomov } 3530cd1a677cSIlya Dryomov 3531cd1a677cSIlya Dryomov void ceph_con_v2_reset_session(struct ceph_connection *con) 3532cd1a677cSIlya Dryomov { 3533cd1a677cSIlya Dryomov con->v2.client_cookie = 0; 3534cd1a677cSIlya Dryomov con->v2.server_cookie = 0; 3535cd1a677cSIlya Dryomov con->v2.global_seq = 0; 3536cd1a677cSIlya Dryomov con->v2.connect_seq = 0; 3537cd1a677cSIlya Dryomov con->v2.peer_global_seq = 0; 3538cd1a677cSIlya Dryomov } 3539cd1a677cSIlya Dryomov 3540cd1a677cSIlya Dryomov void ceph_con_v2_reset_protocol(struct ceph_connection *con) 3541cd1a677cSIlya Dryomov { 3542cd1a677cSIlya Dryomov iov_iter_truncate(&con->v2.in_iter, 0); 3543cd1a677cSIlya Dryomov iov_iter_truncate(&con->v2.out_iter, 0); 3544cd1a677cSIlya Dryomov con->v2.out_zero = 0; 3545cd1a677cSIlya Dryomov 3546cd1a677cSIlya Dryomov clear_in_sign_kvecs(con); 3547cd1a677cSIlya Dryomov clear_out_sign_kvecs(con); 3548cd1a677cSIlya Dryomov free_conn_bufs(con); 3549cd1a677cSIlya Dryomov 35502ea88716SIlya Dryomov if (con->v2.in_enc_pages) { 35512ea88716SIlya Dryomov WARN_ON(!con->v2.in_enc_page_cnt); 35522ea88716SIlya Dryomov ceph_release_page_vector(con->v2.in_enc_pages, 35532ea88716SIlya Dryomov con->v2.in_enc_page_cnt); 35542ea88716SIlya Dryomov con->v2.in_enc_pages = NULL; 35552ea88716SIlya Dryomov con->v2.in_enc_page_cnt = 0; 35562ea88716SIlya Dryomov } 3557cd1a677cSIlya Dryomov if (con->v2.out_enc_pages) { 3558cd1a677cSIlya Dryomov WARN_ON(!con->v2.out_enc_page_cnt); 3559cd1a677cSIlya Dryomov ceph_release_page_vector(con->v2.out_enc_pages, 3560cd1a677cSIlya Dryomov con->v2.out_enc_page_cnt); 3561cd1a677cSIlya Dryomov con->v2.out_enc_pages = NULL; 3562cd1a677cSIlya Dryomov con->v2.out_enc_page_cnt = 0; 3563cd1a677cSIlya Dryomov } 3564cd1a677cSIlya Dryomov 3565cd1a677cSIlya Dryomov con->v2.con_mode = CEPH_CON_MODE_UNKNOWN; 356610f42b3eSIlya Dryomov memzero_explicit(&con->v2.in_gcm_nonce, CEPH_GCM_IV_LEN); 356710f42b3eSIlya Dryomov memzero_explicit(&con->v2.out_gcm_nonce, CEPH_GCM_IV_LEN); 3568cd1a677cSIlya Dryomov 3569cd1a677cSIlya Dryomov if (con->v2.hmac_tfm) { 3570cd1a677cSIlya Dryomov crypto_free_shash(con->v2.hmac_tfm); 3571cd1a677cSIlya Dryomov con->v2.hmac_tfm = NULL; 3572cd1a677cSIlya Dryomov } 3573cd1a677cSIlya Dryomov if (con->v2.gcm_req) { 3574cd1a677cSIlya Dryomov aead_request_free(con->v2.gcm_req); 3575cd1a677cSIlya Dryomov con->v2.gcm_req = NULL; 3576cd1a677cSIlya Dryomov } 3577cd1a677cSIlya Dryomov if (con->v2.gcm_tfm) { 3578cd1a677cSIlya Dryomov crypto_free_aead(con->v2.gcm_tfm); 3579cd1a677cSIlya Dryomov con->v2.gcm_tfm = NULL; 3580cd1a677cSIlya Dryomov } 3581cd1a677cSIlya Dryomov } 3582