linux/drivers/net/amt.c

// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (c) 2021 Taehee Yoo <[email protected]> */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/jhash.h>
#include <linux/if_tunnel.h>
#include <linux/net.h>
#include <linux/igmp.h>
#include <linux/workqueue.h>
#include <net/pkt_sched.h>
#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>
#include <net/icmp.h>
#include <net/mld.h>
#include <net/amt.h>
#include <uapi/linux/amt.h>
#include <linux/security.h>
#include <net/gro_cells.h>
#include <net/ipv6.h>
#include <net/if_inet6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <net/inet_common.h>
#include <net/ip6_checksum.h>

static struct workqueue_struct *amt_wq;

static HLIST_HEAD(source_gc_list);
/* Lock for source_gc_list */
static spinlock_t source_gc_lock;
static struct delayed_work source_gc_wq;
static char *status_str[] =;

static char *type_str[] =;

static char *action_str[] =;

static struct igmpv3_grec igmpv3_zero_grec;

#if IS_ENABLED(CONFIG_IPV6)
#define MLD2_ALL_NODE_INIT
static struct in6_addr mld2_all_node =;
static struct mld2_grec mldv2_zero_grec;
#endif

static struct amt_skb_cb *amt_skb_cb(struct sk_buff *skb)
{}

static void __amt_source_gc_work(void)
{}

static void amt_source_gc_work(struct work_struct *work)
{}

static bool amt_addr_equal(union amt_addr *a, union amt_addr *b)
{}

static u32 amt_source_hash(struct amt_tunnel_list *tunnel, union amt_addr *src)
{}

static bool amt_status_filter(struct amt_source_node *snode,
			      enum amt_filter filter)
{}

static struct amt_source_node *amt_lookup_src(struct amt_tunnel_list *tunnel,
					      struct amt_group_node *gnode,
					      enum amt_filter filter,
					      union amt_addr *src)
{}

static u32 amt_group_hash(struct amt_tunnel_list *tunnel, union amt_addr *group)
{}

static struct amt_group_node *amt_lookup_group(struct amt_tunnel_list *tunnel,
					       union amt_addr *group,
					       union amt_addr *host,
					       bool v6)
{}

static void amt_destroy_source(struct amt_source_node *snode)
{}

static void amt_del_group(struct amt_dev *amt, struct amt_group_node *gnode)
{}

/* If a source timer expires with a router filter-mode for the group of
 * INCLUDE, the router concludes that traffic from this particular
 * source is no longer desired on the attached network, and deletes the
 * associated source record.
 */
static void amt_source_work(struct work_struct *work)
{}

static void amt_act_src(struct amt_tunnel_list *tunnel,
			struct amt_group_node *gnode,
			struct amt_source_node *snode,
			enum amt_act act)
{}

static struct amt_source_node *amt_alloc_snode(struct amt_group_node *gnode,
					       union amt_addr *src)
{}

/* RFC 3810 - 7.2.2.  Definition of Filter Timers
 *
 *  Router Mode          Filter Timer         Actions/Comments
 *  -----------       -----------------       ----------------
 *
 *    INCLUDE             Not Used            All listeners in
 *                                            INCLUDE mode.
 *
 *    EXCLUDE             Timer > 0           At least one listener
 *                                            in EXCLUDE mode.
 *
 *    EXCLUDE             Timer == 0          No more listeners in
 *                                            EXCLUDE mode for the
 *                                            multicast address.
 *                                            If the Requested List
 *                                            is empty, delete
 *                                            Multicast Address
 *                                            Record.  If not, switch
 *                                            to INCLUDE filter mode;
 *                                            the sources in the
 *                                            Requested List are
 *                                            moved to the Include
 *                                            List, and the Exclude
 *                                            List is deleted.
 */
static void amt_group_work(struct work_struct *work)
{}

/* Non-existent group is created as INCLUDE {empty}:
 *
 * RFC 3376 - 5.1. Action on Change of Interface State
 *
 * If no interface state existed for that multicast address before
 * the change (i.e., the change consisted of creating a new
 * per-interface record), or if no state exists after the change
 * (i.e., the change consisted of deleting a per-interface record),
 * then the "non-existent" state is considered to have a filter mode
 * of INCLUDE and an empty source list.
 */
static struct amt_group_node *amt_add_group(struct amt_dev *amt,
					    struct amt_tunnel_list *tunnel,
					    union amt_addr *group,
					    union amt_addr *host,
					    bool v6)
{}

