| /* 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 sock __rcu *sk; | |
| 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_ */ |