Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | // SPDX-License-Identifier: GPL-2.0 #include <linux/ceph/ceph_debug.h> #include <linux/inet.h> #include <linux/ceph/decode.h> static int ceph_decode_entity_addr_versioned(void **p, void *end, struct ceph_entity_addr *addr) { int ret; u8 struct_v; u32 struct_len, addr_len; void *struct_end; ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v, &struct_len); if (ret) goto bad; ret = -EINVAL; struct_end = *p + struct_len; ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad); ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); ceph_decode_32_safe(p, end, addr_len, bad); if (addr_len > sizeof(addr->in_addr)) goto bad; memset(&addr->in_addr, 0, sizeof(addr->in_addr)); if (addr_len) { ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad); addr->in_addr.ss_family = le16_to_cpu((__force __le16)addr->in_addr.ss_family); } /* Advance past anything the client doesn't yet understand */ *p = struct_end; ret = 0; bad: return ret; } static int ceph_decode_entity_addr_legacy(void **p, void *end, struct ceph_entity_addr *addr) { int ret = -EINVAL; /* Skip rest of type field */ ceph_decode_skip_n(p, end, 3, bad); /* * Clients that don't support ADDR2 always send TYPE_NONE, change it * to TYPE_LEGACY for forward compatibility. */ addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY; ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad); memset(&addr->in_addr, 0, sizeof(addr->in_addr)); ceph_decode_copy_safe(p, end, &addr->in_addr, sizeof(addr->in_addr), bad); addr->in_addr.ss_family = be16_to_cpu((__force __be16)addr->in_addr.ss_family); ret = 0; bad: return ret; } int ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr) { u8 marker; ceph_decode_8_safe(p, end, marker, bad); if (marker == 1) return ceph_decode_entity_addr_versioned(p, end, addr); else if (marker == 0) return ceph_decode_entity_addr_legacy(p, end, addr); bad: return -EINVAL; } 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)); } |