18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __NET_GUE_H
38c2ecf20Sopenharmony_ci#define __NET_GUE_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/* Definitions for the GUE header, standard and private flags, lengths
68c2ecf20Sopenharmony_ci * of optional fields are below.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Diagram of GUE header:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118c2ecf20Sopenharmony_ci * |Ver|C|  Hlen   | Proto/ctype   |        Standard flags       |P|
128c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138c2ecf20Sopenharmony_ci * |                                                               |
148c2ecf20Sopenharmony_ci * ~                      Fields (optional)                        ~
158c2ecf20Sopenharmony_ci * |                                                               |
168c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178c2ecf20Sopenharmony_ci * |            Private flags (optional, P bit is set)             |
188c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198c2ecf20Sopenharmony_ci * |                                                               |
208c2ecf20Sopenharmony_ci * ~                   Private fields (optional)                   ~
218c2ecf20Sopenharmony_ci * |                                                               |
228c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * C bit indicates control message when set, data message when unset.
258c2ecf20Sopenharmony_ci * For a control message, proto/ctype is interpreted as a type of
268c2ecf20Sopenharmony_ci * control message. For data messages, proto/ctype is the IP protocol
278c2ecf20Sopenharmony_ci * of the next header.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * P bit indicates private flags field is present. The private flags
308c2ecf20Sopenharmony_ci * may refer to options placed after this field.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct guehdr {
348c2ecf20Sopenharmony_ci	union {
358c2ecf20Sopenharmony_ci		struct {
368c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD)
378c2ecf20Sopenharmony_ci			__u8	hlen:5,
388c2ecf20Sopenharmony_ci				control:1,
398c2ecf20Sopenharmony_ci				version:2;
408c2ecf20Sopenharmony_ci#elif defined (__BIG_ENDIAN_BITFIELD)
418c2ecf20Sopenharmony_ci			__u8	version:2,
428c2ecf20Sopenharmony_ci				control:1,
438c2ecf20Sopenharmony_ci				hlen:5;
448c2ecf20Sopenharmony_ci#else
458c2ecf20Sopenharmony_ci#error  "Please fix <asm/byteorder.h>"
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci			__u8	proto_ctype;
488c2ecf20Sopenharmony_ci			__be16	flags;
498c2ecf20Sopenharmony_ci		};
508c2ecf20Sopenharmony_ci		__be32	word;
518c2ecf20Sopenharmony_ci	};
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Standard flags in GUE header */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define GUE_FLAG_PRIV	htons(1<<0)	/* Private flags are in options */
578c2ecf20Sopenharmony_ci#define GUE_LEN_PRIV	4
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define GUE_FLAGS_ALL	(GUE_FLAG_PRIV)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* Private flags in the private option extension */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define GUE_PFLAG_REMCSUM	htonl(1U << 31)
648c2ecf20Sopenharmony_ci#define GUE_PLEN_REMCSUM	4
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define GUE_PFLAGS_ALL	(GUE_PFLAG_REMCSUM)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* Functions to compute options length corresponding to flags.
698c2ecf20Sopenharmony_ci * If we ever have a lot of flags this can be potentially be
708c2ecf20Sopenharmony_ci * converted to a more optimized algorithm (table lookup
718c2ecf20Sopenharmony_ci * for instance).
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_cistatic inline size_t guehdr_flags_len(__be16 flags)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline size_t guehdr_priv_flags_len(__be32 flags)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Validate standard and private flags. Returns non-zero (meaning invalid)
848c2ecf20Sopenharmony_ci * if there is an unknown standard or private flags, or the options length for
858c2ecf20Sopenharmony_ci * the flags exceeds the options length specific in hlen of the GUE header.
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	__be16 flags = guehdr->flags;
908c2ecf20Sopenharmony_ci	size_t len;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (flags & ~GUE_FLAGS_ALL)
938c2ecf20Sopenharmony_ci		return 1;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	len = guehdr_flags_len(flags);
968c2ecf20Sopenharmony_ci	if (len > optlen)
978c2ecf20Sopenharmony_ci		return 1;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (flags & GUE_FLAG_PRIV) {
1008c2ecf20Sopenharmony_ci		/* Private flags are last four bytes accounted in
1018c2ecf20Sopenharmony_ci		 * guehdr_flags_len
1028c2ecf20Sopenharmony_ci		 */
1038c2ecf20Sopenharmony_ci		__be32 pflags = *(__be32 *)((void *)&guehdr[1] +
1048c2ecf20Sopenharmony_ci					    len - GUE_LEN_PRIV);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		if (pflags & ~GUE_PFLAGS_ALL)
1078c2ecf20Sopenharmony_ci			return 1;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		len += guehdr_priv_flags_len(pflags);
1108c2ecf20Sopenharmony_ci		if (len > optlen)
1118c2ecf20Sopenharmony_ci			return 1;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#endif
118