xref: /linux/net/ceph/decode.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
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