libceph, ceph: implement msgr2.1 protocol (crc and secure modes)
[linux-2.6-microblaze.git] / net / ceph / decode.c
index eea5295..b44f765 100644 (file)
@@ -1,4 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/ceph/ceph_debug.h>
+
+#include <linux/inet.h>
 
 #include <linux/ceph/decode.h>
 
@@ -82,3 +85,101 @@ bad:
 }
 EXPORT_SYMBOL(ceph_decode_entity_addr);
 
+/*
+ * Return addr of desired type (MSGR2 or LEGACY) or error.
+ * Make sure there is only one match.
+ *
+ * Assume encoding with MSG_ADDR2.
+ */
+int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
+                              struct ceph_entity_addr *addr)
+{
+       __le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
+                                CEPH_ENTITY_ADDR_TYPE_LEGACY;
+       struct ceph_entity_addr tmp_addr;
+       int addr_cnt;
+       bool found;
+       u8 marker;
+       int ret;
+       int i;
+
+       ceph_decode_8_safe(p, end, marker, e_inval);
+       if (marker != 2) {
+               pr_err("bad addrvec marker %d\n", marker);
+               return -EINVAL;
+       }
+
+       ceph_decode_32_safe(p, end, addr_cnt, e_inval);
+
+       found = false;
+       for (i = 0; i < addr_cnt; i++) {
+               ret = ceph_decode_entity_addr(p, end, &tmp_addr);
+               if (ret)
+                       return ret;
+
+               if (tmp_addr.type == my_type) {
+                       if (found) {
+                               pr_err("another match of type %d in addrvec\n",
+                                      le32_to_cpu(my_type));
+                               return -EINVAL;
+                       }
+
+                       memcpy(addr, &tmp_addr, sizeof(*addr));
+                       found = true;
+               }
+       }
+       if (!found && addr_cnt != 0) {
+               pr_err("no match of type %d in addrvec\n",
+                      le32_to_cpu(my_type));
+               return -ENOENT;
+       }
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+EXPORT_SYMBOL(ceph_decode_entity_addrvec);
+
+static int get_sockaddr_encoding_len(sa_family_t family)
+{
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+               struct sockaddr_in6 sin6;
+       } u;
+
+       switch (family) {
+       case AF_INET:
+               return sizeof(u.sin);
+       case AF_INET6:
+               return sizeof(u.sin6);
+       default:
+               return sizeof(u);
+       }
+}
+
+int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr)
+{
+       sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
+       int addr_len = get_sockaddr_encoding_len(family);
+
+       return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len;
+}
+
+void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr)
+{
+       sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
+       int addr_len = get_sockaddr_encoding_len(family);
+
+       ceph_encode_8(p, 1);  /* marker */
+       ceph_start_encoding(p, 1, 1, sizeof(addr->type) +
+                                    sizeof(addr->nonce) +
+                                    sizeof(u32) + addr_len);
+       ceph_encode_copy(p, &addr->type, sizeof(addr->type));
+       ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce));
+
+       ceph_encode_32(p, addr_len);
+       ceph_encode_16(p, family);
+       ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family));
+}