[DUMMY]: Use rtnl_link API
[safe/jmp/linux-2.6] / drivers / net / dummy.c
1 /* dummy.c: a dummy net driver
2
3         The purpose of this driver is to provide a device to point a
4         route through, but not to actually transmit packets.
5
6         Why?  If you have a machine whose only connection is an occasional
7         PPP/SLIP/PLIP link, you can only connect to your own hostname
8         when the link is up.  Otherwise you have to use localhost.
9         This isn't very consistent.
10
11         One solution is to set up a dummy link using PPP/SLIP/PLIP,
12         but this seems (to me) too much overhead for too little gain.
13         This driver provides a small alternative. Thus you can do
14
15         [when not running slip]
16                 ifconfig dummy slip.addr.ess.here up
17         [to go to slip]
18                 ifconfig dummy down
19                 dip whatever
20
21         This was written by looking at Donald Becker's skeleton driver
22         and the loopback driver.  I then threw away anything that didn't
23         apply!  Thanks to Alan Cox for the key clue on what to do with
24         misguided packets.
25
26                         Nick Holloway, 27th May 1994
27         [I tweaked this explanation a little but that's all]
28                         Alan Cox, 30th May 1994
29 */
30
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/netdevice.h>
34 #include <linux/etherdevice.h>
35 #include <linux/init.h>
36 #include <linux/moduleparam.h>
37 #include <linux/rtnetlink.h>
38 #include <net/rtnetlink.h>
39
40 struct dummy_priv {
41         struct net_device *dev;
42         struct list_head list;
43 };
44
45 static int numdummies = 1;
46
47 static int dummy_xmit(struct sk_buff *skb, struct net_device *dev);
48
49 static int dummy_set_address(struct net_device *dev, void *p)
50 {
51         struct sockaddr *sa = p;
52
53         if (!is_valid_ether_addr(sa->sa_data))
54                 return -EADDRNOTAVAIL;
55
56         memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
57         return 0;
58 }
59
60 /* fake multicast ability */
61 static void set_multicast_list(struct net_device *dev)
62 {
63 }
64
65 static void dummy_setup(struct net_device *dev)
66 {
67         /* Initialize the device structure. */
68         dev->hard_start_xmit = dummy_xmit;
69         dev->set_multicast_list = set_multicast_list;
70         dev->set_mac_address = dummy_set_address;
71         dev->destructor = free_netdev;
72
73         /* Fill in device structure with ethernet-generic values. */
74         ether_setup(dev);
75         dev->tx_queue_len = 0;
76         dev->change_mtu = NULL;
77         dev->flags |= IFF_NOARP;
78         dev->flags &= ~IFF_MULTICAST;
79         SET_MODULE_OWNER(dev);
80         random_ether_addr(dev->dev_addr);
81 }
82
83 static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
84 {
85         dev->stats.tx_packets++;
86         dev->stats.tx_bytes += skb->len;
87
88         dev_kfree_skb(skb);
89         return 0;
90 }
91
92 static LIST_HEAD(dummies);
93
94 static int dummy_newlink(struct net_device *dev,
95                          struct nlattr *tb[], struct nlattr *data[])
96 {
97         struct dummy_priv *priv = netdev_priv(dev);
98         int err;
99
100         err = register_netdevice(dev);
101         if (err < 0)
102                 return err;
103
104         priv->dev = dev;
105         list_add_tail(&priv->list, &dummies);
106         return 0;
107 }
108
109 static void dummy_dellink(struct net_device *dev)
110 {
111         struct dummy_priv *priv = netdev_priv(dev);
112
113         list_del(&priv->list);
114         unregister_netdevice(dev);
115 }
116
117 static struct rtnl_link_ops dummy_link_ops __read_mostly = {
118         .kind           = "dummy",
119         .priv_size      = sizeof(struct dummy_priv),
120         .setup          = dummy_setup,
121         .newlink        = dummy_newlink,
122         .dellink        = dummy_dellink,
123 };
124
125 /* Number of dummy devices to be set up by this module. */
126 module_param(numdummies, int, 0);
127 MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
128
129 static int __init dummy_init_one(void)
130 {
131         struct net_device *dev_dummy;
132         struct dummy_priv *priv;
133         int err;
134
135         dev_dummy = alloc_netdev(sizeof(struct dummy_priv), "dummy%d",
136                                  dummy_setup);
137
138         if (!dev_dummy)
139                 return -ENOMEM;
140
141         err = dev_alloc_name(dev_dummy, dev_dummy->name);
142         if (err < 0)
143                 goto err;
144
145         dev_dummy->rtnl_link_ops = &dummy_link_ops;
146         err = register_netdevice(dev_dummy);
147         if (err < 0)
148                 goto err;
149
150         priv = netdev_priv(dev_dummy);
151         priv->dev = dev_dummy;
152         list_add_tail(&priv->list, &dummies);
153         return 0;
154
155 err:
156         free_netdev(dev_dummy);
157         return err;
158 }
159
160 static int __init dummy_init_module(void)
161 {
162         struct dummy_priv *priv, *next;
163         int i, err = 0;
164
165         rtnl_lock();
166         err = __rtnl_link_register(&dummy_link_ops);
167
168         for (i = 0; i < numdummies && !err; i++)
169                 err = dummy_init_one();
170         if (err < 0) {
171                 list_for_each_entry_safe(priv, next, &dummies, list)
172                         dummy_dellink(priv->dev);
173                 __rtnl_link_unregister(&dummy_link_ops);
174         }
175         rtnl_unlock();
176
177         return err;
178 }
179
180 static void __exit dummy_cleanup_module(void)
181 {
182         struct dummy_priv *priv, *next;
183
184         rtnl_lock();
185         list_for_each_entry_safe(priv, next, &dummies, list)
186                 dummy_dellink(priv->dev);
187
188         __rtnl_link_unregister(&dummy_link_ops);
189         rtnl_unlock();
190 }
191
192 module_init(dummy_init_module);
193 module_exit(dummy_cleanup_module);
194 MODULE_LICENSE("GPL");
195 MODULE_ALIAS_RTNL_LINK("dummy");