12f713615SIlya Dryomov // SPDX-License-Identifier: GPL-2.0 22f713615SIlya Dryomov #include <linux/ceph/ceph_debug.h> 32f713615SIlya Dryomov 42f713615SIlya Dryomov #include <linux/bvec.h> 52f713615SIlya Dryomov #include <linux/crc32c.h> 62f713615SIlya Dryomov #include <linux/net.h> 72f713615SIlya Dryomov #include <linux/socket.h> 82f713615SIlya Dryomov #include <net/sock.h> 92f713615SIlya Dryomov 102f713615SIlya Dryomov #include <linux/ceph/ceph_features.h> 112f713615SIlya Dryomov #include <linux/ceph/decode.h> 122f713615SIlya Dryomov #include <linux/ceph/libceph.h> 132f713615SIlya Dryomov #include <linux/ceph/messenger.h> 142f713615SIlya Dryomov 152f713615SIlya Dryomov /* static tag bytes (protocol control messages) */ 162f713615SIlya Dryomov static char tag_msg = CEPH_MSGR_TAG_MSG; 172f713615SIlya Dryomov static char tag_ack = CEPH_MSGR_TAG_ACK; 182f713615SIlya Dryomov static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; 192f713615SIlya Dryomov static char tag_keepalive2 = CEPH_MSGR_TAG_KEEPALIVE2; 202f713615SIlya Dryomov 212f713615SIlya Dryomov /* 222f713615SIlya Dryomov * If @buf is NULL, discard up to @len bytes. 232f713615SIlya Dryomov */ 242f713615SIlya Dryomov static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len) 252f713615SIlya Dryomov { 262f713615SIlya Dryomov struct kvec iov = {buf, len}; 272f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 282f713615SIlya Dryomov int r; 292f713615SIlya Dryomov 302f713615SIlya Dryomov if (!buf) 312f713615SIlya Dryomov msg.msg_flags |= MSG_TRUNC; 322f713615SIlya Dryomov 332f713615SIlya Dryomov iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, len); 342f713615SIlya Dryomov r = sock_recvmsg(sock, &msg, msg.msg_flags); 352f713615SIlya Dryomov if (r == -EAGAIN) 362f713615SIlya Dryomov r = 0; 372f713615SIlya Dryomov return r; 382f713615SIlya Dryomov } 392f713615SIlya Dryomov 402f713615SIlya Dryomov static int ceph_tcp_recvpage(struct socket *sock, struct page *page, 412f713615SIlya Dryomov int page_offset, size_t length) 422f713615SIlya Dryomov { 432f713615SIlya Dryomov struct bio_vec bvec = { 442f713615SIlya Dryomov .bv_page = page, 452f713615SIlya Dryomov .bv_offset = page_offset, 462f713615SIlya Dryomov .bv_len = length 472f713615SIlya Dryomov }; 482f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 492f713615SIlya Dryomov int r; 502f713615SIlya Dryomov 512f713615SIlya Dryomov BUG_ON(page_offset + length > PAGE_SIZE); 522f713615SIlya Dryomov iov_iter_bvec(&msg.msg_iter, READ, &bvec, 1, length); 532f713615SIlya Dryomov r = sock_recvmsg(sock, &msg, msg.msg_flags); 542f713615SIlya Dryomov if (r == -EAGAIN) 552f713615SIlya Dryomov r = 0; 562f713615SIlya Dryomov return r; 572f713615SIlya Dryomov } 582f713615SIlya Dryomov 592f713615SIlya Dryomov /* 602f713615SIlya Dryomov * write something. @more is true if caller will be sending more data 612f713615SIlya Dryomov * shortly. 622f713615SIlya Dryomov */ 632f713615SIlya Dryomov static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, 642f713615SIlya Dryomov size_t kvlen, size_t len, bool more) 652f713615SIlya Dryomov { 662f713615SIlya Dryomov struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; 672f713615SIlya Dryomov int r; 682f713615SIlya Dryomov 692f713615SIlya Dryomov if (more) 702f713615SIlya Dryomov msg.msg_flags |= MSG_MORE; 712f713615SIlya Dryomov else 722f713615SIlya Dryomov msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */ 732f713615SIlya Dryomov 742f713615SIlya Dryomov r = kernel_sendmsg(sock, &msg, iov, kvlen, len); 752f713615SIlya Dryomov if (r == -EAGAIN) 762f713615SIlya Dryomov r = 0; 772f713615SIlya Dryomov return r; 782f713615SIlya Dryomov } 792f713615SIlya Dryomov 802f713615SIlya Dryomov /* 812f713615SIlya Dryomov * @more: either or both of MSG_MORE and MSG_SENDPAGE_NOTLAST 822f713615SIlya Dryomov */ 832f713615SIlya Dryomov static int ceph_tcp_sendpage(struct socket *sock, struct page *page, 842f713615SIlya Dryomov int offset, size_t size, int more) 852f713615SIlya Dryomov { 862f713615SIlya Dryomov ssize_t (*sendpage)(struct socket *sock, struct page *page, 872f713615SIlya Dryomov int offset, size_t size, int flags); 882f713615SIlya Dryomov int flags = MSG_DONTWAIT | MSG_NOSIGNAL | more; 892f713615SIlya Dryomov int ret; 902f713615SIlya Dryomov 912f713615SIlya Dryomov /* 922f713615SIlya Dryomov * sendpage cannot properly handle pages with page_count == 0, 932f713615SIlya Dryomov * we need to fall back to sendmsg if that's the case. 942f713615SIlya Dryomov * 952f713615SIlya Dryomov * Same goes for slab pages: skb_can_coalesce() allows 962f713615SIlya Dryomov * coalescing neighboring slab objects into a single frag which 972f713615SIlya Dryomov * triggers one of hardened usercopy checks. 982f713615SIlya Dryomov */ 992f713615SIlya Dryomov if (sendpage_ok(page)) 1002f713615SIlya Dryomov sendpage = sock->ops->sendpage; 1012f713615SIlya Dryomov else 1022f713615SIlya Dryomov sendpage = sock_no_sendpage; 1032f713615SIlya Dryomov 1042f713615SIlya Dryomov ret = sendpage(sock, page, offset, size, flags); 1052f713615SIlya Dryomov if (ret == -EAGAIN) 1062f713615SIlya Dryomov ret = 0; 1072f713615SIlya Dryomov 1082f713615SIlya Dryomov return ret; 1092f713615SIlya Dryomov } 1102f713615SIlya Dryomov 1112f713615SIlya Dryomov static void con_out_kvec_reset(struct ceph_connection *con) 1122f713615SIlya Dryomov { 113a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_skip); 1142f713615SIlya Dryomov 115a56dd9bfSIlya Dryomov con->v1.out_kvec_left = 0; 116a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes = 0; 117a56dd9bfSIlya Dryomov con->v1.out_kvec_cur = &con->v1.out_kvec[0]; 1182f713615SIlya Dryomov } 1192f713615SIlya Dryomov 1202f713615SIlya Dryomov static void con_out_kvec_add(struct ceph_connection *con, 1212f713615SIlya Dryomov size_t size, void *data) 1222f713615SIlya Dryomov { 123a56dd9bfSIlya Dryomov int index = con->v1.out_kvec_left; 1242f713615SIlya Dryomov 125a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_skip); 126a56dd9bfSIlya Dryomov BUG_ON(index >= ARRAY_SIZE(con->v1.out_kvec)); 1272f713615SIlya Dryomov 128a56dd9bfSIlya Dryomov con->v1.out_kvec[index].iov_len = size; 129a56dd9bfSIlya Dryomov con->v1.out_kvec[index].iov_base = data; 130a56dd9bfSIlya Dryomov con->v1.out_kvec_left++; 131a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes += size; 1322f713615SIlya Dryomov } 1332f713615SIlya Dryomov 1342f713615SIlya Dryomov /* 1352f713615SIlya Dryomov * Chop off a kvec from the end. Return residual number of bytes for 1362f713615SIlya Dryomov * that kvec, i.e. how many bytes would have been written if the kvec 1372f713615SIlya Dryomov * hadn't been nuked. 1382f713615SIlya Dryomov */ 1392f713615SIlya Dryomov static int con_out_kvec_skip(struct ceph_connection *con) 1402f713615SIlya Dryomov { 1412f713615SIlya Dryomov int skip = 0; 1422f713615SIlya Dryomov 143a56dd9bfSIlya Dryomov if (con->v1.out_kvec_bytes > 0) { 144a56dd9bfSIlya Dryomov skip = con->v1.out_kvec_cur[con->v1.out_kvec_left - 1].iov_len; 145a56dd9bfSIlya Dryomov BUG_ON(con->v1.out_kvec_bytes < skip); 146a56dd9bfSIlya Dryomov BUG_ON(!con->v1.out_kvec_left); 147a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes -= skip; 148a56dd9bfSIlya Dryomov con->v1.out_kvec_left--; 1492f713615SIlya Dryomov } 1502f713615SIlya Dryomov 1512f713615SIlya Dryomov return skip; 1522f713615SIlya Dryomov } 1532f713615SIlya Dryomov 1542f713615SIlya Dryomov static size_t sizeof_footer(struct ceph_connection *con) 1552f713615SIlya Dryomov { 1562f713615SIlya Dryomov return (con->peer_features & CEPH_FEATURE_MSG_AUTH) ? 1572f713615SIlya Dryomov sizeof(struct ceph_msg_footer) : 1582f713615SIlya Dryomov sizeof(struct ceph_msg_footer_old); 1592f713615SIlya Dryomov } 1602f713615SIlya Dryomov 1612f713615SIlya Dryomov static void prepare_message_data(struct ceph_msg *msg, u32 data_len) 1622f713615SIlya Dryomov { 1632f713615SIlya Dryomov /* Initialize data cursor */ 1642f713615SIlya Dryomov 1652f713615SIlya Dryomov ceph_msg_data_cursor_init(&msg->cursor, msg, data_len); 1662f713615SIlya Dryomov } 1672f713615SIlya Dryomov 1682f713615SIlya Dryomov /* 1692f713615SIlya Dryomov * Prepare footer for currently outgoing message, and finish things 1702f713615SIlya Dryomov * off. Assumes out_kvec* are already valid.. we just add on to the end. 1712f713615SIlya Dryomov */ 1722f713615SIlya Dryomov static void prepare_write_message_footer(struct ceph_connection *con) 1732f713615SIlya Dryomov { 1742f713615SIlya Dryomov struct ceph_msg *m = con->out_msg; 1752f713615SIlya Dryomov 1762f713615SIlya Dryomov m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE; 1772f713615SIlya Dryomov 1782f713615SIlya Dryomov dout("prepare_write_message_footer %p\n", con); 1792f713615SIlya Dryomov con_out_kvec_add(con, sizeof_footer(con), &m->footer); 1802f713615SIlya Dryomov if (con->peer_features & CEPH_FEATURE_MSG_AUTH) { 1812f713615SIlya Dryomov if (con->ops->sign_message) 1822f713615SIlya Dryomov con->ops->sign_message(m); 1832f713615SIlya Dryomov else 1842f713615SIlya Dryomov m->footer.sig = 0; 1852f713615SIlya Dryomov } else { 1862f713615SIlya Dryomov m->old_footer.flags = m->footer.flags; 1872f713615SIlya Dryomov } 188a56dd9bfSIlya Dryomov con->v1.out_more = m->more_to_follow; 189a56dd9bfSIlya Dryomov con->v1.out_msg_done = true; 1902f713615SIlya Dryomov } 1912f713615SIlya Dryomov 1922f713615SIlya Dryomov /* 1932f713615SIlya Dryomov * Prepare headers for the next outgoing message. 1942f713615SIlya Dryomov */ 1952f713615SIlya Dryomov static void prepare_write_message(struct ceph_connection *con) 1962f713615SIlya Dryomov { 1972f713615SIlya Dryomov struct ceph_msg *m; 1982f713615SIlya Dryomov u32 crc; 1992f713615SIlya Dryomov 2002f713615SIlya Dryomov con_out_kvec_reset(con); 201a56dd9bfSIlya Dryomov con->v1.out_msg_done = false; 2022f713615SIlya Dryomov 2032f713615SIlya Dryomov /* Sneak an ack in there first? If we can get it into the same 2042f713615SIlya Dryomov * TCP packet that's a good thing. */ 2052f713615SIlya Dryomov if (con->in_seq > con->in_seq_acked) { 2062f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2072f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 208a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 209a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 210a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2112f713615SIlya Dryomov } 2122f713615SIlya Dryomov 2132f713615SIlya Dryomov ceph_con_get_out_msg(con); 2142f713615SIlya Dryomov m = con->out_msg; 2152f713615SIlya Dryomov 2162f713615SIlya Dryomov dout("prepare_write_message %p seq %lld type %d len %d+%d+%zd\n", 2172f713615SIlya Dryomov m, con->out_seq, le16_to_cpu(m->hdr.type), 2182f713615SIlya Dryomov le32_to_cpu(m->hdr.front_len), le32_to_cpu(m->hdr.middle_len), 2192f713615SIlya Dryomov m->data_length); 2202f713615SIlya Dryomov WARN_ON(m->front.iov_len != le32_to_cpu(m->hdr.front_len)); 2212f713615SIlya Dryomov WARN_ON(m->data_length != le32_to_cpu(m->hdr.data_len)); 2222f713615SIlya Dryomov 2232f713615SIlya Dryomov /* tag + hdr + front + middle */ 2242f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); 225a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_hdr), &con->v1.out_hdr); 2262f713615SIlya Dryomov con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); 2272f713615SIlya Dryomov 2282f713615SIlya Dryomov if (m->middle) 2292f713615SIlya Dryomov con_out_kvec_add(con, m->middle->vec.iov_len, 2302f713615SIlya Dryomov m->middle->vec.iov_base); 2312f713615SIlya Dryomov 2322f713615SIlya Dryomov /* fill in hdr crc and finalize hdr */ 2332f713615SIlya Dryomov crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); 2342f713615SIlya Dryomov con->out_msg->hdr.crc = cpu_to_le32(crc); 235a56dd9bfSIlya Dryomov memcpy(&con->v1.out_hdr, &con->out_msg->hdr, sizeof(con->v1.out_hdr)); 2362f713615SIlya Dryomov 2372f713615SIlya Dryomov /* fill in front and middle crc, footer */ 2382f713615SIlya Dryomov crc = crc32c(0, m->front.iov_base, m->front.iov_len); 2392f713615SIlya Dryomov con->out_msg->footer.front_crc = cpu_to_le32(crc); 2402f713615SIlya Dryomov if (m->middle) { 2412f713615SIlya Dryomov crc = crc32c(0, m->middle->vec.iov_base, 2422f713615SIlya Dryomov m->middle->vec.iov_len); 2432f713615SIlya Dryomov con->out_msg->footer.middle_crc = cpu_to_le32(crc); 2442f713615SIlya Dryomov } else 2452f713615SIlya Dryomov con->out_msg->footer.middle_crc = 0; 2462f713615SIlya Dryomov dout("%s front_crc %u middle_crc %u\n", __func__, 2472f713615SIlya Dryomov le32_to_cpu(con->out_msg->footer.front_crc), 2482f713615SIlya Dryomov le32_to_cpu(con->out_msg->footer.middle_crc)); 2492f713615SIlya Dryomov con->out_msg->footer.flags = 0; 2502f713615SIlya Dryomov 2512f713615SIlya Dryomov /* is there a data payload? */ 2522f713615SIlya Dryomov con->out_msg->footer.data_crc = 0; 2532f713615SIlya Dryomov if (m->data_length) { 2542f713615SIlya Dryomov prepare_message_data(con->out_msg, m->data_length); 255a56dd9bfSIlya Dryomov con->v1.out_more = 1; /* data + footer will follow */ 2562f713615SIlya Dryomov } else { 2572f713615SIlya Dryomov /* no, queue up footer too and be done */ 2582f713615SIlya Dryomov prepare_write_message_footer(con); 2592f713615SIlya Dryomov } 2602f713615SIlya Dryomov 2612f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 2622f713615SIlya Dryomov } 2632f713615SIlya Dryomov 2642f713615SIlya Dryomov /* 2652f713615SIlya Dryomov * Prepare an ack. 2662f713615SIlya Dryomov */ 2672f713615SIlya Dryomov static void prepare_write_ack(struct ceph_connection *con) 2682f713615SIlya Dryomov { 2692f713615SIlya Dryomov dout("prepare_write_ack %p %llu -> %llu\n", con, 2702f713615SIlya Dryomov con->in_seq_acked, con->in_seq); 2712f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2722f713615SIlya Dryomov 2732f713615SIlya Dryomov con_out_kvec_reset(con); 2742f713615SIlya Dryomov 2752f713615SIlya Dryomov con_out_kvec_add(con, sizeof (tag_ack), &tag_ack); 2762f713615SIlya Dryomov 277a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 278a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 279a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2802f713615SIlya Dryomov 281a56dd9bfSIlya Dryomov con->v1.out_more = 1; /* more will follow.. eventually.. */ 2822f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 2832f713615SIlya Dryomov } 2842f713615SIlya Dryomov 2852f713615SIlya Dryomov /* 2862f713615SIlya Dryomov * Prepare to share the seq during handshake 2872f713615SIlya Dryomov */ 2882f713615SIlya Dryomov static void prepare_write_seq(struct ceph_connection *con) 2892f713615SIlya Dryomov { 2902f713615SIlya Dryomov dout("prepare_write_seq %p %llu -> %llu\n", con, 2912f713615SIlya Dryomov con->in_seq_acked, con->in_seq); 2922f713615SIlya Dryomov con->in_seq_acked = con->in_seq; 2932f713615SIlya Dryomov 2942f713615SIlya Dryomov con_out_kvec_reset(con); 2952f713615SIlya Dryomov 296a56dd9bfSIlya Dryomov con->v1.out_temp_ack = cpu_to_le64(con->in_seq_acked); 297a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_ack), 298a56dd9bfSIlya Dryomov &con->v1.out_temp_ack); 2992f713615SIlya Dryomov 3002f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3012f713615SIlya Dryomov } 3022f713615SIlya Dryomov 3032f713615SIlya Dryomov /* 3042f713615SIlya Dryomov * Prepare to write keepalive byte. 3052f713615SIlya Dryomov */ 3062f713615SIlya Dryomov static void prepare_write_keepalive(struct ceph_connection *con) 3072f713615SIlya Dryomov { 3082f713615SIlya Dryomov dout("prepare_write_keepalive %p\n", con); 3092f713615SIlya Dryomov con_out_kvec_reset(con); 3102f713615SIlya Dryomov if (con->peer_features & CEPH_FEATURE_MSGR_KEEPALIVE2) { 3112f713615SIlya Dryomov struct timespec64 now; 3122f713615SIlya Dryomov 3132f713615SIlya Dryomov ktime_get_real_ts64(&now); 3142f713615SIlya Dryomov con_out_kvec_add(con, sizeof(tag_keepalive2), &tag_keepalive2); 315a56dd9bfSIlya Dryomov ceph_encode_timespec64(&con->v1.out_temp_keepalive2, &now); 316a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_temp_keepalive2), 317a56dd9bfSIlya Dryomov &con->v1.out_temp_keepalive2); 3182f713615SIlya Dryomov } else { 3192f713615SIlya Dryomov con_out_kvec_add(con, sizeof(tag_keepalive), &tag_keepalive); 3202f713615SIlya Dryomov } 3212f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3222f713615SIlya Dryomov } 3232f713615SIlya Dryomov 3242f713615SIlya Dryomov /* 3252f713615SIlya Dryomov * Connection negotiation. 3262f713615SIlya Dryomov */ 3272f713615SIlya Dryomov 3282f713615SIlya Dryomov static int get_connect_authorizer(struct ceph_connection *con) 3292f713615SIlya Dryomov { 3302f713615SIlya Dryomov struct ceph_auth_handshake *auth; 3312f713615SIlya Dryomov int auth_proto; 3322f713615SIlya Dryomov 3332f713615SIlya Dryomov if (!con->ops->get_authorizer) { 334a56dd9bfSIlya Dryomov con->v1.auth = NULL; 335a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN; 336a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_len = 0; 3372f713615SIlya Dryomov return 0; 3382f713615SIlya Dryomov } 3392f713615SIlya Dryomov 340a56dd9bfSIlya Dryomov auth = con->ops->get_authorizer(con, &auth_proto, con->v1.auth_retry); 3412f713615SIlya Dryomov if (IS_ERR(auth)) 3422f713615SIlya Dryomov return PTR_ERR(auth); 3432f713615SIlya Dryomov 344a56dd9bfSIlya Dryomov con->v1.auth = auth; 345a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_protocol = cpu_to_le32(auth_proto); 346a56dd9bfSIlya Dryomov con->v1.out_connect.authorizer_len = 347a56dd9bfSIlya Dryomov cpu_to_le32(auth->authorizer_buf_len); 3482f713615SIlya Dryomov return 0; 3492f713615SIlya Dryomov } 3502f713615SIlya Dryomov 3512f713615SIlya Dryomov /* 3522f713615SIlya Dryomov * We connected to a peer and are saying hello. 3532f713615SIlya Dryomov */ 3542f713615SIlya Dryomov static void prepare_write_banner(struct ceph_connection *con) 3552f713615SIlya Dryomov { 3562f713615SIlya Dryomov con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER); 3572f713615SIlya Dryomov con_out_kvec_add(con, sizeof (con->msgr->my_enc_addr), 3582f713615SIlya Dryomov &con->msgr->my_enc_addr); 3592f713615SIlya Dryomov 360a56dd9bfSIlya Dryomov con->v1.out_more = 0; 3612f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3622f713615SIlya Dryomov } 3632f713615SIlya Dryomov 3642f713615SIlya Dryomov static void __prepare_write_connect(struct ceph_connection *con) 3652f713615SIlya Dryomov { 366a56dd9bfSIlya Dryomov con_out_kvec_add(con, sizeof(con->v1.out_connect), 367a56dd9bfSIlya Dryomov &con->v1.out_connect); 368a56dd9bfSIlya Dryomov if (con->v1.auth) 369a56dd9bfSIlya Dryomov con_out_kvec_add(con, con->v1.auth->authorizer_buf_len, 370a56dd9bfSIlya Dryomov con->v1.auth->authorizer_buf); 3712f713615SIlya Dryomov 372a56dd9bfSIlya Dryomov con->v1.out_more = 0; 3732f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_WRITE_PENDING); 3742f713615SIlya Dryomov } 3752f713615SIlya Dryomov 3762f713615SIlya Dryomov static int prepare_write_connect(struct ceph_connection *con) 3772f713615SIlya Dryomov { 3782f713615SIlya Dryomov unsigned int global_seq = ceph_get_global_seq(con->msgr, 0); 3792f713615SIlya Dryomov int proto; 3802f713615SIlya Dryomov int ret; 3812f713615SIlya Dryomov 3822f713615SIlya Dryomov switch (con->peer_name.type) { 3832f713615SIlya Dryomov case CEPH_ENTITY_TYPE_MON: 3842f713615SIlya Dryomov proto = CEPH_MONC_PROTOCOL; 3852f713615SIlya Dryomov break; 3862f713615SIlya Dryomov case CEPH_ENTITY_TYPE_OSD: 3872f713615SIlya Dryomov proto = CEPH_OSDC_PROTOCOL; 3882f713615SIlya Dryomov break; 3892f713615SIlya Dryomov case CEPH_ENTITY_TYPE_MDS: 3902f713615SIlya Dryomov proto = CEPH_MDSC_PROTOCOL; 3912f713615SIlya Dryomov break; 3922f713615SIlya Dryomov default: 3932f713615SIlya Dryomov BUG(); 3942f713615SIlya Dryomov } 3952f713615SIlya Dryomov 3962f713615SIlya Dryomov dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, 397a56dd9bfSIlya Dryomov con->v1.connect_seq, global_seq, proto); 3982f713615SIlya Dryomov 399a56dd9bfSIlya Dryomov con->v1.out_connect.features = 4002f713615SIlya Dryomov cpu_to_le64(from_msgr(con->msgr)->supported_features); 401a56dd9bfSIlya Dryomov con->v1.out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); 402a56dd9bfSIlya Dryomov con->v1.out_connect.connect_seq = cpu_to_le32(con->v1.connect_seq); 403a56dd9bfSIlya Dryomov con->v1.out_connect.global_seq = cpu_to_le32(global_seq); 404a56dd9bfSIlya Dryomov con->v1.out_connect.protocol_version = cpu_to_le32(proto); 405a56dd9bfSIlya Dryomov con->v1.out_connect.flags = 0; 4062f713615SIlya Dryomov 4072f713615SIlya Dryomov ret = get_connect_authorizer(con); 4082f713615SIlya Dryomov if (ret) 4092f713615SIlya Dryomov return ret; 4102f713615SIlya Dryomov 4112f713615SIlya Dryomov __prepare_write_connect(con); 4122f713615SIlya Dryomov return 0; 4132f713615SIlya Dryomov } 4142f713615SIlya Dryomov 4152f713615SIlya Dryomov /* 4162f713615SIlya Dryomov * write as much of pending kvecs to the socket as we can. 4172f713615SIlya Dryomov * 1 -> done 4182f713615SIlya Dryomov * 0 -> socket full, but more to do 4192f713615SIlya Dryomov * <0 -> error 4202f713615SIlya Dryomov */ 4212f713615SIlya Dryomov static int write_partial_kvec(struct ceph_connection *con) 4222f713615SIlya Dryomov { 4232f713615SIlya Dryomov int ret; 4242f713615SIlya Dryomov 425a56dd9bfSIlya Dryomov dout("write_partial_kvec %p %d left\n", con, con->v1.out_kvec_bytes); 426a56dd9bfSIlya Dryomov while (con->v1.out_kvec_bytes > 0) { 427a56dd9bfSIlya Dryomov ret = ceph_tcp_sendmsg(con->sock, con->v1.out_kvec_cur, 428a56dd9bfSIlya Dryomov con->v1.out_kvec_left, 429a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, 430a56dd9bfSIlya Dryomov con->v1.out_more); 4312f713615SIlya Dryomov if (ret <= 0) 4322f713615SIlya Dryomov goto out; 433a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes -= ret; 434a56dd9bfSIlya Dryomov if (!con->v1.out_kvec_bytes) 4352f713615SIlya Dryomov break; /* done */ 4362f713615SIlya Dryomov 4372f713615SIlya Dryomov /* account for full iov entries consumed */ 438a56dd9bfSIlya Dryomov while (ret >= con->v1.out_kvec_cur->iov_len) { 439a56dd9bfSIlya Dryomov BUG_ON(!con->v1.out_kvec_left); 440a56dd9bfSIlya Dryomov ret -= con->v1.out_kvec_cur->iov_len; 441a56dd9bfSIlya Dryomov con->v1.out_kvec_cur++; 442a56dd9bfSIlya Dryomov con->v1.out_kvec_left--; 4432f713615SIlya Dryomov } 4442f713615SIlya Dryomov /* and for a partially-consumed entry */ 4452f713615SIlya Dryomov if (ret) { 446a56dd9bfSIlya Dryomov con->v1.out_kvec_cur->iov_len -= ret; 447a56dd9bfSIlya Dryomov con->v1.out_kvec_cur->iov_base += ret; 4482f713615SIlya Dryomov } 4492f713615SIlya Dryomov } 450a56dd9bfSIlya Dryomov con->v1.out_kvec_left = 0; 4512f713615SIlya Dryomov ret = 1; 4522f713615SIlya Dryomov out: 4532f713615SIlya Dryomov dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con, 454a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, con->v1.out_kvec_left, ret); 4552f713615SIlya Dryomov return ret; /* done! */ 4562f713615SIlya Dryomov } 4572f713615SIlya Dryomov 4582f713615SIlya Dryomov /* 4592f713615SIlya Dryomov * Write as much message data payload as we can. If we finish, queue 4602f713615SIlya Dryomov * up the footer. 4612f713615SIlya Dryomov * 1 -> done, footer is now queued in out_kvec[]. 4622f713615SIlya Dryomov * 0 -> socket full, but more to do 4632f713615SIlya Dryomov * <0 -> error 4642f713615SIlya Dryomov */ 4652f713615SIlya Dryomov static int write_partial_message_data(struct ceph_connection *con) 4662f713615SIlya Dryomov { 4672f713615SIlya Dryomov struct ceph_msg *msg = con->out_msg; 4682f713615SIlya Dryomov struct ceph_msg_data_cursor *cursor = &msg->cursor; 4692f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 4702f713615SIlya Dryomov int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; 4712f713615SIlya Dryomov u32 crc; 4722f713615SIlya Dryomov 4732f713615SIlya Dryomov dout("%s %p msg %p\n", __func__, con, msg); 4742f713615SIlya Dryomov 4752f713615SIlya Dryomov if (!msg->num_data_items) 4762f713615SIlya Dryomov return -EINVAL; 4772f713615SIlya Dryomov 4782f713615SIlya Dryomov /* 4792f713615SIlya Dryomov * Iterate through each page that contains data to be 4802f713615SIlya Dryomov * written, and send as much as possible for each. 4812f713615SIlya Dryomov * 4822f713615SIlya Dryomov * If we are calculating the data crc (the default), we will 4832f713615SIlya Dryomov * need to map the page. If we have no pages, they have 4842f713615SIlya Dryomov * been revoked, so use the zero page. 4852f713615SIlya Dryomov */ 4862f713615SIlya Dryomov crc = do_datacrc ? le32_to_cpu(msg->footer.data_crc) : 0; 4872f713615SIlya Dryomov while (cursor->total_resid) { 4882f713615SIlya Dryomov struct page *page; 4892f713615SIlya Dryomov size_t page_offset; 4902f713615SIlya Dryomov size_t length; 4912f713615SIlya Dryomov int ret; 4922f713615SIlya Dryomov 4932f713615SIlya Dryomov if (!cursor->resid) { 4942f713615SIlya Dryomov ceph_msg_data_advance(cursor, 0); 4952f713615SIlya Dryomov continue; 4962f713615SIlya Dryomov } 4972f713615SIlya Dryomov 4982f713615SIlya Dryomov page = ceph_msg_data_next(cursor, &page_offset, &length, NULL); 4992f713615SIlya Dryomov if (length == cursor->total_resid) 5002f713615SIlya Dryomov more = MSG_MORE; 5012f713615SIlya Dryomov ret = ceph_tcp_sendpage(con->sock, page, page_offset, length, 5022f713615SIlya Dryomov more); 5032f713615SIlya Dryomov if (ret <= 0) { 5042f713615SIlya Dryomov if (do_datacrc) 5052f713615SIlya Dryomov msg->footer.data_crc = cpu_to_le32(crc); 5062f713615SIlya Dryomov 5072f713615SIlya Dryomov return ret; 5082f713615SIlya Dryomov } 5092f713615SIlya Dryomov if (do_datacrc && cursor->need_crc) 5102f713615SIlya Dryomov crc = ceph_crc32c_page(crc, page, page_offset, length); 5112f713615SIlya Dryomov ceph_msg_data_advance(cursor, (size_t)ret); 5122f713615SIlya Dryomov } 5132f713615SIlya Dryomov 5142f713615SIlya Dryomov dout("%s %p msg %p done\n", __func__, con, msg); 5152f713615SIlya Dryomov 5162f713615SIlya Dryomov /* prepare and queue up footer, too */ 5172f713615SIlya Dryomov if (do_datacrc) 5182f713615SIlya Dryomov msg->footer.data_crc = cpu_to_le32(crc); 5192f713615SIlya Dryomov else 5202f713615SIlya Dryomov msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC; 5212f713615SIlya Dryomov con_out_kvec_reset(con); 5222f713615SIlya Dryomov prepare_write_message_footer(con); 5232f713615SIlya Dryomov 5242f713615SIlya Dryomov return 1; /* must return > 0 to indicate success */ 5252f713615SIlya Dryomov } 5262f713615SIlya Dryomov 5272f713615SIlya Dryomov /* 5282f713615SIlya Dryomov * write some zeros 5292f713615SIlya Dryomov */ 5302f713615SIlya Dryomov static int write_partial_skip(struct ceph_connection *con) 5312f713615SIlya Dryomov { 5322f713615SIlya Dryomov int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; 5332f713615SIlya Dryomov int ret; 5342f713615SIlya Dryomov 535a56dd9bfSIlya Dryomov dout("%s %p %d left\n", __func__, con, con->v1.out_skip); 536a56dd9bfSIlya Dryomov while (con->v1.out_skip > 0) { 537a56dd9bfSIlya Dryomov size_t size = min(con->v1.out_skip, (int)PAGE_SIZE); 5382f713615SIlya Dryomov 539a56dd9bfSIlya Dryomov if (size == con->v1.out_skip) 5402f713615SIlya Dryomov more = MSG_MORE; 5412f713615SIlya Dryomov ret = ceph_tcp_sendpage(con->sock, ceph_zero_page, 0, size, 5422f713615SIlya Dryomov more); 5432f713615SIlya Dryomov if (ret <= 0) 5442f713615SIlya Dryomov goto out; 545a56dd9bfSIlya Dryomov con->v1.out_skip -= ret; 5462f713615SIlya Dryomov } 5472f713615SIlya Dryomov ret = 1; 5482f713615SIlya Dryomov out: 5492f713615SIlya Dryomov return ret; 5502f713615SIlya Dryomov } 5512f713615SIlya Dryomov 5522f713615SIlya Dryomov /* 5532f713615SIlya Dryomov * Prepare to read connection handshake, or an ack. 5542f713615SIlya Dryomov */ 5552f713615SIlya Dryomov static void prepare_read_banner(struct ceph_connection *con) 5562f713615SIlya Dryomov { 5572f713615SIlya Dryomov dout("prepare_read_banner %p\n", con); 558a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5592f713615SIlya Dryomov } 5602f713615SIlya Dryomov 5612f713615SIlya Dryomov static void prepare_read_connect(struct ceph_connection *con) 5622f713615SIlya Dryomov { 5632f713615SIlya Dryomov dout("prepare_read_connect %p\n", con); 564a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5652f713615SIlya Dryomov } 5662f713615SIlya Dryomov 5672f713615SIlya Dryomov static void prepare_read_ack(struct ceph_connection *con) 5682f713615SIlya Dryomov { 5692f713615SIlya Dryomov dout("prepare_read_ack %p\n", con); 570a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5712f713615SIlya Dryomov } 5722f713615SIlya Dryomov 5732f713615SIlya Dryomov static void prepare_read_seq(struct ceph_connection *con) 5742f713615SIlya Dryomov { 5752f713615SIlya Dryomov dout("prepare_read_seq %p\n", con); 576a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 577a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_SEQ; 5782f713615SIlya Dryomov } 5792f713615SIlya Dryomov 5802f713615SIlya Dryomov static void prepare_read_tag(struct ceph_connection *con) 5812f713615SIlya Dryomov { 5822f713615SIlya Dryomov dout("prepare_read_tag %p\n", con); 583a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 584a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 5852f713615SIlya Dryomov } 5862f713615SIlya Dryomov 5872f713615SIlya Dryomov static void prepare_read_keepalive_ack(struct ceph_connection *con) 5882f713615SIlya Dryomov { 5892f713615SIlya Dryomov dout("prepare_read_keepalive_ack %p\n", con); 590a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 5912f713615SIlya Dryomov } 5922f713615SIlya Dryomov 5932f713615SIlya Dryomov /* 5942f713615SIlya Dryomov * Prepare to read a message. 5952f713615SIlya Dryomov */ 5962f713615SIlya Dryomov static int prepare_read_message(struct ceph_connection *con) 5972f713615SIlya Dryomov { 5982f713615SIlya Dryomov dout("prepare_read_message %p\n", con); 5992f713615SIlya Dryomov BUG_ON(con->in_msg != NULL); 600a56dd9bfSIlya Dryomov con->v1.in_base_pos = 0; 6012f713615SIlya Dryomov con->in_front_crc = con->in_middle_crc = con->in_data_crc = 0; 6022f713615SIlya Dryomov return 0; 6032f713615SIlya Dryomov } 6042f713615SIlya Dryomov 6052f713615SIlya Dryomov static int read_partial(struct ceph_connection *con, 6062f713615SIlya Dryomov int end, int size, void *object) 6072f713615SIlya Dryomov { 608a56dd9bfSIlya Dryomov while (con->v1.in_base_pos < end) { 609a56dd9bfSIlya Dryomov int left = end - con->v1.in_base_pos; 6102f713615SIlya Dryomov int have = size - left; 6112f713615SIlya Dryomov int ret = ceph_tcp_recvmsg(con->sock, object + have, left); 6122f713615SIlya Dryomov if (ret <= 0) 6132f713615SIlya Dryomov return ret; 614a56dd9bfSIlya Dryomov con->v1.in_base_pos += ret; 6152f713615SIlya Dryomov } 6162f713615SIlya Dryomov return 1; 6172f713615SIlya Dryomov } 6182f713615SIlya Dryomov 6192f713615SIlya Dryomov /* 6202f713615SIlya Dryomov * Read all or part of the connect-side handshake on a new connection 6212f713615SIlya Dryomov */ 6222f713615SIlya Dryomov static int read_partial_banner(struct ceph_connection *con) 6232f713615SIlya Dryomov { 6242f713615SIlya Dryomov int size; 6252f713615SIlya Dryomov int end; 6262f713615SIlya Dryomov int ret; 6272f713615SIlya Dryomov 628a56dd9bfSIlya Dryomov dout("read_partial_banner %p at %d\n", con, con->v1.in_base_pos); 6292f713615SIlya Dryomov 6302f713615SIlya Dryomov /* peer's banner */ 6312f713615SIlya Dryomov size = strlen(CEPH_BANNER); 6322f713615SIlya Dryomov end = size; 633a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, con->v1.in_banner); 6342f713615SIlya Dryomov if (ret <= 0) 6352f713615SIlya Dryomov goto out; 6362f713615SIlya Dryomov 637a56dd9bfSIlya Dryomov size = sizeof(con->v1.actual_peer_addr); 6382f713615SIlya Dryomov end += size; 639a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.actual_peer_addr); 6402f713615SIlya Dryomov if (ret <= 0) 6412f713615SIlya Dryomov goto out; 642a56dd9bfSIlya Dryomov ceph_decode_banner_addr(&con->v1.actual_peer_addr); 6432f713615SIlya Dryomov 644a56dd9bfSIlya Dryomov size = sizeof(con->v1.peer_addr_for_me); 6452f713615SIlya Dryomov end += size; 646a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.peer_addr_for_me); 6472f713615SIlya Dryomov if (ret <= 0) 6482f713615SIlya Dryomov goto out; 649a56dd9bfSIlya Dryomov ceph_decode_banner_addr(&con->v1.peer_addr_for_me); 6502f713615SIlya Dryomov 6512f713615SIlya Dryomov out: 6522f713615SIlya Dryomov return ret; 6532f713615SIlya Dryomov } 6542f713615SIlya Dryomov 6552f713615SIlya Dryomov static int read_partial_connect(struct ceph_connection *con) 6562f713615SIlya Dryomov { 6572f713615SIlya Dryomov int size; 6582f713615SIlya Dryomov int end; 6592f713615SIlya Dryomov int ret; 6602f713615SIlya Dryomov 661a56dd9bfSIlya Dryomov dout("read_partial_connect %p at %d\n", con, con->v1.in_base_pos); 6622f713615SIlya Dryomov 663a56dd9bfSIlya Dryomov size = sizeof(con->v1.in_reply); 6642f713615SIlya Dryomov end = size; 665a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.in_reply); 6662f713615SIlya Dryomov if (ret <= 0) 6672f713615SIlya Dryomov goto out; 6682f713615SIlya Dryomov 669a56dd9bfSIlya Dryomov if (con->v1.auth) { 670a56dd9bfSIlya Dryomov size = le32_to_cpu(con->v1.in_reply.authorizer_len); 671a56dd9bfSIlya Dryomov if (size > con->v1.auth->authorizer_reply_buf_len) { 6722f713615SIlya Dryomov pr_err("authorizer reply too big: %d > %zu\n", size, 673a56dd9bfSIlya Dryomov con->v1.auth->authorizer_reply_buf_len); 6742f713615SIlya Dryomov ret = -EINVAL; 6752f713615SIlya Dryomov goto out; 6762f713615SIlya Dryomov } 6772f713615SIlya Dryomov 6782f713615SIlya Dryomov end += size; 6792f713615SIlya Dryomov ret = read_partial(con, end, size, 680a56dd9bfSIlya Dryomov con->v1.auth->authorizer_reply_buf); 6812f713615SIlya Dryomov if (ret <= 0) 6822f713615SIlya Dryomov goto out; 6832f713615SIlya Dryomov } 6842f713615SIlya Dryomov 6852f713615SIlya Dryomov dout("read_partial_connect %p tag %d, con_seq = %u, g_seq = %u\n", 686a56dd9bfSIlya Dryomov con, con->v1.in_reply.tag, 687a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq), 688a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 6892f713615SIlya Dryomov out: 6902f713615SIlya Dryomov return ret; 6912f713615SIlya Dryomov } 6922f713615SIlya Dryomov 6932f713615SIlya Dryomov /* 6942f713615SIlya Dryomov * Verify the hello banner looks okay. 6952f713615SIlya Dryomov */ 6962f713615SIlya Dryomov static int verify_hello(struct ceph_connection *con) 6972f713615SIlya Dryomov { 698a56dd9bfSIlya Dryomov if (memcmp(con->v1.in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) { 6992f713615SIlya Dryomov pr_err("connect to %s got bad banner\n", 7002f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr)); 7012f713615SIlya Dryomov con->error_msg = "protocol error, bad banner"; 7022f713615SIlya Dryomov return -1; 7032f713615SIlya Dryomov } 7042f713615SIlya Dryomov return 0; 7052f713615SIlya Dryomov } 7062f713615SIlya Dryomov 7072f713615SIlya Dryomov static int process_banner(struct ceph_connection *con) 7082f713615SIlya Dryomov { 7092f713615SIlya Dryomov struct ceph_entity_addr *my_addr = &con->msgr->inst.addr; 7102f713615SIlya Dryomov 7112f713615SIlya Dryomov dout("process_banner on %p\n", con); 7122f713615SIlya Dryomov 7132f713615SIlya Dryomov if (verify_hello(con) < 0) 7142f713615SIlya Dryomov return -1; 7152f713615SIlya Dryomov 7162f713615SIlya Dryomov /* 7172f713615SIlya Dryomov * Make sure the other end is who we wanted. note that the other 7182f713615SIlya Dryomov * end may not yet know their ip address, so if it's 0.0.0.0, give 7192f713615SIlya Dryomov * them the benefit of the doubt. 7202f713615SIlya Dryomov */ 721a56dd9bfSIlya Dryomov if (memcmp(&con->peer_addr, &con->v1.actual_peer_addr, 7222f713615SIlya Dryomov sizeof(con->peer_addr)) != 0 && 723a56dd9bfSIlya Dryomov !(ceph_addr_is_blank(&con->v1.actual_peer_addr) && 724a56dd9bfSIlya Dryomov con->v1.actual_peer_addr.nonce == con->peer_addr.nonce)) { 7252f713615SIlya Dryomov pr_warn("wrong peer, want %s/%u, got %s/%u\n", 7262f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 7272f713615SIlya Dryomov le32_to_cpu(con->peer_addr.nonce), 728a56dd9bfSIlya Dryomov ceph_pr_addr(&con->v1.actual_peer_addr), 729a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.actual_peer_addr.nonce)); 7302f713615SIlya Dryomov con->error_msg = "wrong peer at address"; 7312f713615SIlya Dryomov return -1; 7322f713615SIlya Dryomov } 7332f713615SIlya Dryomov 7342f713615SIlya Dryomov /* 7352f713615SIlya Dryomov * did we learn our address? 7362f713615SIlya Dryomov */ 7372f713615SIlya Dryomov if (ceph_addr_is_blank(my_addr)) { 7382f713615SIlya Dryomov memcpy(&my_addr->in_addr, 739a56dd9bfSIlya Dryomov &con->v1.peer_addr_for_me.in_addr, 740a56dd9bfSIlya Dryomov sizeof(con->v1.peer_addr_for_me.in_addr)); 7412f713615SIlya Dryomov ceph_addr_set_port(my_addr, 0); 7422f713615SIlya Dryomov ceph_encode_my_addr(con->msgr); 7432f713615SIlya Dryomov dout("process_banner learned my addr is %s\n", 7442f713615SIlya Dryomov ceph_pr_addr(my_addr)); 7452f713615SIlya Dryomov } 7462f713615SIlya Dryomov 7472f713615SIlya Dryomov return 0; 7482f713615SIlya Dryomov } 7492f713615SIlya Dryomov 7502f713615SIlya Dryomov static int process_connect(struct ceph_connection *con) 7512f713615SIlya Dryomov { 7522f713615SIlya Dryomov u64 sup_feat = from_msgr(con->msgr)->supported_features; 7532f713615SIlya Dryomov u64 req_feat = from_msgr(con->msgr)->required_features; 754a56dd9bfSIlya Dryomov u64 server_feat = le64_to_cpu(con->v1.in_reply.features); 7552f713615SIlya Dryomov int ret; 7562f713615SIlya Dryomov 757a56dd9bfSIlya Dryomov dout("process_connect on %p tag %d\n", con, con->v1.in_tag); 7582f713615SIlya Dryomov 759a56dd9bfSIlya Dryomov if (con->v1.auth) { 760a56dd9bfSIlya Dryomov int len = le32_to_cpu(con->v1.in_reply.authorizer_len); 7612f713615SIlya Dryomov 7622f713615SIlya Dryomov /* 7632f713615SIlya Dryomov * Any connection that defines ->get_authorizer() 7642f713615SIlya Dryomov * should also define ->add_authorizer_challenge() and 7652f713615SIlya Dryomov * ->verify_authorizer_reply(). 7662f713615SIlya Dryomov * 7672f713615SIlya Dryomov * See get_connect_authorizer(). 7682f713615SIlya Dryomov */ 769a56dd9bfSIlya Dryomov if (con->v1.in_reply.tag == 770a56dd9bfSIlya Dryomov CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) { 7712f713615SIlya Dryomov ret = con->ops->add_authorizer_challenge( 772a56dd9bfSIlya Dryomov con, con->v1.auth->authorizer_reply_buf, len); 7732f713615SIlya Dryomov if (ret < 0) 7742f713615SIlya Dryomov return ret; 7752f713615SIlya Dryomov 7762f713615SIlya Dryomov con_out_kvec_reset(con); 7772f713615SIlya Dryomov __prepare_write_connect(con); 7782f713615SIlya Dryomov prepare_read_connect(con); 7792f713615SIlya Dryomov return 0; 7802f713615SIlya Dryomov } 7812f713615SIlya Dryomov 7822f713615SIlya Dryomov if (len) { 7832f713615SIlya Dryomov ret = con->ops->verify_authorizer_reply(con); 7842f713615SIlya Dryomov if (ret < 0) { 7852f713615SIlya Dryomov con->error_msg = "bad authorize reply"; 7862f713615SIlya Dryomov return ret; 7872f713615SIlya Dryomov } 7882f713615SIlya Dryomov } 7892f713615SIlya Dryomov } 7902f713615SIlya Dryomov 791a56dd9bfSIlya Dryomov switch (con->v1.in_reply.tag) { 7922f713615SIlya Dryomov case CEPH_MSGR_TAG_FEATURES: 7932f713615SIlya Dryomov pr_err("%s%lld %s feature set mismatch," 7942f713615SIlya Dryomov " my %llx < server's %llx, missing %llx\n", 7952f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 7962f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 7972f713615SIlya Dryomov sup_feat, server_feat, server_feat & ~sup_feat); 7982f713615SIlya Dryomov con->error_msg = "missing required protocol features"; 7992f713615SIlya Dryomov return -1; 8002f713615SIlya Dryomov 8012f713615SIlya Dryomov case CEPH_MSGR_TAG_BADPROTOVER: 8022f713615SIlya Dryomov pr_err("%s%lld %s protocol version mismatch," 8032f713615SIlya Dryomov " my %d != server's %d\n", 8042f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8052f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 806a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.out_connect.protocol_version), 807a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.protocol_version)); 8082f713615SIlya Dryomov con->error_msg = "protocol version mismatch"; 8092f713615SIlya Dryomov return -1; 8102f713615SIlya Dryomov 8112f713615SIlya Dryomov case CEPH_MSGR_TAG_BADAUTHORIZER: 812a56dd9bfSIlya Dryomov con->v1.auth_retry++; 8132f713615SIlya Dryomov dout("process_connect %p got BADAUTHORIZER attempt %d\n", con, 814a56dd9bfSIlya Dryomov con->v1.auth_retry); 815a56dd9bfSIlya Dryomov if (con->v1.auth_retry == 2) { 8162f713615SIlya Dryomov con->error_msg = "connect authorization failure"; 8172f713615SIlya Dryomov return -1; 8182f713615SIlya Dryomov } 8192f713615SIlya Dryomov con_out_kvec_reset(con); 8202f713615SIlya Dryomov ret = prepare_write_connect(con); 8212f713615SIlya Dryomov if (ret < 0) 8222f713615SIlya Dryomov return ret; 8232f713615SIlya Dryomov prepare_read_connect(con); 8242f713615SIlya Dryomov break; 8252f713615SIlya Dryomov 8262f713615SIlya Dryomov case CEPH_MSGR_TAG_RESETSESSION: 8272f713615SIlya Dryomov /* 8282f713615SIlya Dryomov * If we connected with a large connect_seq but the peer 8292f713615SIlya Dryomov * has no record of a session with us (no connection, or 8302f713615SIlya Dryomov * connect_seq == 0), they will send RESETSESION to indicate 8312f713615SIlya Dryomov * that they must have reset their session, and may have 8322f713615SIlya Dryomov * dropped messages. 8332f713615SIlya Dryomov */ 8342f713615SIlya Dryomov dout("process_connect got RESET peer seq %u\n", 835a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 8362f713615SIlya Dryomov pr_info("%s%lld %s session reset\n", 8372f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8382f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr)); 8392f713615SIlya Dryomov ceph_con_reset_session(con); 8402f713615SIlya Dryomov con_out_kvec_reset(con); 8412f713615SIlya Dryomov ret = prepare_write_connect(con); 8422f713615SIlya Dryomov if (ret < 0) 8432f713615SIlya Dryomov return ret; 8442f713615SIlya Dryomov prepare_read_connect(con); 8452f713615SIlya Dryomov 8462f713615SIlya Dryomov /* Tell ceph about it. */ 8472f713615SIlya Dryomov mutex_unlock(&con->mutex); 8482f713615SIlya Dryomov if (con->ops->peer_reset) 8492f713615SIlya Dryomov con->ops->peer_reset(con); 8502f713615SIlya Dryomov mutex_lock(&con->mutex); 8512f713615SIlya Dryomov if (con->state != CEPH_CON_S_V1_CONNECT_MSG) 8522f713615SIlya Dryomov return -EAGAIN; 8532f713615SIlya Dryomov break; 8542f713615SIlya Dryomov 8552f713615SIlya Dryomov case CEPH_MSGR_TAG_RETRY_SESSION: 8562f713615SIlya Dryomov /* 8572f713615SIlya Dryomov * If we sent a smaller connect_seq than the peer has, try 8582f713615SIlya Dryomov * again with a larger value. 8592f713615SIlya Dryomov */ 8602f713615SIlya Dryomov dout("process_connect got RETRY_SESSION my seq %u, peer %u\n", 861a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.out_connect.connect_seq), 862a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 863a56dd9bfSIlya Dryomov con->v1.connect_seq = le32_to_cpu(con->v1.in_reply.connect_seq); 8642f713615SIlya Dryomov con_out_kvec_reset(con); 8652f713615SIlya Dryomov ret = prepare_write_connect(con); 8662f713615SIlya Dryomov if (ret < 0) 8672f713615SIlya Dryomov return ret; 8682f713615SIlya Dryomov prepare_read_connect(con); 8692f713615SIlya Dryomov break; 8702f713615SIlya Dryomov 8712f713615SIlya Dryomov case CEPH_MSGR_TAG_RETRY_GLOBAL: 8722f713615SIlya Dryomov /* 8732f713615SIlya Dryomov * If we sent a smaller global_seq than the peer has, try 8742f713615SIlya Dryomov * again with a larger value. 8752f713615SIlya Dryomov */ 8762f713615SIlya Dryomov dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n", 877a56dd9bfSIlya Dryomov con->v1.peer_global_seq, 878a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 8792f713615SIlya Dryomov ceph_get_global_seq(con->msgr, 880a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq)); 8812f713615SIlya Dryomov con_out_kvec_reset(con); 8822f713615SIlya Dryomov ret = prepare_write_connect(con); 8832f713615SIlya Dryomov if (ret < 0) 8842f713615SIlya Dryomov return ret; 8852f713615SIlya Dryomov prepare_read_connect(con); 8862f713615SIlya Dryomov break; 8872f713615SIlya Dryomov 8882f713615SIlya Dryomov case CEPH_MSGR_TAG_SEQ: 8892f713615SIlya Dryomov case CEPH_MSGR_TAG_READY: 8902f713615SIlya Dryomov if (req_feat & ~server_feat) { 8912f713615SIlya Dryomov pr_err("%s%lld %s protocol feature mismatch," 8922f713615SIlya Dryomov " my required %llx > server's %llx, need %llx\n", 8932f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 8942f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 8952f713615SIlya Dryomov req_feat, server_feat, req_feat & ~server_feat); 8962f713615SIlya Dryomov con->error_msg = "missing required protocol features"; 8972f713615SIlya Dryomov return -1; 8982f713615SIlya Dryomov } 8992f713615SIlya Dryomov 9002f713615SIlya Dryomov WARN_ON(con->state != CEPH_CON_S_V1_CONNECT_MSG); 9012f713615SIlya Dryomov con->state = CEPH_CON_S_OPEN; 902a56dd9bfSIlya Dryomov con->v1.auth_retry = 0; /* we authenticated; clear flag */ 903a56dd9bfSIlya Dryomov con->v1.peer_global_seq = 904a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.global_seq); 905a56dd9bfSIlya Dryomov con->v1.connect_seq++; 9062f713615SIlya Dryomov con->peer_features = server_feat; 9072f713615SIlya Dryomov dout("process_connect got READY gseq %d cseq %d (%d)\n", 908a56dd9bfSIlya Dryomov con->v1.peer_global_seq, 909a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq), 910a56dd9bfSIlya Dryomov con->v1.connect_seq); 911a56dd9bfSIlya Dryomov WARN_ON(con->v1.connect_seq != 912a56dd9bfSIlya Dryomov le32_to_cpu(con->v1.in_reply.connect_seq)); 9132f713615SIlya Dryomov 914a56dd9bfSIlya Dryomov if (con->v1.in_reply.flags & CEPH_MSG_CONNECT_LOSSY) 9152f713615SIlya Dryomov ceph_con_flag_set(con, CEPH_CON_F_LOSSYTX); 9162f713615SIlya Dryomov 9172f713615SIlya Dryomov con->delay = 0; /* reset backoff memory */ 9182f713615SIlya Dryomov 919a56dd9bfSIlya Dryomov if (con->v1.in_reply.tag == CEPH_MSGR_TAG_SEQ) { 9202f713615SIlya Dryomov prepare_write_seq(con); 9212f713615SIlya Dryomov prepare_read_seq(con); 9222f713615SIlya Dryomov } else { 9232f713615SIlya Dryomov prepare_read_tag(con); 9242f713615SIlya Dryomov } 9252f713615SIlya Dryomov break; 9262f713615SIlya Dryomov 9272f713615SIlya Dryomov case CEPH_MSGR_TAG_WAIT: 9282f713615SIlya Dryomov /* 9292f713615SIlya Dryomov * If there is a connection race (we are opening 9302f713615SIlya Dryomov * connections to each other), one of us may just have 9312f713615SIlya Dryomov * to WAIT. This shouldn't happen if we are the 9322f713615SIlya Dryomov * client. 9332f713615SIlya Dryomov */ 9342f713615SIlya Dryomov con->error_msg = "protocol error, got WAIT as client"; 9352f713615SIlya Dryomov return -1; 9362f713615SIlya Dryomov 9372f713615SIlya Dryomov default: 9382f713615SIlya Dryomov con->error_msg = "protocol error, garbage tag during connect"; 9392f713615SIlya Dryomov return -1; 9402f713615SIlya Dryomov } 9412f713615SIlya Dryomov return 0; 9422f713615SIlya Dryomov } 9432f713615SIlya Dryomov 9442f713615SIlya Dryomov /* 9452f713615SIlya Dryomov * read (part of) an ack 9462f713615SIlya Dryomov */ 9472f713615SIlya Dryomov static int read_partial_ack(struct ceph_connection *con) 9482f713615SIlya Dryomov { 949a56dd9bfSIlya Dryomov int size = sizeof(con->v1.in_temp_ack); 9502f713615SIlya Dryomov int end = size; 9512f713615SIlya Dryomov 952a56dd9bfSIlya Dryomov return read_partial(con, end, size, &con->v1.in_temp_ack); 9532f713615SIlya Dryomov } 9542f713615SIlya Dryomov 9552f713615SIlya Dryomov /* 9562f713615SIlya Dryomov * We can finally discard anything that's been acked. 9572f713615SIlya Dryomov */ 9582f713615SIlya Dryomov static void process_ack(struct ceph_connection *con) 9592f713615SIlya Dryomov { 960a56dd9bfSIlya Dryomov u64 ack = le64_to_cpu(con->v1.in_temp_ack); 9612f713615SIlya Dryomov 962a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_ACK) 9632f713615SIlya Dryomov ceph_con_discard_sent(con, ack); 9642f713615SIlya Dryomov else 9652f713615SIlya Dryomov ceph_con_discard_requeued(con, ack); 9662f713615SIlya Dryomov 9672f713615SIlya Dryomov prepare_read_tag(con); 9682f713615SIlya Dryomov } 9692f713615SIlya Dryomov 9702f713615SIlya Dryomov static int read_partial_message_section(struct ceph_connection *con, 9712f713615SIlya Dryomov struct kvec *section, 9722f713615SIlya Dryomov unsigned int sec_len, u32 *crc) 9732f713615SIlya Dryomov { 9742f713615SIlya Dryomov int ret, left; 9752f713615SIlya Dryomov 9762f713615SIlya Dryomov BUG_ON(!section); 9772f713615SIlya Dryomov 9782f713615SIlya Dryomov while (section->iov_len < sec_len) { 9792f713615SIlya Dryomov BUG_ON(section->iov_base == NULL); 9802f713615SIlya Dryomov left = sec_len - section->iov_len; 9812f713615SIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, (char *)section->iov_base + 9822f713615SIlya Dryomov section->iov_len, left); 9832f713615SIlya Dryomov if (ret <= 0) 9842f713615SIlya Dryomov return ret; 9852f713615SIlya Dryomov section->iov_len += ret; 9862f713615SIlya Dryomov } 9872f713615SIlya Dryomov if (section->iov_len == sec_len) 9882f713615SIlya Dryomov *crc = crc32c(0, section->iov_base, section->iov_len); 9892f713615SIlya Dryomov 9902f713615SIlya Dryomov return 1; 9912f713615SIlya Dryomov } 9922f713615SIlya Dryomov 9932f713615SIlya Dryomov static int read_partial_msg_data(struct ceph_connection *con) 9942f713615SIlya Dryomov { 995*038b8d1dSIlya Dryomov struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 9962f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 9972f713615SIlya Dryomov struct page *page; 9982f713615SIlya Dryomov size_t page_offset; 9992f713615SIlya Dryomov size_t length; 10002f713615SIlya Dryomov u32 crc = 0; 10012f713615SIlya Dryomov int ret; 10022f713615SIlya Dryomov 10032f713615SIlya Dryomov if (do_datacrc) 10042f713615SIlya Dryomov crc = con->in_data_crc; 10052f713615SIlya Dryomov while (cursor->total_resid) { 10062f713615SIlya Dryomov if (!cursor->resid) { 10072f713615SIlya Dryomov ceph_msg_data_advance(cursor, 0); 10082f713615SIlya Dryomov continue; 10092f713615SIlya Dryomov } 10102f713615SIlya Dryomov 10112f713615SIlya Dryomov page = ceph_msg_data_next(cursor, &page_offset, &length, NULL); 10122f713615SIlya Dryomov ret = ceph_tcp_recvpage(con->sock, page, page_offset, length); 10132f713615SIlya Dryomov if (ret <= 0) { 10142f713615SIlya Dryomov if (do_datacrc) 10152f713615SIlya Dryomov con->in_data_crc = crc; 10162f713615SIlya Dryomov 10172f713615SIlya Dryomov return ret; 10182f713615SIlya Dryomov } 10192f713615SIlya Dryomov 10202f713615SIlya Dryomov if (do_datacrc) 10212f713615SIlya Dryomov crc = ceph_crc32c_page(crc, page, page_offset, ret); 10222f713615SIlya Dryomov ceph_msg_data_advance(cursor, (size_t)ret); 10232f713615SIlya Dryomov } 10242f713615SIlya Dryomov if (do_datacrc) 10252f713615SIlya Dryomov con->in_data_crc = crc; 10262f713615SIlya Dryomov 10272f713615SIlya Dryomov return 1; /* must return > 0 to indicate success */ 10282f713615SIlya Dryomov } 10292f713615SIlya Dryomov 1030*038b8d1dSIlya Dryomov static int read_partial_msg_data_bounce(struct ceph_connection *con) 1031*038b8d1dSIlya Dryomov { 1032*038b8d1dSIlya Dryomov struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor; 1033*038b8d1dSIlya Dryomov struct page *page; 1034*038b8d1dSIlya Dryomov size_t off, len; 1035*038b8d1dSIlya Dryomov u32 crc; 1036*038b8d1dSIlya Dryomov int ret; 1037*038b8d1dSIlya Dryomov 1038*038b8d1dSIlya Dryomov if (unlikely(!con->bounce_page)) { 1039*038b8d1dSIlya Dryomov con->bounce_page = alloc_page(GFP_NOIO); 1040*038b8d1dSIlya Dryomov if (!con->bounce_page) { 1041*038b8d1dSIlya Dryomov pr_err("failed to allocate bounce page\n"); 1042*038b8d1dSIlya Dryomov return -ENOMEM; 1043*038b8d1dSIlya Dryomov } 1044*038b8d1dSIlya Dryomov } 1045*038b8d1dSIlya Dryomov 1046*038b8d1dSIlya Dryomov crc = con->in_data_crc; 1047*038b8d1dSIlya Dryomov while (cursor->total_resid) { 1048*038b8d1dSIlya Dryomov if (!cursor->resid) { 1049*038b8d1dSIlya Dryomov ceph_msg_data_advance(cursor, 0); 1050*038b8d1dSIlya Dryomov continue; 1051*038b8d1dSIlya Dryomov } 1052*038b8d1dSIlya Dryomov 1053*038b8d1dSIlya Dryomov page = ceph_msg_data_next(cursor, &off, &len, NULL); 1054*038b8d1dSIlya Dryomov ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len); 1055*038b8d1dSIlya Dryomov if (ret <= 0) { 1056*038b8d1dSIlya Dryomov con->in_data_crc = crc; 1057*038b8d1dSIlya Dryomov return ret; 1058*038b8d1dSIlya Dryomov } 1059*038b8d1dSIlya Dryomov 1060*038b8d1dSIlya Dryomov crc = crc32c(crc, page_address(con->bounce_page), ret); 1061*038b8d1dSIlya Dryomov memcpy_to_page(page, off, page_address(con->bounce_page), ret); 1062*038b8d1dSIlya Dryomov 1063*038b8d1dSIlya Dryomov ceph_msg_data_advance(cursor, ret); 1064*038b8d1dSIlya Dryomov } 1065*038b8d1dSIlya Dryomov con->in_data_crc = crc; 1066*038b8d1dSIlya Dryomov 1067*038b8d1dSIlya Dryomov return 1; /* must return > 0 to indicate success */ 1068*038b8d1dSIlya Dryomov } 1069*038b8d1dSIlya Dryomov 10702f713615SIlya Dryomov /* 10712f713615SIlya Dryomov * read (part of) a message. 10722f713615SIlya Dryomov */ 10732f713615SIlya Dryomov static int read_partial_message(struct ceph_connection *con) 10742f713615SIlya Dryomov { 10752f713615SIlya Dryomov struct ceph_msg *m = con->in_msg; 10762f713615SIlya Dryomov int size; 10772f713615SIlya Dryomov int end; 10782f713615SIlya Dryomov int ret; 10792f713615SIlya Dryomov unsigned int front_len, middle_len, data_len; 10802f713615SIlya Dryomov bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); 10812f713615SIlya Dryomov bool need_sign = (con->peer_features & CEPH_FEATURE_MSG_AUTH); 10822f713615SIlya Dryomov u64 seq; 10832f713615SIlya Dryomov u32 crc; 10842f713615SIlya Dryomov 10852f713615SIlya Dryomov dout("read_partial_message con %p msg %p\n", con, m); 10862f713615SIlya Dryomov 10872f713615SIlya Dryomov /* header */ 1088a56dd9bfSIlya Dryomov size = sizeof(con->v1.in_hdr); 10892f713615SIlya Dryomov end = size; 1090a56dd9bfSIlya Dryomov ret = read_partial(con, end, size, &con->v1.in_hdr); 10912f713615SIlya Dryomov if (ret <= 0) 10922f713615SIlya Dryomov return ret; 10932f713615SIlya Dryomov 1094a56dd9bfSIlya Dryomov crc = crc32c(0, &con->v1.in_hdr, offsetof(struct ceph_msg_header, crc)); 1095a56dd9bfSIlya Dryomov if (cpu_to_le32(crc) != con->v1.in_hdr.crc) { 10962f713615SIlya Dryomov pr_err("read_partial_message bad hdr crc %u != expected %u\n", 1097a56dd9bfSIlya Dryomov crc, con->v1.in_hdr.crc); 10982f713615SIlya Dryomov return -EBADMSG; 10992f713615SIlya Dryomov } 11002f713615SIlya Dryomov 1101a56dd9bfSIlya Dryomov front_len = le32_to_cpu(con->v1.in_hdr.front_len); 11022f713615SIlya Dryomov if (front_len > CEPH_MSG_MAX_FRONT_LEN) 11032f713615SIlya Dryomov return -EIO; 1104a56dd9bfSIlya Dryomov middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 11052f713615SIlya Dryomov if (middle_len > CEPH_MSG_MAX_MIDDLE_LEN) 11062f713615SIlya Dryomov return -EIO; 1107a56dd9bfSIlya Dryomov data_len = le32_to_cpu(con->v1.in_hdr.data_len); 11082f713615SIlya Dryomov if (data_len > CEPH_MSG_MAX_DATA_LEN) 11092f713615SIlya Dryomov return -EIO; 11102f713615SIlya Dryomov 11112f713615SIlya Dryomov /* verify seq# */ 1112a56dd9bfSIlya Dryomov seq = le64_to_cpu(con->v1.in_hdr.seq); 11132f713615SIlya Dryomov if ((s64)seq - (s64)con->in_seq < 1) { 11142f713615SIlya Dryomov pr_info("skipping %s%lld %s seq %lld expected %lld\n", 11152f713615SIlya Dryomov ENTITY_NAME(con->peer_name), 11162f713615SIlya Dryomov ceph_pr_addr(&con->peer_addr), 11172f713615SIlya Dryomov seq, con->in_seq + 1); 1118a56dd9bfSIlya Dryomov con->v1.in_base_pos = -front_len - middle_len - data_len - 11192f713615SIlya Dryomov sizeof_footer(con); 1120a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 11212f713615SIlya Dryomov return 1; 11222f713615SIlya Dryomov } else if ((s64)seq - (s64)con->in_seq > 1) { 11232f713615SIlya Dryomov pr_err("read_partial_message bad seq %lld expected %lld\n", 11242f713615SIlya Dryomov seq, con->in_seq + 1); 11252f713615SIlya Dryomov con->error_msg = "bad message sequence # for incoming message"; 11262f713615SIlya Dryomov return -EBADE; 11272f713615SIlya Dryomov } 11282f713615SIlya Dryomov 11292f713615SIlya Dryomov /* allocate message? */ 11302f713615SIlya Dryomov if (!con->in_msg) { 11312f713615SIlya Dryomov int skip = 0; 11322f713615SIlya Dryomov 1133a56dd9bfSIlya Dryomov dout("got hdr type %d front %d data %d\n", con->v1.in_hdr.type, 11342f713615SIlya Dryomov front_len, data_len); 1135a56dd9bfSIlya Dryomov ret = ceph_con_in_msg_alloc(con, &con->v1.in_hdr, &skip); 11362f713615SIlya Dryomov if (ret < 0) 11372f713615SIlya Dryomov return ret; 11382f713615SIlya Dryomov 11399d5ae6f3SIlya Dryomov BUG_ON((!con->in_msg) ^ skip); 11402f713615SIlya Dryomov if (skip) { 11412f713615SIlya Dryomov /* skip this message */ 11422f713615SIlya Dryomov dout("alloc_msg said skip message\n"); 1143a56dd9bfSIlya Dryomov con->v1.in_base_pos = -front_len - middle_len - 1144a56dd9bfSIlya Dryomov data_len - sizeof_footer(con); 1145a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 11462f713615SIlya Dryomov con->in_seq++; 11472f713615SIlya Dryomov return 1; 11482f713615SIlya Dryomov } 11492f713615SIlya Dryomov 11502f713615SIlya Dryomov BUG_ON(!con->in_msg); 11512f713615SIlya Dryomov BUG_ON(con->in_msg->con != con); 11522f713615SIlya Dryomov m = con->in_msg; 11532f713615SIlya Dryomov m->front.iov_len = 0; /* haven't read it yet */ 11542f713615SIlya Dryomov if (m->middle) 11552f713615SIlya Dryomov m->middle->vec.iov_len = 0; 11562f713615SIlya Dryomov 11572f713615SIlya Dryomov /* prepare for data payload, if any */ 11582f713615SIlya Dryomov 11592f713615SIlya Dryomov if (data_len) 11602f713615SIlya Dryomov prepare_message_data(con->in_msg, data_len); 11612f713615SIlya Dryomov } 11622f713615SIlya Dryomov 11632f713615SIlya Dryomov /* front */ 11642f713615SIlya Dryomov ret = read_partial_message_section(con, &m->front, front_len, 11652f713615SIlya Dryomov &con->in_front_crc); 11662f713615SIlya Dryomov if (ret <= 0) 11672f713615SIlya Dryomov return ret; 11682f713615SIlya Dryomov 11692f713615SIlya Dryomov /* middle */ 11702f713615SIlya Dryomov if (m->middle) { 11712f713615SIlya Dryomov ret = read_partial_message_section(con, &m->middle->vec, 11722f713615SIlya Dryomov middle_len, 11732f713615SIlya Dryomov &con->in_middle_crc); 11742f713615SIlya Dryomov if (ret <= 0) 11752f713615SIlya Dryomov return ret; 11762f713615SIlya Dryomov } 11772f713615SIlya Dryomov 11782f713615SIlya Dryomov /* (page) data */ 11792f713615SIlya Dryomov if (data_len) { 1180*038b8d1dSIlya Dryomov if (!m->num_data_items) 1181*038b8d1dSIlya Dryomov return -EIO; 1182*038b8d1dSIlya Dryomov 1183*038b8d1dSIlya Dryomov if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) 1184*038b8d1dSIlya Dryomov ret = read_partial_msg_data_bounce(con); 1185*038b8d1dSIlya Dryomov else 11862f713615SIlya Dryomov ret = read_partial_msg_data(con); 11872f713615SIlya Dryomov if (ret <= 0) 11882f713615SIlya Dryomov return ret; 11892f713615SIlya Dryomov } 11902f713615SIlya Dryomov 11912f713615SIlya Dryomov /* footer */ 11922f713615SIlya Dryomov size = sizeof_footer(con); 11932f713615SIlya Dryomov end += size; 11942f713615SIlya Dryomov ret = read_partial(con, end, size, &m->footer); 11952f713615SIlya Dryomov if (ret <= 0) 11962f713615SIlya Dryomov return ret; 11972f713615SIlya Dryomov 11982f713615SIlya Dryomov if (!need_sign) { 11992f713615SIlya Dryomov m->footer.flags = m->old_footer.flags; 12002f713615SIlya Dryomov m->footer.sig = 0; 12012f713615SIlya Dryomov } 12022f713615SIlya Dryomov 12032f713615SIlya Dryomov dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n", 12042f713615SIlya Dryomov m, front_len, m->footer.front_crc, middle_len, 12052f713615SIlya Dryomov m->footer.middle_crc, data_len, m->footer.data_crc); 12062f713615SIlya Dryomov 12072f713615SIlya Dryomov /* crc ok? */ 12082f713615SIlya Dryomov if (con->in_front_crc != le32_to_cpu(m->footer.front_crc)) { 12092f713615SIlya Dryomov pr_err("read_partial_message %p front crc %u != exp. %u\n", 12102f713615SIlya Dryomov m, con->in_front_crc, m->footer.front_crc); 12112f713615SIlya Dryomov return -EBADMSG; 12122f713615SIlya Dryomov } 12132f713615SIlya Dryomov if (con->in_middle_crc != le32_to_cpu(m->footer.middle_crc)) { 12142f713615SIlya Dryomov pr_err("read_partial_message %p middle crc %u != exp %u\n", 12152f713615SIlya Dryomov m, con->in_middle_crc, m->footer.middle_crc); 12162f713615SIlya Dryomov return -EBADMSG; 12172f713615SIlya Dryomov } 12182f713615SIlya Dryomov if (do_datacrc && 12192f713615SIlya Dryomov (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 && 12202f713615SIlya Dryomov con->in_data_crc != le32_to_cpu(m->footer.data_crc)) { 12212f713615SIlya Dryomov pr_err("read_partial_message %p data crc %u != exp. %u\n", m, 12222f713615SIlya Dryomov con->in_data_crc, le32_to_cpu(m->footer.data_crc)); 12232f713615SIlya Dryomov return -EBADMSG; 12242f713615SIlya Dryomov } 12252f713615SIlya Dryomov 12262f713615SIlya Dryomov if (need_sign && con->ops->check_message_signature && 12272f713615SIlya Dryomov con->ops->check_message_signature(m)) { 12282f713615SIlya Dryomov pr_err("read_partial_message %p signature check failed\n", m); 12292f713615SIlya Dryomov return -EBADMSG; 12302f713615SIlya Dryomov } 12312f713615SIlya Dryomov 12322f713615SIlya Dryomov return 1; /* done! */ 12332f713615SIlya Dryomov } 12342f713615SIlya Dryomov 12352f713615SIlya Dryomov static int read_keepalive_ack(struct ceph_connection *con) 12362f713615SIlya Dryomov { 12372f713615SIlya Dryomov struct ceph_timespec ceph_ts; 12382f713615SIlya Dryomov size_t size = sizeof(ceph_ts); 12392f713615SIlya Dryomov int ret = read_partial(con, size, size, &ceph_ts); 12402f713615SIlya Dryomov if (ret <= 0) 12412f713615SIlya Dryomov return ret; 12422f713615SIlya Dryomov ceph_decode_timespec64(&con->last_keepalive_ack, &ceph_ts); 12432f713615SIlya Dryomov prepare_read_tag(con); 12442f713615SIlya Dryomov return 1; 12452f713615SIlya Dryomov } 12462f713615SIlya Dryomov 12472f713615SIlya Dryomov /* 12482f713615SIlya Dryomov * Read what we can from the socket. 12492f713615SIlya Dryomov */ 12502f713615SIlya Dryomov int ceph_con_v1_try_read(struct ceph_connection *con) 12512f713615SIlya Dryomov { 12522f713615SIlya Dryomov int ret = -1; 12532f713615SIlya Dryomov 12542f713615SIlya Dryomov more: 12552f713615SIlya Dryomov dout("try_read start %p state %d\n", con, con->state); 12562f713615SIlya Dryomov if (con->state != CEPH_CON_S_V1_BANNER && 12572f713615SIlya Dryomov con->state != CEPH_CON_S_V1_CONNECT_MSG && 12582f713615SIlya Dryomov con->state != CEPH_CON_S_OPEN) 12592f713615SIlya Dryomov return 0; 12602f713615SIlya Dryomov 12612f713615SIlya Dryomov BUG_ON(!con->sock); 12622f713615SIlya Dryomov 1263a56dd9bfSIlya Dryomov dout("try_read tag %d in_base_pos %d\n", con->v1.in_tag, 1264a56dd9bfSIlya Dryomov con->v1.in_base_pos); 12652f713615SIlya Dryomov 12662f713615SIlya Dryomov if (con->state == CEPH_CON_S_V1_BANNER) { 12672f713615SIlya Dryomov ret = read_partial_banner(con); 12682f713615SIlya Dryomov if (ret <= 0) 12692f713615SIlya Dryomov goto out; 12702f713615SIlya Dryomov ret = process_banner(con); 12712f713615SIlya Dryomov if (ret < 0) 12722f713615SIlya Dryomov goto out; 12732f713615SIlya Dryomov 12742f713615SIlya Dryomov con->state = CEPH_CON_S_V1_CONNECT_MSG; 12752f713615SIlya Dryomov 12762f713615SIlya Dryomov /* 12772f713615SIlya Dryomov * Received banner is good, exchange connection info. 12782f713615SIlya Dryomov * Do not reset out_kvec, as sending our banner raced 12792f713615SIlya Dryomov * with receiving peer banner after connect completed. 12802f713615SIlya Dryomov */ 12812f713615SIlya Dryomov ret = prepare_write_connect(con); 12822f713615SIlya Dryomov if (ret < 0) 12832f713615SIlya Dryomov goto out; 12842f713615SIlya Dryomov prepare_read_connect(con); 12852f713615SIlya Dryomov 12862f713615SIlya Dryomov /* Send connection info before awaiting response */ 12872f713615SIlya Dryomov goto out; 12882f713615SIlya Dryomov } 12892f713615SIlya Dryomov 12902f713615SIlya Dryomov if (con->state == CEPH_CON_S_V1_CONNECT_MSG) { 12912f713615SIlya Dryomov ret = read_partial_connect(con); 12922f713615SIlya Dryomov if (ret <= 0) 12932f713615SIlya Dryomov goto out; 12942f713615SIlya Dryomov ret = process_connect(con); 12952f713615SIlya Dryomov if (ret < 0) 12962f713615SIlya Dryomov goto out; 12972f713615SIlya Dryomov goto more; 12982f713615SIlya Dryomov } 12992f713615SIlya Dryomov 13002f713615SIlya Dryomov WARN_ON(con->state != CEPH_CON_S_OPEN); 13012f713615SIlya Dryomov 1302a56dd9bfSIlya Dryomov if (con->v1.in_base_pos < 0) { 13032f713615SIlya Dryomov /* 13042f713615SIlya Dryomov * skipping + discarding content. 13052f713615SIlya Dryomov */ 1306a56dd9bfSIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, NULL, -con->v1.in_base_pos); 13072f713615SIlya Dryomov if (ret <= 0) 13082f713615SIlya Dryomov goto out; 1309a56dd9bfSIlya Dryomov dout("skipped %d / %d bytes\n", ret, -con->v1.in_base_pos); 1310a56dd9bfSIlya Dryomov con->v1.in_base_pos += ret; 1311a56dd9bfSIlya Dryomov if (con->v1.in_base_pos) 13122f713615SIlya Dryomov goto more; 13132f713615SIlya Dryomov } 1314a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_READY) { 13152f713615SIlya Dryomov /* 13162f713615SIlya Dryomov * what's next? 13172f713615SIlya Dryomov */ 1318a56dd9bfSIlya Dryomov ret = ceph_tcp_recvmsg(con->sock, &con->v1.in_tag, 1); 13192f713615SIlya Dryomov if (ret <= 0) 13202f713615SIlya Dryomov goto out; 1321a56dd9bfSIlya Dryomov dout("try_read got tag %d\n", con->v1.in_tag); 1322a56dd9bfSIlya Dryomov switch (con->v1.in_tag) { 13232f713615SIlya Dryomov case CEPH_MSGR_TAG_MSG: 13242f713615SIlya Dryomov prepare_read_message(con); 13252f713615SIlya Dryomov break; 13262f713615SIlya Dryomov case CEPH_MSGR_TAG_ACK: 13272f713615SIlya Dryomov prepare_read_ack(con); 13282f713615SIlya Dryomov break; 13292f713615SIlya Dryomov case CEPH_MSGR_TAG_KEEPALIVE2_ACK: 13302f713615SIlya Dryomov prepare_read_keepalive_ack(con); 13312f713615SIlya Dryomov break; 13322f713615SIlya Dryomov case CEPH_MSGR_TAG_CLOSE: 13332f713615SIlya Dryomov ceph_con_close_socket(con); 13342f713615SIlya Dryomov con->state = CEPH_CON_S_CLOSED; 13352f713615SIlya Dryomov goto out; 13362f713615SIlya Dryomov default: 13372f713615SIlya Dryomov goto bad_tag; 13382f713615SIlya Dryomov } 13392f713615SIlya Dryomov } 1340a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_MSG) { 13412f713615SIlya Dryomov ret = read_partial_message(con); 13422f713615SIlya Dryomov if (ret <= 0) { 13432f713615SIlya Dryomov switch (ret) { 13442f713615SIlya Dryomov case -EBADMSG: 13452f713615SIlya Dryomov con->error_msg = "bad crc/signature"; 13462f713615SIlya Dryomov fallthrough; 13472f713615SIlya Dryomov case -EBADE: 13482f713615SIlya Dryomov ret = -EIO; 13492f713615SIlya Dryomov break; 13502f713615SIlya Dryomov case -EIO: 13512f713615SIlya Dryomov con->error_msg = "io error"; 13522f713615SIlya Dryomov break; 13532f713615SIlya Dryomov } 13542f713615SIlya Dryomov goto out; 13552f713615SIlya Dryomov } 1356a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_READY) 13572f713615SIlya Dryomov goto more; 13582f713615SIlya Dryomov ceph_con_process_message(con); 13592f713615SIlya Dryomov if (con->state == CEPH_CON_S_OPEN) 13602f713615SIlya Dryomov prepare_read_tag(con); 13612f713615SIlya Dryomov goto more; 13622f713615SIlya Dryomov } 1363a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_ACK || 1364a56dd9bfSIlya Dryomov con->v1.in_tag == CEPH_MSGR_TAG_SEQ) { 13652f713615SIlya Dryomov /* 13662f713615SIlya Dryomov * the final handshake seq exchange is semantically 13672f713615SIlya Dryomov * equivalent to an ACK 13682f713615SIlya Dryomov */ 13692f713615SIlya Dryomov ret = read_partial_ack(con); 13702f713615SIlya Dryomov if (ret <= 0) 13712f713615SIlya Dryomov goto out; 13722f713615SIlya Dryomov process_ack(con); 13732f713615SIlya Dryomov goto more; 13742f713615SIlya Dryomov } 1375a56dd9bfSIlya Dryomov if (con->v1.in_tag == CEPH_MSGR_TAG_KEEPALIVE2_ACK) { 13762f713615SIlya Dryomov ret = read_keepalive_ack(con); 13772f713615SIlya Dryomov if (ret <= 0) 13782f713615SIlya Dryomov goto out; 13792f713615SIlya Dryomov goto more; 13802f713615SIlya Dryomov } 13812f713615SIlya Dryomov 13822f713615SIlya Dryomov out: 13832f713615SIlya Dryomov dout("try_read done on %p ret %d\n", con, ret); 13842f713615SIlya Dryomov return ret; 13852f713615SIlya Dryomov 13862f713615SIlya Dryomov bad_tag: 1387a56dd9bfSIlya Dryomov pr_err("try_read bad tag %d\n", con->v1.in_tag); 13882f713615SIlya Dryomov con->error_msg = "protocol error, garbage tag"; 13892f713615SIlya Dryomov ret = -1; 13902f713615SIlya Dryomov goto out; 13912f713615SIlya Dryomov } 13922f713615SIlya Dryomov 13932f713615SIlya Dryomov /* 13942f713615SIlya Dryomov * Write something to the socket. Called in a worker thread when the 13952f713615SIlya Dryomov * socket appears to be writeable and we have something ready to send. 13962f713615SIlya Dryomov */ 13972f713615SIlya Dryomov int ceph_con_v1_try_write(struct ceph_connection *con) 13982f713615SIlya Dryomov { 13992f713615SIlya Dryomov int ret = 1; 14002f713615SIlya Dryomov 14012f713615SIlya Dryomov dout("try_write start %p state %d\n", con, con->state); 14022f713615SIlya Dryomov if (con->state != CEPH_CON_S_PREOPEN && 14032f713615SIlya Dryomov con->state != CEPH_CON_S_V1_BANNER && 14042f713615SIlya Dryomov con->state != CEPH_CON_S_V1_CONNECT_MSG && 14052f713615SIlya Dryomov con->state != CEPH_CON_S_OPEN) 14062f713615SIlya Dryomov return 0; 14072f713615SIlya Dryomov 14082f713615SIlya Dryomov /* open the socket first? */ 14092f713615SIlya Dryomov if (con->state == CEPH_CON_S_PREOPEN) { 14102f713615SIlya Dryomov BUG_ON(con->sock); 14112f713615SIlya Dryomov con->state = CEPH_CON_S_V1_BANNER; 14122f713615SIlya Dryomov 14132f713615SIlya Dryomov con_out_kvec_reset(con); 14142f713615SIlya Dryomov prepare_write_banner(con); 14152f713615SIlya Dryomov prepare_read_banner(con); 14162f713615SIlya Dryomov 14172f713615SIlya Dryomov BUG_ON(con->in_msg); 1418a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 14192f713615SIlya Dryomov dout("try_write initiating connect on %p new state %d\n", 14202f713615SIlya Dryomov con, con->state); 14212f713615SIlya Dryomov ret = ceph_tcp_connect(con); 14222f713615SIlya Dryomov if (ret < 0) { 14232f713615SIlya Dryomov con->error_msg = "connect error"; 14242f713615SIlya Dryomov goto out; 14252f713615SIlya Dryomov } 14262f713615SIlya Dryomov } 14272f713615SIlya Dryomov 14282f713615SIlya Dryomov more: 1429a56dd9bfSIlya Dryomov dout("try_write out_kvec_bytes %d\n", con->v1.out_kvec_bytes); 14302f713615SIlya Dryomov BUG_ON(!con->sock); 14312f713615SIlya Dryomov 14322f713615SIlya Dryomov /* kvec data queued? */ 1433a56dd9bfSIlya Dryomov if (con->v1.out_kvec_left) { 14342f713615SIlya Dryomov ret = write_partial_kvec(con); 14352f713615SIlya Dryomov if (ret <= 0) 14362f713615SIlya Dryomov goto out; 14372f713615SIlya Dryomov } 1438a56dd9bfSIlya Dryomov if (con->v1.out_skip) { 14392f713615SIlya Dryomov ret = write_partial_skip(con); 14402f713615SIlya Dryomov if (ret <= 0) 14412f713615SIlya Dryomov goto out; 14422f713615SIlya Dryomov } 14432f713615SIlya Dryomov 14442f713615SIlya Dryomov /* msg pages? */ 14452f713615SIlya Dryomov if (con->out_msg) { 1446a56dd9bfSIlya Dryomov if (con->v1.out_msg_done) { 14472f713615SIlya Dryomov ceph_msg_put(con->out_msg); 14482f713615SIlya Dryomov con->out_msg = NULL; /* we're done with this one */ 14492f713615SIlya Dryomov goto do_next; 14502f713615SIlya Dryomov } 14512f713615SIlya Dryomov 14522f713615SIlya Dryomov ret = write_partial_message_data(con); 14532f713615SIlya Dryomov if (ret == 1) 14542f713615SIlya Dryomov goto more; /* we need to send the footer, too! */ 14552f713615SIlya Dryomov if (ret == 0) 14562f713615SIlya Dryomov goto out; 14572f713615SIlya Dryomov if (ret < 0) { 14582f713615SIlya Dryomov dout("try_write write_partial_message_data err %d\n", 14592f713615SIlya Dryomov ret); 14602f713615SIlya Dryomov goto out; 14612f713615SIlya Dryomov } 14622f713615SIlya Dryomov } 14632f713615SIlya Dryomov 14642f713615SIlya Dryomov do_next: 14652f713615SIlya Dryomov if (con->state == CEPH_CON_S_OPEN) { 14662f713615SIlya Dryomov if (ceph_con_flag_test_and_clear(con, 14672f713615SIlya Dryomov CEPH_CON_F_KEEPALIVE_PENDING)) { 14682f713615SIlya Dryomov prepare_write_keepalive(con); 14692f713615SIlya Dryomov goto more; 14702f713615SIlya Dryomov } 14712f713615SIlya Dryomov /* is anything else pending? */ 14722f713615SIlya Dryomov if (!list_empty(&con->out_queue)) { 14732f713615SIlya Dryomov prepare_write_message(con); 14742f713615SIlya Dryomov goto more; 14752f713615SIlya Dryomov } 14762f713615SIlya Dryomov if (con->in_seq > con->in_seq_acked) { 14772f713615SIlya Dryomov prepare_write_ack(con); 14782f713615SIlya Dryomov goto more; 14792f713615SIlya Dryomov } 14802f713615SIlya Dryomov } 14812f713615SIlya Dryomov 14822f713615SIlya Dryomov /* Nothing to do! */ 14832f713615SIlya Dryomov ceph_con_flag_clear(con, CEPH_CON_F_WRITE_PENDING); 14842f713615SIlya Dryomov dout("try_write nothing else to write.\n"); 14852f713615SIlya Dryomov ret = 0; 14862f713615SIlya Dryomov out: 14872f713615SIlya Dryomov dout("try_write done on %p ret %d\n", con, ret); 14882f713615SIlya Dryomov return ret; 14892f713615SIlya Dryomov } 14902f713615SIlya Dryomov 14912f713615SIlya Dryomov void ceph_con_v1_revoke(struct ceph_connection *con) 14922f713615SIlya Dryomov { 14932f713615SIlya Dryomov struct ceph_msg *msg = con->out_msg; 14942f713615SIlya Dryomov 1495a56dd9bfSIlya Dryomov WARN_ON(con->v1.out_skip); 14962f713615SIlya Dryomov /* footer */ 1497a56dd9bfSIlya Dryomov if (con->v1.out_msg_done) { 1498a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 14992f713615SIlya Dryomov } else { 15002f713615SIlya Dryomov WARN_ON(!msg->data_length); 1501a56dd9bfSIlya Dryomov con->v1.out_skip += sizeof_footer(con); 15022f713615SIlya Dryomov } 15032f713615SIlya Dryomov /* data, middle, front */ 15042f713615SIlya Dryomov if (msg->data_length) 1505a56dd9bfSIlya Dryomov con->v1.out_skip += msg->cursor.total_resid; 15062f713615SIlya Dryomov if (msg->middle) 1507a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 1508a56dd9bfSIlya Dryomov con->v1.out_skip += con_out_kvec_skip(con); 15092f713615SIlya Dryomov 15102f713615SIlya Dryomov dout("%s con %p out_kvec_bytes %d out_skip %d\n", __func__, con, 1511a56dd9bfSIlya Dryomov con->v1.out_kvec_bytes, con->v1.out_skip); 15122f713615SIlya Dryomov } 15132f713615SIlya Dryomov 15142f713615SIlya Dryomov void ceph_con_v1_revoke_incoming(struct ceph_connection *con) 15152f713615SIlya Dryomov { 1516a56dd9bfSIlya Dryomov unsigned int front_len = le32_to_cpu(con->v1.in_hdr.front_len); 1517a56dd9bfSIlya Dryomov unsigned int middle_len = le32_to_cpu(con->v1.in_hdr.middle_len); 1518a56dd9bfSIlya Dryomov unsigned int data_len = le32_to_cpu(con->v1.in_hdr.data_len); 15192f713615SIlya Dryomov 15202f713615SIlya Dryomov /* skip rest of message */ 1521a56dd9bfSIlya Dryomov con->v1.in_base_pos = con->v1.in_base_pos - 15222f713615SIlya Dryomov sizeof(struct ceph_msg_header) - 15232f713615SIlya Dryomov front_len - 15242f713615SIlya Dryomov middle_len - 15252f713615SIlya Dryomov data_len - 15262f713615SIlya Dryomov sizeof(struct ceph_msg_footer); 15272f713615SIlya Dryomov 1528a56dd9bfSIlya Dryomov con->v1.in_tag = CEPH_MSGR_TAG_READY; 15292f713615SIlya Dryomov con->in_seq++; 15302f713615SIlya Dryomov 1531a56dd9bfSIlya Dryomov dout("%s con %p in_base_pos %d\n", __func__, con, con->v1.in_base_pos); 15322f713615SIlya Dryomov } 15332f713615SIlya Dryomov 15342f713615SIlya Dryomov bool ceph_con_v1_opened(struct ceph_connection *con) 15352f713615SIlya Dryomov { 1536a56dd9bfSIlya Dryomov return con->v1.connect_seq; 15372f713615SIlya Dryomov } 15382f713615SIlya Dryomov 15392f713615SIlya Dryomov void ceph_con_v1_reset_session(struct ceph_connection *con) 15402f713615SIlya Dryomov { 1541a56dd9bfSIlya Dryomov con->v1.connect_seq = 0; 1542a56dd9bfSIlya Dryomov con->v1.peer_global_seq = 0; 15432f713615SIlya Dryomov } 15442f713615SIlya Dryomov 15452f713615SIlya Dryomov void ceph_con_v1_reset_protocol(struct ceph_connection *con) 15462f713615SIlya Dryomov { 1547a56dd9bfSIlya Dryomov con->v1.out_skip = 0; 15482f713615SIlya Dryomov } 1549