linux/net/ceph/decode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/inet.h>
   5
   6#include <linux/ceph/decode.h>
   7#include <linux/ceph/messenger.h>  /* for ceph_pr_addr() */
   8
   9static int
  10ceph_decode_entity_addr_versioned(void **p, void *end,
  11                                  struct ceph_entity_addr *addr)
  12{
  13        int ret;
  14        u8 struct_v;
  15        u32 struct_len, addr_len;
  16        void *struct_end;
  17
  18        ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v,
  19                                  &struct_len);
  20        if (ret)
  21                goto bad;
  22
  23        ret = -EINVAL;
  24        struct_end = *p + struct_len;
  25
  26        ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad);
  27
  28        ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
  29
  30        ceph_decode_32_safe(p, end, addr_len, bad);
  31        if (addr_len > sizeof(addr->in_addr))
  32                goto bad;
  33
  34        memset(&addr->in_addr, 0, sizeof(addr->in_addr));
  35        if (addr_len) {
  36                ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad);
  37
  38                addr->in_addr.ss_family =
  39                        le16_to_cpu((__force __le16)addr->in_addr.ss_family);
  40        }
  41
  42        /* Advance past anything the client doesn't yet understand */
  43        *p = struct_end;
  44        ret = 0;
  45bad:
  46        return ret;
  47}
  48
  49static int
  50ceph_decode_entity_addr_legacy(void **p, void *end,
  51                               struct ceph_entity_addr *addr)
  52{
  53        int ret = -EINVAL;
  54
  55        /* Skip rest of type field */
  56        ceph_decode_skip_n(p, end, 3, bad);
  57
  58        /*
  59         * Clients that don't support ADDR2 always send TYPE_NONE, change it
  60         * to TYPE_LEGACY for forward compatibility.
  61         */
  62        addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
  63        ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
  64        memset(&addr->in_addr, 0, sizeof(addr->in_addr));
  65        ceph_decode_copy_safe(p, end, &addr->in_addr,
  66                              sizeof(addr->in_addr), bad);
  67        addr->in_addr.ss_family =
  68                        be16_to_cpu((__force __be16)addr->in_addr.ss_family);
  69        ret = 0;
  70bad:
  71        return ret;
  72}
  73
  74int
  75ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr)
  76{
  77        u8 marker;
  78
  79        ceph_decode_8_safe(p, end, marker, bad);
  80        if (marker == 1)
  81                return ceph_decode_entity_addr_versioned(p, end, addr);
  82        else if (marker == 0)
  83                return ceph_decode_entity_addr_legacy(p, end, addr);
  84bad:
  85        return -EINVAL;
  86}
  87EXPORT_SYMBOL(ceph_decode_entity_addr);
  88
  89/*
  90 * Return addr of desired type (MSGR2 or LEGACY) or error.
  91 * Make sure there is only one match.
  92 *
  93 * Assume encoding with MSG_ADDR2.
  94 */
  95int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
  96                               struct ceph_entity_addr *addr)
  97{
  98        __le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
  99                                 CEPH_ENTITY_ADDR_TYPE_LEGACY;
 100        struct ceph_entity_addr tmp_addr;
 101        int addr_cnt;
 102        bool found;
 103        u8 marker;
 104        int ret;
 105        int i;
 106
 107        ceph_decode_8_safe(p, end, marker, e_inval);
 108        if (marker != 2) {
 109                pr_err("bad addrvec marker %d\n", marker);
 110                return -EINVAL;
 111        }
 112
 113        ceph_decode_32_safe(p, end, addr_cnt, e_inval);
 114        dout("%s addr_cnt %d\n", __func__, addr_cnt);
 115
 116        found = false;
 117        for (i = 0; i < addr_cnt; i++) {
 118                ret = ceph_decode_entity_addr(p, end, &tmp_addr);
 119                if (ret)
 120                        return ret;
 121
 122                dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
 123                if (tmp_addr.type == my_type) {
 124                        if (found) {
 125                                pr_err("another match of type %d in addrvec\n",
 126                                       le32_to_cpu(my_type));
 127                                return -EINVAL;
 128                        }
 129
 130                        memcpy(addr, &tmp_addr, sizeof(*addr));
 131                        found = true;
 132                }
 133        }
 134
 135        if (found)
 136                return 0;
 137
 138        if (!addr_cnt)
 139                return 0;  /* normal -- e.g. unused OSD id/slot */
 140
 141        if (addr_cnt == 1 && !memchr_inv(&tmp_addr, 0, sizeof(tmp_addr)))
 142                return 0;  /* weird but effectively the same as !addr_cnt */
 143
 144        pr_err("no match of type %d in addrvec\n", le32_to_cpu(my_type));
 145        return -ENOENT;
 146
 147e_inval:
 148        return -EINVAL;
 149}
 150EXPORT_SYMBOL(ceph_decode_entity_addrvec);
 151
 152static int get_sockaddr_encoding_len(sa_family_t family)
 153{
 154        union {
 155                struct sockaddr sa;
 156                struct sockaddr_in sin;
 157                struct sockaddr_in6 sin6;
 158        } u;
 159
 160        switch (family) {
 161        case AF_INET:
 162                return sizeof(u.sin);
 163        case AF_INET6:
 164                return sizeof(u.sin6);
 165        default:
 166                return sizeof(u);
 167        }
 168}
 169
 170int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr)
 171{
 172        sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
 173        int addr_len = get_sockaddr_encoding_len(family);
 174
 175        return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len;
 176}
 177
 178void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr)
 179{
 180        sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
 181        int addr_len = get_sockaddr_encoding_len(family);
 182
 183        ceph_encode_8(p, 1);  /* marker */
 184        ceph_start_encoding(p, 1, 1, sizeof(addr->type) +
 185                                     sizeof(addr->nonce) +
 186                                     sizeof(u32) + addr_len);
 187        ceph_encode_copy(p, &addr->type, sizeof(addr->type));
 188        ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce));
 189
 190        ceph_encode_32(p, addr_len);
 191        ceph_encode_16(p, family);
 192        ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family));
 193}
 194