1#ifndef __CEPH_DECODE_H 2#define __CEPH_DECODE_H 3 4#include <linux/err.h> 5#include <linux/bug.h> 6#include <linux/time.h> 7#include <asm/unaligned.h> 8 9#include <linux/ceph/types.h> 10 11/* 12 * in all cases, 13 * void **p pointer to position pointer 14 * void *end pointer to end of buffer (last byte + 1) 15 */ 16 17static inline u64 ceph_decode_64(void **p) 18{ 19 u64 v = get_unaligned_le64(*p); 20 *p += sizeof(u64); 21 return v; 22} 23static inline u32 ceph_decode_32(void **p) 24{ 25 u32 v = get_unaligned_le32(*p); 26 *p += sizeof(u32); 27 return v; 28} 29static inline u16 ceph_decode_16(void **p) 30{ 31 u16 v = get_unaligned_le16(*p); 32 *p += sizeof(u16); 33 return v; 34} 35static inline u8 ceph_decode_8(void **p) 36{ 37 u8 v = *(u8 *)*p; 38 (*p)++; 39 return v; 40} 41static inline void ceph_decode_copy(void **p, void *pv, size_t n) 42{ 43 memcpy(pv, *p, n); 44 *p += n; 45} 46 47/* 48 * bounds check input. 49 */ 50static inline int ceph_has_room(void **p, void *end, size_t n) 51{ 52 return end >= *p && n <= end - *p; 53} 54 55#define ceph_decode_need(p, end, n, bad) \ 56 do { \ 57 if (!likely(ceph_has_room(p, end, n))) \ 58 goto bad; \ 59 } while (0) 60 61#define ceph_decode_64_safe(p, end, v, bad) \ 62 do { \ 63 ceph_decode_need(p, end, sizeof(u64), bad); \ 64 v = ceph_decode_64(p); \ 65 } while (0) 66#define ceph_decode_32_safe(p, end, v, bad) \ 67 do { \ 68 ceph_decode_need(p, end, sizeof(u32), bad); \ 69 v = ceph_decode_32(p); \ 70 } while (0) 71#define ceph_decode_16_safe(p, end, v, bad) \ 72 do { \ 73 ceph_decode_need(p, end, sizeof(u16), bad); \ 74 v = ceph_decode_16(p); \ 75 } while (0) 76#define ceph_decode_8_safe(p, end, v, bad) \ 77 do { \ 78 ceph_decode_need(p, end, sizeof(u8), bad); \ 79 v = ceph_decode_8(p); \ 80 } while (0) 81 82#define ceph_decode_copy_safe(p, end, pv, n, bad) \ 83 do { \ 84 ceph_decode_need(p, end, n, bad); \ 85 ceph_decode_copy(p, pv, n); \ 86 } while (0) 87 88/* 89 * Allocate a buffer big enough to hold the wire-encoded string, and 90 * decode the string into it. The resulting string will always be 91 * terminated with '\0'. If successful, *p will be advanced 92 * past the decoded data. Also, if lenp is not a null pointer, the 93 * length (not including the terminating '\0') will be recorded in 94 * *lenp. Note that a zero-length string is a valid return value. 95 * 96 * Returns a pointer to the newly-allocated string buffer, or a 97 * pointer-coded errno if an error occurs. Neither *p nor *lenp 98 * will have been updated if an error is returned. 99 * 100 * There are two possible failures: 101 * - converting the string would require accessing memory at or 102 * beyond the "end" pointer provided (-ERANGE) 103 * - memory could not be allocated for the result (-ENOMEM) 104 */ 105static inline char *ceph_extract_encoded_string(void **p, void *end, 106 size_t *lenp, gfp_t gfp) 107{ 108 u32 len; 109 void *sp = *p; 110 char *buf; 111 112 ceph_decode_32_safe(&sp, end, len, bad); 113 if (!ceph_has_room(&sp, end, len)) 114 goto bad; 115 116 buf = kmalloc(len + 1, gfp); 117 if (!buf) 118 return ERR_PTR(-ENOMEM); 119 120 if (len) 121 memcpy(buf, sp, len); 122 buf[len] = '\0'; 123 124 *p = (char *) *p + sizeof (u32) + len; 125 if (lenp) 126 *lenp = (size_t) len; 127 128 return buf; 129 130bad: 131 return ERR_PTR(-ERANGE); 132} 133 134/* 135 * struct ceph_timespec <-> struct timespec 136 */ 137static inline void ceph_decode_timespec(struct timespec *ts, 138 const struct ceph_timespec *tv) 139{ 140 ts->tv_sec = (__kernel_time_t)le32_to_cpu(tv->tv_sec); 141 ts->tv_nsec = (long)le32_to_cpu(tv->tv_nsec); 142} 143static inline void ceph_encode_timespec(struct ceph_timespec *tv, 144 const struct timespec *ts) 145{ 146 tv->tv_sec = cpu_to_le32((u32)ts->tv_sec); 147 tv->tv_nsec = cpu_to_le32((u32)ts->tv_nsec); 148} 149 150/* 151 * sockaddr_storage <-> ceph_sockaddr 152 */ 153static inline void ceph_encode_addr(struct ceph_entity_addr *a) 154{ 155 __be16 ss_family = htons(a->in_addr.ss_family); 156 a->in_addr.ss_family = *(__u16 *)&ss_family; 157} 158static inline void ceph_decode_addr(struct ceph_entity_addr *a) 159{ 160 __be16 ss_family = *(__be16 *)&a->in_addr.ss_family; 161 a->in_addr.ss_family = ntohs(ss_family); 162 WARN_ON(a->in_addr.ss_family == 512); 163} 164 165/* 166 * encoders 167 */ 168static inline void ceph_encode_64(void **p, u64 v) 169{ 170 put_unaligned_le64(v, (__le64 *)*p); 171 *p += sizeof(u64); 172} 173static inline void ceph_encode_32(void **p, u32 v) 174{ 175 put_unaligned_le32(v, (__le32 *)*p); 176 *p += sizeof(u32); 177} 178static inline void ceph_encode_16(void **p, u16 v) 179{ 180 put_unaligned_le16(v, (__le16 *)*p); 181 *p += sizeof(u16); 182} 183static inline void ceph_encode_8(void **p, u8 v) 184{ 185 *(u8 *)*p = v; 186 (*p)++; 187} 188static inline void ceph_encode_copy(void **p, const void *s, int len) 189{ 190 memcpy(*p, s, len); 191 *p += len; 192} 193 194/* 195 * filepath, string encoders 196 */ 197static inline void ceph_encode_filepath(void **p, void *end, 198 u64 ino, const char *path) 199{ 200 u32 len = path ? strlen(path) : 0; 201 BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end); 202 ceph_encode_8(p, 1); 203 ceph_encode_64(p, ino); 204 ceph_encode_32(p, len); 205 if (len) 206 memcpy(*p, path, len); 207 *p += len; 208} 209 210static inline void ceph_encode_string(void **p, void *end, 211 const char *s, u32 len) 212{ 213 BUG_ON(*p + sizeof(len) + len > end); 214 ceph_encode_32(p, len); 215 if (len) 216 memcpy(*p, s, len); 217 *p += len; 218} 219 220#define ceph_encode_need(p, end, n, bad) \ 221 do { \ 222 if (!likely(ceph_has_room(p, end, n))) \ 223 goto bad; \ 224 } while (0) 225 226#define ceph_encode_64_safe(p, end, v, bad) \ 227 do { \ 228 ceph_encode_need(p, end, sizeof(u64), bad); \ 229 ceph_encode_64(p, v); \ 230 } while (0) 231#define ceph_encode_32_safe(p, end, v, bad) \ 232 do { \ 233 ceph_encode_need(p, end, sizeof(u32), bad); \ 234 ceph_encode_32(p, v); \ 235 } while (0) 236#define ceph_encode_16_safe(p, end, v, bad) \ 237 do { \ 238 ceph_encode_need(p, end, sizeof(u16), bad); \ 239 ceph_encode_16(p, v); \ 240 } while (0) 241#define ceph_encode_8_safe(p, end, v, bad) \ 242 do { \ 243 ceph_encode_need(p, end, sizeof(u8), bad); \ 244 ceph_encode_8(p, v); \ 245 } while (0) 246 247#define ceph_encode_copy_safe(p, end, pv, n, bad) \ 248 do { \ 249 ceph_encode_need(p, end, n, bad); \ 250 ceph_encode_copy(p, pv, n); \ 251 } while (0) 252#define ceph_encode_string_safe(p, end, s, n, bad) \ 253 do { \ 254 ceph_encode_need(p, end, n, bad); \ 255 ceph_encode_string(p, end, s, n); \ 256 } while (0) 257 258 259#endif 260