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