1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __NET_GUE_H 3 #define __NET_GUE_H 4 5 /* Definitions for the GUE header, standard and private flags, lengths 6 * of optional fields are below. 7 * 8 * Diagram of GUE header: 9 * 10 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 11 * |Ver|C| Hlen | Proto/ctype | Standard flags |P| 12 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 13 * | | 14 * ~ Fields (optional) ~ 15 * | | 16 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 17 * | Private flags (optional, P bit is set) | 18 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 19 * | | 20 * ~ Private fields (optional) ~ 21 * | | 22 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 23 * 24 * C bit indicates control message when set, data message when unset. 25 * For a control message, proto/ctype is interpreted as a type of 26 * control message. For data messages, proto/ctype is the IP protocol 27 * of the next header. 28 * 29 * P bit indicates private flags field is present. The private flags 30 * may refer to options placed after this field. 31 */ 32 33 #include <asm/byteorder.h> 34 #include <linux/types.h> 35 36 struct guehdr { 37 union { 38 struct { 39 #if defined(__LITTLE_ENDIAN_BITFIELD) 40 __u8 hlen:5, 41 control:1, 42 version:2; 43 #elif defined (__BIG_ENDIAN_BITFIELD) 44 __u8 version:2, 45 control:1, 46 hlen:5; 47 #else 48 #error "Please fix <asm/byteorder.h>" 49 #endif 50 __u8 proto_ctype; 51 __be16 flags; 52 }; 53 __be32 word; 54 }; 55 }; 56 57 /* Standard flags in GUE header */ 58 59 #define GUE_FLAG_PRIV htons(1<<0) /* Private flags are in options */ 60 #define GUE_LEN_PRIV 4 61 62 #define GUE_FLAGS_ALL (GUE_FLAG_PRIV) 63 64 /* Private flags in the private option extension */ 65 66 #define GUE_PFLAG_REMCSUM htonl(1U << 31) 67 #define GUE_PLEN_REMCSUM 4 68 69 #define GUE_PFLAGS_ALL (GUE_PFLAG_REMCSUM) 70 71 /* Functions to compute options length corresponding to flags. 72 * If we ever have a lot of flags this can be potentially be 73 * converted to a more optimized algorithm (table lookup 74 * for instance). 75 */ 76 static inline size_t guehdr_flags_len(__be16 flags) 77 { 78 return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0); 79 } 80 81 static inline size_t guehdr_priv_flags_len(__be32 flags) 82 { 83 return (flags & GUE_PFLAG_REMCSUM) ? GUE_PLEN_REMCSUM : 0; 84 } 85 86 /* Validate standard and private flags. Returns non-zero (meaning invalid) 87 * if there is an unknown standard or private flags, if the options length for 88 * the flags exceeds the options length specified in hlen of the GUE header, or 89 * if a private option contains invalid data. 90 */ 91 static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen) 92 { 93 __be16 flags = guehdr->flags; 94 size_t len; 95 96 if (flags & ~GUE_FLAGS_ALL) 97 return 1; 98 99 len = guehdr_flags_len(flags); 100 if (len > optlen) 101 return 1; 102 103 if (flags & GUE_FLAG_PRIV) { 104 /* Private flags are last four bytes accounted in 105 * guehdr_flags_len 106 */ 107 void *data = (void *)&guehdr[1] + len; 108 __be32 pflags = *(__be32 *)(data - GUE_LEN_PRIV); 109 110 if (pflags & ~GUE_PFLAGS_ALL) 111 return 1; 112 113 len += guehdr_priv_flags_len(pflags); 114 if (len > optlen) 115 return 1; 116 117 if (pflags & GUE_PFLAG_REMCSUM) { 118 __be16 *pd = data; 119 120 /* The field offset pd[1] must not be less 121 * than the start pd[0]. 122 */ 123 if (ntohs(pd[1]) < ntohs(pd[0])) 124 return 1; 125 } 126 } 127 128 return 0; 129 } 130 131 #endif 132