root/include/linux/ceph/decode.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. ceph_decode_64
  2. ceph_decode_32
  3. ceph_decode_16
  4. ceph_decode_8
  5. ceph_decode_copy
  6. ceph_has_room
  7. ceph_extract_encoded_string
  8. ceph_decode_timespec64
  9. ceph_encode_timespec64
  10. ceph_encode_banner_addr
  11. ceph_decode_banner_addr
  12. ceph_encode_64
  13. ceph_encode_32
  14. ceph_encode_16
  15. ceph_encode_8
  16. ceph_encode_copy
  17. ceph_encode_filepath
  18. ceph_encode_string
  19. ceph_start_encoding
  20. ceph_start_decoding

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 #ifndef __CEPH_DECODE_H
   3 #define __CEPH_DECODE_H
   4 
   5 #include <linux/err.h>
   6 #include <linux/bug.h>
   7 #include <linux/slab.h>
   8 #include <linux/time.h>
   9 #include <asm/unaligned.h>
  10 
  11 #include <linux/ceph/types.h>
  12 
  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 
  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 
  49 /*
  50  * bounds check input.
  51  */
  52 static inline bool ceph_has_room(void **p, void *end, size_t n)
  53 {
  54         return end >= *p && n <= end - *p;
  55 }
  56 
  57 #define ceph_decode_need(p, end, n, bad)                        \
  58         do {                                                    \
  59                 if (!likely(ceph_has_room(p, end, n)))          \
  60                         goto bad;                               \
  61         } while (0)
  62 
  63 #define ceph_decode_64_safe(p, end, v, bad)                     \
  64         do {                                                    \
  65                 ceph_decode_need(p, end, sizeof(u64), bad);     \
  66                 v = ceph_decode_64(p);                          \
  67         } while (0)
  68 #define ceph_decode_32_safe(p, end, v, bad)                     \
  69         do {                                                    \
  70                 ceph_decode_need(p, end, sizeof(u32), bad);     \
  71                 v = ceph_decode_32(p);                          \
  72         } while (0)
  73 #define ceph_decode_16_safe(p, end, v, bad)                     \
  74         do {                                                    \
  75                 ceph_decode_need(p, end, sizeof(u16), bad);     \
  76                 v = ceph_decode_16(p);                          \
  77         } while (0)
  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)
  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 
  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
 104  *     beyond the "end" pointer provided (-ERANGE)
 105  *   - memory could not be allocated for the result (-ENOMEM)
 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 
 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 
 196 /*
 197  * struct ceph_timespec <-> struct timespec64
 198  */
 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);
 216 }
 217 
 218 /*
 219  * sockaddr_storage <-> ceph_sockaddr
 220  */
 221 #define CEPH_ENTITY_ADDR_TYPE_NONE      0
 222 #define CEPH_ENTITY_ADDR_TYPE_LEGACY    __cpu_to_le32(1)
 223 
 224 static inline void ceph_encode_banner_addr(struct ceph_entity_addr *a)
 225 {
 226         __be16 ss_family = htons(a->in_addr.ss_family);
 227         a->in_addr.ss_family = *(__u16 *)&ss_family;
 228 
 229         /* Banner addresses require TYPE_NONE */
 230         a->type = CEPH_ENTITY_ADDR_TYPE_NONE;
 231 }
 232 static inline void ceph_decode_banner_addr(struct ceph_entity_addr *a)
 233 {
 234         __be16 ss_family = *(__be16 *)&a->in_addr.ss_family;
 235         a->in_addr.ss_family = ntohs(ss_family);
 236         WARN_ON(a->in_addr.ss_family == 512);
 237         a->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
 238 }
 239 
 240 extern int ceph_decode_entity_addr(void **p, void *end,
 241                                    struct ceph_entity_addr *addr);
 242 /*
 243  * encoders
 244  */
 245 static inline void ceph_encode_64(void **p, u64 v)
 246 {
 247         put_unaligned_le64(v, (__le64 *)*p);
 248         *p += sizeof(u64);
 249 }
 250 static inline void ceph_encode_32(void **p, u32 v)
 251 {
 252         put_unaligned_le32(v, (__le32 *)*p);
 253         *p += sizeof(u32);
 254 }
 255 static inline void ceph_encode_16(void **p, u16 v)
 256 {
 257         put_unaligned_le16(v, (__le16 *)*p);
 258         *p += sizeof(u16);
 259 }
 260 static inline void ceph_encode_8(void **p, u8 v)
 261 {
 262         *(u8 *)*p = v;
 263         (*p)++;
 264 }
 265 static inline void ceph_encode_copy(void **p, const void *s, int len)
 266 {
 267         memcpy(*p, s, len);
 268         *p += len;
 269 }
 270 
 271 /*
 272  * filepath, string encoders
 273  */
 274 static inline void ceph_encode_filepath(void **p, void *end,
 275                                         u64 ino, const char *path)
 276 {
 277         u32 len = path ? strlen(path) : 0;
 278         BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end);
 279         ceph_encode_8(p, 1);
 280         ceph_encode_64(p, ino);
 281         ceph_encode_32(p, len);
 282         if (len)
 283                 memcpy(*p, path, len);
 284         *p += len;
 285 }
 286 
 287 static inline void ceph_encode_string(void **p, void *end,
 288                                       const char *s, u32 len)
 289 {
 290         BUG_ON(*p + sizeof(len) + len > end);
 291         ceph_encode_32(p, len);
 292         if (len)
 293                 memcpy(*p, s, len);
 294         *p += len;
 295 }
 296 
 297 /*
 298  * version and length starting block encoders/decoders
 299  */
 300 
 301 /* current code version (u8) + compat code version (u8) + len of struct (u32) */
 302 #define CEPH_ENCODING_START_BLK_LEN 6
 303 
 304 /**
 305  * ceph_start_encoding - start encoding block
 306  * @struct_v: current (code) version of the encoding
 307  * @struct_compat: oldest code version that can decode it
 308  * @struct_len: length of struct encoding
 309  */
 310 static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat,
 311                                        u32 struct_len)
 312 {
 313         ceph_encode_8(p, struct_v);
 314         ceph_encode_8(p, struct_compat);
 315         ceph_encode_32(p, struct_len);
 316 }
 317 
 318 /**
 319  * ceph_start_decoding - start decoding block
 320  * @v: current version of the encoding that the code supports
 321  * @name: name of the struct (free-form)
 322  * @struct_v: out param for the encoding version
 323  * @struct_len: out param for the length of struct encoding
 324  *
 325  * Validates the length of struct encoding, so unsafe ceph_decode_*
 326  * variants can be used for decoding.
 327  */
 328 static inline int ceph_start_decoding(void **p, void *end, u8 v,
 329                                       const char *name, u8 *struct_v,
 330                                       u32 *struct_len)
 331 {
 332         u8 struct_compat;
 333 
 334         ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad);
 335         *struct_v = ceph_decode_8(p);
 336         struct_compat = ceph_decode_8(p);
 337         if (v < struct_compat) {
 338                 pr_warn("got struct_v %d struct_compat %d > %d of %s\n",
 339                         *struct_v, struct_compat, v, name);
 340                 return -EINVAL;
 341         }
 342 
 343         *struct_len = ceph_decode_32(p);
 344         ceph_decode_need(p, end, *struct_len, bad);
 345         return 0;
 346 
 347 bad:
 348         return -ERANGE;
 349 }
 350 
 351 #define ceph_encode_need(p, end, n, bad)                        \
 352         do {                                                    \
 353                 if (!likely(ceph_has_room(p, end, n)))          \
 354                         goto bad;                               \
 355         } while (0)
 356 
 357 #define ceph_encode_64_safe(p, end, v, bad)                     \
 358         do {                                                    \
 359                 ceph_encode_need(p, end, sizeof(u64), bad);     \
 360                 ceph_encode_64(p, v);                           \
 361         } while (0)
 362 #define ceph_encode_32_safe(p, end, v, bad)                     \
 363         do {                                                    \
 364                 ceph_encode_need(p, end, sizeof(u32), bad);     \
 365                 ceph_encode_32(p, v);                           \
 366         } while (0)
 367 #define ceph_encode_16_safe(p, end, v, bad)                     \
 368         do {                                                    \
 369                 ceph_encode_need(p, end, sizeof(u16), bad);     \
 370                 ceph_encode_16(p, v);                           \
 371         } while (0)
 372 #define ceph_encode_8_safe(p, end, v, bad)                      \
 373         do {                                                    \
 374                 ceph_encode_need(p, end, sizeof(u8), bad);      \
 375                 ceph_encode_8(p, v);                            \
 376         } while (0)
 377 
 378 #define ceph_encode_copy_safe(p, end, pv, n, bad)               \
 379         do {                                                    \
 380                 ceph_encode_need(p, end, n, bad);               \
 381                 ceph_encode_copy(p, pv, n);                     \
 382         } while (0)
 383 #define ceph_encode_string_safe(p, end, s, n, bad)              \
 384         do {                                                    \
 385                 ceph_encode_need(p, end, n, bad);               \
 386                 ceph_encode_string(p, end, s, n);               \
 387         } while (0)
 388 
 389 
 390 #endif

/* [<][>][^][v][top][bottom][index][help] */