static struct sk_buff *amt_build_igmp_gq(struct amt_dev *amt)
{}

static void amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
				 bool validate)
{}

static void __amt_update_relay_status(struct amt_tunnel_list *tunnel,
				      enum amt_status status,
				      bool validate)
{}

static void amt_update_relay_status(struct amt_tunnel_list *tunnel,
				    enum amt_status status, bool validate)
{}

static void amt_send_discovery(struct amt_dev *amt)
{}

static void amt_send_request(struct amt_dev *amt, bool v6)
{}

static void amt_send_igmp_gq(struct amt_dev *amt,
			     struct amt_tunnel_list *tunnel)
{}

#if IS_ENABLED(CONFIG_IPV6)
static struct sk_buff *amt_build_mld_gq(struct amt_dev *amt)
{}

static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
{}
#else
static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
{
}
#endif

static bool amt_queue_event(struct amt_dev *amt, enum amt_event event,
			    struct sk_buff *skb)
{}

static void amt_secret_work(struct work_struct *work)
{}

static void amt_event_send_discovery(struct amt_dev *amt)
{}

static void amt_discovery_work(struct work_struct *work)
{}

static void amt_event_send_request(struct amt_dev *amt)
{}

static void amt_req_work(struct work_struct *work)
{}

static bool amt_send_membership_update(struct amt_dev *amt,
				       struct sk_buff *skb,
				       bool v6)
{}

static void amt_send_multicast_data(struct amt_dev *amt,
				    const struct sk_buff *oskb,
				    struct amt_tunnel_list *tunnel,
				    bool v6)
{}

static bool amt_send_membership_query(struct amt_dev *amt,
				      struct sk_buff *skb,
				      struct amt_tunnel_list *tunnel,
				      bool v6)
{}

static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{}

static int amt_parse_type(struct sk_buff *skb)
{}

static void amt_clear_groups(struct amt_tunnel_list *tunnel)
{}

static void amt_tunnel_expire(struct work_struct *work)
{}

static void amt_cleanup_srcs(struct amt_dev *amt,
			     struct amt_tunnel_list *tunnel,
			     struct amt_group_node *gnode)
{}

static void amt_add_srcs(struct amt_dev *amt, struct amt_tunnel_list *tunnel,
			 struct amt_group_node *gnode, void *grec,
			 bool v6)
{}

/* Router State   Report Rec'd New Router State
 * ------------   ------------ ----------------
 * EXCLUDE (X,Y)  IS_IN (A)    EXCLUDE (X+A,Y-A)
 *
 * -----------+-----------+-----------+
 *            |    OLD    |    NEW    |
 * -----------+-----------+-----------+
 *    FWD     |     X     |    X+A    |
 * -----------+-----------+-----------+
 *    D_FWD   |     Y     |    Y-A    |
 * -----------+-----------+-----------+
 *    NONE    |           |     A     |
 * -----------+-----------+-----------+
 *
 * a) Received sources are NONE/NEW
 * b) All NONE will be deleted by amt_cleanup_srcs().
 * c) All OLD will be deleted by amt_cleanup_srcs().
 * d) After delete, NEW source will be switched to OLD.
 */
static void amt_lookup_act_srcs(struct amt_tunnel_list *tunnel,
				struct amt_group_node *gnode,
				void *grec,
				enum amt_ops ops,
				enum amt_filter filter,
				enum amt_act act,
				bool v6)
{}

static void amt_mcast_is_in_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

static void amt_mcast_is_ex_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

static void amt_mcast_to_in_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

static void amt_mcast_to_ex_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

static void amt_mcast_allow_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

static void amt_mcast_block_handler(struct amt_dev *amt,
				    struct amt_tunnel_list *tunnel,
				    struct amt_group_node *gnode,
				    void *grec, void *zero_grec, bool v6)
{}

/* RFC 3376
 * 7.3.2. In the Presence of Older Version Group Members
 *
 * When Group Compatibility Mode is IGMPv2, a router internally
 * translates the following IGMPv2 messages for that group to their
 * IGMPv3 equivalents:
 *
 * IGMPv2 Message                IGMPv3 Equivalent
 * --------------                -----------------
 * Report                        IS_EX( {} )
 * Leave                         TO_IN( {} )
 */
static void amt_igmpv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				      struct amt_tunnel_list *tunnel)
{}

