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