aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2015-02-24 16:15:32 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-25 17:03:38 -0500
commitd87d6f44d7c1254fd9560a5191659cb00882db56 (patch)
treeedc80a71daf91645aa2e74a798f97a9fd836a35a /net/dsa
parent92bf200881d978bc3c6a290991ae1f9ddc7b5411 (diff)
net: dsa: Ensure that port array elements are initialized before being used
A network device notifier can be called for one or more of the created slave devices before all slave devices have been registered. This can result in a mismatch between ds->phys_port_mask and the registered devices by the time the call is made, and it can result in a slave device being added to a bridge before its entry in ds->ports[] has been initialized. Rework the initialization code to initialize entries in ds->ports[] in dsa_slave_create. With this change, dsa_slave_create no longer needs to return slave_dev but can return an error code instead. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa.c10
-rw-r--r--net/dsa/dsa_priv.h5
-rw-r--r--net/dsa/slave.c15
3 files changed, 13 insertions, 17 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 2173402d87e0..fc1813140be6 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -314,19 +314,15 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
314 * Create network devices for physical switch ports. 314 * Create network devices for physical switch ports.
315 */ 315 */
316 for (i = 0; i < DSA_MAX_PORTS; i++) { 316 for (i = 0; i < DSA_MAX_PORTS; i++) {
317 struct net_device *slave_dev;
318
319 if (!(ds->phys_port_mask & (1 << i))) 317 if (!(ds->phys_port_mask & (1 << i)))
320 continue; 318 continue;
321 319
322 slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); 320 ret = dsa_slave_create(ds, parent, i, pd->port_names[i]);
323 if (slave_dev == NULL) { 321 if (ret < 0) {
324 netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n", 322 netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
325 index, i, pd->port_names[i]); 323 index, i, pd->port_names[i]);
326 continue; 324 ret = 0;
327 } 325 }
328
329 ds->ports[i] = slave_dev;
330 } 326 }
331 327
332#ifdef CONFIG_NET_DSA_HWMON 328#ifdef CONFIG_NET_DSA_HWMON
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index dc9756d3154c..7eb1a6acd46c 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -53,9 +53,8 @@ extern char dsa_driver_version[];
53/* slave.c */ 53/* slave.c */
54extern const struct dsa_device_ops notag_netdev_ops; 54extern const struct dsa_device_ops notag_netdev_ops;
55void dsa_slave_mii_bus_init(struct dsa_switch *ds); 55void dsa_slave_mii_bus_init(struct dsa_switch *ds);
56struct net_device *dsa_slave_create(struct dsa_switch *ds, 56int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
57 struct device *parent, 57 int port, char *name);
58 int port, char *name);
59int dsa_slave_suspend(struct net_device *slave_dev); 58int dsa_slave_suspend(struct net_device *slave_dev);
60int dsa_slave_resume(struct net_device *slave_dev); 59int dsa_slave_resume(struct net_device *slave_dev);
61 60
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index f23deadf42a0..5be4c928c9c9 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -605,9 +605,8 @@ int dsa_slave_resume(struct net_device *slave_dev)
605 return 0; 605 return 0;
606} 606}
607 607
608struct net_device * 608int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
609dsa_slave_create(struct dsa_switch *ds, struct device *parent, 609 int port, char *name)
610 int port, char *name)
611{ 610{
612 struct net_device *master = ds->dst->master_netdev; 611 struct net_device *master = ds->dst->master_netdev;
613 struct net_device *slave_dev; 612 struct net_device *slave_dev;
@@ -617,7 +616,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
617 slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, 616 slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
618 NET_NAME_UNKNOWN, ether_setup); 617 NET_NAME_UNKNOWN, ether_setup);
619 if (slave_dev == NULL) 618 if (slave_dev == NULL)
620 return slave_dev; 619 return -ENOMEM;
621 620
622 slave_dev->features = master->vlan_features; 621 slave_dev->features = master->vlan_features;
623 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 622 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
@@ -667,19 +666,21 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
667 ret = dsa_slave_phy_setup(p, slave_dev); 666 ret = dsa_slave_phy_setup(p, slave_dev);
668 if (ret) { 667 if (ret) {
669 free_netdev(slave_dev); 668 free_netdev(slave_dev);
670 return NULL; 669 return ret;
671 } 670 }
672 671
672 ds->ports[port] = slave_dev;
673 ret = register_netdev(slave_dev); 673 ret = register_netdev(slave_dev);
674 if (ret) { 674 if (ret) {
675 netdev_err(master, "error %d registering interface %s\n", 675 netdev_err(master, "error %d registering interface %s\n",
676 ret, slave_dev->name); 676 ret, slave_dev->name);
677 phy_disconnect(p->phy); 677 phy_disconnect(p->phy);
678 ds->ports[port] = NULL;
678 free_netdev(slave_dev); 679 free_netdev(slave_dev);
679 return NULL; 680 return ret;
680 } 681 }
681 682
682 netif_carrier_off(slave_dev); 683 netif_carrier_off(slave_dev);
683 684
684 return slave_dev; 685 return 0;
685} 686}