xref: /openbmc/linux/drivers/net/dummy.c (revision 1e952e95843d437b8a904dbd5b48d72db8ac23ec)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /* dummy.c: a dummy net driver
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds 	The purpose of this driver is to provide a device to point a
51da177e4SLinus Torvalds 	route through, but not to actually transmit packets.
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds 	Why?  If you have a machine whose only connection is an occasional
81da177e4SLinus Torvalds 	PPP/SLIP/PLIP link, you can only connect to your own hostname
91da177e4SLinus Torvalds 	when the link is up.  Otherwise you have to use localhost.
101da177e4SLinus Torvalds 	This isn't very consistent.
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds 	One solution is to set up a dummy link using PPP/SLIP/PLIP,
131da177e4SLinus Torvalds 	but this seems (to me) too much overhead for too little gain.
141da177e4SLinus Torvalds 	This driver provides a small alternative. Thus you can do
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds 	[when not running slip]
171da177e4SLinus Torvalds 		ifconfig dummy slip.addr.ess.here up
181da177e4SLinus Torvalds 	[to go to slip]
191da177e4SLinus Torvalds 		ifconfig dummy down
201da177e4SLinus Torvalds 		dip whatever
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds 	This was written by looking at Donald Becker's skeleton driver
231da177e4SLinus Torvalds 	and the loopback driver.  I then threw away anything that didn't
241da177e4SLinus Torvalds 	apply!	Thanks to Alan Cox for the key clue on what to do with
251da177e4SLinus Torvalds 	misguided packets.
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 			Nick Holloway, 27th May 1994
281da177e4SLinus Torvalds 	[I tweaked this explanation a little but that's all]
291da177e4SLinus Torvalds 			Alan Cox, 30th May 1994
301da177e4SLinus Torvalds */
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #include <linux/module.h>
331da177e4SLinus Torvalds #include <linux/kernel.h>
341da177e4SLinus Torvalds #include <linux/netdevice.h>
351da177e4SLinus Torvalds #include <linux/etherdevice.h>
36abe9fd57SJulian Wiedmann #include <linux/ethtool.h>
371da177e4SLinus Torvalds #include <linux/init.h>
381da177e4SLinus Torvalds #include <linux/moduleparam.h>
39206c9fb2SPatrick McHardy #include <linux/rtnetlink.h>
406df014cfSEzequiel Lara Gomez #include <linux/net_tstamp.h>
415d5cb173SPatrick McHardy #include <net/rtnetlink.h>
426d81f41cSEric Dumazet #include <linux/u64_stats_sync.h>
43206c9fb2SPatrick McHardy 
44c19be735SFlavio Leitner #define DRV_NAME	"dummy"
45c19be735SFlavio Leitner 
461da177e4SLinus Torvalds static int numdummies = 1;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds /* fake multicast ability */
set_multicast_list(struct net_device * dev)491da177e4SLinus Torvalds static void set_multicast_list(struct net_device *dev)
501da177e4SLinus Torvalds {
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
dummy_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * stats)53bc1f4470Sstephen hemminger static void dummy_get_stats64(struct net_device *dev,
546d81f41cSEric Dumazet 			      struct rtnl_link_stats64 *stats)
556d81f41cSEric Dumazet {
564a43b1f9SEric Dumazet 	dev_lstats_read(dev, &stats->tx_packets, &stats->tx_bytes);
576d81f41cSEric Dumazet }
58424efe9cSStephen Hemminger 
dummy_xmit(struct sk_buff * skb,struct net_device * dev)59424efe9cSStephen Hemminger static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
60424efe9cSStephen Hemminger {
614a43b1f9SEric Dumazet 	dev_lstats_add(dev, skb->len);
62424efe9cSStephen Hemminger 
636df014cfSEzequiel Lara Gomez 	skb_tx_timestamp(skb);
64424efe9cSStephen Hemminger 	dev_kfree_skb(skb);
65424efe9cSStephen Hemminger 	return NETDEV_TX_OK;
66424efe9cSStephen Hemminger }
67424efe9cSStephen Hemminger 
dummy_dev_init(struct net_device * dev)686d81f41cSEric Dumazet static int dummy_dev_init(struct net_device *dev)
696d81f41cSEric Dumazet {
704a43b1f9SEric Dumazet 	dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
714a43b1f9SEric Dumazet 	if (!dev->lstats)
726d81f41cSEric Dumazet 		return -ENOMEM;
736d81f41cSEric Dumazet 
74*a7b862abSEric Dumazet 	netdev_lockdep_set_classes(dev);
756d81f41cSEric Dumazet 	return 0;
766d81f41cSEric Dumazet }
776d81f41cSEric Dumazet 
dummy_dev_uninit(struct net_device * dev)78890fdf2aSHiroaki SHIMODA static void dummy_dev_uninit(struct net_device *dev)
796d81f41cSEric Dumazet {
804a43b1f9SEric Dumazet 	free_percpu(dev->lstats);
816d81f41cSEric Dumazet }
826d81f41cSEric Dumazet 
dummy_change_carrier(struct net_device * dev,bool new_carrier)83210ab665SJiri Pirko static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
84210ab665SJiri Pirko {
85210ab665SJiri Pirko 	if (new_carrier)
86210ab665SJiri Pirko 		netif_carrier_on(dev);
87210ab665SJiri Pirko 	else
88210ab665SJiri Pirko 		netif_carrier_off(dev);
89210ab665SJiri Pirko 	return 0;
90210ab665SJiri Pirko }
91210ab665SJiri Pirko 
92aa18e9e8SStephen Hemminger static const struct net_device_ops dummy_netdev_ops = {
936d81f41cSEric Dumazet 	.ndo_init		= dummy_dev_init,
94890fdf2aSHiroaki SHIMODA 	.ndo_uninit		= dummy_dev_uninit,
95aa18e9e8SStephen Hemminger 	.ndo_start_xmit		= dummy_xmit,
96aa18e9e8SStephen Hemminger 	.ndo_validate_addr	= eth_validate_addr,
97afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= set_multicast_list,
980d1632b4SJiri Pirko 	.ndo_set_mac_address	= eth_mac_addr,
996d81f41cSEric Dumazet 	.ndo_get_stats64	= dummy_get_stats64,
100210ab665SJiri Pirko 	.ndo_change_carrier	= dummy_change_carrier,
101aa18e9e8SStephen Hemminger };
102aa18e9e8SStephen Hemminger 
103c19be735SFlavio Leitner static const struct ethtool_ops dummy_ethtool_ops = {
104abe9fd57SJulian Wiedmann 	.get_ts_info		= ethtool_op_get_ts_info,
105c19be735SFlavio Leitner };
106c19be735SFlavio Leitner 
dummy_setup(struct net_device * dev)1075d5cb173SPatrick McHardy static void dummy_setup(struct net_device *dev)
1081da177e4SLinus Torvalds {
109aa18e9e8SStephen Hemminger 	ether_setup(dev);
110aa18e9e8SStephen Hemminger 
1111da177e4SLinus Torvalds 	/* Initialize the device structure. */
112aa18e9e8SStephen Hemminger 	dev->netdev_ops = &dummy_netdev_ops;
113c19be735SFlavio Leitner 	dev->ethtool_ops = &dummy_ethtool_ops;
114cf124db5SDavid S. Miller 	dev->needs_free_netdev = true;
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	/* Fill in device structure with ethernet-generic values. */
1171da177e4SLinus Torvalds 	dev->flags |= IFF_NOARP;
1181da177e4SLinus Torvalds 	dev->flags &= ~IFF_MULTICAST;
119ff42c02cSPhil Sutter 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
1208f3af277SEric Dumazet 	dev->features	|= NETIF_F_SG | NETIF_F_FRAGLIST;
121ecb8fed4SAlexander Lobakin 	dev->features	|= NETIF_F_GSO_SOFTWARE;
12234324dc2SMichał Mirosław 	dev->features	|= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
1238f3af277SEric Dumazet 	dev->features	|= NETIF_F_GSO_ENCAP_ALL;
1248f3af277SEric Dumazet 	dev->hw_features |= dev->features;
1258f3af277SEric Dumazet 	dev->hw_enc_features |= dev->features;
1267ce5d222SDanny Kukawka 	eth_hw_addr_random(dev);
12725e3e84bSZhang Shengju 
12825e3e84bSZhang Shengju 	dev->min_mtu = 0;
129e94cd811SZhang Shengju 	dev->max_mtu = 0;
1301da177e4SLinus Torvalds }
1316d81f41cSEric Dumazet 
dummy_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)132a8b8a889SMatthias Schiffer static int dummy_validate(struct nlattr *tb[], struct nlattr *data[],
133a8b8a889SMatthias Schiffer 			  struct netlink_ext_ack *extack)
1340e06877cSPatrick McHardy {
1350e06877cSPatrick McHardy 	if (tb[IFLA_ADDRESS]) {
1360e06877cSPatrick McHardy 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1370e06877cSPatrick McHardy 			return -EINVAL;
1380e06877cSPatrick McHardy 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1390e06877cSPatrick McHardy 			return -EADDRNOTAVAIL;
1400e06877cSPatrick McHardy 	}
1410e06877cSPatrick McHardy 	return 0;
1420e06877cSPatrick McHardy }
1430e06877cSPatrick McHardy 
1445d5cb173SPatrick McHardy static struct rtnl_link_ops dummy_link_ops __read_mostly = {
145c19be735SFlavio Leitner 	.kind		= DRV_NAME,
1465d5cb173SPatrick McHardy 	.setup		= dummy_setup,
1470e06877cSPatrick McHardy 	.validate	= dummy_validate,
1485d5cb173SPatrick McHardy };
1495d5cb173SPatrick McHardy 
1501da177e4SLinus Torvalds /* Number of dummy devices to be set up by this module. */
1511da177e4SLinus Torvalds module_param(numdummies, int, 0);
1521da177e4SLinus Torvalds MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
1531da177e4SLinus Torvalds 
dummy_init_one(void)154206c9fb2SPatrick McHardy static int __init dummy_init_one(void)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds 	struct net_device *dev_dummy;
1571da177e4SLinus Torvalds 	int err;
1581da177e4SLinus Torvalds 
159c3361610SJakub Kicinski 	dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_ENUM, dummy_setup);
1601da177e4SLinus Torvalds 	if (!dev_dummy)
1611da177e4SLinus Torvalds 		return -ENOMEM;
1621da177e4SLinus Torvalds 
1635d5cb173SPatrick McHardy 	dev_dummy->rtnl_link_ops = &dummy_link_ops;
1645d5cb173SPatrick McHardy 	err = register_netdevice(dev_dummy);
1655d5cb173SPatrick McHardy 	if (err < 0)
1665d5cb173SPatrick McHardy 		goto err;
1675d5cb173SPatrick McHardy 	return 0;
1681da177e4SLinus Torvalds 
1695d5cb173SPatrick McHardy err:
1705d5cb173SPatrick McHardy 	free_netdev(dev_dummy);
1711da177e4SLinus Torvalds 	return err;
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
dummy_init_module(void)1741da177e4SLinus Torvalds static int __init dummy_init_module(void)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	int i, err = 0;
177206c9fb2SPatrick McHardy 
178554873e5SKirill Tkhai 	down_write(&pernet_ops_rwsem);
1795d5cb173SPatrick McHardy 	rtnl_lock();
1805d5cb173SPatrick McHardy 	err = __rtnl_link_register(&dummy_link_ops);
1812c8a0189Sdingtianhong 	if (err < 0)
1822c8a0189Sdingtianhong 		goto out;
1835d5cb173SPatrick McHardy 
18416b0dc29SEric Dumazet 	for (i = 0; i < numdummies && !err; i++) {
185206c9fb2SPatrick McHardy 		err = dummy_init_one();
18616b0dc29SEric Dumazet 		cond_resched();
18716b0dc29SEric Dumazet 	}
1882d85cba2SPatrick McHardy 	if (err < 0)
1895d5cb173SPatrick McHardy 		__rtnl_link_unregister(&dummy_link_ops);
1902c8a0189Sdingtianhong 
1912c8a0189Sdingtianhong out:
1925d5cb173SPatrick McHardy 	rtnl_unlock();
193554873e5SKirill Tkhai 	up_write(&pernet_ops_rwsem);
1945d5cb173SPatrick McHardy 
1951da177e4SLinus Torvalds 	return err;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
dummy_cleanup_module(void)1981da177e4SLinus Torvalds static void __exit dummy_cleanup_module(void)
1991da177e4SLinus Torvalds {
2002d85cba2SPatrick McHardy 	rtnl_link_unregister(&dummy_link_ops);
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds module_init(dummy_init_module);
2041da177e4SLinus Torvalds module_exit(dummy_cleanup_module);
2051da177e4SLinus Torvalds MODULE_LICENSE("GPL");
206c19be735SFlavio Leitner MODULE_ALIAS_RTNL_LINK(DRV_NAME);
207