| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef __NET_GUE_H | |
| #define __NET_GUE_H | |
| /* Definitions for the GUE header, standard and private flags, lengths | |
| * of optional fields are below. | |
| * | |
| * Diagram of GUE header: | |
| * | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| * |Ver|C| Hlen | Proto/ctype | Standard flags |P| | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| * | | | |
| * ~ Fields (optional) ~ | |
| * | | | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| * | Private flags (optional, P bit is set) | | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| * | | | |
| * ~ Private fields (optional) ~ | |
| * | | | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| * | |
| * C bit indicates control message when set, data message when unset. | |
| * For a control message, proto/ctype is interpreted as a type of | |
| * control message. For data messages, proto/ctype is the IP protocol | |
| * of the next header. | |
| * | |
| * P bit indicates private flags field is present. The private flags | |
| * may refer to options placed after this field. | |
| */ | |
| #include <asm/byteorder.h> | |
| #include <linux/types.h> | |
| struct guehdr { | |
| union { | |
| struct { | |
| #if defined(__LITTLE_ENDIAN_BITFIELD) | |
| __u8 hlen:5, | |
| control:1, | |
| version:2; | |
| #elif defined (__BIG_ENDIAN_BITFIELD) | |
| __u8 version:2, | |
| control:1, | |
| hlen:5; | |
| #else | |
| #error "Please fix <asm/byteorder.h>" | |
| #endif | |
| __u8 proto_ctype; | |
| __be16 flags; | |
| }; | |
| __be32 word; | |
| }; | |
| }; | |
| /* Standard flags in GUE header */ | |
| #define GUE_FLAG_PRIV htons(1<<0) /* Private flags are in options */ | |
| #define GUE_LEN_PRIV 4 | |
| #define GUE_FLAGS_ALL (GUE_FLAG_PRIV) | |
| /* Private flags in the private option extension */ | |
| #define GUE_PFLAG_REMCSUM htonl(1U << 31) | |
| #define GUE_PLEN_REMCSUM 4 | |
| #define GUE_PFLAGS_ALL (GUE_PFLAG_REMCSUM) | |
| /* Functions to compute options length corresponding to flags. | |
| * If we ever have a lot of flags this can be potentially be | |
| * converted to a more optimized algorithm (table lookup | |
| * for instance). | |
| */ | |
| static inline size_t guehdr_flags_len(__be16 flags) | |
| { | |
| return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0); | |
| } | |
| static inline size_t guehdr_priv_flags_len(__be32 flags) | |
| { | |
| return (flags & GUE_PFLAG_REMCSUM) ? GUE_PLEN_REMCSUM : 0; | |
| } | |
| /* Validate standard and private flags. Returns non-zero (meaning invalid) | |
| * if there is an unknown standard or private flags, or the options length for | |
| * the flags exceeds the options length specific in hlen of the GUE header. | |
| */ | |
| static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen) | |
| { | |
| __be16 flags = guehdr->flags; | |
| size_t len; | |
| if (flags & ~GUE_FLAGS_ALL) | |
| return 1; | |
| len = guehdr_flags_len(flags); | |
| if (len > optlen) | |
| return 1; | |
| if (flags & GUE_FLAG_PRIV) { | |
| /* Private flags are last four bytes accounted in | |
| * guehdr_flags_len | |
| */ | |
| __be32 pflags = *(__be32 *)((void *)&guehdr[1] + | |
| len - GUE_LEN_PRIV); | |
| if (pflags & ~GUE_PFLAGS_ALL) | |
| return 1; | |
| len += guehdr_priv_flags_len(pflags); | |
| if (len > optlen) | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| #endif |