162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/inet.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/ceph/decode.h>
762306a36Sopenharmony_ci#include <linux/ceph/messenger.h>  /* for ceph_pr_addr() */
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic int
1062306a36Sopenharmony_ciceph_decode_entity_addr_versioned(void **p, void *end,
1162306a36Sopenharmony_ci				  struct ceph_entity_addr *addr)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	int ret;
1462306a36Sopenharmony_ci	u8 struct_v;
1562306a36Sopenharmony_ci	u32 struct_len, addr_len;
1662306a36Sopenharmony_ci	void *struct_end;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v,
1962306a36Sopenharmony_ci				  &struct_len);
2062306a36Sopenharmony_ci	if (ret)
2162306a36Sopenharmony_ci		goto bad;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	ret = -EINVAL;
2462306a36Sopenharmony_ci	struct_end = *p + struct_len;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	ceph_decode_32_safe(p, end, addr_len, bad);
3162306a36Sopenharmony_ci	if (addr_len > sizeof(addr->in_addr))
3262306a36Sopenharmony_ci		goto bad;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	memset(&addr->in_addr, 0, sizeof(addr->in_addr));
3562306a36Sopenharmony_ci	if (addr_len) {
3662306a36Sopenharmony_ci		ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci		addr->in_addr.ss_family =
3962306a36Sopenharmony_ci			le16_to_cpu((__force __le16)addr->in_addr.ss_family);
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/* Advance past anything the client doesn't yet understand */
4362306a36Sopenharmony_ci	*p = struct_end;
4462306a36Sopenharmony_ci	ret = 0;
4562306a36Sopenharmony_cibad:
4662306a36Sopenharmony_ci	return ret;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int
5062306a36Sopenharmony_ciceph_decode_entity_addr_legacy(void **p, void *end,
5162306a36Sopenharmony_ci			       struct ceph_entity_addr *addr)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int ret = -EINVAL;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Skip rest of type field */
5662306a36Sopenharmony_ci	ceph_decode_skip_n(p, end, 3, bad);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * Clients that don't support ADDR2 always send TYPE_NONE, change it
6062306a36Sopenharmony_ci	 * to TYPE_LEGACY for forward compatibility.
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
6362306a36Sopenharmony_ci	ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
6462306a36Sopenharmony_ci	memset(&addr->in_addr, 0, sizeof(addr->in_addr));
6562306a36Sopenharmony_ci	ceph_decode_copy_safe(p, end, &addr->in_addr,
6662306a36Sopenharmony_ci			      sizeof(addr->in_addr), bad);
6762306a36Sopenharmony_ci	addr->in_addr.ss_family =
6862306a36Sopenharmony_ci			be16_to_cpu((__force __be16)addr->in_addr.ss_family);
6962306a36Sopenharmony_ci	ret = 0;
7062306a36Sopenharmony_cibad:
7162306a36Sopenharmony_ci	return ret;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciint
7562306a36Sopenharmony_ciceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	u8 marker;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ceph_decode_8_safe(p, end, marker, bad);
8062306a36Sopenharmony_ci	if (marker == 1)
8162306a36Sopenharmony_ci		return ceph_decode_entity_addr_versioned(p, end, addr);
8262306a36Sopenharmony_ci	else if (marker == 0)
8362306a36Sopenharmony_ci		return ceph_decode_entity_addr_legacy(p, end, addr);
8462306a36Sopenharmony_cibad:
8562306a36Sopenharmony_ci	return -EINVAL;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_decode_entity_addr);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * Return addr of desired type (MSGR2 or LEGACY) or error.
9162306a36Sopenharmony_ci * Make sure there is only one match.
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * Assume encoding with MSG_ADDR2.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_ciint ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
9662306a36Sopenharmony_ci			       struct ceph_entity_addr *addr)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	__le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
9962306a36Sopenharmony_ci				 CEPH_ENTITY_ADDR_TYPE_LEGACY;
10062306a36Sopenharmony_ci	struct ceph_entity_addr tmp_addr;
10162306a36Sopenharmony_ci	int addr_cnt;
10262306a36Sopenharmony_ci	bool found;
10362306a36Sopenharmony_ci	u8 marker;
10462306a36Sopenharmony_ci	int ret;
10562306a36Sopenharmony_ci	int i;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	ceph_decode_8_safe(p, end, marker, e_inval);
10862306a36Sopenharmony_ci	if (marker != 2) {
10962306a36Sopenharmony_ci		pr_err("bad addrvec marker %d\n", marker);
11062306a36Sopenharmony_ci		return -EINVAL;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ceph_decode_32_safe(p, end, addr_cnt, e_inval);
11462306a36Sopenharmony_ci	dout("%s addr_cnt %d\n", __func__, addr_cnt);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	found = false;
11762306a36Sopenharmony_ci	for (i = 0; i < addr_cnt; i++) {
11862306a36Sopenharmony_ci		ret = ceph_decode_entity_addr(p, end, &tmp_addr);
11962306a36Sopenharmony_ci		if (ret)
12062306a36Sopenharmony_ci			return ret;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
12362306a36Sopenharmony_ci		if (tmp_addr.type == my_type) {
12462306a36Sopenharmony_ci			if (found) {
12562306a36Sopenharmony_ci				pr_err("another match of type %d in addrvec\n",
12662306a36Sopenharmony_ci				       le32_to_cpu(my_type));
12762306a36Sopenharmony_ci				return -EINVAL;
12862306a36Sopenharmony_ci			}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci			memcpy(addr, &tmp_addr, sizeof(*addr));
13162306a36Sopenharmony_ci			found = true;
13262306a36Sopenharmony_ci		}
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (found)
13662306a36Sopenharmony_ci		return 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (!addr_cnt)
13962306a36Sopenharmony_ci		return 0;  /* normal -- e.g. unused OSD id/slot */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (addr_cnt == 1 && !memchr_inv(&tmp_addr, 0, sizeof(tmp_addr)))
14262306a36Sopenharmony_ci		return 0;  /* weird but effectively the same as !addr_cnt */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	pr_err("no match of type %d in addrvec\n", le32_to_cpu(my_type));
14562306a36Sopenharmony_ci	return -ENOENT;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cie_inval:
14862306a36Sopenharmony_ci	return -EINVAL;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_decode_entity_addrvec);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int get_sockaddr_encoding_len(sa_family_t family)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	union {
15562306a36Sopenharmony_ci		struct sockaddr sa;
15662306a36Sopenharmony_ci		struct sockaddr_in sin;
15762306a36Sopenharmony_ci		struct sockaddr_in6 sin6;
15862306a36Sopenharmony_ci	} u;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	switch (family) {
16162306a36Sopenharmony_ci	case AF_INET:
16262306a36Sopenharmony_ci		return sizeof(u.sin);
16362306a36Sopenharmony_ci	case AF_INET6:
16462306a36Sopenharmony_ci		return sizeof(u.sin6);
16562306a36Sopenharmony_ci	default:
16662306a36Sopenharmony_ci		return sizeof(u);
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciint ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
17362306a36Sopenharmony_ci	int addr_len = get_sockaddr_encoding_len(family);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_civoid ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
18162306a36Sopenharmony_ci	int addr_len = get_sockaddr_encoding_len(family);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	ceph_encode_8(p, 1);  /* marker */
18462306a36Sopenharmony_ci	ceph_start_encoding(p, 1, 1, sizeof(addr->type) +
18562306a36Sopenharmony_ci				     sizeof(addr->nonce) +
18662306a36Sopenharmony_ci				     sizeof(u32) + addr_len);
18762306a36Sopenharmony_ci	ceph_encode_copy(p, &addr->type, sizeof(addr->type));
18862306a36Sopenharmony_ci	ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce));
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	ceph_encode_32(p, addr_len);
19162306a36Sopenharmony_ci	ceph_encode_16(p, family);
19262306a36Sopenharmony_ci	ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family));
19362306a36Sopenharmony_ci}
194