1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
237dd0247STom Herbert #ifndef __NET_GUE_H
337dd0247STom Herbert #define __NET_GUE_H
437dd0247STom Herbert
55024c33aSTom Herbert /* Definitions for the GUE header, standard and private flags, lengths
65024c33aSTom Herbert * of optional fields are below.
75024c33aSTom Herbert *
85024c33aSTom Herbert * Diagram of GUE header:
95024c33aSTom Herbert *
105024c33aSTom Herbert * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115024c33aSTom Herbert * |Ver|C| Hlen | Proto/ctype | Standard flags |P|
125024c33aSTom Herbert * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135024c33aSTom Herbert * | |
145024c33aSTom Herbert * ~ Fields (optional) ~
155024c33aSTom Herbert * | |
165024c33aSTom Herbert * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175024c33aSTom Herbert * | Private flags (optional, P bit is set) |
185024c33aSTom Herbert * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195024c33aSTom Herbert * | |
205024c33aSTom Herbert * ~ Private fields (optional) ~
215024c33aSTom Herbert * | |
225024c33aSTom Herbert * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
235024c33aSTom Herbert *
2426ac10beSAiden Leong * C bit indicates control message when set, data message when unset.
255024c33aSTom Herbert * For a control message, proto/ctype is interpreted as a type of
265024c33aSTom Herbert * control message. For data messages, proto/ctype is the IP protocol
275024c33aSTom Herbert * of the next header.
285024c33aSTom Herbert *
295024c33aSTom Herbert * P bit indicates private flags field is present. The private flags
305024c33aSTom Herbert * may refer to options placed after this field.
315024c33aSTom Herbert */
325024c33aSTom Herbert
33*949d6b40SJakub Kicinski #include <asm/byteorder.h>
34*949d6b40SJakub Kicinski #include <linux/types.h>
35*949d6b40SJakub Kicinski
3637dd0247STom Herbert struct guehdr {
3737dd0247STom Herbert union {
3837dd0247STom Herbert struct {
3937dd0247STom Herbert #if defined(__LITTLE_ENDIAN_BITFIELD)
405024c33aSTom Herbert __u8 hlen:5,
415024c33aSTom Herbert control:1,
425024c33aSTom Herbert version:2;
4337dd0247STom Herbert #elif defined (__BIG_ENDIAN_BITFIELD)
445024c33aSTom Herbert __u8 version:2,
455024c33aSTom Herbert control:1,
465024c33aSTom Herbert hlen:5;
4737dd0247STom Herbert #else
4837dd0247STom Herbert #error "Please fix <asm/byteorder.h>"
4937dd0247STom Herbert #endif
505024c33aSTom Herbert __u8 proto_ctype;
5120080971SXin Long __be16 flags;
5237dd0247STom Herbert };
5320080971SXin Long __be32 word;
5437dd0247STom Herbert };
5537dd0247STom Herbert };
5637dd0247STom Herbert
575024c33aSTom Herbert /* Standard flags in GUE header */
585024c33aSTom Herbert
595024c33aSTom Herbert #define GUE_FLAG_PRIV htons(1<<0) /* Private flags are in options */
605024c33aSTom Herbert #define GUE_LEN_PRIV 4
615024c33aSTom Herbert
625024c33aSTom Herbert #define GUE_FLAGS_ALL (GUE_FLAG_PRIV)
635024c33aSTom Herbert
645024c33aSTom Herbert /* Private flags in the private option extension */
655024c33aSTom Herbert
6688405680SVandana BN #define GUE_PFLAG_REMCSUM htonl(1U << 31)
67c1aa8347STom Herbert #define GUE_PLEN_REMCSUM 4
68c1aa8347STom Herbert
69c1aa8347STom Herbert #define GUE_PFLAGS_ALL (GUE_PFLAG_REMCSUM)
705024c33aSTom Herbert
715024c33aSTom Herbert /* Functions to compute options length corresponding to flags.
725024c33aSTom Herbert * If we ever have a lot of flags this can be potentially be
735024c33aSTom Herbert * converted to a more optimized algorithm (table lookup
745024c33aSTom Herbert * for instance).
755024c33aSTom Herbert */
guehdr_flags_len(__be16 flags)765024c33aSTom Herbert static inline size_t guehdr_flags_len(__be16 flags)
775024c33aSTom Herbert {
785024c33aSTom Herbert return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0);
795024c33aSTom Herbert }
805024c33aSTom Herbert
guehdr_priv_flags_len(__be32 flags)815024c33aSTom Herbert static inline size_t guehdr_priv_flags_len(__be32 flags)
825024c33aSTom Herbert {
835024c33aSTom Herbert return 0;
845024c33aSTom Herbert }
855024c33aSTom Herbert
865024c33aSTom Herbert /* Validate standard and private flags. Returns non-zero (meaning invalid)
875024c33aSTom Herbert * if there is an unknown standard or private flags, or the options length for
885024c33aSTom Herbert * the flags exceeds the options length specific in hlen of the GUE header.
895024c33aSTom Herbert */
validate_gue_flags(struct guehdr * guehdr,size_t optlen)9020080971SXin Long static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen)
915024c33aSTom Herbert {
9220080971SXin Long __be16 flags = guehdr->flags;
935024c33aSTom Herbert size_t len;
945024c33aSTom Herbert
955024c33aSTom Herbert if (flags & ~GUE_FLAGS_ALL)
965024c33aSTom Herbert return 1;
975024c33aSTom Herbert
985024c33aSTom Herbert len = guehdr_flags_len(flags);
995024c33aSTom Herbert if (len > optlen)
1005024c33aSTom Herbert return 1;
1015024c33aSTom Herbert
1025024c33aSTom Herbert if (flags & GUE_FLAG_PRIV) {
1035024c33aSTom Herbert /* Private flags are last four bytes accounted in
1045024c33aSTom Herbert * guehdr_flags_len
1055024c33aSTom Herbert */
10620080971SXin Long __be32 pflags = *(__be32 *)((void *)&guehdr[1] +
10720080971SXin Long len - GUE_LEN_PRIV);
1085024c33aSTom Herbert
10920080971SXin Long if (pflags & ~GUE_PFLAGS_ALL)
1105024c33aSTom Herbert return 1;
1115024c33aSTom Herbert
11220080971SXin Long len += guehdr_priv_flags_len(pflags);
1135024c33aSTom Herbert if (len > optlen)
1145024c33aSTom Herbert return 1;
1155024c33aSTom Herbert }
1165024c33aSTom Herbert
1175024c33aSTom Herbert return 0;
1185024c33aSTom Herbert }
1195024c33aSTom Herbert
12037dd0247STom Herbert #endif
121