[DUMMY]: Use rtnl_link API
[deliverable/linux.git] / 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");
This page took 0.046758 seconds and 6 git commands to generate.