diff options
-rw-r--r-- | drivers/net/dummy.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 2f2cf3c04bc7..91126b9ce453 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/rtnetlink.h> | 37 | #include <linux/rtnetlink.h> |
38 | #include <net/rtnetlink.h> | ||
38 | 39 | ||
39 | struct dummy_priv { | 40 | struct dummy_priv { |
40 | struct net_device *dev; | 41 | struct net_device *dev; |
@@ -61,12 +62,13 @@ static void set_multicast_list(struct net_device *dev) | |||
61 | { | 62 | { |
62 | } | 63 | } |
63 | 64 | ||
64 | static void __init dummy_setup(struct net_device *dev) | 65 | static void dummy_setup(struct net_device *dev) |
65 | { | 66 | { |
66 | /* Initialize the device structure. */ | 67 | /* Initialize the device structure. */ |
67 | dev->hard_start_xmit = dummy_xmit; | 68 | dev->hard_start_xmit = dummy_xmit; |
68 | dev->set_multicast_list = set_multicast_list; | 69 | dev->set_multicast_list = set_multicast_list; |
69 | dev->set_mac_address = dummy_set_address; | 70 | dev->set_mac_address = dummy_set_address; |
71 | dev->destructor = free_netdev; | ||
70 | 72 | ||
71 | /* Fill in device structure with ethernet-generic values. */ | 73 | /* Fill in device structure with ethernet-generic values. */ |
72 | ether_setup(dev); | 74 | ether_setup(dev); |
@@ -89,6 +91,37 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev) | |||
89 | 91 | ||
90 | static LIST_HEAD(dummies); | 92 | static LIST_HEAD(dummies); |
91 | 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 | |||
92 | /* Number of dummy devices to be set up by this module. */ | 125 | /* Number of dummy devices to be set up by this module. */ |
93 | module_param(numdummies, int, 0); | 126 | module_param(numdummies, int, 0); |
94 | MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices"); | 127 | MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices"); |
@@ -105,25 +138,23 @@ static int __init dummy_init_one(void) | |||
105 | if (!dev_dummy) | 138 | if (!dev_dummy) |
106 | return -ENOMEM; | 139 | return -ENOMEM; |
107 | 140 | ||
108 | if ((err = register_netdev(dev_dummy))) { | 141 | err = dev_alloc_name(dev_dummy, dev_dummy->name); |
109 | free_netdev(dev_dummy); | 142 | if (err < 0) |
110 | dev_dummy = NULL; | 143 | goto err; |
111 | } else { | ||
112 | priv = netdev_priv(dev_dummy); | ||
113 | priv->dev = dev_dummy; | ||
114 | list_add_tail(&priv->list, &dummies); | ||
115 | } | ||
116 | 144 | ||
117 | return err; | 145 | dev_dummy->rtnl_link_ops = &dummy_link_ops; |
118 | } | 146 | err = register_netdevice(dev_dummy); |
147 | if (err < 0) | ||
148 | goto err; | ||
119 | 149 | ||
120 | static void dummy_free_one(struct net_device *dev) | 150 | priv = netdev_priv(dev_dummy); |
121 | { | 151 | priv->dev = dev_dummy; |
122 | struct dummy_priv *priv = netdev_priv(dev); | 152 | list_add_tail(&priv->list, &dummies); |
153 | return 0; | ||
123 | 154 | ||
124 | list_del(&priv->list); | 155 | err: |
125 | unregister_netdev(dev); | 156 | free_netdev(dev_dummy); |
126 | free_netdev(dev); | 157 | return err; |
127 | } | 158 | } |
128 | 159 | ||
129 | static int __init dummy_init_module(void) | 160 | static int __init dummy_init_module(void) |
@@ -131,12 +162,18 @@ static int __init dummy_init_module(void) | |||
131 | struct dummy_priv *priv, *next; | 162 | struct dummy_priv *priv, *next; |
132 | int i, err = 0; | 163 | int i, err = 0; |
133 | 164 | ||
165 | rtnl_lock(); | ||
166 | err = __rtnl_link_register(&dummy_link_ops); | ||
167 | |||
134 | for (i = 0; i < numdummies && !err; i++) | 168 | for (i = 0; i < numdummies && !err; i++) |
135 | err = dummy_init_one(); | 169 | err = dummy_init_one(); |
136 | if (err) { | 170 | if (err < 0) { |
137 | list_for_each_entry_safe(priv, next, &dummies, list) | 171 | list_for_each_entry_safe(priv, next, &dummies, list) |
138 | dummy_free_one(priv->dev); | 172 | dummy_dellink(priv->dev); |
173 | __rtnl_link_unregister(&dummy_link_ops); | ||
139 | } | 174 | } |
175 | rtnl_unlock(); | ||
176 | |||
140 | return err; | 177 | return err; |
141 | } | 178 | } |
142 | 179 | ||
@@ -144,10 +181,15 @@ static void __exit dummy_cleanup_module(void) | |||
144 | { | 181 | { |
145 | struct dummy_priv *priv, *next; | 182 | struct dummy_priv *priv, *next; |
146 | 183 | ||
184 | rtnl_lock(); | ||
147 | list_for_each_entry_safe(priv, next, &dummies, list) | 185 | list_for_each_entry_safe(priv, next, &dummies, list) |
148 | dummy_free_one(priv->dev); | 186 | dummy_dellink(priv->dev); |
187 | |||
188 | __rtnl_link_unregister(&dummy_link_ops); | ||
189 | rtnl_unlock(); | ||
149 | } | 190 | } |
150 | 191 | ||
151 | module_init(dummy_init_module); | 192 | module_init(dummy_init_module); |
152 | module_exit(dummy_cleanup_module); | 193 | module_exit(dummy_cleanup_module); |
153 | MODULE_LICENSE("GPL"); | 194 | MODULE_LICENSE("GPL"); |
195 | MODULE_ALIAS_RTNL_LINK("dummy"); | ||