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 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 /* Advance past anything the client doesn't yet understand */ 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 /* 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; 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. 91 * Make sure there is only one match. 92 * 93 * Assume encoding with MSG_ADDR2. 94 */ 95 int 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 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); /* 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.