Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 2 | #ifndef __NET_GUE_H |
| 3 | #define __NET_GUE_H |
| 4 | |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 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 contol 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 | |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 33 | struct guehdr { |
| 34 | union { |
| 35 | struct { |
| 36 | #if defined(__LITTLE_ENDIAN_BITFIELD) |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 37 | __u8 hlen:5, |
| 38 | control:1, |
| 39 | version:2; |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 40 | #elif defined (__BIG_ENDIAN_BITFIELD) |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 41 | __u8 version:2, |
| 42 | control:1, |
| 43 | hlen:5; |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 44 | #else |
| 45 | #error "Please fix <asm/byteorder.h>" |
| 46 | #endif |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 47 | __u8 proto_ctype; |
| 48 | __be16 flags; |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 49 | }; |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 50 | __be32 word; |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 51 | }; |
| 52 | }; |
| 53 | |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 54 | /* Standard flags in GUE header */ |
| 55 | |
| 56 | #define GUE_FLAG_PRIV htons(1<<0) /* Private flags are in options */ |
| 57 | #define GUE_LEN_PRIV 4 |
| 58 | |
| 59 | #define GUE_FLAGS_ALL (GUE_FLAG_PRIV) |
| 60 | |
| 61 | /* Private flags in the private option extension */ |
| 62 | |
Tom Herbert | c1aa834 | 2014-11-04 09:06:55 -0800 | [diff] [blame] | 63 | #define GUE_PFLAG_REMCSUM htonl(1 << 31) |
| 64 | #define GUE_PLEN_REMCSUM 4 |
| 65 | |
| 66 | #define GUE_PFLAGS_ALL (GUE_PFLAG_REMCSUM) |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 67 | |
| 68 | /* Functions to compute options length corresponding to flags. |
| 69 | * If we ever have a lot of flags this can be potentially be |
| 70 | * converted to a more optimized algorithm (table lookup |
| 71 | * for instance). |
| 72 | */ |
| 73 | static inline size_t guehdr_flags_len(__be16 flags) |
| 74 | { |
| 75 | return ((flags & GUE_FLAG_PRIV) ? GUE_LEN_PRIV : 0); |
| 76 | } |
| 77 | |
| 78 | static inline size_t guehdr_priv_flags_len(__be32 flags) |
| 79 | { |
| 80 | return 0; |
| 81 | } |
| 82 | |
| 83 | /* Validate standard and private flags. Returns non-zero (meaning invalid) |
| 84 | * if there is an unknown standard or private flags, or the options length for |
| 85 | * the flags exceeds the options length specific in hlen of the GUE header. |
| 86 | */ |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 87 | static inline int validate_gue_flags(struct guehdr *guehdr, size_t optlen) |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 88 | { |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 89 | __be16 flags = guehdr->flags; |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 90 | size_t len; |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 91 | |
| 92 | if (flags & ~GUE_FLAGS_ALL) |
| 93 | return 1; |
| 94 | |
| 95 | len = guehdr_flags_len(flags); |
| 96 | if (len > optlen) |
| 97 | return 1; |
| 98 | |
| 99 | if (flags & GUE_FLAG_PRIV) { |
| 100 | /* Private flags are last four bytes accounted in |
| 101 | * guehdr_flags_len |
| 102 | */ |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 103 | __be32 pflags = *(__be32 *)((void *)&guehdr[1] + |
| 104 | len - GUE_LEN_PRIV); |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 105 | |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 106 | if (pflags & ~GUE_PFLAGS_ALL) |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 107 | return 1; |
| 108 | |
Xin Long | 2008097 | 2017-12-10 16:56:00 +0800 | [diff] [blame] | 109 | len += guehdr_priv_flags_len(pflags); |
Tom Herbert | 5024c33 | 2014-11-04 09:06:53 -0800 | [diff] [blame] | 110 | if (len > optlen) |
| 111 | return 1; |
| 112 | } |
| 113 | |
| 114 | return 0; |
| 115 | } |
| 116 | |
Tom Herbert | 37dd024 | 2014-10-03 15:48:09 -0700 | [diff] [blame] | 117 | #endif |