xref: /openbmc/linux/net/ceph/decode.c (revision 3f1c6f21)
16c37f0e6SJeff Layton // SPDX-License-Identifier: GPL-2.0
2a5cbd5fcSIlya Dryomov #include <linux/ceph/ceph_debug.h>
36c37f0e6SJeff Layton 
4cd1a677cSIlya Dryomov #include <linux/inet.h>
5cd1a677cSIlya Dryomov 
66c37f0e6SJeff Layton #include <linux/ceph/decode.h>
7*3f1c6f21SIlya Dryomov #include <linux/ceph/messenger.h>  /* for ceph_pr_addr() */
86c37f0e6SJeff Layton 
96c37f0e6SJeff Layton static int
ceph_decode_entity_addr_versioned(void ** p,void * end,struct ceph_entity_addr * addr)106c37f0e6SJeff Layton ceph_decode_entity_addr_versioned(void **p, void *end,
116c37f0e6SJeff Layton 				  struct ceph_entity_addr *addr)
126c37f0e6SJeff Layton {
136c37f0e6SJeff Layton 	int ret;
146c37f0e6SJeff Layton 	u8 struct_v;
156c37f0e6SJeff Layton 	u32 struct_len, addr_len;
166c37f0e6SJeff Layton 	void *struct_end;
176c37f0e6SJeff Layton 
186c37f0e6SJeff Layton 	ret = ceph_start_decoding(p, end, 1, "entity_addr_t", &struct_v,
196c37f0e6SJeff Layton 				  &struct_len);
206c37f0e6SJeff Layton 	if (ret)
216c37f0e6SJeff Layton 		goto bad;
226c37f0e6SJeff Layton 
236c37f0e6SJeff Layton 	ret = -EINVAL;
246c37f0e6SJeff Layton 	struct_end = *p + struct_len;
256c37f0e6SJeff Layton 
266c37f0e6SJeff Layton 	ceph_decode_copy_safe(p, end, &addr->type, sizeof(addr->type), bad);
276c37f0e6SJeff Layton 
286c37f0e6SJeff Layton 	ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
296c37f0e6SJeff Layton 
306c37f0e6SJeff Layton 	ceph_decode_32_safe(p, end, addr_len, bad);
316c37f0e6SJeff Layton 	if (addr_len > sizeof(addr->in_addr))
326c37f0e6SJeff Layton 		goto bad;
336c37f0e6SJeff Layton 
346c37f0e6SJeff Layton 	memset(&addr->in_addr, 0, sizeof(addr->in_addr));
356c37f0e6SJeff Layton 	if (addr_len) {
366c37f0e6SJeff Layton 		ceph_decode_copy_safe(p, end, &addr->in_addr, addr_len, bad);
376c37f0e6SJeff Layton 
386c37f0e6SJeff Layton 		addr->in_addr.ss_family =
396c37f0e6SJeff Layton 			le16_to_cpu((__force __le16)addr->in_addr.ss_family);
406c37f0e6SJeff Layton 	}
416c37f0e6SJeff Layton 
426c37f0e6SJeff Layton 	/* Advance past anything the client doesn't yet understand */
436c37f0e6SJeff Layton 	*p = struct_end;
446c37f0e6SJeff Layton 	ret = 0;
456c37f0e6SJeff Layton bad:
466c37f0e6SJeff Layton 	return ret;
476c37f0e6SJeff Layton }
486c37f0e6SJeff Layton 
496c37f0e6SJeff Layton static int
ceph_decode_entity_addr_legacy(void ** p,void * end,struct ceph_entity_addr * addr)506c37f0e6SJeff Layton ceph_decode_entity_addr_legacy(void **p, void *end,
516c37f0e6SJeff Layton 			       struct ceph_entity_addr *addr)
526c37f0e6SJeff Layton {
536c37f0e6SJeff Layton 	int ret = -EINVAL;
546c37f0e6SJeff Layton 
556c37f0e6SJeff Layton 	/* Skip rest of type field */
566c37f0e6SJeff Layton 	ceph_decode_skip_n(p, end, 3, bad);
57d3c3c0a8SJeff Layton 
58d3c3c0a8SJeff Layton 	/*
59d3c3c0a8SJeff Layton 	 * Clients that don't support ADDR2 always send TYPE_NONE, change it
60d3c3c0a8SJeff Layton 	 * to TYPE_LEGACY for forward compatibility.
61d3c3c0a8SJeff Layton 	 */
62d3c3c0a8SJeff Layton 	addr->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
636c37f0e6SJeff Layton 	ceph_decode_copy_safe(p, end, &addr->nonce, sizeof(addr->nonce), bad);
646c37f0e6SJeff Layton 	memset(&addr->in_addr, 0, sizeof(addr->in_addr));
656c37f0e6SJeff Layton 	ceph_decode_copy_safe(p, end, &addr->in_addr,
666c37f0e6SJeff Layton 			      sizeof(addr->in_addr), bad);
676c37f0e6SJeff Layton 	addr->in_addr.ss_family =
686c37f0e6SJeff Layton 			be16_to_cpu((__force __be16)addr->in_addr.ss_family);
696c37f0e6SJeff Layton 	ret = 0;
706c37f0e6SJeff Layton bad:
716c37f0e6SJeff Layton 	return ret;
726c37f0e6SJeff Layton }
736c37f0e6SJeff Layton 
746c37f0e6SJeff Layton int
ceph_decode_entity_addr(void ** p,void * end,struct ceph_entity_addr * addr)756c37f0e6SJeff Layton ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr)
766c37f0e6SJeff Layton {
776c37f0e6SJeff Layton 	u8 marker;
786c37f0e6SJeff Layton 
796c37f0e6SJeff Layton 	ceph_decode_8_safe(p, end, marker, bad);
806c37f0e6SJeff Layton 	if (marker == 1)
816c37f0e6SJeff Layton 		return ceph_decode_entity_addr_versioned(p, end, addr);
826c37f0e6SJeff Layton 	else if (marker == 0)
836c37f0e6SJeff Layton 		return ceph_decode_entity_addr_legacy(p, end, addr);
846c37f0e6SJeff Layton bad:
856c37f0e6SJeff Layton 	return -EINVAL;
866c37f0e6SJeff Layton }
876c37f0e6SJeff Layton EXPORT_SYMBOL(ceph_decode_entity_addr);
886c37f0e6SJeff Layton 
89a5cbd5fcSIlya Dryomov /*
90a5cbd5fcSIlya Dryomov  * Return addr of desired type (MSGR2 or LEGACY) or error.
91a5cbd5fcSIlya Dryomov  * Make sure there is only one match.
92a5cbd5fcSIlya Dryomov  *
93a5cbd5fcSIlya Dryomov  * Assume encoding with MSG_ADDR2.
94a5cbd5fcSIlya Dryomov  */
ceph_decode_entity_addrvec(void ** p,void * end,bool msgr2,struct ceph_entity_addr * addr)95a5cbd5fcSIlya Dryomov int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
96a5cbd5fcSIlya Dryomov 			       struct ceph_entity_addr *addr)
97a5cbd5fcSIlya Dryomov {
98a5cbd5fcSIlya Dryomov 	__le32 my_type = msgr2 ? CEPH_ENTITY_ADDR_TYPE_MSGR2 :
99a5cbd5fcSIlya Dryomov 				 CEPH_ENTITY_ADDR_TYPE_LEGACY;
100a5cbd5fcSIlya Dryomov 	struct ceph_entity_addr tmp_addr;
101a5cbd5fcSIlya Dryomov 	int addr_cnt;
102a5cbd5fcSIlya Dryomov 	bool found;
103a5cbd5fcSIlya Dryomov 	u8 marker;
104a5cbd5fcSIlya Dryomov 	int ret;
105a5cbd5fcSIlya Dryomov 	int i;
106a5cbd5fcSIlya Dryomov 
107a5cbd5fcSIlya Dryomov 	ceph_decode_8_safe(p, end, marker, e_inval);
108a5cbd5fcSIlya Dryomov 	if (marker != 2) {
109a5cbd5fcSIlya Dryomov 		pr_err("bad addrvec marker %d\n", marker);
110a5cbd5fcSIlya Dryomov 		return -EINVAL;
111a5cbd5fcSIlya Dryomov 	}
112a5cbd5fcSIlya Dryomov 
113a5cbd5fcSIlya Dryomov 	ceph_decode_32_safe(p, end, addr_cnt, e_inval);
114*3f1c6f21SIlya Dryomov 	dout("%s addr_cnt %d\n", __func__, addr_cnt);
115a5cbd5fcSIlya Dryomov 
116a5cbd5fcSIlya Dryomov 	found = false;
117a5cbd5fcSIlya Dryomov 	for (i = 0; i < addr_cnt; i++) {
118a5cbd5fcSIlya Dryomov 		ret = ceph_decode_entity_addr(p, end, &tmp_addr);
119a5cbd5fcSIlya Dryomov 		if (ret)
120a5cbd5fcSIlya Dryomov 			return ret;
121a5cbd5fcSIlya Dryomov 
122*3f1c6f21SIlya Dryomov 		dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
123a5cbd5fcSIlya Dryomov 		if (tmp_addr.type == my_type) {
124a5cbd5fcSIlya Dryomov 			if (found) {
125a5cbd5fcSIlya Dryomov 				pr_err("another match of type %d in addrvec\n",
126a5cbd5fcSIlya Dryomov 				       le32_to_cpu(my_type));
127a5cbd5fcSIlya Dryomov 				return -EINVAL;
128a5cbd5fcSIlya Dryomov 			}
129a5cbd5fcSIlya Dryomov 
130a5cbd5fcSIlya Dryomov 			memcpy(addr, &tmp_addr, sizeof(*addr));
131a5cbd5fcSIlya Dryomov 			found = true;
132a5cbd5fcSIlya Dryomov 		}
133a5cbd5fcSIlya Dryomov 	}
134a5cbd5fcSIlya Dryomov 
135*3f1c6f21SIlya Dryomov 	if (found)
136a5cbd5fcSIlya Dryomov 		return 0;
137a5cbd5fcSIlya Dryomov 
138*3f1c6f21SIlya Dryomov 	if (!addr_cnt)
139*3f1c6f21SIlya Dryomov 		return 0;  /* normal -- e.g. unused OSD id/slot */
140*3f1c6f21SIlya Dryomov 
141*3f1c6f21SIlya Dryomov 	if (addr_cnt == 1 && !memchr_inv(&tmp_addr, 0, sizeof(tmp_addr)))
142*3f1c6f21SIlya Dryomov 		return 0;  /* weird but effectively the same as !addr_cnt */
143*3f1c6f21SIlya Dryomov 
144*3f1c6f21SIlya Dryomov 	pr_err("no match of type %d in addrvec\n", le32_to_cpu(my_type));
145*3f1c6f21SIlya Dryomov 	return -ENOENT;
146*3f1c6f21SIlya Dryomov 
147a5cbd5fcSIlya Dryomov e_inval:
148a5cbd5fcSIlya Dryomov 	return -EINVAL;
149a5cbd5fcSIlya Dryomov }
150a5cbd5fcSIlya Dryomov EXPORT_SYMBOL(ceph_decode_entity_addrvec);
151cd1a677cSIlya Dryomov 
get_sockaddr_encoding_len(sa_family_t family)152cd1a677cSIlya Dryomov static int get_sockaddr_encoding_len(sa_family_t family)
153cd1a677cSIlya Dryomov {
154cd1a677cSIlya Dryomov 	union {
155cd1a677cSIlya Dryomov 		struct sockaddr sa;
156cd1a677cSIlya Dryomov 		struct sockaddr_in sin;
157cd1a677cSIlya Dryomov 		struct sockaddr_in6 sin6;
158cd1a677cSIlya Dryomov 	} u;
159cd1a677cSIlya Dryomov 
160cd1a677cSIlya Dryomov 	switch (family) {
161cd1a677cSIlya Dryomov 	case AF_INET:
162cd1a677cSIlya Dryomov 		return sizeof(u.sin);
163cd1a677cSIlya Dryomov 	case AF_INET6:
164cd1a677cSIlya Dryomov 		return sizeof(u.sin6);
165cd1a677cSIlya Dryomov 	default:
166cd1a677cSIlya Dryomov 		return sizeof(u);
167cd1a677cSIlya Dryomov 	}
168cd1a677cSIlya Dryomov }
169cd1a677cSIlya Dryomov 
ceph_entity_addr_encoding_len(const struct ceph_entity_addr * addr)170cd1a677cSIlya Dryomov int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr)
171cd1a677cSIlya Dryomov {
172cd1a677cSIlya Dryomov 	sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
173cd1a677cSIlya Dryomov 	int addr_len = get_sockaddr_encoding_len(family);
174cd1a677cSIlya Dryomov 
175cd1a677cSIlya Dryomov 	return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len;
176cd1a677cSIlya Dryomov }
177cd1a677cSIlya Dryomov 
ceph_encode_entity_addr(void ** p,const struct ceph_entity_addr * addr)178cd1a677cSIlya Dryomov void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr)
179cd1a677cSIlya Dryomov {
180cd1a677cSIlya Dryomov 	sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
181cd1a677cSIlya Dryomov 	int addr_len = get_sockaddr_encoding_len(family);
182cd1a677cSIlya Dryomov 
183cd1a677cSIlya Dryomov 	ceph_encode_8(p, 1);  /* marker */
184cd1a677cSIlya Dryomov 	ceph_start_encoding(p, 1, 1, sizeof(addr->type) +
185cd1a677cSIlya Dryomov 				     sizeof(addr->nonce) +
186cd1a677cSIlya Dryomov 				     sizeof(u32) + addr_len);
187cd1a677cSIlya Dryomov 	ceph_encode_copy(p, &addr->type, sizeof(addr->type));
188cd1a677cSIlya Dryomov 	ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce));
189cd1a677cSIlya Dryomov 
190cd1a677cSIlya Dryomov 	ceph_encode_32(p, addr_len);
191cd1a677cSIlya Dryomov 	ceph_encode_16(p, family);
192cd1a677cSIlya Dryomov 	ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family));
193cd1a677cSIlya Dryomov }
194