brintos

brintos / linux-shallow public Read only

0
0
Text · 9.9 KiB · 8fc1aed Raw
399 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#ifndef __CEPH_DECODE_H3#define __CEPH_DECODE_H4 5#include <linux/err.h>6#include <linux/bug.h>7#include <linux/slab.h>8#include <linux/time.h>9#include <linux/unaligned.h>10 11#include <linux/ceph/types.h>12 13/*14 * in all cases,15 *   void **p     pointer to position pointer16 *   void *end    pointer to end of buffer (last byte + 1)17 */18 19static inline u64 ceph_decode_64(void **p)20{21	u64 v = get_unaligned_le64(*p);22	*p += sizeof(u64);23	return v;24}25static inline u32 ceph_decode_32(void **p)26{27	u32 v = get_unaligned_le32(*p);28	*p += sizeof(u32);29	return v;30}31static inline u16 ceph_decode_16(void **p)32{33	u16 v = get_unaligned_le16(*p);34	*p += sizeof(u16);35	return v;36}37static inline u8 ceph_decode_8(void **p)38{39	u8 v = *(u8 *)*p;40	(*p)++;41	return v;42}43static 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 */52static 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, and92 * decode the string into it.  The resulting string will always be93 * terminated with '\0'.  If successful, *p will be advanced94 * past the decoded data.  Also, if lenp is not a null pointer, the95 * length (not including the terminating '\0') will be recorded in96 * *lenp.  Note that a zero-length string is a valid return value.97 *98 * Returns a pointer to the newly-allocated string buffer, or a99 * pointer-coded errno if an error occurs.  Neither *p nor *lenp100 * 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 or104 *     beyond the "end" pointer provided (-ERANGE)105 *   - memory could not be allocated for the result (-ENOMEM)106 */107static 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 132bad:133	return ERR_PTR(-ERANGE);134}135 136/*137 * skip helpers138 */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)			\146ceph_decode_skip_n(p, end, sizeof(u64), bad)147 148#define ceph_decode_skip_32(p, end, bad)			\149ceph_decode_skip_n(p, end, sizeof(u32), bad)150 151#define ceph_decode_skip_16(p, end, bad)			\152ceph_decode_skip_n(p, end, sizeof(u16), bad)153 154#define ceph_decode_skip_8(p, end, bad)				\155ceph_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 timespec64198 */199static 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 extend204	 * the protocol to steal two more bits from tv_nsec to205	 * add three more 136 year epochs after that the way ext4206	 * 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}211static 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_sockaddr220 */221#define CEPH_ENTITY_ADDR_TYPE_NONE	0222#define CEPH_ENTITY_ADDR_TYPE_LEGACY	__cpu_to_le32(1)223#define CEPH_ENTITY_ADDR_TYPE_MSGR2	__cpu_to_le32(2)224#define CEPH_ENTITY_ADDR_TYPE_ANY	__cpu_to_le32(3)225 226static inline void ceph_encode_banner_addr(struct ceph_entity_addr *a)227{228	__be16 ss_family = htons(a->in_addr.ss_family);229	a->in_addr.ss_family = *(__u16 *)&ss_family;230 231	/* Banner addresses require TYPE_NONE */232	a->type = CEPH_ENTITY_ADDR_TYPE_NONE;233}234static inline void ceph_decode_banner_addr(struct ceph_entity_addr *a)235{236	__be16 ss_family = *(__be16 *)&a->in_addr.ss_family;237	a->in_addr.ss_family = ntohs(ss_family);238	WARN_ON(a->in_addr.ss_family == 512);239	a->type = CEPH_ENTITY_ADDR_TYPE_LEGACY;240}241 242extern int ceph_decode_entity_addr(void **p, void *end,243				   struct ceph_entity_addr *addr);244int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,245			       struct ceph_entity_addr *addr);246 247int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr);248void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr);249 250/*251 * encoders252 */253static inline void ceph_encode_64(void **p, u64 v)254{255	put_unaligned_le64(v, (__le64 *)*p);256	*p += sizeof(u64);257}258static inline void ceph_encode_32(void **p, u32 v)259{260	put_unaligned_le32(v, (__le32 *)*p);261	*p += sizeof(u32);262}263static inline void ceph_encode_16(void **p, u16 v)264{265	put_unaligned_le16(v, (__le16 *)*p);266	*p += sizeof(u16);267}268static inline void ceph_encode_8(void **p, u8 v)269{270	*(u8 *)*p = v;271	(*p)++;272}273static inline void ceph_encode_copy(void **p, const void *s, int len)274{275	memcpy(*p, s, len);276	*p += len;277}278 279/*280 * filepath, string encoders281 */282static inline void ceph_encode_filepath(void **p, void *end,283					u64 ino, const char *path)284{285	u32 len = path ? strlen(path) : 0;286	BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end);287	ceph_encode_8(p, 1);288	ceph_encode_64(p, ino);289	ceph_encode_32(p, len);290	if (len)291		memcpy(*p, path, len);292	*p += len;293}294 295static inline void ceph_encode_string(void **p, void *end,296				      const char *s, u32 len)297{298	BUG_ON(*p + sizeof(len) + len > end);299	ceph_encode_32(p, len);300	if (len)301		memcpy(*p, s, len);302	*p += len;303}304 305/*306 * version and length starting block encoders/decoders307 */308 309/* current code version (u8) + compat code version (u8) + len of struct (u32) */310#define CEPH_ENCODING_START_BLK_LEN 6311 312/**313 * ceph_start_encoding - start encoding block314 * @struct_v: current (code) version of the encoding315 * @struct_compat: oldest code version that can decode it316 * @struct_len: length of struct encoding317 */318static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat,319				       u32 struct_len)320{321	ceph_encode_8(p, struct_v);322	ceph_encode_8(p, struct_compat);323	ceph_encode_32(p, struct_len);324}325 326/**327 * ceph_start_decoding - start decoding block328 * @v: current version of the encoding that the code supports329 * @name: name of the struct (free-form)330 * @struct_v: out param for the encoding version331 * @struct_len: out param for the length of struct encoding332 *333 * Validates the length of struct encoding, so unsafe ceph_decode_*334 * variants can be used for decoding.335 */336static inline int ceph_start_decoding(void **p, void *end, u8 v,337				      const char *name, u8 *struct_v,338				      u32 *struct_len)339{340	u8 struct_compat;341 342	ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad);343	*struct_v = ceph_decode_8(p);344	struct_compat = ceph_decode_8(p);345	if (v < struct_compat) {346		pr_warn("got struct_v %d struct_compat %d > %d of %s\n",347			*struct_v, struct_compat, v, name);348		return -EINVAL;349	}350 351	*struct_len = ceph_decode_32(p);352	ceph_decode_need(p, end, *struct_len, bad);353	return 0;354 355bad:356	return -ERANGE;357}358 359#define ceph_encode_need(p, end, n, bad)			\360	do {							\361		if (!likely(ceph_has_room(p, end, n)))		\362			goto bad;				\363	} while (0)364 365#define ceph_encode_64_safe(p, end, v, bad)			\366	do {							\367		ceph_encode_need(p, end, sizeof(u64), bad);	\368		ceph_encode_64(p, v);				\369	} while (0)370#define ceph_encode_32_safe(p, end, v, bad)			\371	do {							\372		ceph_encode_need(p, end, sizeof(u32), bad);	\373		ceph_encode_32(p, v);				\374	} while (0)375#define ceph_encode_16_safe(p, end, v, bad)			\376	do {							\377		ceph_encode_need(p, end, sizeof(u16), bad);	\378		ceph_encode_16(p, v);				\379	} while (0)380#define ceph_encode_8_safe(p, end, v, bad)			\381	do {							\382		ceph_encode_need(p, end, sizeof(u8), bad);	\383		ceph_encode_8(p, v);				\384	} while (0)385 386#define ceph_encode_copy_safe(p, end, pv, n, bad)		\387	do {							\388		ceph_encode_need(p, end, n, bad);		\389		ceph_encode_copy(p, pv, n);			\390	} while (0)391#define ceph_encode_string_safe(p, end, s, n, bad)		\392	do {							\393		ceph_encode_need(p, end, n, bad);		\394		ceph_encode_string(p, end, s, n);		\395	} while (0)396 397 398#endif399