[PATCH] bonding: support carrier state for master

	Add support for the bonding master to specify its carrier state
based upon the state of the slaves.  For 802.3ad, the bond is up if
there is an active, parterned aggregator.  For other modes, the bond is
up if any slaves are up.  Updates driver version to 3.0.3.

	Based on a patch by jamal <hadi@cyberus.ca>.

Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f13a539..55d2367 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -559,6 +559,42 @@
 /*------------------------------- Link status -------------------------------*/
 
 /*
+ * Set the carrier state for the master according to the state of its
+ * slaves.  If any slaves are up, the master is up.  In 802.3ad mode,
+ * do special 802.3ad magic.
+ *
+ * Returns zero if carrier state does not change, nonzero if it does.
+ */
+static int bond_set_carrier(struct bonding *bond)
+{
+	struct slave *slave;
+	int i;
+
+	if (bond->slave_cnt == 0)
+		goto down;
+
+	if (bond->params.mode == BOND_MODE_8023AD)
+		return bond_3ad_set_carrier(bond);
+
+	bond_for_each_slave(bond, slave, i) {
+		if (slave->link == BOND_LINK_UP) {
+			if (!netif_carrier_ok(bond->dev)) {
+				netif_carrier_on(bond->dev);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+down:
+	if (netif_carrier_ok(bond->dev)) {
+		netif_carrier_off(bond->dev);
+		return 1;
+	}
+	return 0;
+}
+
+/*
  * Get link speed and duplex from the slave's base driver
  * using ethtool. If for some reason the call fails or the
  * values are invalid, fake speed and duplex to 100/Full
@@ -1074,10 +1110,24 @@
 void bond_select_active_slave(struct bonding *bond)
 {
 	struct slave *best_slave;
+	int rv;
 
 	best_slave = bond_find_best_slave(bond);
 	if (best_slave != bond->curr_active_slave) {
 		bond_change_active_slave(bond, best_slave);
+		rv = bond_set_carrier(bond);
+		if (!rv)
+			return;
+
+		if (netif_carrier_ok(bond->dev)) {
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+		} else {
+			printk(KERN_INFO DRV_NAME ": %s: "
+			       "now running without any active interface !\n",
+			       bond->dev->name);
+		}
 	}
 }
 
@@ -1458,10 +1508,14 @@
 		if (((!bond->curr_active_slave) ||
 		     (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
 		    (new_slave->link != BOND_LINK_DOWN)) {
-			dprintk("This is the first active slave\n");
 			/* first slave or no active slave yet, and this link
 			   is OK, so make this interface the active one */
 			bond_change_active_slave(bond, new_slave);
+			printk(KERN_INFO DRV_NAME
+			       ": %s: first active interface up!\n",
+			       bond->dev->name);
+			netif_carrier_on(bond->dev);
+
 		} else {
 			dprintk("This is just a backup slave\n");
 			bond_set_slave_inactive_flags(new_slave);
@@ -1517,6 +1571,8 @@
 		break;
 	} /* switch(bond_mode) */
 
+	bond_set_carrier(bond);
+
 	write_unlock_bh(&bond->lock);
 
 	res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1656,18 +1712,12 @@
 		bond_alb_deinit_slave(bond, slave);
 	}
 
-	if (oldcurrent == slave) {
+	if (oldcurrent == slave)
 		bond_select_active_slave(bond);
 
-		if (!bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-	}
-
 	if (bond->slave_cnt == 0) {
+		bond_set_carrier(bond);
+
 		/* if the last slave was removed, zero the mac address
 		 * of the master so it will be set by the application
 		 * to the mac address of the first slave
@@ -1751,6 +1801,8 @@
 
 	write_lock_bh(&bond->lock);
 
+	netif_carrier_off(bond_dev);
+
 	if (bond->slave_cnt == 0) {
 		goto out;
 	}
@@ -2187,15 +2239,9 @@
 
 		bond_select_active_slave(bond);
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
-	}
+	} else
+		bond_set_carrier(bond);
 
 re_arm:
 	if (bond->params.miimon) {
@@ -2499,13 +2545,6 @@
 
 		bond_select_active_slave(bond);
 
-		if (oldcurrent && !bond->curr_active_slave) {
-			printk(KERN_INFO DRV_NAME
-			       ": %s: now running without any active "
-			       "interface !\n",
-			       bond_dev->name);
-		}
-
 		write_unlock(&bond->curr_slave_lock);
 	}
 
@@ -2579,12 +2618,15 @@
 					bond->current_arp_slave = NULL;
 				}
 
+				bond_set_carrier(bond);
+
 				if (slave == bond->curr_active_slave) {
 					printk(KERN_INFO DRV_NAME
 					       ": %s: %s is up and now the "
 					       "active interface\n",
 					       bond_dev->name,
 					       slave->dev->name);
+					netif_carrier_on(bond->dev);
 				} else {
 					printk(KERN_INFO DRV_NAME
 					       ": %s: backup interface %s is "
@@ -2844,7 +2886,8 @@
 			   (curr) ? curr->dev->name : "None");
 	}
 
-	seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down");
+	seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ?
+		   "up" : "down");
 	seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon);
 	seq_printf(seq, "Up Delay (ms): %d\n",
 		   bond->params.updelay * bond->params.miimon);
@@ -4531,6 +4574,8 @@
 	if (newbond)
 		*newbond = bond_dev->priv;
 
+	netif_carrier_off(bond_dev);
+
 	rtnl_unlock(); /* allows sysfs registration of net device */
 	res = bond_create_sysfs_entry(bond_dev->priv);
 	goto done;