Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
31b8006e SW |
2 | #ifndef __CEPH_DECODE_H |
3 | #define __CEPH_DECODE_H | |
4 | ||
f8c36c58 | 5 | #include <linux/err.h> |
187f1882 | 6 | #include <linux/bug.h> |
b2aa5d0b | 7 | #include <linux/slab.h> |
c7e337d6 | 8 | #include <linux/time.h> |
187f1882 | 9 | #include <asm/unaligned.h> |
31b8006e | 10 | |
a1ce3928 | 11 | #include <linux/ceph/types.h> |
c89136ea | 12 | |
31b8006e SW |
13 | /* |
14 | * in all cases, | |
15 | * void **p pointer to position pointer | |
16 | * void *end pointer to end of buffer (last byte + 1) | |
17 | */ | |
18 | ||
c89136ea SW |
19 | static inline u64 ceph_decode_64(void **p) |
20 | { | |
21 | u64 v = get_unaligned_le64(*p); | |
22 | *p += sizeof(u64); | |
23 | return v; | |
24 | } | |
25 | static inline u32 ceph_decode_32(void **p) | |
26 | { | |
27 | u32 v = get_unaligned_le32(*p); | |
28 | *p += sizeof(u32); | |
29 | return v; | |
30 | } | |
31 | static inline u16 ceph_decode_16(void **p) | |
32 | { | |
33 | u16 v = get_unaligned_le16(*p); | |
34 | *p += sizeof(u16); | |
35 | return v; | |
36 | } | |
37 | static inline u8 ceph_decode_8(void **p) | |
38 | { | |
39 | u8 v = *(u8 *)*p; | |
40 | (*p)++; | |
41 | return v; | |
42 | } | |
43 | static inline void ceph_decode_copy(void **p, void *pv, size_t n) | |
44 | { | |
45 | memcpy(pv, *p, n); | |
46 | *p += n; | |
47 | } | |
48 | ||
31b8006e SW |
49 | /* |
50 | * bounds check input. | |
51 | */ | |
3b33f692 | 52 | static inline bool ceph_has_room(void **p, void *end, size_t n) |
76aa542f XW |
53 | { |
54 | return end >= *p && n <= end - *p; | |
55 | } | |
56 | ||
dd5f049d AE |
57 | #define ceph_decode_need(p, end, n, bad) \ |
58 | do { \ | |
59 | if (!likely(ceph_has_room(p, end, n))) \ | |
60 | goto bad; \ | |
31b8006e SW |
61 | } while (0) |
62 | ||
31b8006e SW |
63 | #define ceph_decode_64_safe(p, end, v, bad) \ |
64 | do { \ | |
65 | ceph_decode_need(p, end, sizeof(u64), bad); \ | |
c89136ea | 66 | v = ceph_decode_64(p); \ |
31b8006e SW |
67 | } while (0) |
68 | #define ceph_decode_32_safe(p, end, v, bad) \ | |
69 | do { \ | |
70 | ceph_decode_need(p, end, sizeof(u32), bad); \ | |
c89136ea | 71 | v = ceph_decode_32(p); \ |
31b8006e SW |
72 | } while (0) |
73 | #define ceph_decode_16_safe(p, end, v, bad) \ | |
74 | do { \ | |
75 | ceph_decode_need(p, end, sizeof(u16), bad); \ | |
c89136ea | 76 | v = ceph_decode_16(p); \ |
31b8006e | 77 | } while (0) |
c7e337d6 SW |
78 | #define ceph_decode_8_safe(p, end, v, bad) \ |
79 | do { \ | |
80 | ceph_decode_need(p, end, sizeof(u8), bad); \ | |
81 | v = ceph_decode_8(p); \ | |
82 | } while (0) | |
31b8006e SW |
83 | |
84 | #define ceph_decode_copy_safe(p, end, pv, n, bad) \ | |
85 | do { \ | |
86 | ceph_decode_need(p, end, n, bad); \ | |
87 | ceph_decode_copy(p, pv, n); \ | |
88 | } while (0) | |
89 | ||
f8c36c58 AE |
90 | /* |
91 | * Allocate a buffer big enough to hold the wire-encoded string, and | |
92 | * decode the string into it. The resulting string will always be | |
93 | * terminated with '\0'. If successful, *p will be advanced | |
94 | * past the decoded data. Also, if lenp is not a null pointer, the | |
95 | * length (not including the terminating '\0') will be recorded in | |
96 | * *lenp. Note that a zero-length string is a valid return value. | |
97 | * | |
98 | * Returns a pointer to the newly-allocated string buffer, or a | |
99 | * pointer-coded errno if an error occurs. Neither *p nor *lenp | |
100 | * will have been updated if an error is returned. | |
101 | * | |
102 | * There are two possible failures: | |
103 | * - converting the string would require accessing memory at or | |
dd5f049d AE |
104 | * beyond the "end" pointer provided (-ERANGE) |
105 | * - memory could not be allocated for the result (-ENOMEM) | |
f8c36c58 AE |
106 | */ |
107 | static inline char *ceph_extract_encoded_string(void **p, void *end, | |
108 | size_t *lenp, gfp_t gfp) | |
109 | { | |
110 | u32 len; | |
111 | void *sp = *p; | |
112 | char *buf; | |
113 | ||
114 | ceph_decode_32_safe(&sp, end, len, bad); | |
115 | if (!ceph_has_room(&sp, end, len)) | |
116 | goto bad; | |
117 | ||
118 | buf = kmalloc(len + 1, gfp); | |
119 | if (!buf) | |
120 | return ERR_PTR(-ENOMEM); | |
121 | ||
122 | if (len) | |
123 | memcpy(buf, sp, len); | |
124 | buf[len] = '\0'; | |
125 | ||
126 | *p = (char *) *p + sizeof (u32) + len; | |
127 | if (lenp) | |
128 | *lenp = (size_t) len; | |
129 | ||
130 | return buf; | |
131 | ||
132 | bad: | |
133 | return ERR_PTR(-ERANGE); | |
134 | } | |
135 | ||
278b1d70 ID |
136 | /* |
137 | * skip helpers | |
138 | */ | |
139 | #define ceph_decode_skip_n(p, end, n, bad) \ | |
140 | do { \ | |
141 | ceph_decode_need(p, end, n, bad); \ | |
142 | *p += n; \ | |
143 | } while (0) | |
144 | ||
145 | #define ceph_decode_skip_64(p, end, bad) \ | |
146 | ceph_decode_skip_n(p, end, sizeof(u64), bad) | |
147 | ||
148 | #define ceph_decode_skip_32(p, end, bad) \ | |
149 | ceph_decode_skip_n(p, end, sizeof(u32), bad) | |
150 | ||
151 | #define ceph_decode_skip_16(p, end, bad) \ | |
152 | ceph_decode_skip_n(p, end, sizeof(u16), bad) | |
153 | ||
154 | #define ceph_decode_skip_8(p, end, bad) \ | |
155 | ceph_decode_skip_n(p, end, sizeof(u8), bad) | |
156 | ||
157 | #define ceph_decode_skip_string(p, end, bad) \ | |
158 | do { \ | |
159 | u32 len; \ | |
160 | \ | |
161 | ceph_decode_32_safe(p, end, len, bad); \ | |
162 | ceph_decode_skip_n(p, end, len, bad); \ | |
163 | } while (0) | |
164 | ||
165 | #define ceph_decode_skip_set(p, end, type, bad) \ | |
166 | do { \ | |
167 | u32 len; \ | |
168 | \ | |
169 | ceph_decode_32_safe(p, end, len, bad); \ | |
170 | while (len--) \ | |
171 | ceph_decode_skip_##type(p, end, bad); \ | |
172 | } while (0) | |
173 | ||
174 | #define ceph_decode_skip_map(p, end, ktype, vtype, bad) \ | |
175 | do { \ | |
176 | u32 len; \ | |
177 | \ | |
178 | ceph_decode_32_safe(p, end, len, bad); \ | |
179 | while (len--) { \ | |
180 | ceph_decode_skip_##ktype(p, end, bad); \ | |
181 | ceph_decode_skip_##vtype(p, end, bad); \ | |
182 | } \ | |
183 | } while (0) | |
184 | ||
185 | #define ceph_decode_skip_map_of_map(p, end, ktype1, ktype2, vtype2, bad) \ | |
186 | do { \ | |
187 | u32 len; \ | |
188 | \ | |
189 | ceph_decode_32_safe(p, end, len, bad); \ | |
190 | while (len--) { \ | |
191 | ceph_decode_skip_##ktype1(p, end, bad); \ | |
192 | ceph_decode_skip_map(p, end, ktype2, vtype2, bad); \ | |
193 | } \ | |
194 | } while (0) | |
195 | ||
31b8006e | 196 | /* |
473bd2d7 | 197 | * struct ceph_timespec <-> struct timespec64 |
31b8006e | 198 | */ |
473bd2d7 AB |
199 | static inline void ceph_decode_timespec64(struct timespec64 *ts, |
200 | const struct ceph_timespec *tv) | |
201 | { | |
202 | /* | |
203 | * This will still overflow in year 2106. We could extend | |
204 | * the protocol to steal two more bits from tv_nsec to | |
205 | * add three more 136 year epochs after that the way ext4 | |
206 | * does if necessary. | |
207 | */ | |
208 | ts->tv_sec = (time64_t)le32_to_cpu(tv->tv_sec); | |
209 | ts->tv_nsec = (long)le32_to_cpu(tv->tv_nsec); | |
210 | } | |
211 | static inline void ceph_encode_timespec64(struct ceph_timespec *tv, | |
212 | const struct timespec64 *ts) | |
213 | { | |
214 | tv->tv_sec = cpu_to_le32((u32)ts->tv_sec); | |
215 | tv->tv_nsec = cpu_to_le32((u32)ts->tv_nsec); | |
c89136ea | 216 | } |
31b8006e | 217 | |
63f2d211 SW |
218 | /* |
219 | * sockaddr_storage <-> ceph_sockaddr | |
220 | */ | |
221 | static inline void ceph_encode_addr(struct ceph_entity_addr *a) | |
222 | { | |
cd84db6e YS |
223 | __be16 ss_family = htons(a->in_addr.ss_family); |
224 | a->in_addr.ss_family = *(__u16 *)&ss_family; | |
63f2d211 SW |
225 | } |
226 | static inline void ceph_decode_addr(struct ceph_entity_addr *a) | |
227 | { | |
cd84db6e YS |
228 | __be16 ss_family = *(__be16 *)&a->in_addr.ss_family; |
229 | a->in_addr.ss_family = ntohs(ss_family); | |
4e7a5dcd | 230 | WARN_ON(a->in_addr.ss_family == 512); |
63f2d211 SW |
231 | } |
232 | ||
31b8006e SW |
233 | /* |
234 | * encoders | |
235 | */ | |
c89136ea SW |
236 | static inline void ceph_encode_64(void **p, u64 v) |
237 | { | |
238 | put_unaligned_le64(v, (__le64 *)*p); | |
239 | *p += sizeof(u64); | |
240 | } | |
241 | static inline void ceph_encode_32(void **p, u32 v) | |
242 | { | |
243 | put_unaligned_le32(v, (__le32 *)*p); | |
244 | *p += sizeof(u32); | |
245 | } | |
246 | static inline void ceph_encode_16(void **p, u16 v) | |
247 | { | |
248 | put_unaligned_le16(v, (__le16 *)*p); | |
249 | *p += sizeof(u16); | |
250 | } | |
251 | static inline void ceph_encode_8(void **p, u8 v) | |
252 | { | |
253 | *(u8 *)*p = v; | |
254 | (*p)++; | |
255 | } | |
4e7a5dcd SW |
256 | static inline void ceph_encode_copy(void **p, const void *s, int len) |
257 | { | |
258 | memcpy(*p, s, len); | |
259 | *p += len; | |
260 | } | |
31b8006e SW |
261 | |
262 | /* | |
263 | * filepath, string encoders | |
264 | */ | |
265 | static inline void ceph_encode_filepath(void **p, void *end, | |
266 | u64 ino, const char *path) | |
267 | { | |
268 | u32 len = path ? strlen(path) : 0; | |
c61a1abd | 269 | BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end); |
ac8839d7 | 270 | ceph_encode_8(p, 1); |
31b8006e SW |
271 | ceph_encode_64(p, ino); |
272 | ceph_encode_32(p, len); | |
273 | if (len) | |
274 | memcpy(*p, path, len); | |
275 | *p += len; | |
276 | } | |
277 | ||
278 | static inline void ceph_encode_string(void **p, void *end, | |
279 | const char *s, u32 len) | |
280 | { | |
281 | BUG_ON(*p + sizeof(len) + len > end); | |
282 | ceph_encode_32(p, len); | |
283 | if (len) | |
284 | memcpy(*p, s, len); | |
285 | *p += len; | |
286 | } | |
287 | ||
22748f9d ID |
288 | /* |
289 | * version and length starting block encoders/decoders | |
290 | */ | |
291 | ||
292 | /* current code version (u8) + compat code version (u8) + len of struct (u32) */ | |
293 | #define CEPH_ENCODING_START_BLK_LEN 6 | |
294 | ||
295 | /** | |
296 | * ceph_start_encoding - start encoding block | |
297 | * @struct_v: current (code) version of the encoding | |
298 | * @struct_compat: oldest code version that can decode it | |
299 | * @struct_len: length of struct encoding | |
300 | */ | |
301 | static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat, | |
302 | u32 struct_len) | |
303 | { | |
304 | ceph_encode_8(p, struct_v); | |
305 | ceph_encode_8(p, struct_compat); | |
306 | ceph_encode_32(p, struct_len); | |
307 | } | |
308 | ||
309 | /** | |
310 | * ceph_start_decoding - start decoding block | |
311 | * @v: current version of the encoding that the code supports | |
312 | * @name: name of the struct (free-form) | |
313 | * @struct_v: out param for the encoding version | |
314 | * @struct_len: out param for the length of struct encoding | |
315 | * | |
316 | * Validates the length of struct encoding, so unsafe ceph_decode_* | |
317 | * variants can be used for decoding. | |
318 | */ | |
319 | static inline int ceph_start_decoding(void **p, void *end, u8 v, | |
320 | const char *name, u8 *struct_v, | |
321 | u32 *struct_len) | |
322 | { | |
323 | u8 struct_compat; | |
324 | ||
325 | ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad); | |
326 | *struct_v = ceph_decode_8(p); | |
327 | struct_compat = ceph_decode_8(p); | |
328 | if (v < struct_compat) { | |
329 | pr_warn("got struct_v %d struct_compat %d > %d of %s\n", | |
330 | *struct_v, struct_compat, v, name); | |
331 | return -EINVAL; | |
332 | } | |
333 | ||
334 | *struct_len = ceph_decode_32(p); | |
335 | ceph_decode_need(p, end, *struct_len, bad); | |
336 | return 0; | |
337 | ||
338 | bad: | |
339 | return -ERANGE; | |
340 | } | |
341 | ||
dd5f049d AE |
342 | #define ceph_encode_need(p, end, n, bad) \ |
343 | do { \ | |
344 | if (!likely(ceph_has_room(p, end, n))) \ | |
345 | goto bad; \ | |
c7e337d6 SW |
346 | } while (0) |
347 | ||
348 | #define ceph_encode_64_safe(p, end, v, bad) \ | |
349 | do { \ | |
350 | ceph_encode_need(p, end, sizeof(u64), bad); \ | |
351 | ceph_encode_64(p, v); \ | |
352 | } while (0) | |
353 | #define ceph_encode_32_safe(p, end, v, bad) \ | |
354 | do { \ | |
355 | ceph_encode_need(p, end, sizeof(u32), bad); \ | |
dd5f049d | 356 | ceph_encode_32(p, v); \ |
c7e337d6 SW |
357 | } while (0) |
358 | #define ceph_encode_16_safe(p, end, v, bad) \ | |
359 | do { \ | |
360 | ceph_encode_need(p, end, sizeof(u16), bad); \ | |
dd5f049d AE |
361 | ceph_encode_16(p, v); \ |
362 | } while (0) | |
363 | #define ceph_encode_8_safe(p, end, v, bad) \ | |
364 | do { \ | |
365 | ceph_encode_need(p, end, sizeof(u8), bad); \ | |
366 | ceph_encode_8(p, v); \ | |
c7e337d6 SW |
367 | } while (0) |
368 | ||
369 | #define ceph_encode_copy_safe(p, end, pv, n, bad) \ | |
370 | do { \ | |
371 | ceph_encode_need(p, end, n, bad); \ | |
372 | ceph_encode_copy(p, pv, n); \ | |
373 | } while (0) | |
ae1533b6 YS |
374 | #define ceph_encode_string_safe(p, end, s, n, bad) \ |
375 | do { \ | |
376 | ceph_encode_need(p, end, n, bad); \ | |
377 | ceph_encode_string(p, end, s, n); \ | |
378 | } while (0) | |
c7e337d6 | 379 | |
31b8006e SW |
380 | |
381 | #endif |