|  | /* 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_ */ |