121 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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 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
 |