| 1 | |
| 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>
|
| 8 |
|
| 9 | static int
|
| 10 | ceph_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 |
|
| 43 | *p = struct_end;
|
| 44 | ret = 0;
|
| 45 | bad:
|
| 46 | return ret;
|
| 47 | }
|
| 48 |
|
| 49 | static int
|
| 50 | ceph_decode_entity_addr_legacy(void **p, void *end,
|
| 51 | struct ceph_entity_addr *addr)
|
| 52 | {
|
| 53 | int ret = -EINVAL;
|
| 54 |
|
| 55 |
|
| 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;
|
| 70 | bad:
|
| 71 | return ret;
|
| 72 | }
|
| 73 |
|
| 74 | int
|
| 75 | ceph_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);
|
| 84 | bad:
|
| 85 | return -EINVAL;
|
| 86 | }
|
| 87 | EXPORT_SYMBOL(ceph_decode_entity_addr);
|
| 88 |
|
| 89 | |
| 90 | * Return addr of desired type (MSGR2 or LEGACY) or error. In case of
|
| 91 | * multiple matches, use the first one for compatibility with userspace
|
| 92 | * messenger.
|
| 93 | *
|
| 94 | * Assume encoding with MSG_ADDR2.
|
| 95 |
|
| 96 | int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
|
| 97 | struct ceph_entity_addr *addr)
|
| 98 | {
|
| 99 | __le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
|
| 100 | CEPH_ENTITY_ADDR_TYPE_LEGACY;
|
| 101 | struct ceph_entity_addr tmp_addr;
|
| 102 | int addr_cnt;
|
| 103 | bool found;
|
| 104 | u8 marker;
|
| 105 | int ret;
|
| 106 | int i;
|
| 107 |
|
| 108 | ceph_decode_8_safe(p, end, marker, e_inval);
|
| 109 | if (marker != 2) {
|
| 110 | pr_err("bad addrvec marker %d\n", marker);
|
| 111 | return -EINVAL;
|
| 112 | }
|
| 113 |
|
| 114 | ceph_decode_32_safe(p, end, addr_cnt, e_inval);
|
| 115 | dout("%s addr_cnt %d\n", __func__, addr_cnt);
|
| 116 |
|
| 117 | found = false;
|
| 118 | for (i = 0; i < addr_cnt; i++) {
|
| 119 | ret = ceph_decode_entity_addr(p, end, &tmp_addr);
|
| 120 | if (ret)
|
| 121 | return ret;
|
| 122 |
|
| 123 | dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
|
| 124 | if (tmp_addr.type == my_type) {
|
| 125 | if (!found) {
|
| 126 | memcpy(addr, &tmp_addr, sizeof(*addr));
|
| 127 | found = true;
|
| 128 | } else {
|
| 129 | dout("%s skipping extra match of type %d in addrvec\n",
|
| 130 | __func__, le32_to_cpu(my_type));
|
| 131 | }
|
| 132 | }
|
| 133 | }
|
| 134 |
|
| 135 | if (found)
|
| 136 | return 0;
|
| 137 |
|
| 138 | if (!addr_cnt)
|
| 139 | return 0;
|
| 140 |
|
| 141 | if (addr_cnt == 1 && !memchr_inv(&tmp_addr, 0, sizeof(tmp_addr)))
|
| 142 | return 0;
|
| 143 |
|
| 144 | pr_err("no match of type %d in addrvec\n", le32_to_cpu(my_type));
|
| 145 | return -ENOENT;
|
| 146 |
|
| 147 | e_inval:
|
| 148 | return -EINVAL;
|
| 149 | }
|
| 150 | EXPORT_SYMBOL(ceph_decode_entity_addrvec);
|
| 151 |
|
| 152 | static 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 |
|
| 170 | int 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 |
|
| 178 | void 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);
|
| 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 | }
|