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