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 17 static inline u64 ceph_decode_64(void **p) 18 { 19 u64 v = get_unaligned_le64(*p); 20 *p += sizeof(u64); 21 return v; 22 } 23 static inline u32 ceph_decode_32(void **p) 24 { 25 u32 v = get_unaligned_le32(*p); 26 *p += sizeof(u32); 27 return v; 28 } 29 static inline u16 ceph_decode_16(void **p) 30 { 31 u16 v = get_unaligned_le16(*p); 32 *p += sizeof(u16); 33 return v; 34 } 35 static inline u8 ceph_decode_8(void **p) 36 { 37 u8 v = *(u8 *)*p; 38 (*p)++; 39 return v; 40 } 41 static 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 */ 50 static 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 */ 105 static 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 130 bad: 131 return ERR_PTR(-ERANGE); 132 } 133 134 /* 135 * struct ceph_timespec <-> struct timespec 136 */ 137 static 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 } 143 static 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 */ 153 static 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 } 158 static 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 */ 168 static inline void ceph_encode_64(void **p, u64 v) 169 { 170 put_unaligned_le64(v, (__le64 *)*p); 171 *p += sizeof(u64); 172 } 173 static inline void ceph_encode_32(void **p, u32 v) 174 { 175 put_unaligned_le32(v, (__le32 *)*p); 176 *p += sizeof(u32); 177 } 178 static inline void ceph_encode_16(void **p, u16 v) 179 { 180 put_unaligned_le16(v, (__le16 *)*p); 181 *p += sizeof(u16); 182 } 183 static inline void ceph_encode_8(void **p, u8 v) 184 { 185 *(u8 *)*p = v; 186 (*p)++; 187 } 188 static 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 */ 197 static 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 210 static 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