2005-04-17 02:20:36 +04:00
/* dummy.c: a dummy net driver
The purpose of this driver is to provide a device to point a
route through , but not to actually transmit packets .
Why ? If you have a machine whose only connection is an occasional
PPP / SLIP / PLIP link , you can only connect to your own hostname
when the link is up . Otherwise you have to use localhost .
This isn ' t very consistent .
One solution is to set up a dummy link using PPP / SLIP / PLIP ,
but this seems ( to me ) too much overhead for too little gain .
This driver provides a small alternative . Thus you can do
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
[ when not running slip ]
ifconfig dummy slip . addr . ess . here up
[ to go to slip ]
ifconfig dummy down
dip whatever
This was written by looking at Donald Becker ' s skeleton driver
and the loopback driver . I then threw away anything that didn ' t
apply ! Thanks to Alan Cox for the key clue on what to do with
misguided packets .
Nick Holloway , 27 th May 1994
[ I tweaked this explanation a little but that ' s all ]
Alan Cox , 30 th May 1994
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/init.h>
# include <linux/moduleparam.h>
2007-06-13 23:04:20 +04:00
# include <linux/rtnetlink.h>
2007-06-13 23:04:34 +04:00
# include <net/rtnetlink.h>
2007-06-13 23:04:20 +04:00
2005-04-17 02:20:36 +04:00
static int numdummies = 1 ;
static int dummy_xmit ( struct sk_buff * skb , struct net_device * dev ) ;
static int dummy_set_address ( struct net_device * dev , void * p )
{
struct sockaddr * sa = p ;
2006-09-13 21:24:59 +04:00
if ( ! is_valid_ether_addr ( sa - > sa_data ) )
2005-04-17 02:20:36 +04:00
return - EADDRNOTAVAIL ;
2006-09-13 21:24:59 +04:00
2005-04-17 02:20:36 +04:00
memcpy ( dev - > dev_addr , sa - > sa_data , ETH_ALEN ) ;
return 0 ;
}
/* fake multicast ability */
static void set_multicast_list ( struct net_device * dev )
{
}
2008-11-21 07:28:00 +03:00
static const struct net_device_ops dummy_netdev_ops = {
. ndo_start_xmit = dummy_xmit ,
. ndo_validate_addr = eth_validate_addr ,
. ndo_set_multicast_list = set_multicast_list ,
. ndo_set_mac_address = dummy_set_address ,
} ;
2007-06-13 23:04:34 +04:00
static void dummy_setup ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
2008-11-21 07:28:00 +03:00
ether_setup ( dev ) ;
2005-04-17 02:20:36 +04:00
/* Initialize the device structure. */
2008-11-21 07:28:00 +03:00
dev - > netdev_ops = & dummy_netdev_ops ;
2007-06-13 23:04:34 +04:00
dev - > destructor = free_netdev ;
2005-04-17 02:20:36 +04:00
/* Fill in device structure with ethernet-generic values. */
dev - > tx_queue_len = 0 ;
dev - > flags | = IFF_NOARP ;
dev - > flags & = ~ IFF_MULTICAST ;
random_ether_addr ( dev - > dev_addr ) ;
}
static int dummy_xmit ( struct sk_buff * skb , struct net_device * dev )
{
2007-06-13 23:04:06 +04:00
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
2005-04-17 02:20:36 +04:00
dev_kfree_skb ( skb ) ;
return 0 ;
}
2007-07-12 06:42:31 +04:00
static int dummy_validate ( struct nlattr * tb [ ] , struct nlattr * data [ ] )
{
if ( tb [ IFLA_ADDRESS ] ) {
if ( nla_len ( tb [ IFLA_ADDRESS ] ) ! = ETH_ALEN )
return - EINVAL ;
if ( ! is_valid_ether_addr ( nla_data ( tb [ IFLA_ADDRESS ] ) ) )
return - EADDRNOTAVAIL ;
}
return 0 ;
}
2007-06-13 23:04:34 +04:00
static struct rtnl_link_ops dummy_link_ops __read_mostly = {
. kind = " dummy " ,
. setup = dummy_setup ,
2007-07-12 06:42:31 +04:00
. validate = dummy_validate ,
2007-06-13 23:04:34 +04:00
} ;
2005-04-17 02:20:36 +04:00
/* Number of dummy devices to be set up by this module. */
module_param ( numdummies , int , 0 ) ;
MODULE_PARM_DESC ( numdummies , " Number of dummy pseudo devices " ) ;
2007-06-13 23:04:20 +04:00
static int __init dummy_init_one ( void )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev_dummy ;
int err ;
2007-07-12 06:42:13 +04:00
dev_dummy = alloc_netdev ( 0 , " dummy%d " , dummy_setup ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev_dummy )
return - ENOMEM ;
2007-06-13 23:04:34 +04:00
err = dev_alloc_name ( dev_dummy , dev_dummy - > name ) ;
if ( err < 0 )
goto err ;
2005-04-17 02:20:36 +04:00
2007-06-13 23:04:34 +04:00
dev_dummy - > rtnl_link_ops = & dummy_link_ops ;
err = register_netdevice ( dev_dummy ) ;
if ( err < 0 )
goto err ;
return 0 ;
2007-06-13 23:04:20 +04:00
2007-06-13 23:04:34 +04:00
err :
free_netdev ( dev_dummy ) ;
return err ;
2006-09-13 21:24:59 +04:00
}
2005-04-17 02:20:36 +04:00
static int __init dummy_init_module ( void )
2006-09-13 21:24:59 +04:00
{
2005-04-17 02:20:36 +04:00
int i , err = 0 ;
2007-06-13 23:04:20 +04:00
2007-06-13 23:04:34 +04:00
rtnl_lock ( ) ;
err = __rtnl_link_register ( & dummy_link_ops ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < numdummies & & ! err ; i + + )
2007-06-13 23:04:20 +04:00
err = dummy_init_one ( ) ;
2007-07-12 06:42:13 +04:00
if ( err < 0 )
2007-06-13 23:04:34 +04:00
__rtnl_link_unregister ( & dummy_link_ops ) ;
rtnl_unlock ( ) ;
2005-04-17 02:20:36 +04:00
return err ;
2006-09-13 21:24:59 +04:00
}
2005-04-17 02:20:36 +04:00
static void __exit dummy_cleanup_module ( void )
{
2007-07-12 06:42:13 +04:00
rtnl_link_unregister ( & dummy_link_ops ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( dummy_init_module ) ;
module_exit ( dummy_cleanup_module ) ;
MODULE_LICENSE ( " GPL " ) ;
2007-06-13 23:04:34 +04:00
MODULE_ALIAS_RTNL_LINK ( " dummy " ) ;