diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ifb.c | 80 |
1 files changed, 60 insertions, 20 deletions
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 819945e3b330..669ee1a1b284 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c | |||
@@ -139,13 +139,14 @@ resched: | |||
139 | 139 | ||
140 | } | 140 | } |
141 | 141 | ||
142 | static void __init ifb_setup(struct net_device *dev) | 142 | static void ifb_setup(struct net_device *dev) |
143 | { | 143 | { |
144 | /* Initialize the device structure. */ | 144 | /* Initialize the device structure. */ |
145 | dev->get_stats = ifb_get_stats; | 145 | dev->get_stats = ifb_get_stats; |
146 | dev->hard_start_xmit = ifb_xmit; | 146 | dev->hard_start_xmit = ifb_xmit; |
147 | dev->open = &ifb_open; | 147 | dev->open = &ifb_open; |
148 | dev->stop = &ifb_close; | 148 | dev->stop = &ifb_close; |
149 | dev->destructor = free_netdev; | ||
149 | 150 | ||
150 | /* Fill in device structure with ethernet-generic values. */ | 151 | /* Fill in device structure with ethernet-generic values. */ |
151 | ether_setup(dev); | 152 | ether_setup(dev); |
@@ -229,6 +230,37 @@ static int ifb_open(struct net_device *dev) | |||
229 | return 0; | 230 | return 0; |
230 | } | 231 | } |
231 | 232 | ||
233 | static int ifb_newlink(struct net_device *dev, | ||
234 | struct nlattr *tb[], struct nlattr *data[]) | ||
235 | { | ||
236 | struct ifb_private *priv = netdev_priv(dev); | ||
237 | int err; | ||
238 | |||
239 | err = register_netdevice(dev); | ||
240 | if (err < 0) | ||
241 | return err; | ||
242 | |||
243 | priv->dev = dev; | ||
244 | list_add_tail(&priv->list, &ifbs); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void ifb_dellink(struct net_device *dev) | ||
249 | { | ||
250 | struct ifb_private *priv = netdev_priv(dev); | ||
251 | |||
252 | list_del(&priv->list); | ||
253 | unregister_netdevice(dev); | ||
254 | } | ||
255 | |||
256 | static struct rtnl_link_ops ifb_link_ops __read_mostly = { | ||
257 | .kind = "ifb", | ||
258 | .priv_size = sizeof(struct ifb_private), | ||
259 | .setup = ifb_setup, | ||
260 | .newlink = ifb_newlink, | ||
261 | .dellink = ifb_dellink, | ||
262 | }; | ||
263 | |||
232 | static int __init ifb_init_one(int index) | 264 | static int __init ifb_init_one(int index) |
233 | { | 265 | { |
234 | struct net_device *dev_ifb; | 266 | struct net_device *dev_ifb; |
@@ -241,38 +273,41 @@ static int __init ifb_init_one(int index) | |||
241 | if (!dev_ifb) | 273 | if (!dev_ifb) |
242 | return -ENOMEM; | 274 | return -ENOMEM; |
243 | 275 | ||
244 | if ((err = register_netdev(dev_ifb))) { | 276 | err = dev_alloc_name(dev_ifb, dev_ifb->name); |
245 | free_netdev(dev_ifb); | 277 | if (err < 0) |
246 | dev_ifb = NULL; | 278 | goto err; |
247 | } else { | ||
248 | priv = netdev_priv(dev_ifb); | ||
249 | priv->dev = dev_ifb; | ||
250 | list_add_tail(&priv->list, &ifbs); | ||
251 | } | ||
252 | 279 | ||
253 | return err; | 280 | dev_ifb->rtnl_link_ops = &ifb_link_ops; |
254 | } | 281 | err = register_netdevice(dev_ifb); |
282 | if (err < 0) | ||
283 | goto err; | ||
255 | 284 | ||
256 | static void ifb_free_one(struct net_device *dev) | 285 | priv = netdev_priv(dev_ifb); |
257 | { | 286 | priv->dev = dev_ifb; |
258 | struct ifb_private *priv = netdev_priv(dev); | 287 | list_add_tail(&priv->list, &ifbs); |
288 | return 0; | ||
259 | 289 | ||
260 | list_del(&priv->list); | 290 | err: |
261 | unregister_netdev(dev); | 291 | free_netdev(dev_ifb); |
262 | free_netdev(dev); | 292 | return err; |
263 | } | 293 | } |
264 | 294 | ||
265 | static int __init ifb_init_module(void) | 295 | static int __init ifb_init_module(void) |
266 | { | 296 | { |
267 | struct ifb_private *priv, *next; | 297 | struct ifb_private *priv, *next; |
268 | int i, err = 0; | 298 | int i, err; |
299 | |||
300 | rtnl_lock(); | ||
301 | err = __rtnl_link_register(&ifb_link_ops); | ||
269 | 302 | ||
270 | for (i = 0; i < numifbs && !err; i++) | 303 | for (i = 0; i < numifbs && !err; i++) |
271 | err = ifb_init_one(i); | 304 | err = ifb_init_one(i); |
272 | if (err) { | 305 | if (err) { |
273 | list_for_each_entry_safe(priv, next, &ifbs, list) | 306 | list_for_each_entry_safe(priv, next, &ifbs, list) |
274 | ifb_free_one(priv->dev); | 307 | ifb_dellink(priv->dev); |
308 | __rtnl_link_unregister(&ifb_link_ops); | ||
275 | } | 309 | } |
310 | rtnl_unlock(); | ||
276 | 311 | ||
277 | return err; | 312 | return err; |
278 | } | 313 | } |
@@ -281,11 +316,16 @@ static void __exit ifb_cleanup_module(void) | |||
281 | { | 316 | { |
282 | struct ifb_private *priv, *next; | 317 | struct ifb_private *priv, *next; |
283 | 318 | ||
319 | rtnl_lock(); | ||
284 | list_for_each_entry_safe(priv, next, &ifbs, list) | 320 | list_for_each_entry_safe(priv, next, &ifbs, list) |
285 | ifb_free_one(priv->dev); | 321 | ifb_dellink(priv->dev); |
322 | |||
323 | __rtnl_link_unregister(&ifb_link_ops); | ||
324 | rtnl_unlock(); | ||
286 | } | 325 | } |
287 | 326 | ||
288 | module_init(ifb_init_module); | 327 | module_init(ifb_init_module); |
289 | module_exit(ifb_cleanup_module); | 328 | module_exit(ifb_cleanup_module); |
290 | MODULE_LICENSE("GPL"); | 329 | MODULE_LICENSE("GPL"); |
291 | MODULE_AUTHOR("Jamal Hadi Salim"); | 330 | MODULE_AUTHOR("Jamal Hadi Salim"); |
331 | MODULE_ALIAS_RTNL_LINK("ifb"); | ||