/* RFC 3376
 * 7.3.2. In the Presence of Older Version Group Members
 *
 * When Group Compatibility Mode is IGMPv2, a router internally
 * translates the following IGMPv2 messages for that group to their
 * IGMPv3 equivalents:
 *
 * IGMPv2 Message                IGMPv3 Equivalent
 * --------------                -----------------
 * Report                        IS_EX( {} )
 * Leave                         TO_IN( {} )
 */
static void amt_igmpv2_leave_handler(struct amt_dev *amt, struct sk_buff *skb,
				     struct amt_tunnel_list *tunnel)
{}

static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				      struct amt_tunnel_list *tunnel)
{}

/* caller held tunnel->lock */
static void amt_igmp_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				    struct amt_tunnel_list *tunnel)
{}

#if IS_ENABLED(CONFIG_IPV6)
/* RFC 3810
 * 8.3.2. In the Presence of MLDv1 Multicast Address Listeners
 *
 * When Multicast Address Compatibility Mode is MLDv2, a router acts
 * using the MLDv2 protocol for that multicast address.  When Multicast
 * Address Compatibility Mode is MLDv1, a router internally translates
 * the following MLDv1 messages for that multicast address to their
 * MLDv2 equivalents:
 *
 * MLDv1 Message                 MLDv2 Equivalent
 * --------------                -----------------
 * Report                        IS_EX( {} )
 * Done                          TO_IN( {} )
 */
static void amt_mldv1_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				     struct amt_tunnel_list *tunnel)
{}

/* RFC 3810
 * 8.3.2. In the Presence of MLDv1 Multicast Address Listeners
 *
 * When Multicast Address Compatibility Mode is MLDv2, a router acts
 * using the MLDv2 protocol for that multicast address.  When Multicast
 * Address Compatibility Mode is MLDv1, a router internally translates
 * the following MLDv1 messages for that multicast address to their
 * MLDv2 equivalents:
 *
 * MLDv1 Message                 MLDv2 Equivalent
 * --------------                -----------------
 * Report                        IS_EX( {} )
 * Done                          TO_IN( {} )
 */
static void amt_mldv1_leave_handler(struct amt_dev *amt, struct sk_buff *skb,
				    struct amt_tunnel_list *tunnel)
{}

static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				     struct amt_tunnel_list *tunnel)
{}

/* caller held tunnel->lock */
static void amt_mld_report_handler(struct amt_dev *amt, struct sk_buff *skb,
				   struct amt_tunnel_list *tunnel)
{}
#endif

static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb)
{}

static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
{}

static bool amt_membership_query_handler(struct amt_dev *amt,
					 struct sk_buff *skb)
{}

static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
{}

static void amt_send_advertisement(struct amt_dev *amt, __be32 nonce,
				   __be32 daddr, __be16 dport)
{}

static bool amt_discovery_handler(struct amt_dev *amt, struct sk_buff *skb)
{}

static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
{}

static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
{}

static int amt_rcv(struct sock *sk, struct sk_buff *skb)
{}

static void amt_event_work(struct work_struct *work)
{}

static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
{}

static struct socket *amt_create_sock(struct net *net, __be16 port)
{}

static int amt_socket_create(struct amt_dev *amt)
{}

static int amt_dev_open(struct net_device *dev)
{}

static int amt_dev_stop(struct net_device *dev)
{}

static const struct device_type amt_type =;

static int amt_dev_init(struct net_device *dev)
{}

static void amt_dev_uninit(struct net_device *dev)
{}

static const struct net_device_ops amt_netdev_ops =;

static void amt_link_setup(struct net_device *dev)
{}

static const struct nla_policy amt_policy[IFLA_AMT_MAX + 1] =;

static int amt_validate(struct nlattr *tb[], struct nlattr *data[],
			struct netlink_ext_ack *extack)
{}

static int amt_newlink(struct net *net, struct net_device *dev,
		       struct nlattr *tb[], struct nlattr *data[],
		       struct netlink_ext_ack *extack)
{}

static void amt_dellink(struct net_device *dev, struct list_head *head)
{}

static size_t amt_get_size(const struct net_device *dev)
{}

static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
{}

static struct rtnl_link_ops amt_link_ops __read_mostly =;

static struct net_device *amt_lookup_upper_dev(struct net_device *dev)
{}

static int amt_device_event(struct notifier_block *unused,
			    unsigned long event, void *ptr)
{}

static struct notifier_block amt_notifier_block __read_mostly =;

static int __init amt_init(void)
{}
late_initcall(amt_init);

static void __exit amt_fini(void)
{}
module_exit(amt_fini);

MODULE_LICENSE();
MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_ALIAS_RTNL_LINK();