]>
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 SW |
196 | /* |
197 | * struct ceph_timespec <-> struct timespec | |
198 | */ | |
c89136ea | 199 | static inline void ceph_decode_timespec(struct timespec *ts, |
63f2d211 | 200 | const struct ceph_timespec *tv) |
c89136ea | 201 | { |
c3f56102 AE |
202 | ts->tv_sec = (__kernel_time_t)le32_to_cpu(tv->tv_sec); |
203 | ts->tv_nsec = (long)le32_to_cpu(tv->tv_nsec); | |
c89136ea SW |
204 | } |
205 | static inline void ceph_encode_timespec(struct ceph_timespec *tv, | |
63f2d211 | 206 | const struct timespec *ts) |
c89136ea | 207 | { |
c3f56102 AE |
208 | tv->tv_sec = cpu_to_le32((u32)ts->tv_sec); |
209 | tv->tv_nsec = cpu_to_le32((u32)ts->tv_nsec); | |
c89136ea | 210 | } |
31b8006e | 211 | |
63f2d211 SW |
212 | /* |
213 | * sockaddr_storage <-> ceph_sockaddr | |
214 | */ | |
215 | static inline void ceph_encode_addr(struct ceph_entity_addr *a) | |
216 | { | |
cd84db6e YS |
217 | __be16 ss_family = htons(a->in_addr.ss_family); |
218 | a->in_addr.ss_family = *(__u16 *)&ss_family; | |
63f2d211 SW |
219 | } |
220 | static inline void ceph_decode_addr(struct ceph_entity_addr *a) | |
221 | { | |
cd84db6e YS |
222 | __be16 ss_family = *(__be16 *)&a->in_addr.ss_family; |
223 | a->in_addr.ss_family = ntohs(ss_family); | |
4e7a5dcd | 224 | WARN_ON(a->in_addr.ss_family == 512); |
63f2d211 SW |
225 | } |
226 | ||
31b8006e SW |
227 | /* |
228 | * encoders | |
229 | */ | |
c89136ea SW |
230 | static inline void ceph_encode_64(void **p, u64 v) |
231 | { | |
232 | put_unaligned_le64(v, (__le64 *)*p); | |
233 | *p += sizeof(u64); | |
234 | } | |
235 | static inline void ceph_encode_32(void **p, u32 v) | |
236 | { | |
237 | put_unaligned_le32(v, (__le32 *)*p); | |
238 | *p += sizeof(u32); | |
239 | } | |
240 | static inline void ceph_encode_16(void **p, u16 v) | |
241 | { | |
242 | put_unaligned_le16(v, (__le16 *)*p); | |
243 | *p += sizeof(u16); | |
244 | } | |
245 | static inline void ceph_encode_8(void **p, u8 v) | |
246 | { | |
247 | *(u8 *)*p = v; | |
248 | (*p)++; | |
249 | } | |
4e7a5dcd SW |
250 | static inline void ceph_encode_copy(void **p, const void *s, int len) |
251 | { | |
252 | memcpy(*p, s, len); | |
253 | *p += len; | |
254 | } | |
31b8006e SW |
255 | |
256 | /* | |
257 | * filepath, string encoders | |
258 | */ | |
259 | static inline void ceph_encode_filepath(void **p, void *end, | |
260 | u64 ino, const char *path) | |
261 | { | |
262 | u32 len = path ? strlen(path) : 0; | |
c61a1abd | 263 | BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end); |
ac8839d7 | 264 | ceph_encode_8(p, 1); |
31b8006e SW |
265 | ceph_encode_64(p, ino); |
266 | ceph_encode_32(p, len); | |
267 | if (len) | |
268 | memcpy(*p, path, len); | |
269 | *p += len; | |
270 | } | |
271 | ||
272 | static inline void ceph_encode_string(void **p, void *end, | |
273 | const char *s, u32 len) | |
274 | { | |
275 | BUG_ON(*p + sizeof(len) + len > end); | |
276 | ceph_encode_32(p, len); | |
277 | if (len) | |
278 | memcpy(*p, s, len); | |
279 | *p += len; | |
280 | } | |
281 | ||
22748f9d ID |
282 | /* |
283 | * version and length starting block encoders/decoders | |
284 | */ | |
285 | ||
286 | /* current code version (u8) + compat code version (u8) + len of struct (u32) */ | |
287 | #define CEPH_ENCODING_START_BLK_LEN 6 | |
288 | ||
289 | /** | |
290 | * ceph_start_encoding - start encoding block | |
291 | * @struct_v: current (code) version of the encoding | |
292 | * @struct_compat: oldest code version that can decode it | |
293 | * @struct_len: length of struct encoding | |
294 | */ | |
295 | static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat, | |
296 | u32 struct_len) | |
297 | { | |
298 | ceph_encode_8(p, struct_v); | |
299 | ceph_encode_8(p, struct_compat); | |
300 | ceph_encode_32(p, struct_len); | |
301 | } | |
302 | ||
303 | /** | |
304 | * ceph_start_decoding - start decoding block | |
305 | * @v: current version of the encoding that the code supports | |
306 | * @name: name of the struct (free-form) | |
307 | * @struct_v: out param for the encoding version | |
308 | * @struct_len: out param for the length of struct encoding | |
309 | * | |
310 | * Validates the length of struct encoding, so unsafe ceph_decode_* | |
311 | * variants can be used for decoding. | |
312 | */ | |
313 | static inline int ceph_start_decoding(void **p, void *end, u8 v, | |
314 | const char *name, u8 *struct_v, | |
315 | u32 *struct_len) | |
316 | { | |
317 | u8 struct_compat; | |
318 | ||
319 | ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad); | |
320 | *struct_v = ceph_decode_8(p); | |
321 | struct_compat = ceph_decode_8(p); | |
322 | if (v < struct_compat) { | |
323 | pr_warn("got struct_v %d struct_compat %d > %d of %s\n", | |
324 | *struct_v, struct_compat, v, name); | |
325 | return -EINVAL; | |
326 | } | |
327 | ||
328 | *struct_len = ceph_decode_32(p); | |
329 | ceph_decode_need(p, end, *struct_len, bad); | |
330 | return 0; | |
331 | ||
332 | bad: | |
333 | return -ERANGE; | |
334 | } | |
335 | ||
dd5f049d AE |
336 | #define ceph_encode_need(p, end, n, bad) \ |
337 | do { \ | |
338 | if (!likely(ceph_has_room(p, end, n))) \ | |
339 | goto bad; \ | |
c7e337d6 SW |
340 | } while (0) |
341 | ||
342 | #define ceph_encode_64_safe(p, end, v, bad) \ | |
343 | do { \ | |
344 | ceph_encode_need(p, end, sizeof(u64), bad); \ | |
345 | ceph_encode_64(p, v); \ | |
346 | } while (0) | |
347 | #define ceph_encode_32_safe(p, end, v, bad) \ | |
348 | do { \ | |
349 | ceph_encode_need(p, end, sizeof(u32), bad); \ | |
dd5f049d | 350 | ceph_encode_32(p, v); \ |
c7e337d6 SW |
351 | } while (0) |
352 | #define ceph_encode_16_safe(p, end, v, bad) \ | |
353 | do { \ | |
354 | ceph_encode_need(p, end, sizeof(u16), bad); \ | |
dd5f049d AE |
355 | ceph_encode_16(p, v); \ |
356 | } while (0) | |
357 | #define ceph_encode_8_safe(p, end, v, bad) \ | |
358 | do { \ | |
359 | ceph_encode_need(p, end, sizeof(u8), bad); \ | |
360 | ceph_encode_8(p, v); \ | |
c7e337d6 SW |
361 | } while (0) |
362 | ||
363 | #define ceph_encode_copy_safe(p, end, pv, n, bad) \ | |
364 | do { \ | |
365 | ceph_encode_need(p, end, n, bad); \ | |
366 | ceph_encode_copy(p, pv, n); \ | |
367 | } while (0) | |
ae1533b6 YS |
368 | #define ceph_encode_string_safe(p, end, s, n, bad) \ |
369 | do { \ | |
370 | ceph_encode_need(p, end, n, bad); \ | |
371 | ceph_encode_string(p, end, s, n); \ | |
372 | } while (0) | |
c7e337d6 | 373 | |
31b8006e SW |
374 | |
375 | #endif |