162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __NET_GUE_H
362306a36Sopenharmony_ci#define __NET_GUE_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/* Definitions for the GUE header, standard and private flags, lengths
662306a36Sopenharmony_ci * of optional fields are below.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Diagram of GUE header:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1162306a36Sopenharmony_ci * |Ver|C|  Hlen   | Proto/ctype   |        Standard flags       |P|
1262306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1362306a36Sopenharmony_ci * |                                                               |
1462306a36Sopenharmony_ci * ~                      Fields (optional)                        ~
1562306a36Sopenharmony_ci * |                                                               |
1662306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1762306a36Sopenharmony_ci * |            Private flags (optional, P bit is set)             |
1862306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1962306a36Sopenharmony_ci * |                                                               |
2062306a36Sopenharmony_ci * ~                   Private fields (optional)                   ~
2162306a36Sopenharmony_ci * |                                                               |
2262306a36Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * C bit indicates control message when set, data message when unset.
2562306a36Sopenharmony_ci * For a control message, proto/ctype is interpreted as a type of
2662306a36Sopenharmony_ci * control message. For data messages, proto/ctype is the IP protocol
2762306a36Sopenharmony_ci * of the next header.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * P bit indicates private flags field is present. The private flags
3062306a36Sopenharmony_ci * may refer to options placed after this field.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <asm/byteorder.h>
3462306a36Sopenharmony_ci#include <linux/types.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct guehdr {
3762306a36Sopenharmony_ci	union {
3862306a36Sopenharmony_ci		struct {
3962306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD)
4062306a36Sopenharmony_ci			__u8	hlen:5,
4162306a36Sopenharmony_ci				control:1,
4262306a36Sopenharmony_ci				version:2;
4362306a36Sopenharmony_ci#elif defined (__BIG_ENDIAN_BITFIELD)
4462306a36Sopenharmony_ci			__u8	version:2,
4562306a36Sopenharmony_ci				control:1,
4662306a36Sopenharmony_ci				hlen:5;
4762306a36Sopenharmony_ci#else
4862306a36Sopenharmony_ci#error  "Please fix <asm/byteorder.h>"
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci			__u8	proto_ctype;
5162306a36Sopenharmony_ci			__be16	flags;
5262306a36Sopenharmony_ci		};
5362306a36Sopenharmony_ci		__be32	word;
5462306a36Sopenharmony_ci	};
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Standard flags in GUE header */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define GUE_FLAG_PRIV	htons(1<<0)	/* Private flags are in options */
6062306a36Sopenharmony_ci#define GUE_LEN_PRIV	4
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define GUE_FLAGS_ALL	(GUE_FLAG_PRIV)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Private flags in the private option extension */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define GUE_PFLAG_REMCSUM	htonl(1U << 31)
6762306a36Sopenharmony_ci#define GUE_PLEN_REMCSUM	4
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define GUE_PFLAGS_ALL	(GUE_PFLAG_REMCSUM)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Functions to compute options length corresponding to flags.
7262306a36Sopenharmony_ci * If we ever have a lot of flags this can be potentially be
7362306a36Sopenharmony_ci * converted to a more optimized algorithm (table lookup
7462306a36Sopenharmony_ci * for instance).
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic inline size_t guehdr_flags_len(__be16 flags)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline size_t guehdr_priv_flags_len(__be32 flags)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	return 0;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* Validate standard and private flags. Returns non-zero (meaning invalid)
8762306a36Sopenharmony_ci * if there is an unknown standard or private flags, or the options length for
8862306a36Sopenharmony_ci * the flags exceeds the options length specific in hlen of the GUE header.
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	__be16 flags = guehdr->flags;
9362306a36Sopenharmony_ci	size_t len;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (flags & ~GUE_FLAGS_ALL)
9662306a36Sopenharmony_ci		return 1;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	len = guehdr_flags_len(flags);
9962306a36Sopenharmony_ci	if (len > optlen)
10062306a36Sopenharmony_ci		return 1;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (flags & GUE_FLAG_PRIV) {
10362306a36Sopenharmony_ci		/* Private flags are last four bytes accounted in
10462306a36Sopenharmony_ci		 * guehdr_flags_len
10562306a36Sopenharmony_ci		 */
10662306a36Sopenharmony_ci		__be32 pflags = *(__be32 *)((void *)&guehdr[1] +
10762306a36Sopenharmony_ci					    len - GUE_LEN_PRIV);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		if (pflags & ~GUE_PFLAGS_ALL)
11062306a36Sopenharmony_ci			return 1;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		len += guehdr_priv_flags_len(pflags);
11362306a36Sopenharmony_ci		if (len > optlen)
11462306a36Sopenharmony_ci			return 1;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return 0;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#endif
121