162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * INET		An implementation of the TCP/IP protocol suite for the LINUX
462306a36Sopenharmony_ci *		operating system.  INET is implemented using the  BSD Socket
562306a36Sopenharmony_ci *		interface as the means of communication with the user level.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *		Pseudo-driver for the loopback interface.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Version:	@(#)loopback.c	1.0.4b	08/16/93
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Authors:	Ross Biro
1262306a36Sopenharmony_ci *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
1362306a36Sopenharmony_ci *		Donald Becker, <becker@scyld.com>
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *		Alan Cox	:	Fixed oddments for NET3.014
1662306a36Sopenharmony_ci *		Alan Cox	:	Rejig for NET3.029 snap #3
1762306a36Sopenharmony_ci *		Alan Cox	:	Fixed NET3.029 bugs and sped up
1862306a36Sopenharmony_ci *		Larry McVoy	:	Tiny tweak to double performance
1962306a36Sopenharmony_ci *		Alan Cox	:	Backed out LMV's tweak - the linux mm
2062306a36Sopenharmony_ci *					can't take it...
2162306a36Sopenharmony_ci *              Michael Griffith:       Don't bother computing the checksums
2262306a36Sopenharmony_ci *                                      on packets received on the loopback
2362306a36Sopenharmony_ci *                                      interface.
2462306a36Sopenharmony_ci *		Alexey Kuznetsov:	Potential hang under some extreme
2562306a36Sopenharmony_ci *					cases removed.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#include <linux/kernel.h>
2862306a36Sopenharmony_ci#include <linux/jiffies.h>
2962306a36Sopenharmony_ci#include <linux/module.h>
3062306a36Sopenharmony_ci#include <linux/interrupt.h>
3162306a36Sopenharmony_ci#include <linux/fs.h>
3262306a36Sopenharmony_ci#include <linux/types.h>
3362306a36Sopenharmony_ci#include <linux/string.h>
3462306a36Sopenharmony_ci#include <linux/socket.h>
3562306a36Sopenharmony_ci#include <linux/errno.h>
3662306a36Sopenharmony_ci#include <linux/fcntl.h>
3762306a36Sopenharmony_ci#include <linux/in.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <linux/uaccess.h>
4062306a36Sopenharmony_ci#include <linux/io.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <linux/inet.h>
4362306a36Sopenharmony_ci#include <linux/netdevice.h>
4462306a36Sopenharmony_ci#include <linux/etherdevice.h>
4562306a36Sopenharmony_ci#include <linux/skbuff.h>
4662306a36Sopenharmony_ci#include <linux/ethtool.h>
4762306a36Sopenharmony_ci#include <net/sch_generic.h>
4862306a36Sopenharmony_ci#include <net/sock.h>
4962306a36Sopenharmony_ci#include <net/checksum.h>
5062306a36Sopenharmony_ci#include <linux/if_ether.h>	/* For the statistics structure. */
5162306a36Sopenharmony_ci#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
5262306a36Sopenharmony_ci#include <linux/ip.h>
5362306a36Sopenharmony_ci#include <linux/tcp.h>
5462306a36Sopenharmony_ci#include <linux/percpu.h>
5562306a36Sopenharmony_ci#include <linux/net_tstamp.h>
5662306a36Sopenharmony_ci#include <net/net_namespace.h>
5762306a36Sopenharmony_ci#include <linux/u64_stats_sync.h>
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* blackhole_netdev - a device used for dsts that are marked expired!
6062306a36Sopenharmony_ci * This is global device (instead of per-net-ns) since it's not needed
6162306a36Sopenharmony_ci * to be per-ns and gets initialized at boot time.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistruct net_device *blackhole_netdev;
6462306a36Sopenharmony_ciEXPORT_SYMBOL(blackhole_netdev);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* The higher levels take care of making this non-reentrant (it's
6762306a36Sopenharmony_ci * called with bh's disabled).
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic netdev_tx_t loopback_xmit(struct sk_buff *skb,
7062306a36Sopenharmony_ci				 struct net_device *dev)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	int len;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	skb_tx_timestamp(skb);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* do not fool net_timestamp_check() with various clock bases */
7762306a36Sopenharmony_ci	skb_clear_tstamp(skb);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	skb_orphan(skb);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* Before queueing this packet to __netif_rx(),
8262306a36Sopenharmony_ci	 * make sure dst is refcounted.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	skb_dst_force(skb);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, dev);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	len = skb->len;
8962306a36Sopenharmony_ci	if (likely(__netif_rx(skb) == NET_RX_SUCCESS))
9062306a36Sopenharmony_ci		dev_lstats_add(dev, len);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return NETDEV_TX_OK;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_civoid dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	int i;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	*packets = 0;
10062306a36Sopenharmony_ci	*bytes = 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	for_each_possible_cpu(i) {
10362306a36Sopenharmony_ci		const struct pcpu_lstats *lb_stats;
10462306a36Sopenharmony_ci		u64 tbytes, tpackets;
10562306a36Sopenharmony_ci		unsigned int start;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		lb_stats = per_cpu_ptr(dev->lstats, i);
10862306a36Sopenharmony_ci		do {
10962306a36Sopenharmony_ci			start = u64_stats_fetch_begin(&lb_stats->syncp);
11062306a36Sopenharmony_ci			tpackets = u64_stats_read(&lb_stats->packets);
11162306a36Sopenharmony_ci			tbytes = u64_stats_read(&lb_stats->bytes);
11262306a36Sopenharmony_ci		} while (u64_stats_fetch_retry(&lb_stats->syncp, start));
11362306a36Sopenharmony_ci		*bytes   += tbytes;
11462306a36Sopenharmony_ci		*packets += tpackets;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ciEXPORT_SYMBOL(dev_lstats_read);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void loopback_get_stats64(struct net_device *dev,
12062306a36Sopenharmony_ci				 struct rtnl_link_stats64 *stats)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	u64 packets, bytes;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	dev_lstats_read(dev, &packets, &bytes);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	stats->rx_packets = packets;
12762306a36Sopenharmony_ci	stats->tx_packets = packets;
12862306a36Sopenharmony_ci	stats->rx_bytes   = bytes;
12962306a36Sopenharmony_ci	stats->tx_bytes   = bytes;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic u32 always_on(struct net_device *dev)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return 1;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const struct ethtool_ops loopback_ethtool_ops = {
13862306a36Sopenharmony_ci	.get_link		= always_on,
13962306a36Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int loopback_dev_init(struct net_device *dev)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
14562306a36Sopenharmony_ci	if (!dev->lstats)
14662306a36Sopenharmony_ci		return -ENOMEM;
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void loopback_dev_free(struct net_device *dev)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	dev_net(dev)->loopback_dev = NULL;
15362306a36Sopenharmony_ci	free_percpu(dev->lstats);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic const struct net_device_ops loopback_ops = {
15762306a36Sopenharmony_ci	.ndo_init        = loopback_dev_init,
15862306a36Sopenharmony_ci	.ndo_start_xmit  = loopback_xmit,
15962306a36Sopenharmony_ci	.ndo_get_stats64 = loopback_get_stats64,
16062306a36Sopenharmony_ci	.ndo_set_mac_address = eth_mac_addr,
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic void gen_lo_setup(struct net_device *dev,
16462306a36Sopenharmony_ci			 unsigned int mtu,
16562306a36Sopenharmony_ci			 const struct ethtool_ops *eth_ops,
16662306a36Sopenharmony_ci			 const struct header_ops *hdr_ops,
16762306a36Sopenharmony_ci			 const struct net_device_ops *dev_ops,
16862306a36Sopenharmony_ci			 void (*dev_destructor)(struct net_device *dev))
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	dev->mtu		= mtu;
17162306a36Sopenharmony_ci	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
17262306a36Sopenharmony_ci	dev->min_header_len	= ETH_HLEN;	/* 14	*/
17362306a36Sopenharmony_ci	dev->addr_len		= ETH_ALEN;	/* 6	*/
17462306a36Sopenharmony_ci	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
17562306a36Sopenharmony_ci	dev->flags		= IFF_LOOPBACK;
17662306a36Sopenharmony_ci	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
17762306a36Sopenharmony_ci	netif_keep_dst(dev);
17862306a36Sopenharmony_ci	dev->hw_features	= NETIF_F_GSO_SOFTWARE;
17962306a36Sopenharmony_ci	dev->features		= NETIF_F_SG | NETIF_F_FRAGLIST
18062306a36Sopenharmony_ci		| NETIF_F_GSO_SOFTWARE
18162306a36Sopenharmony_ci		| NETIF_F_HW_CSUM
18262306a36Sopenharmony_ci		| NETIF_F_RXCSUM
18362306a36Sopenharmony_ci		| NETIF_F_SCTP_CRC
18462306a36Sopenharmony_ci		| NETIF_F_HIGHDMA
18562306a36Sopenharmony_ci		| NETIF_F_LLTX
18662306a36Sopenharmony_ci		| NETIF_F_NETNS_LOCAL
18762306a36Sopenharmony_ci		| NETIF_F_VLAN_CHALLENGED
18862306a36Sopenharmony_ci		| NETIF_F_LOOPBACK;
18962306a36Sopenharmony_ci	dev->ethtool_ops	= eth_ops;
19062306a36Sopenharmony_ci	dev->header_ops		= hdr_ops;
19162306a36Sopenharmony_ci	dev->netdev_ops		= dev_ops;
19262306a36Sopenharmony_ci	dev->needs_free_netdev	= true;
19362306a36Sopenharmony_ci	dev->priv_destructor	= dev_destructor;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	netif_set_tso_max_size(dev, GSO_MAX_SIZE);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* The loopback device is special. There is only one instance
19962306a36Sopenharmony_ci * per network namespace.
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistatic void loopback_setup(struct net_device *dev)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,
20462306a36Sopenharmony_ci		     &loopback_ops, loopback_dev_free);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* Setup and register the loopback device. */
20862306a36Sopenharmony_cistatic __net_init int loopback_net_init(struct net *net)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct net_device *dev;
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	err = -ENOMEM;
21462306a36Sopenharmony_ci	dev = alloc_netdev(0, "lo", NET_NAME_PREDICTABLE, loopback_setup);
21562306a36Sopenharmony_ci	if (!dev)
21662306a36Sopenharmony_ci		goto out;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	dev_net_set(dev, net);
21962306a36Sopenharmony_ci	err = register_netdev(dev);
22062306a36Sopenharmony_ci	if (err)
22162306a36Sopenharmony_ci		goto out_free_netdev;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	BUG_ON(dev->ifindex != LOOPBACK_IFINDEX);
22462306a36Sopenharmony_ci	net->loopback_dev = dev;
22562306a36Sopenharmony_ci	return 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciout_free_netdev:
22862306a36Sopenharmony_ci	free_netdev(dev);
22962306a36Sopenharmony_ciout:
23062306a36Sopenharmony_ci	if (net_eq(net, &init_net))
23162306a36Sopenharmony_ci		panic("loopback: Failed to register netdevice: %d\n", err);
23262306a36Sopenharmony_ci	return err;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/* Registered in net/core/dev.c */
23662306a36Sopenharmony_cistruct pernet_operations __net_initdata loopback_net_ops = {
23762306a36Sopenharmony_ci	.init = loopback_net_init,
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/* blackhole netdevice */
24162306a36Sopenharmony_cistatic netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
24262306a36Sopenharmony_ci					 struct net_device *dev)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	kfree_skb(skb);
24562306a36Sopenharmony_ci	net_warn_ratelimited("%s(): Dropping skb.\n", __func__);
24662306a36Sopenharmony_ci	return NETDEV_TX_OK;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic const struct net_device_ops blackhole_netdev_ops = {
25062306a36Sopenharmony_ci	.ndo_start_xmit = blackhole_netdev_xmit,
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* This is a dst-dummy device used specifically for invalidated
25462306a36Sopenharmony_ci * DSTs and unlike loopback, this is not per-ns.
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_cistatic void blackhole_netdev_setup(struct net_device *dev)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* Setup and register the blackhole_netdev. */
26262306a36Sopenharmony_cistatic int __init blackhole_netdev_init(void)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN,
26562306a36Sopenharmony_ci					blackhole_netdev_setup);
26662306a36Sopenharmony_ci	if (!blackhole_netdev)
26762306a36Sopenharmony_ci		return -ENOMEM;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	rtnl_lock();
27062306a36Sopenharmony_ci	dev_init_scheduler(blackhole_netdev);
27162306a36Sopenharmony_ci	dev_activate(blackhole_netdev);
27262306a36Sopenharmony_ci	rtnl_unlock();
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	blackhole_netdev->flags |= IFF_UP | IFF_RUNNING;
27562306a36Sopenharmony_ci	dev_net_set(blackhole_netdev, &init_net);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cidevice_initcall(blackhole_netdev_init);
281