| /* SPDX-License-Identifier: GPL-2.0+ */ | 
 | /* | 
 |  * Copyright (c) 2021 Taehee Yoo <ap420073@gmail.com> | 
 |  */ | 
 | #ifndef _NET_AMT_H_ | 
 | #define _NET_AMT_H_ | 
 |  | 
 | #include <linux/siphash.h> | 
 | #include <linux/jhash.h> | 
 | #include <linux/netdevice.h> | 
 | #include <net/gro_cells.h> | 
 | #include <net/rtnetlink.h> | 
 |  | 
 | enum amt_msg_type { | 
 | 	AMT_MSG_DISCOVERY = 1, | 
 | 	AMT_MSG_ADVERTISEMENT, | 
 | 	AMT_MSG_REQUEST, | 
 | 	AMT_MSG_MEMBERSHIP_QUERY, | 
 | 	AMT_MSG_MEMBERSHIP_UPDATE, | 
 | 	AMT_MSG_MULTICAST_DATA, | 
 | 	AMT_MSG_TEARDOWN, | 
 | 	__AMT_MSG_MAX, | 
 | }; | 
 |  | 
 | #define AMT_MSG_MAX (__AMT_MSG_MAX - 1) | 
 |  | 
 | enum amt_ops { | 
 | 	/* A*B */ | 
 | 	AMT_OPS_INT, | 
 | 	/* A+B */ | 
 | 	AMT_OPS_UNI, | 
 | 	/* A-B */ | 
 | 	AMT_OPS_SUB, | 
 | 	/* B-A */ | 
 | 	AMT_OPS_SUB_REV, | 
 | 	__AMT_OPS_MAX, | 
 | }; | 
 |  | 
 | #define AMT_OPS_MAX (__AMT_OPS_MAX - 1) | 
 |  | 
 | enum amt_filter { | 
 | 	AMT_FILTER_FWD, | 
 | 	AMT_FILTER_D_FWD, | 
 | 	AMT_FILTER_FWD_NEW, | 
 | 	AMT_FILTER_D_FWD_NEW, | 
 | 	AMT_FILTER_ALL, | 
 | 	AMT_FILTER_NONE_NEW, | 
 | 	AMT_FILTER_BOTH, | 
 | 	AMT_FILTER_BOTH_NEW, | 
 | 	__AMT_FILTER_MAX, | 
 | }; | 
 |  | 
 | #define AMT_FILTER_MAX (__AMT_FILTER_MAX - 1) | 
 |  | 
 | enum amt_act { | 
 | 	AMT_ACT_GMI, | 
 | 	AMT_ACT_GMI_ZERO, | 
 | 	AMT_ACT_GT, | 
 | 	AMT_ACT_STATUS_FWD_NEW, | 
 | 	AMT_ACT_STATUS_D_FWD_NEW, | 
 | 	AMT_ACT_STATUS_NONE_NEW, | 
 | 	__AMT_ACT_MAX, | 
 | }; | 
 |  | 
 | #define AMT_ACT_MAX (__AMT_ACT_MAX - 1) | 
 |  | 
 | enum amt_status { | 
 | 	AMT_STATUS_INIT, | 
 | 	AMT_STATUS_SENT_DISCOVERY, | 
 | 	AMT_STATUS_RECEIVED_DISCOVERY, | 
 | 	AMT_STATUS_SENT_ADVERTISEMENT, | 
 | 	AMT_STATUS_RECEIVED_ADVERTISEMENT, | 
 | 	AMT_STATUS_SENT_REQUEST, | 
 | 	AMT_STATUS_RECEIVED_REQUEST, | 
 | 	AMT_STATUS_SENT_QUERY, | 
 | 	AMT_STATUS_RECEIVED_QUERY, | 
 | 	AMT_STATUS_SENT_UPDATE, | 
 | 	AMT_STATUS_RECEIVED_UPDATE, | 
 | 	__AMT_STATUS_MAX, | 
 | }; | 
 |  | 
 | #define AMT_STATUS_MAX (__AMT_STATUS_MAX - 1) | 
 |  | 
 | /* Gateway events only */ | 
 | enum amt_event { | 
 | 	AMT_EVENT_NONE, | 
 | 	AMT_EVENT_RECEIVE, | 
 | 	AMT_EVENT_SEND_DISCOVERY, | 
 | 	AMT_EVENT_SEND_REQUEST, | 
 | 	__AMT_EVENT_MAX, | 
 | }; | 
 |  | 
 | struct amt_header { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u8 type:4, | 
 | 	   version:4; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u8 version:4, | 
 | 	   type:4; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | } __packed; | 
 |  | 
 | struct amt_header_discovery { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u32	type:4, | 
 | 		version:4, | 
 | 		reserved:24; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u32	version:4, | 
 | 		type:4, | 
 | 		reserved:24; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | 	__be32	nonce; | 
 | } __packed; | 
 |  | 
 | struct amt_header_advertisement { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u32	type:4, | 
 | 		version:4, | 
 | 		reserved:24; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u32	version:4, | 
 | 		type:4, | 
 | 		reserved:24; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | 	__be32	nonce; | 
 | 	__be32	ip4; | 
 | } __packed; | 
 |  | 
 | struct amt_header_request { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u32	type:4, | 
 | 		version:4, | 
 | 		reserved1:7, | 
 | 		p:1, | 
 | 		reserved2:16; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u32	version:4, | 
 | 		type:4, | 
 | 		p:1, | 
 | 		reserved1:7, | 
 | 		reserved2:16; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | 	__be32	nonce; | 
 | } __packed; | 
 |  | 
 | struct amt_header_membership_query { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u64	type:4, | 
 | 		version:4, | 
 | 		reserved:6, | 
 | 		l:1, | 
 | 		g:1, | 
 | 		response_mac:48; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u64	version:4, | 
 | 		type:4, | 
 | 		g:1, | 
 | 		l:1, | 
 | 		reserved:6, | 
 | 		response_mac:48; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | 	__be32	nonce; | 
 | } __packed; | 
 |  | 
 | struct amt_header_membership_update { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u64	type:4, | 
 | 		version:4, | 
 | 		reserved:8, | 
 | 		response_mac:48; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u64	version:4, | 
 | 		type:4, | 
 | 		reserved:8, | 
 | 		response_mac:48; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | 	__be32	nonce; | 
 | } __packed; | 
 |  | 
 | struct amt_header_mcast_data { | 
 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 
 | 	u16	type:4, | 
 | 		version:4, | 
 | 		reserved:8; | 
 | #elif defined(__BIG_ENDIAN_BITFIELD) | 
 | 	u16	version:4, | 
 | 		type:4, | 
 | 		reserved:8; | 
 | #else | 
 | #error  "Please fix <asm/byteorder.h>" | 
 | #endif | 
 | } __packed; | 
 |  | 
 | struct amt_headers { | 
 | 	union { | 
 | 		struct amt_header_discovery discovery; | 
 | 		struct amt_header_advertisement advertisement; | 
 | 		struct amt_header_request request; | 
 | 		struct amt_header_membership_query query; | 
 | 		struct amt_header_membership_update update; | 
 | 		struct amt_header_mcast_data data; | 
 | 	}; | 
 | } __packed; | 
 |  | 
 | struct amt_gw_headers { | 
 | 	union { | 
 | 		struct amt_header_discovery discovery; | 
 | 		struct amt_header_request request; | 
 | 		struct amt_header_membership_update update; | 
 | 	}; | 
 | } __packed; | 
 |  | 
 | struct amt_relay_headers { | 
 | 	union { | 
 | 		struct amt_header_advertisement advertisement; | 
 | 		struct amt_header_membership_query query; | 
 | 		struct amt_header_mcast_data data; | 
 | 	}; | 
 | } __packed; | 
 |  | 
 | struct amt_skb_cb { | 
 | 	struct amt_tunnel_list *tunnel; | 
 | }; | 
 |  | 
 | struct amt_tunnel_list { | 
 | 	struct list_head	list; | 
 | 	/* Protect All resources under an amt_tunne_list */ | 
 | 	spinlock_t		lock; | 
 | 	struct amt_dev		*amt; | 
 | 	u32			nr_groups; | 
 | 	u32			nr_sources; | 
 | 	enum amt_status		status; | 
 | 	struct delayed_work	gc_wq; | 
 | 	__be16			source_port; | 
 | 	__be32			ip4; | 
 | 	__be32			nonce; | 
 | 	siphash_key_t		key; | 
 | 	u64			mac:48, | 
 | 				reserved:16; | 
 | 	struct rcu_head		rcu; | 
 | 	struct hlist_head	groups[]; | 
 | }; | 
 |  | 
 | union amt_addr { | 
 | 	__be32			ip4; | 
 | #if IS_ENABLED(CONFIG_IPV6) | 
 | 	struct in6_addr		ip6; | 
 | #endif | 
 | }; | 
 |  | 
 | /* RFC 3810 | 
 |  * | 
 |  * When the router is in EXCLUDE mode, the router state is represented | 
 |  * by the notation EXCLUDE (X,Y), where X is called the "Requested List" | 
 |  * and Y is called the "Exclude List".  All sources, except those from | 
 |  * the Exclude List, will be forwarded by the router | 
 |  */ | 
 | enum amt_source_status { | 
 | 	AMT_SOURCE_STATUS_NONE, | 
 | 	/* Node of Requested List */ | 
 | 	AMT_SOURCE_STATUS_FWD, | 
 | 	/* Node of Exclude List */ | 
 | 	AMT_SOURCE_STATUS_D_FWD, | 
 | }; | 
 |  | 
 | /* protected by gnode->lock */ | 
 | struct amt_source_node { | 
 | 	struct hlist_node	node; | 
 | 	struct amt_group_node	*gnode; | 
 | 	struct delayed_work     source_timer; | 
 | 	union amt_addr		source_addr; | 
 | 	enum amt_source_status	status; | 
 | #define AMT_SOURCE_OLD	0 | 
 | #define AMT_SOURCE_NEW	1 | 
 | 	u8			flags; | 
 | 	struct rcu_head		rcu; | 
 | }; | 
 |  | 
 | /* Protected by amt_tunnel_list->lock */ | 
 | struct amt_group_node { | 
 | 	struct amt_dev		*amt; | 
 | 	union amt_addr		group_addr; | 
 | 	union amt_addr		host_addr; | 
 | 	bool			v6; | 
 | 	u8			filter_mode; | 
 | 	u32			nr_sources; | 
 | 	struct amt_tunnel_list	*tunnel_list; | 
 | 	struct hlist_node	node; | 
 | 	struct delayed_work     group_timer; | 
 | 	struct rcu_head		rcu; | 
 | 	struct hlist_head	sources[]; | 
 | }; | 
 |  | 
 | #define AMT_MAX_EVENTS	16 | 
 | struct amt_events { | 
 | 	enum amt_event event; | 
 | 	struct sk_buff *skb; | 
 | }; | 
 |  | 
 | struct amt_dev { | 
 | 	struct net_device       *dev; | 
 | 	struct net_device       *stream_dev; | 
 | 	struct net		*net; | 
 | 	/* Global lock for amt device */ | 
 | 	spinlock_t		lock; | 
 | 	/* Used only in relay mode */ | 
 | 	struct list_head        tunnel_list; | 
 | 	struct gro_cells	gro_cells; | 
 |  | 
 | 	/* Protected by RTNL */ | 
 | 	struct delayed_work     discovery_wq; | 
 | 	/* Protected by RTNL */ | 
 | 	struct delayed_work     req_wq; | 
 | 	/* Protected by RTNL */ | 
 | 	struct delayed_work     secret_wq; | 
 | 	struct work_struct	event_wq; | 
 | 	/* AMT status */ | 
 | 	enum amt_status		status; | 
 | 	/* Generated key */ | 
 | 	siphash_key_t		key; | 
 | 	struct socket	  __rcu *sock; | 
 | 	u32			max_groups; | 
 | 	u32			max_sources; | 
 | 	u32			hash_buckets; | 
 | 	u32			hash_seed; | 
 | 	/* Default 128 */ | 
 | 	u32                     max_tunnels; | 
 | 	/* Default 128 */ | 
 | 	u32                     nr_tunnels; | 
 | 	/* Gateway or Relay mode */ | 
 | 	u32                     mode; | 
 | 	/* Default 2268 */ | 
 | 	__be16			relay_port; | 
 | 	/* Default 2268 */ | 
 | 	__be16			gw_port; | 
 | 	/* Outer local ip */ | 
 | 	__be32			local_ip; | 
 | 	/* Outer remote ip */ | 
 | 	__be32			remote_ip; | 
 | 	/* Outer discovery ip */ | 
 | 	__be32			discovery_ip; | 
 | 	/* Only used in gateway mode */ | 
 | 	__be32			nonce; | 
 | 	/* Gateway sent request and received query */ | 
 | 	bool			ready4; | 
 | 	bool			ready6; | 
 | 	u8			req_cnt; | 
 | 	u8			qi; | 
 | 	u64			qrv; | 
 | 	u64			qri; | 
 | 	/* Used only in gateway mode */ | 
 | 	u64			mac:48, | 
 | 				reserved:16; | 
 | 	/* AMT gateway side message handler queue */ | 
 | 	struct amt_events	events[AMT_MAX_EVENTS]; | 
 | 	u8			event_idx; | 
 | 	u8			nr_events; | 
 | }; | 
 |  | 
 | #define AMT_TOS			0xc0 | 
 | #define AMT_IPHDR_OPTS		4 | 
 | #define AMT_IP6HDR_OPTS		8 | 
 | #define AMT_GC_INTERVAL		(30 * 1000) | 
 | #define AMT_MAX_GROUP		32 | 
 | #define AMT_MAX_SOURCE		128 | 
 | #define AMT_HSIZE_SHIFT		8 | 
 | #define AMT_HSIZE		(1 << AMT_HSIZE_SHIFT) | 
 |  | 
 | #define AMT_DISCOVERY_TIMEOUT	5000 | 
 | #define AMT_INIT_REQ_TIMEOUT	1 | 
 | #define AMT_INIT_QUERY_INTERVAL	125 | 
 | #define AMT_MAX_REQ_TIMEOUT	120 | 
 | #define AMT_MAX_REQ_COUNT	3 | 
 | #define AMT_SECRET_TIMEOUT	60000 | 
 | #define IANA_AMT_UDP_PORT	2268 | 
 | #define AMT_MAX_TUNNELS         128 | 
 | #define AMT_MAX_REQS		128 | 
 | #define AMT_GW_HLEN (sizeof(struct iphdr) + \ | 
 | 		     sizeof(struct udphdr) + \ | 
 | 		     sizeof(struct amt_gw_headers)) | 
 | #define AMT_RELAY_HLEN (sizeof(struct iphdr) + \ | 
 | 		     sizeof(struct udphdr) + \ | 
 | 		     sizeof(struct amt_relay_headers)) | 
 |  | 
 | static inline bool netif_is_amt(const struct net_device *dev) | 
 | { | 
 | 	return dev->rtnl_link_ops && !strcmp(dev->rtnl_link_ops->kind, "amt"); | 
 | } | 
 |  | 
 | static inline u64 amt_gmi(const struct amt_dev *amt) | 
 | { | 
 | 	return ((amt->qrv * amt->qi) + amt->qri) * 1000; | 
 | } | 
 |  | 
 | #endif /* _NET_AMT_H_ */ |