Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6.git] / drivers / net / bonding / bond_3ad.c
index 6233c4f..494bf96 100644 (file)
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
- *
- * Changes:
- *
- * 2003/05/01 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
- *             Amir Noam <amir.noam at intel dot com>
- *     - Added support for lacp_rate module param.
- *
- * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Based on discussion on mailing list, changed locking scheme
- *       to use lock/unlock or lock_bh/unlock_bh appropriately instead
- *       of lock_irqsave/unlock_irqrestore. The new scheme helps exposing
- *       hidden bugs and solves system hangs that occurred due to the fact
- *       that holding lock_irqsave doesn't prevent softirqs from running.
- *       This also increases total throughput since interrupts are not
- *       blocked on each transmitted packets or monitor timeout.
- *
- * 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Renamed bond_3ad_link_status_changed() to
- *       bond_3ad_handle_link_change() for compatibility with TLB.
- *
- * 2003/05/20 - Amir Noam <amir.noam at intel dot com>
- *     - Fix long fail over time when releasing last slave of an active
- *       aggregator - send LACPDU on unbind of slave to tell partner this
- *       port is no longer aggregatable.
- *
- * 2003/06/25 - Tsippy Mendelson <tsippy.mendelson at intel dot com>
- *     - Send LACPDU as highest priority packet to further fix the above
- *       problem on very high Tx traffic load where packets may get dropped
- *       by the slave.
- *
- * 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
- *     - Code cleanup and style changes
  */
 
-//#define BONDING_DEBUG 1
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/etherdevice.h>
 #include <linux/if_bonding.h>
 #include <linux/pkt_sched.h>
+#include <net/net_namespace.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 
 #define     AD_LINK_SPEED_BITMASK_10MBPS      0x2
 #define     AD_LINK_SPEED_BITMASK_100MBPS     0x4
 #define     AD_LINK_SPEED_BITMASK_1000MBPS    0x8
+#define     AD_LINK_SPEED_BITMASK_10000MBPS   0x10
 //endalloun
 
 // compare MAC addresses
 #define MAC_ADDRESS_COMPARE(A, B) memcmp(A, B, ETH_ALEN)
 
-static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}};
+static struct mac_addr null_mac_addr = { { 0, 0, 0, 0, 0, 0 } };
 static u16 ad_ticks_per_sec;
 static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
 
-// ================= 3AD api to bonding and kernel code ==================
-static u16 __get_link_speed(struct port *port);
-static u8 __get_duplex(struct port *port);
-static inline void __initialize_port_locks(struct port *port);
-//conversions
-static void __ntohs_lacpdu(struct lacpdu *lacpdu);
-static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
-
-
-// ================= ad code helper functions ==================
-//needed by ad_rx_machine(...)
-static void __record_pdu(struct lacpdu *lacpdu, struct port *port);
-static void __record_default(struct port *port);
-static void __update_selected(struct lacpdu *lacpdu, struct port *port);
-static void __update_default_selected(struct port *port);
-static void __choose_matched(struct lacpdu *lacpdu, struct port *port);
-static void __update_ntt(struct lacpdu *lacpdu, struct port *port);
-
-//needed for ad_mux_machine(..)
-static void __attach_bond_to_agg(struct port *port);
-static void __detach_bond_from_agg(struct port *port);
-static int __agg_ports_are_ready(struct aggregator *aggregator);
-static void __set_agg_ports_ready(struct aggregator *aggregator, int val);
-
-//needed for ad_agg_selection_logic(...)
-static u32 __get_agg_bandwidth(struct aggregator *aggregator);
-static struct aggregator *__get_active_agg(struct aggregator *aggregator);
-
+static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
 // ================= main 802.3ad protocol functions ==================
 static int ad_lacpdu_send(struct port *port);
-static int ad_marker_send(struct port *port, struct marker *marker);
+static int ad_marker_send(struct port *port, struct bond_marker *marker);
 static void ad_mux_machine(struct port *port);
 static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
 static void ad_tx_machine(struct port *port);
@@ -167,11 +111,10 @@ static void ad_agg_selection_logic(struct aggregator *aggregator);
 static void ad_clear_agg(struct aggregator *aggregator);
 static void ad_initialize_agg(struct aggregator *aggregator);
 static void ad_initialize_port(struct port *port, int lacp_fast);
-static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);
 static void ad_enable_collecting_distributing(struct port *port);
 static void ad_disable_collecting_distributing(struct port *port);
-static void ad_marker_info_received(struct marker *marker_info, struct port *port);
-static void ad_marker_response_received(struct marker *marker, struct port *port);
+static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port);
+static void ad_marker_response_received(struct bond_marker *marker, struct port *port);
 
 
 /////////////////////////////////////////////////////////////////////////////////
@@ -186,9 +129,8 @@ static void ad_marker_response_received(struct marker *marker, struct port *port
  */
 static inline struct bonding *__get_bond_by_port(struct port *port)
 {
-       if (port->slave == NULL) {
+       if (port->slave == NULL)
                return NULL;
-       }
 
        return bond_get_bond_by_slave(port->slave);
 }
@@ -201,9 +143,8 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
  */
 static inline struct port *__get_first_port(struct bonding *bond)
 {
-       if (bond->slave_cnt == 0) {
+       if (bond->slave_cnt == 0)
                return NULL;
-       }
 
        return &(SLAVE_AD_INFO(bond->first_slave).port);
 }
@@ -221,9 +162,8 @@ static inline struct port *__get_next_port(struct port *port)
        struct slave *slave = port->slave;
 
        // If there's no bond for this port, or this is the last slave
-       if ((bond == NULL) || (slave->next == bond->first_slave)) {
+       if ((bond == NULL) || (slave->next == bond->first_slave))
                return NULL;
-       }
 
        return &(SLAVE_AD_INFO(slave->next).port);
 }
@@ -240,9 +180,8 @@ static inline struct aggregator *__get_first_agg(struct port *port)
        struct bonding *bond = __get_bond_by_port(port);
 
        // If there's no bond for this port, or bond has no slaves
-       if ((bond == NULL) || (bond->slave_cnt == 0)) {
+       if ((bond == NULL) || (bond->slave_cnt == 0))
                return NULL;
-       }
 
        return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
 }
@@ -260,13 +199,23 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
        struct bonding *bond = bond_get_bond_by_slave(slave);
 
        // If there's no bond for this aggregator, or this is the last slave
-       if ((bond == NULL) || (slave->next == bond->first_slave)) {
+       if ((bond == NULL) || (slave->next == bond->first_slave))
                return NULL;
-       }
 
        return &(SLAVE_AD_INFO(slave->next).aggregator);
 }
 
+/*
+ * __agg_has_partner
+ *
+ * Return nonzero if aggregator has a partner (denoted by a non-zero ether
+ * address for the partner).  Return 0 if not.
+ */
+static inline int __agg_has_partner(struct aggregator *agg)
+{
+       return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
+}
+
 /**
  * __disable_port - disable the port's slave
  * @port: the port we're looking at
@@ -286,9 +235,8 @@ static inline void __enable_port(struct port *port)
 {
        struct slave *slave = port->slave;
 
-       if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) {
+       if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
                bond_set_slave_active_flags(slave);
-       }
 }
 
 /**
@@ -298,22 +246,21 @@ static inline void __enable_port(struct port *port)
  */
 static inline int __port_is_enabled(struct port *port)
 {
-       return(port->slave->state == BOND_STATE_ACTIVE);
+       return bond_is_active_slave(port->slave);
 }
 
 /**
  * __get_agg_selection_mode - get the aggregator selection mode
  * @port: the port we're looking at
  *
- * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT.
+ * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT.
  */
 static inline u32 __get_agg_selection_mode(struct port *port)
 {
        struct bonding *bond = __get_bond_by_port(port);
 
-       if (bond == NULL) {
-               return AD_BANDWIDTH;
-       }
+       if (bond == NULL)
+               return BOND_AD_STABLE;
 
        return BOND_AD_INFO(bond).agg_select_mode;
 }
@@ -327,31 +274,30 @@ static inline int __check_agg_selection_timer(struct port *port)
 {
        struct bonding *bond = __get_bond_by_port(port);
 
-       if (bond == NULL) {
+       if (bond == NULL)
                return 0;
-       }
 
        return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;
 }
 
 /**
- * __get_rx_machine_lock - lock the port's RX machine
+ * __get_state_machine_lock - lock the port's state machines
  * @port: the port we're looking at
  *
  */
-static inline void __get_rx_machine_lock(struct port *port)
+static inline void __get_state_machine_lock(struct port *port)
 {
-       spin_lock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_lock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 /**
- * __release_rx_machine_lock - unlock the port's RX machine
+ * __release_state_machine_lock - unlock the port's state machines
  * @port: the port we're looking at
  *
  */
-static inline void __release_rx_machine_lock(struct port *port)
+static inline void __release_state_machine_lock(struct port *port)
 {
-       spin_unlock(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_unlock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 /**
@@ -362,7 +308,8 @@ static inline void __release_rx_machine_lock(struct port *port)
  *     0,
  *     %AD_LINK_SPEED_BITMASK_10MBPS,
  *     %AD_LINK_SPEED_BITMASK_100MBPS,
- *     %AD_LINK_SPEED_BITMASK_1000MBPS
+ *     %AD_LINK_SPEED_BITMASK_1000MBPS,
+ *     %AD_LINK_SPEED_BITMASK_10000MBPS
  */
 static u16 __get_link_speed(struct port *port)
 {
@@ -373,9 +320,9 @@ static u16 __get_link_speed(struct port *port)
         * link down, it sets the speed to 0.
         * This is done in spite of the fact that the e100 driver reports 0 to be
         * compatible with MVT in the future.*/
-       if (slave->link != BOND_LINK_UP) {
-               speed=0;
-       } else {
+       if (slave->link != BOND_LINK_UP)
+               speed = 0;
+       else {
                switch (slave->speed) {
                case SPEED_10:
                        speed = AD_LINK_SPEED_BITMASK_10MBPS;
@@ -389,13 +336,18 @@ static u16 __get_link_speed(struct port *port)
                        speed = AD_LINK_SPEED_BITMASK_1000MBPS;
                        break;
 
+               case SPEED_10000:
+                       speed = AD_LINK_SPEED_BITMASK_10000MBPS;
+                       break;
+
                default:
                        speed = 0; // unknown speed value from ethtool. shouldn't happen
                        break;
                }
        }
 
-       dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed);
+       pr_debug("Port %d Received link speed %d update from adapter\n",
+                port->actor_port_number, speed);
        return speed;
 }
 
@@ -415,18 +367,20 @@ static u8 __get_duplex(struct port *port)
 
        //  handling a special case: when the configuration starts with
        // link down, it sets the duplex to 0.
-       if (slave->link != BOND_LINK_UP) {
-               retval=0x0;
-       } else {
+       if (slave->link != BOND_LINK_UP)
+               retval = 0x0;
+       else {
                switch (slave->duplex) {
                case DUPLEX_FULL:
-                       retval=0x1;
-                       dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number);
+                       retval = 0x1;
+                       pr_debug("Port %d Received status full duplex update from adapter\n",
+                                port->actor_port_number);
                        break;
                case DUPLEX_HALF:
                default:
-                       retval=0x0;
-                       dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number);
+                       retval = 0x0;
+                       pr_debug("Port %d Received status NOT full duplex update from adapter\n",
+                                port->actor_port_number);
                        break;
                }
        }
@@ -434,37 +388,17 @@ static u8 __get_duplex(struct port *port)
 }
 
 /**
- * __initialize_port_locks - initialize a port's RX machine spinlock
+ * __initialize_port_locks - initialize a port's STATE machine spinlock
  * @port: the port we're looking at
  *
  */
 static inline void __initialize_port_locks(struct port *port)
 {
        // make sure it isn't called twice
-       spin_lock_init(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 //conversions
-/**
- * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
- * @lacpdu: the speicifed lacpdu
- *
- * For each multi-byte field in the lacpdu, convert its content
- */
-static void __ntohs_lacpdu(struct lacpdu *lacpdu)
-{
-       if (lacpdu) {
-               lacpdu->actor_system_priority =   ntohs(lacpdu->actor_system_priority);
-               lacpdu->actor_key =               ntohs(lacpdu->actor_key);
-               lacpdu->actor_port_priority =     ntohs(lacpdu->actor_port_priority);
-               lacpdu->actor_port =              ntohs(lacpdu->actor_port);
-               lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
-               lacpdu->partner_key =             ntohs(lacpdu->partner_key);
-               lacpdu->partner_port_priority =   ntohs(lacpdu->partner_port_priority);
-               lacpdu->partner_port =            ntohs(lacpdu->partner_port);
-               lacpdu->collector_max_delay =     ntohs(lacpdu->collector_max_delay);
-       }
-}
 
 /**
  * __ad_timer_to_ticks - convert a given timer type to AD module ticks
@@ -477,15 +411,14 @@ static void __ntohs_lacpdu(struct lacpdu *lacpdu)
  */
 static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
 {
-       u16 retval=0;    //to silence the compiler
+       u16 retval = 0; /* to silence the compiler */
 
        switch (timer_type) {
        case AD_CURRENT_WHILE_TIMER:   // for rx machine usage
-               if (par) {            // for short or long timeout
+               if (par)
                        retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout
-               } else {
+               else
                        retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout
-               }
                break;
        case AD_ACTOR_CHURN_TIMER:          // for local churn machine
                retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
@@ -509,6 +442,48 @@ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
 /////////////////////////////////////////////////////////////////////////////////
 
 /**
+ * __choose_matched - update a port's matched variable from a received lacpdu
+ * @lacpdu: the lacpdu we've received
+ * @port: the port we're looking at
+ *
+ * Update the value of the matched variable, using parameter values from a
+ * newly received lacpdu. Parameter values for the partner carried in the
+ * received PDU are compared with the corresponding operational parameter
+ * values for the actor. Matched is set to TRUE if all of these parameters
+ * match and the PDU parameter partner_state.aggregation has the same value as
+ * actor_oper_port_state.aggregation and lacp will actively maintain the link
+ * in the aggregation. Matched is also set to TRUE if the value of
+ * actor_state.aggregation in the received PDU is set to FALSE, i.e., indicates
+ * an individual link and lacp will actively maintain the link. Otherwise,
+ * matched is set to FALSE. LACP is considered to be actively maintaining the
+ * link if either the PDU's actor_state.lacp_activity variable is TRUE or both
+ * the actor's actor_oper_port_state.lacp_activity and the PDU's
+ * partner_state.lacp_activity variables are TRUE.
+ *
+ * Note: the AD_PORT_MATCHED "variable" is not specified by 802.3ad; it is
+ * used here to implement the language from 802.3ad 43.4.9 that requires
+ * recordPDU to "match" the LACPDU parameters to the stored values.
+ */
+static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
+{
+       // check if all parameters are alike
+       if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
+            (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
+            !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
+            (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
+            (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
+            ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
+           // or this is individual link(aggregation == FALSE)
+           ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
+               ) {
+               // update the state machine Matched variable
+               port->sm_vars |= AD_PORT_MATCHED;
+       } else {
+               port->sm_vars &= ~AD_PORT_MATCHED;
+       }
+}
+
+/**
  * __record_pdu - record parameters from a received lacpdu
  * @lacpdu: the lacpdu we've received
  * @port: the port we're looking at
@@ -519,34 +494,27 @@ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
  */
 static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
 {
-       // validate lacpdu and port
        if (lacpdu && port) {
+               struct port_params *partner = &port->partner_oper;
+
+               __choose_matched(lacpdu, port);
                // record the new parameter values for the partner operational
-               port->partner_oper_port_number = lacpdu->actor_port;
-               port->partner_oper_port_priority = lacpdu->actor_port_priority;
-               port->partner_oper_system = lacpdu->actor_system;
-               port->partner_oper_system_priority = lacpdu->actor_system_priority;
-               port->partner_oper_key = lacpdu->actor_key;
-               // zero partener's lase states
-               port->partner_oper_port_state = 0;
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_TIMEOUT);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_AGGREGATION);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_COLLECTING);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DISTRIBUTING);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DEFAULTED);
-               port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_EXPIRED);
+               partner->port_number = ntohs(lacpdu->actor_port);
+               partner->port_priority = ntohs(lacpdu->actor_port_priority);
+               partner->system = lacpdu->actor_system;
+               partner->system_priority = ntohs(lacpdu->actor_system_priority);
+               partner->key = ntohs(lacpdu->actor_key);
+               partner->port_state = lacpdu->actor_state;
 
                // set actor_oper_port_state.defaulted to FALSE
                port->actor_oper_port_state &= ~AD_STATE_DEFAULTED;
 
                // set the partner sync. to on if the partner is sync. and the port is matched
-               if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
-                       port->partner_oper_port_state |= AD_STATE_SYNCHRONIZATION;
-               } else {
-                       port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
-               }
+               if ((port->sm_vars & AD_PORT_MATCHED)
+                   && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION))
+                       partner->port_state |= AD_STATE_SYNCHRONIZATION;
+               else
+                       partner->port_state &= ~AD_STATE_SYNCHRONIZATION;
        }
 }
 
@@ -560,15 +528,10 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
  */
 static void __record_default(struct port *port)
 {
-       // validate the port
        if (port) {
                // record the partner admin parameters
-               port->partner_oper_port_number = port->partner_admin_port_number;
-               port->partner_oper_port_priority = port->partner_admin_port_priority;
-               port->partner_oper_system = port->partner_admin_system;
-               port->partner_oper_system_priority = port->partner_admin_system_priority;
-               port->partner_oper_key = port->partner_admin_key;
-               port->partner_oper_port_state = port->partner_admin_port_state;
+               memcpy(&port->partner_oper, &port->partner_admin,
+                      sizeof(struct port_params));
 
                // set actor_oper_port_state.defaulted to true
                port->actor_oper_port_state |= AD_STATE_DEFAULTED;
@@ -590,16 +553,16 @@ static void __record_default(struct port *port)
  */
 static void __update_selected(struct lacpdu *lacpdu, struct port *port)
 {
-       // validate lacpdu and port
        if (lacpdu && port) {
+               const struct port_params *partner = &port->partner_oper;
+
                // check if any parameter is different
-               if ((lacpdu->actor_port != port->partner_oper_port_number) ||
-                   (lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
-                   MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
-                   (lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
-                   (lacpdu->actor_key != port->partner_oper_key) ||
-                   ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
-                  ) {
+               if (ntohs(lacpdu->actor_port) != partner->port_number ||
+                   ntohs(lacpdu->actor_port_priority) != partner->port_priority ||
+                   MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system) ||
+                   ntohs(lacpdu->actor_system_priority) != partner->system_priority ||
+                   ntohs(lacpdu->actor_key) != partner->key ||
+                   (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) {
                        // update the state machine Selected variable
                        port->sm_vars &= ~AD_PORT_SELECTED;
                }
@@ -620,16 +583,18 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port)
  */
 static void __update_default_selected(struct port *port)
 {
-       // validate the port
        if (port) {
+               const struct port_params *admin = &port->partner_admin;
+               const struct port_params *oper = &port->partner_oper;
+
                // check if any parameter is different
-               if ((port->partner_admin_port_number != port->partner_oper_port_number) ||
-                   (port->partner_admin_port_priority != port->partner_oper_port_priority) ||
-                   MAC_ADDRESS_COMPARE(&(port->partner_admin_system), &(port->partner_oper_system)) ||
-                   (port->partner_admin_system_priority != port->partner_oper_system_priority) ||
-                   (port->partner_admin_key != port->partner_oper_key) ||
-                   ((port->partner_admin_port_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
-                  ) {
+               if (admin->port_number != oper->port_number ||
+                   admin->port_priority != oper->port_priority ||
+                   MAC_ADDRESS_COMPARE(&admin->system, &oper->system) ||
+                   admin->system_priority != oper->system_priority ||
+                   admin->key != oper->key ||
+                   (admin->port_state & AD_STATE_AGGREGATION)
+                       != (oper->port_state & AD_STATE_AGGREGATION)) {
                        // update the state machine Selected variable
                        port->sm_vars &= ~AD_PORT_SELECTED;
                }
@@ -637,47 +602,6 @@ static void __update_default_selected(struct port *port)
 }
 
 /**
- * __choose_matched - update a port's matched variable from a received lacpdu
- * @lacpdu: the lacpdu we've received
- * @port: the port we're looking at
- *
- * Update the value of the matched variable, using parameter values from a
- * newly received lacpdu. Parameter values for the partner carried in the
- * received PDU are compared with the corresponding operational parameter
- * values for the actor. Matched is set to TRUE if all of these parameters
- * match and the PDU parameter partner_state.aggregation has the same value as
- * actor_oper_port_state.aggregation and lacp will actively maintain the link
- * in the aggregation. Matched is also set to TRUE if the value of
- * actor_state.aggregation in the received PDU is set to FALSE, i.e., indicates
- * an individual link and lacp will actively maintain the link. Otherwise,
- * matched is set to FALSE. LACP is considered to be actively maintaining the
- * link if either the PDU's actor_state.lacp_activity variable is TRUE or both
- * the actor's actor_oper_port_state.lacp_activity and the PDU's
- * partner_state.lacp_activity variables are TRUE.
- */
-static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
-{
-       // validate lacpdu and port
-       if (lacpdu && port) {
-               // check if all parameters are alike
-               if (((lacpdu->partner_port == port->actor_port_number) &&
-                    (lacpdu->partner_port_priority == port->actor_port_priority) &&
-                    !MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
-                    (lacpdu->partner_system_priority == port->actor_system_priority) &&
-                    (lacpdu->partner_key == port->actor_oper_port_key) &&
-                    ((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
-                   // or this is individual link(aggregation == FALSE)
-                   ((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
-                  ) {
-                       // update the state machine Matched variable
-                       port->sm_vars |= AD_PORT_MATCHED;
-               } else {
-                       port->sm_vars &= ~AD_PORT_MATCHED;
-               }
-       }
-}
-
-/**
  * __update_ntt - update a port's ntt variable from a received lacpdu
  * @lacpdu: the lacpdu we've received
  * @port: the port we're looking at
@@ -694,18 +618,18 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
        // validate lacpdu and port
        if (lacpdu && port) {
                // check if any parameter is different
-               if ((lacpdu->partner_port != port->actor_port_number) ||
-                   (lacpdu->partner_port_priority != port->actor_port_priority) ||
+               if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
+                   (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
                    MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
-                   (lacpdu->partner_system_priority != port->actor_system_priority) ||
-                   (lacpdu->partner_key != port->actor_oper_port_key) ||
+                   (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
+                   (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
                    ((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
                    ((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
                    ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
                    ((lacpdu->partner_state & AD_STATE_AGGREGATION) != (port->actor_oper_port_state & AD_STATE_AGGREGATION))
                   ) {
-                       // set ntt to be TRUE
-                       port->ntt = 1;
+
+                       port->ntt = true;
                }
        }
 }
@@ -720,7 +644,7 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
  */
 static void __attach_bond_to_agg(struct port *port)
 {
-       port=NULL; // just to satisfy the compiler
+       port = NULL; /* just to satisfy the compiler */
        // This function does nothing since the parser/multiplexer of the receive
        // and the parser/multiplexer of the aggregator are already combined
 }
@@ -735,7 +659,7 @@ static void __attach_bond_to_agg(struct port *port)
  */
 static void __detach_bond_from_agg(struct port *port)
 {
-       port=NULL; // just to satisfy the compiler
+       port = NULL; /* just to satisfy the compiler */
        // This function does nothing sience the parser/multiplexer of the receive
        // and the parser/multiplexer of the aggregator are already combined
 }
@@ -752,7 +676,9 @@ static int __agg_ports_are_ready(struct aggregator *aggregator)
 
        if (aggregator) {
                // scan all ports in this aggregator to verfy if they are all ready
-               for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+               for (port = aggregator->lag_ports;
+                    port;
+                    port = port->next_port_in_aggregator) {
                        if (!(port->sm_vars & AD_PORT_READY_N)) {
                                retval = 0;
                                break;
@@ -773,12 +699,12 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
 {
        struct port *port;
 
-       for (port=aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
-               if (val) {
+       for (port = aggregator->lag_ports; port;
+            port = port->next_port_in_aggregator) {
+               if (val)
                        port->sm_vars |= AD_PORT_READY;
-               } else {
+               else
                        port->sm_vars &= ~AD_PORT_READY;
-               }
        }
 }
 
@@ -789,7 +715,7 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
  */
 static u32 __get_agg_bandwidth(struct aggregator *aggregator)
 {
-       u32 bandwidth=0;
+       u32 bandwidth = 0;
        u32 basic_speed;
 
        if (aggregator->num_of_ports) {
@@ -807,8 +733,11 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
                case AD_LINK_SPEED_BITMASK_1000MBPS:
                        bandwidth = aggregator->num_of_ports * 1000;
                        break;
+               case AD_LINK_SPEED_BITMASK_10000MBPS:
+                       bandwidth = aggregator->num_of_ports * 10000;
+                       break;
                default:
-                       bandwidth=0; // to silent the compilor ....
+                       bandwidth = 0; /*to silence the compiler ....*/
                }
        }
        return bandwidth;
@@ -841,6 +770,7 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator)
 static inline void __update_lacpdu_from_port(struct port *port)
 {
        struct lacpdu *lacpdu = &port->lacpdu;
+       const struct port_params *partner = &port->partner_oper;
 
        /* update current actual Actor parameters */
        /* lacpdu->subtype                   initialized
@@ -849,11 +779,11 @@ static inline void __update_lacpdu_from_port(struct port *port)
         * lacpdu->actor_information_length  initialized
         */
 
-       lacpdu->actor_system_priority = port->actor_system_priority;
+       lacpdu->actor_system_priority = htons(port->actor_system_priority);
        lacpdu->actor_system = port->actor_system;
-       lacpdu->actor_key = port->actor_oper_port_key;
-       lacpdu->actor_port_priority = port->actor_port_priority;
-       lacpdu->actor_port = port->actor_port_number;
+       lacpdu->actor_key = htons(port->actor_oper_port_key);
+       lacpdu->actor_port_priority = htons(port->actor_port_priority);
+       lacpdu->actor_port = htons(port->actor_port_number);
        lacpdu->actor_state = port->actor_oper_port_state;
 
        /* lacpdu->reserved_3_1              initialized
@@ -861,12 +791,12 @@ static inline void __update_lacpdu_from_port(struct port *port)
         * lacpdu->partner_information_length initialized
         */
 
-       lacpdu->partner_system_priority = port->partner_oper_system_priority;
-       lacpdu->partner_system = port->partner_oper_system;
-       lacpdu->partner_key = port->partner_oper_key;
-       lacpdu->partner_port_priority = port->partner_oper_port_priority;
-       lacpdu->partner_port = port->partner_oper_port_number;
-       lacpdu->partner_state = port->partner_oper_port_state;
+       lacpdu->partner_system_priority = htons(partner->system_priority);
+       lacpdu->partner_system = partner->system;
+       lacpdu->partner_key = htons(partner->key);
+       lacpdu->partner_port_priority = htons(partner->port_priority);
+       lacpdu->partner_port = htons(partner->port_number);
+       lacpdu->partner_state = partner->port_state;
 
        /* lacpdu->reserved_3_2              initialized
         * lacpdu->tlv_type_collector_info   initialized
@@ -877,9 +807,6 @@ static inline void __update_lacpdu_from_port(struct port *port)
         * terminator_length                 initialized
         * reserved_50[50]                   initialized
         */
-
-       /* Convert all non u8 parameters to Big Endian for transmit */
-       __ntohs_lacpdu(lacpdu);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -899,26 +826,24 @@ static int ad_lacpdu_send(struct port *port)
        struct sk_buff *skb;
        struct lacpdu_header *lacpdu_header;
        int length = sizeof(struct lacpdu_header);
-       struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
 
        skb = dev_alloc_skb(length);
-       if (!skb) {
+       if (!skb)
                return -ENOMEM;
-       }
 
        skb->dev = slave->dev;
-       skb->mac.raw = skb->data;
-       skb->nh.raw = skb->data + ETH_HLEN;
+       skb_reset_mac_header(skb);
+       skb->network_header = skb->mac_header + ETH_HLEN;
        skb->protocol = PKT_TYPE_LACPDU;
        skb->priority = TC_PRIO_CONTROL;
 
        lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
 
-       lacpdu_header->ad_header.destination_address = lacpdu_multicast_address;
-       /* Note: source addres is set to be the member's PERMANENT address, because we use it
-          to identify loopback lacpdus in receive. */
-       lacpdu_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
-       lacpdu_header->ad_header.length_type = PKT_TYPE_LACPDU;
+       memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+       /* Note: source address is set to be the member's PERMANENT address,
+          because we use it to identify loopback lacpdus in receive. */
+       memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+       lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
        lacpdu_header->lacpdu = port->lacpdu; // struct copy
 
@@ -935,33 +860,31 @@ static int ad_lacpdu_send(struct port *port)
  * Returns:   0 on success
  *          < 0 on error
  */
-static int ad_marker_send(struct port *port, struct marker *marker)
+static int ad_marker_send(struct port *port, struct bond_marker *marker)
 {
        struct slave *slave = port->slave;
        struct sk_buff *skb;
-       struct marker_header *marker_header;
-       int length = sizeof(struct marker_header);
-       struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
+       struct bond_marker_header *marker_header;
+       int length = sizeof(struct bond_marker_header);
 
        skb = dev_alloc_skb(length + 16);
-       if (!skb) {
+       if (!skb)
                return -ENOMEM;
-       }
 
        skb_reserve(skb, 16);
 
        skb->dev = slave->dev;
-       skb->mac.raw = skb->data;
-       skb->nh.raw = skb->data + ETH_HLEN;
+       skb_reset_mac_header(skb);
+       skb->network_header = skb->mac_header + ETH_HLEN;
        skb->protocol = PKT_TYPE_LACPDU;
 
-       marker_header = (struct marker_header *)skb_put(skb, length);
+       marker_header = (struct bond_marker_header *)skb_put(skb, length);
 
-       marker_header->ad_header.destination_address = lacpdu_multicast_address;
-       /* Note: source addres is set to be the member's PERMANENT address, because we use it
-          to identify loopback MARKERs in receive. */
-       marker_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr));
-       marker_header->ad_header.length_type = PKT_TYPE_LACPDU;
+       memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+       /* Note: source address is set to be the member's PERMANENT address,
+          because we use it to identify loopback MARKERs in receive. */
+       memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+       marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
        marker_header->marker = *marker; // struct copy
 
@@ -987,9 +910,10 @@ static void ad_mux_machine(struct port *port)
        } else {
                switch (port->sm_mux_state) {
                case AD_MUX_DETACHED:
-                       if ((port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if SELECTED or STANDBY
+                       if ((port->sm_vars & AD_PORT_SELECTED)
+                           || (port->sm_vars & AD_PORT_STANDBY))
+                               /* if SELECTED or STANDBY */
                                port->sm_mux_state = AD_MUX_WAITING; // next state
-                       }
                        break;
                case AD_MUX_WAITING:
                        // if SELECTED == FALSE return to DETACH state
@@ -1003,22 +927,22 @@ static void ad_mux_machine(struct port *port)
                        }
 
                        // check if the wait_while_timer expired
-                       if (port->sm_mux_timer_counter && !(--port->sm_mux_timer_counter)) {
+                       if (port->sm_mux_timer_counter
+                           && !(--port->sm_mux_timer_counter))
                                port->sm_vars |= AD_PORT_READY_N;
-                       }
 
                        // in order to withhold the selection logic to check all ports READY_N value
                        // every callback cycle to update ready variable, we check READY_N and update READY here
                        __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
 
                        // if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state
-                       if ((port->sm_vars & AD_PORT_READY) && !port->sm_mux_timer_counter) {
+                       if ((port->sm_vars & AD_PORT_READY)
+                           && !port->sm_mux_timer_counter)
                                port->sm_mux_state = AD_MUX_ATTACHED;    // next state
-                       }
                        break;
                case AD_MUX_ATTACHED:
                        // check also if agg_select_timer expired(so the edable port will take place only after this timer)
-                       if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
+                       if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
                                port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state
                        } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) {    // if UNSELECTED or STANDBY
                                port->sm_vars &= ~AD_PORT_READY_N;
@@ -1030,7 +954,7 @@ static void ad_mux_machine(struct port *port)
                        break;
                case AD_MUX_COLLECTING_DISTRIBUTING:
                        if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) ||
-                           !(port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION)
+                           !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)
                           ) {
                                port->sm_mux_state = AD_MUX_ATTACHED;// next state
 
@@ -1053,7 +977,9 @@ static void ad_mux_machine(struct port *port)
 
        // check if the state machine was changed
        if (port->sm_mux_state != last_state) {
-               dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state);
+               pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n",
+                        port->actor_port_number, last_state,
+                        port->sm_mux_state);
                switch (port->sm_mux_state) {
                case AD_MUX_DETACHED:
                        __detach_bond_from_agg(port);
@@ -1061,7 +987,7 @@ static void ad_mux_machine(struct port *port)
                        ad_disable_collecting_distributing(port);
                        port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
                        port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
-                       port->ntt = 1;
+                       port->ntt = true;
                        break;
                case AD_MUX_WAITING:
                        port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
@@ -1072,13 +998,13 @@ static void ad_mux_machine(struct port *port)
                        port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
                        port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
                        ad_disable_collecting_distributing(port);
-                       port->ntt = 1;
+                       port->ntt = true;
                        break;
                case AD_MUX_COLLECTING_DISTRIBUTING:
                        port->actor_oper_port_state |= AD_STATE_COLLECTING;
                        port->actor_oper_port_state |= AD_STATE_DISTRIBUTING;
                        ad_enable_collecting_distributing(port);
-                       port->ntt = 1;
+                       port->ntt = true;
                        break;
                default:    //to silence the compiler
                        break;
@@ -1099,21 +1025,19 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 {
        rx_states_t last_state;
 
-       // Lock to prevent 2 instances of this function to run simultaneously(rx interrupt and periodic machine callback)
-       __get_rx_machine_lock(port);
-
        // keep current State Machine state to compare later if it was changed
        last_state = port->sm_rx_state;
 
        // check if state machine should change state
        // first, check if port was reinitialized
-       if (port->sm_vars & AD_PORT_BEGIN) {
-               port->sm_rx_state = AD_RX_INITIALIZE;               // next state
-       }
+       if (port->sm_vars & AD_PORT_BEGIN)
+               /* next state */
+               port->sm_rx_state = AD_RX_INITIALIZE;
        // check if port is not enabled
-       else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) {
-               port->sm_rx_state = AD_RX_PORT_DISABLED;            // next state
-       }
+       else if (!(port->sm_vars & AD_PORT_BEGIN)
+                && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
+               /* next state */
+               port->sm_rx_state = AD_RX_PORT_DISABLED;
        // check if new lacpdu arrived
        else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) {
                port->sm_rx_timer_counter = 0; // zero timer
@@ -1135,13 +1059,16 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        // if no lacpdu arrived and no timer is on
                        switch (port->sm_rx_state) {
                        case AD_RX_PORT_DISABLED:
-                               if (port->sm_vars & AD_PORT_MOVED) {
+                               if (port->sm_vars & AD_PORT_MOVED)
                                        port->sm_rx_state = AD_RX_INITIALIZE;       // next state
-                               } else if (port->is_enabled && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
+                               else if (port->is_enabled
+                                        && (port->sm_vars
+                                            & AD_PORT_LACP_ENABLED))
                                        port->sm_rx_state = AD_RX_EXPIRED;      // next state
-                               } else if (port->is_enabled && ((port->sm_vars & AD_PORT_LACP_ENABLED) == 0)) {
+                               else if (port->is_enabled
+                                        && ((port->sm_vars
+                                             & AD_PORT_LACP_ENABLED) == 0))
                                        port->sm_rx_state = AD_RX_LACP_DISABLED;    // next state
-                               }
                                break;
                        default:    //to silence the compiler
                                break;
@@ -1152,14 +1079,15 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 
        // check if the State machine was changed or new lacpdu arrived
        if ((port->sm_rx_state != last_state) || (lacpdu)) {
-               dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state);
+               pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n",
+                        port->actor_port_number, last_state,
+                        port->sm_rx_state);
                switch (port->sm_rx_state) {
                case AD_RX_INITIALIZE:
-                       if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
+                       if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS))
                                port->sm_vars &= ~AD_PORT_LACP_ENABLED;
-                       } else {
+                       else
                                port->sm_vars |= AD_PORT_LACP_ENABLED;
-                       }
                        port->sm_vars &= ~AD_PORT_SELECTED;
                        __record_default(port);
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
@@ -1174,7 +1102,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                case AD_RX_LACP_DISABLED:
                        port->sm_vars &= ~AD_PORT_SELECTED;
                        __record_default(port);
-                       port->partner_oper_port_state &= ~AD_STATE_AGGREGATION;
+                       port->partner_oper.port_state &= ~AD_STATE_AGGREGATION;
                        port->sm_vars |= AD_PORT_MATCHED;
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
                        break;
@@ -1182,9 +1110,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        //Reset of the Synchronization flag. (Standard 43.4.12)
                        //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the
                        //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
-                       port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
+                       port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
                        port->sm_vars &= ~AD_PORT_MATCHED;
-                       port->partner_oper_port_state |= AD_SHORT_TIMEOUT;
+                       port->partner_oper.port_state |=
+                               AD_STATE_LACP_ACTIVITY;
                        port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
                        port->actor_oper_port_state |= AD_STATE_EXPIRED;
                        break;
@@ -1198,31 +1127,28 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        // detect loopback situation
                        if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) {
                                // INFO_RECEIVED_LOOPBACK_FRAMES
-                               printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n",
-                                               port->slave->dev->name);
-                               printk(KERN_ERR "Check the configuration to verify that all Adapters "
-                                               "are connected to 802.3ad compliant switch ports\n");
-                               __release_rx_machine_lock(port);
+                               pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
+                                      "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
+                                      port->slave->dev->master->name, port->slave->dev->name);
                                return;
                        }
                        __update_selected(lacpdu, port);
                        __update_ntt(lacpdu, port);
                        __record_pdu(lacpdu, port);
-                       __choose_matched(lacpdu, port);
                        port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT));
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
                        // verify that if the aggregator is enabled, the port is enabled too.
                        //(because if the link goes down for a short time, the 802.3ad will not
                        // catch it, and the port will continue to be disabled)
-                       if (port->aggregator && port->aggregator->is_active && !__port_is_enabled(port)) {
+                       if (port->aggregator
+                           && port->aggregator->is_active
+                           && !__port_is_enabled(port))
                                __enable_port(port);
-                       }
                        break;
                default:    //to silence the compiler
                        break;
                }
        }
-       __release_rx_machine_lock(port);
 }
 
 /**
@@ -1237,15 +1163,19 @@ static void ad_tx_machine(struct port *port)
                // check if there is something to send
                if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
                        __update_lacpdu_from_port(port);
-                       // send the lacpdu
+
                        if (ad_lacpdu_send(port) >= 0) {
-                               dprintk("Sent LACPDU on port %d\n", port->actor_port_number);
-                               // mark ntt as false, so it will not be sent again until demanded
-                               port->ntt = 0;
+                               pr_debug("Sent LACPDU on port %d\n",
+                                        port->actor_port_number);
+
+                               /* mark ntt as false, so it will not be sent again until
+                                  demanded */
+                               port->ntt = false;
                        }
                }
                // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND
-               port->sm_tx_timer_counter=ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
+               port->sm_tx_timer_counter =
+                       ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
        }
 }
 
@@ -1264,7 +1194,7 @@ static void ad_periodic_machine(struct port *port)
 
        // check if port was reinitialized
        if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
-           (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY))
+           (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY))
           ) {
                port->sm_periodic_state = AD_NO_PERIODIC;            // next state
        }
@@ -1278,12 +1208,12 @@ static void ad_periodic_machine(struct port *port)
                        // If not expired, check if there is some new timeout parameter from the partner state
                        switch (port->sm_periodic_state) {
                        case AD_FAST_PERIODIC:
-                               if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+                               if (!(port->partner_oper.port_state
+                                     & AD_STATE_LACP_TIMEOUT))
                                        port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
-                               }
                                break;
                        case AD_SLOW_PERIODIC:
-                               if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+                               if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
                                        // stop current timer
                                        port->sm_periodic_timer_counter = 0;
                                        port->sm_periodic_state = AD_PERIODIC_TX;        // next state
@@ -1299,11 +1229,11 @@ static void ad_periodic_machine(struct port *port)
                        port->sm_periodic_state = AD_FAST_PERIODIC;      // next state
                        break;
                case AD_PERIODIC_TX:
-                       if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) {
+                       if (!(port->partner_oper.port_state
+                             & AD_STATE_LACP_TIMEOUT))
                                port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
-                       } else {
+                       else
                                port->sm_periodic_state = AD_FAST_PERIODIC;  // next state
-                       }
                        break;
                default:    //to silence the compiler
                        break;
@@ -1312,7 +1242,9 @@ static void ad_periodic_machine(struct port *port)
 
        // check if the state machine was changed
        if (port->sm_periodic_state != last_state) {
-               dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state);
+               pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n",
+                        port->actor_port_number, last_state,
+                        port->sm_periodic_state);
                switch (port->sm_periodic_state) {
                case AD_NO_PERIODIC:
                        port->sm_periodic_timer_counter = 0;       // zero timer
@@ -1324,7 +1256,7 @@ static void ad_periodic_machine(struct port *port)
                        port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
                        break;
                case AD_PERIODIC_TX:
-                       port->ntt = 1;
+                       port->ntt = true;
                        break;
                default:    //to silence the compiler
                        break;
@@ -1347,41 +1279,46 @@ static void ad_port_selection_logic(struct port *port)
        int found = 0;
 
        // if the port is already Selected, do nothing
-       if (port->sm_vars & AD_PORT_SELECTED) {
+       if (port->sm_vars & AD_PORT_SELECTED)
                return;
-       }
 
        // if the port is connected to other aggregator, detach it
        if (port->aggregator) {
                // detach the port from its former aggregator
-               temp_aggregator=port->aggregator;
-               for (curr_port=temp_aggregator->lag_ports; curr_port; last_port=curr_port, curr_port=curr_port->next_port_in_aggregator) {
+               temp_aggregator = port->aggregator;
+               for (curr_port = temp_aggregator->lag_ports; curr_port;
+                    last_port = curr_port,
+                            curr_port = curr_port->next_port_in_aggregator) {
                        if (curr_port == port) {
                                temp_aggregator->num_of_ports--;
                                if (!last_port) {// if it is the first port attached to the aggregator
-                                       temp_aggregator->lag_ports=port->next_port_in_aggregator;
+                                       temp_aggregator->lag_ports =
+                                               port->next_port_in_aggregator;
                                } else {// not the first port attached to the aggregator
-                                       last_port->next_port_in_aggregator=port->next_port_in_aggregator;
+                                       last_port->next_port_in_aggregator =
+                                               port->next_port_in_aggregator;
                                }
 
                                // clear the port's relations to this aggregator
                                port->aggregator = NULL;
-                               port->next_port_in_aggregator=NULL;
-                               port->actor_port_aggregator_identifier=0;
+                               port->next_port_in_aggregator = NULL;
+                               port->actor_port_aggregator_identifier = 0;
 
-                               dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier);
+                               pr_debug("Port %d left LAG %d\n",
+                                        port->actor_port_number,
+                                        temp_aggregator->aggregator_identifier);
                                // if the aggregator is empty, clear its parameters, and set it ready to be attached
-                               if (!temp_aggregator->lag_ports) {
+                               if (!temp_aggregator->lag_ports)
                                        ad_clear_agg(temp_aggregator);
-                               }
                                break;
                        }
                }
                if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
-                       printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was "
-                              "related to aggregator %d but was not on its port list\n",
-                              port->actor_port_number, port->slave->dev->name,
-                              port->aggregator->aggregator_identifier);
+                       pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
+                                  port->slave->dev->master->name,
+                                  port->actor_port_number,
+                                  port->slave->dev->name,
+                                  port->aggregator->aggregator_identifier);
                }
        }
        // search on all aggregators for a suitable aggregator for this port
@@ -1390,28 +1327,30 @@ static void ad_port_selection_logic(struct port *port)
 
                // keep a free aggregator for later use(if needed)
                if (!aggregator->lag_ports) {
-                       if (!free_aggregator) {
-                               free_aggregator=aggregator;
-                       }
+                       if (!free_aggregator)
+                               free_aggregator = aggregator;
                        continue;
                }
                // check if current aggregator suits us
                if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND
-                    !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) &&
-                    (aggregator->partner_system_priority == port->partner_oper_system_priority) &&
-                    (aggregator->partner_oper_aggregator_key == port->partner_oper_key)
+                    !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper.system)) &&
+                    (aggregator->partner_system_priority == port->partner_oper.system_priority) &&
+                    (aggregator->partner_oper_aggregator_key == port->partner_oper.key)
                    ) &&
-                   ((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers
+                   ((MAC_ADDRESS_COMPARE(&(port->partner_oper.system), &(null_mac_addr)) && // partner answers
                      !aggregator->is_individual)  // but is not individual OR
                    )
                   ) {
                        // attach to the founded aggregator
                        port->aggregator = aggregator;
-                       port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
-                       port->next_port_in_aggregator=aggregator->lag_ports;
+                       port->actor_port_aggregator_identifier =
+                               port->aggregator->aggregator_identifier;
+                       port->next_port_in_aggregator = aggregator->lag_ports;
                        port->aggregator->num_of_ports++;
-                       aggregator->lag_ports=port;
-                       dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+                       aggregator->lag_ports = port;
+                       pr_debug("Port %d joined LAG %d(existing LAG)\n",
+                                port->actor_port_number,
+                                port->aggregator->aggregator_identifier);
 
                        // mark this port as selected
                        port->sm_vars |= AD_PORT_SELECTED;
@@ -1425,21 +1364,24 @@ static void ad_port_selection_logic(struct port *port)
                if (free_aggregator) {
                        // assign port a new aggregator
                        port->aggregator = free_aggregator;
-                       port->actor_port_aggregator_identifier=port->aggregator->aggregator_identifier;
+                       port->actor_port_aggregator_identifier =
+                               port->aggregator->aggregator_identifier;
 
                        // update the new aggregator's parameters
                        // if port was responsed from the end-user
-                       if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex
-                               port->aggregator->is_individual = 0;
-                       } else {
-                               port->aggregator->is_individual = 1;
-                       }
+                       if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)
+                               /* if port is full duplex */
+                               port->aggregator->is_individual = false;
+                       else
+                               port->aggregator->is_individual = true;
 
                        port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key;
                        port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key;
-                       port->aggregator->partner_system=port->partner_oper_system;
-                       port->aggregator->partner_system_priority = port->partner_oper_system_priority;
-                       port->aggregator->partner_oper_aggregator_key = port->partner_oper_key;
+                       port->aggregator->partner_system =
+                               port->partner_oper.system;
+                       port->aggregator->partner_system_priority =
+                               port->partner_oper.system_priority;
+                       port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
                        port->aggregator->receive_state = 1;
                        port->aggregator->transmit_state = 1;
                        port->aggregator->lag_ports = port;
@@ -1448,9 +1390,12 @@ static void ad_port_selection_logic(struct port *port)
                        // mark this port as selected
                        port->sm_vars |= AD_PORT_SELECTED;
 
-                       dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+                       pr_debug("Port %d joined LAG %d(new LAG)\n",
+                                port->actor_port_number,
+                                port->aggregator->aggregator_identifier);
                } else {
-                       printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n",
+                       pr_err("%s: Port %d (on %s) did not find a suitable aggregator\n",
+                              port->slave->dev->master->name,
                               port->actor_port_number, port->slave->dev->name);
                }
        }
@@ -1458,9 +1403,87 @@ static void ad_port_selection_logic(struct port *port)
        // else set ready=FALSE in all aggregator's ports
        __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
 
-       if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) {
-               ad_agg_selection_logic(aggregator);
+       aggregator = __get_first_agg(port);
+       ad_agg_selection_logic(aggregator);
+}
+
+/*
+ * Decide if "agg" is a better choice for the new active aggregator that
+ * the current best, according to the ad_select policy.
+ */
+static struct aggregator *ad_agg_selection_test(struct aggregator *best,
+                                               struct aggregator *curr)
+{
+       /*
+        * 0. If no best, select current.
+        *
+        * 1. If the current agg is not individual, and the best is
+        *    individual, select current.
+        *
+        * 2. If current agg is individual and the best is not, keep best.
+        *
+        * 3. Therefore, current and best are both individual or both not
+        *    individual, so:
+        *
+        * 3a. If current agg partner replied, and best agg partner did not,
+        *     select current.
+        *
+        * 3b. If current agg partner did not reply and best agg partner
+        *     did reply, keep best.
+        *
+        * 4.  Therefore, current and best both have partner replies or
+        *     both do not, so perform selection policy:
+        *
+        * BOND_AD_COUNT: Select by count of ports.  If count is equal,
+        *     select by bandwidth.
+        *
+        * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth.
+        */
+       if (!best)
+               return curr;
+
+       if (!curr->is_individual && best->is_individual)
+               return curr;
+
+       if (curr->is_individual && !best->is_individual)
+               return best;
+
+       if (__agg_has_partner(curr) && !__agg_has_partner(best))
+               return curr;
+
+       if (!__agg_has_partner(curr) && __agg_has_partner(best))
+               return best;
+
+       switch (__get_agg_selection_mode(curr->lag_ports)) {
+       case BOND_AD_COUNT:
+               if (curr->num_of_ports > best->num_of_ports)
+                       return curr;
+
+               if (curr->num_of_ports < best->num_of_ports)
+                       return best;
+
+               /*FALLTHROUGH*/
+       case BOND_AD_STABLE:
+       case BOND_AD_BANDWIDTH:
+               if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best))
+                       return curr;
+
+               break;
+
+       default:
+               pr_warning("%s: Impossible agg select mode %d\n",
+                          curr->slave->dev->master->name,
+                          __get_agg_selection_mode(curr->lag_ports));
+               break;
        }
+
+       return best;
+}
+
+static int agg_device_up(const struct aggregator *agg)
+{
+       return (netif_running(agg->slave->dev) &&
+               netif_carrier_ok(agg->slave->dev));
 }
 
 /**
@@ -1468,155 +1491,135 @@ static void ad_port_selection_logic(struct port *port)
  * @aggregator: the aggregator we're looking at
  *
  * It is assumed that only one aggregator may be selected for a team.
- * The logic of this function is to select (at first time) the aggregator with
- * the most ports attached to it, and to reselect the active aggregator only if
- * the previous aggregator has no more ports related to it.
+ *
+ * The logic of this function is to select the aggregator according to
+ * the ad_select policy:
+ *
+ * BOND_AD_STABLE: select the aggregator with the most ports attached to
+ * it, and to reselect the active aggregator only if the previous
+ * aggregator has no more ports related to it.
+ *
+ * BOND_AD_BANDWIDTH: select the aggregator with the highest total
+ * bandwidth, and reselect whenever a link state change takes place or the
+ * set of slaves in the bond changes.
+ *
+ * BOND_AD_COUNT: select the aggregator with largest number of ports
+ * (slaves), and reselect whenever a link state change takes place or the
+ * set of slaves in the bond changes.
  *
  * FIXME: this function MUST be called with the first agg in the bond, or
  * __get_active_agg() won't work correctly. This function should be better
  * called with the bond itself, and retrieve the first agg from it.
  */
-static void ad_agg_selection_logic(struct aggregator *aggregator)
+static void ad_agg_selection_logic(struct aggregator *agg)
 {
-       struct aggregator *best_aggregator = NULL, *active_aggregator = NULL;
-       struct aggregator *last_active_aggregator = NULL, *origin_aggregator;
+       struct aggregator *best, *active, *origin;
        struct port *port;
-       u16 num_of_aggs=0;
-
-       origin_aggregator = aggregator;
 
-       //get current active aggregator
-       last_active_aggregator = __get_active_agg(aggregator);
+       origin = agg;
+       active = __get_active_agg(agg);
+       best = (active && agg_device_up(active)) ? active : NULL;
 
-       // search for the aggregator with the most ports attached to it.
        do {
-               // count how many candidate lag's we have
-               if (aggregator->lag_ports) {
-                       num_of_aggs++;
-               }
-               if (aggregator->is_active && !aggregator->is_individual &&   // if current aggregator is the active aggregator
-                   MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) {   // and partner answers to 802.3ad PDUs
-                       if (aggregator->num_of_ports) { // if any ports attached to the current aggregator
-                               best_aggregator=NULL;    // disregard the best aggregator that was chosen by now
-                               break;           // stop the selection of other aggregator if there are any ports attached to this active aggregator
-                       } else { // no ports attached to this active aggregator
-                               aggregator->is_active = 0; // mark this aggregator as not active anymore
+               agg->is_active = 0;
+
+               if (agg->num_of_ports && agg_device_up(agg))
+                       best = ad_agg_selection_test(best, agg);
+
+       } while ((agg = __get_next_agg(agg)));
+
+       if (best &&
+           __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) {
+               /*
+                * For the STABLE policy, don't replace the old active
+                * aggregator if it's still active (it has an answering
+                * partner) or if both the best and active don't have an
+                * answering partner.
+                */
+               if (active && active->lag_ports &&
+                   active->lag_ports->is_enabled &&
+                   (__agg_has_partner(active) ||
+                    (!__agg_has_partner(active) && !__agg_has_partner(best)))) {
+                       if (!(!active->actor_oper_aggregator_key &&
+                             best->actor_oper_aggregator_key)) {
+                               best = NULL;
+                               active->is_active = 1;
                        }
                }
-               if (aggregator->num_of_ports) { // if any ports attached
-                       if (best_aggregator) {  // if there is a candidte aggregator
-                               //The reasons for choosing new best aggregator:
-                               // 1. if current agg is NOT individual and the best agg chosen so far is individual OR
-                               // current and best aggs are both individual or both not individual, AND
-                               // 2a.  current agg partner reply but best agg partner do not reply OR
-                               // 2b.  current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND
-                               //      current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN
-                               //      current agg become best agg so far
-
-                               //if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator
-                               if (!aggregator->is_individual && best_aggregator->is_individual) {
-                                       best_aggregator=aggregator;
-                               }
-                               // current and best aggs are both individual or both not individual
-                               else if ((aggregator->is_individual && best_aggregator->is_individual) ||
-                                        (!aggregator->is_individual && !best_aggregator->is_individual)) {
-                                       //  current and best aggs are both individual or both not individual AND
-                                       //  current agg partner reply but best agg partner do not reply
-                                       if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
-                                            !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
-                                               best_aggregator=aggregator;
-                                       }
-                                       //  current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply
-                                       else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) &&
-                                                   MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) {
-                                               if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&&
-                                                   (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) {
-                                                       best_aggregator=aggregator;
-                                               } else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) {
-                                                       if (((aggregator->num_of_ports > best_aggregator->num_of_ports) &&
-                                                            (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))||
-                                                           ((aggregator->num_of_ports == best_aggregator->num_of_ports) &&
-                                                            ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) >
-                                                             (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) {
-                                                               best_aggregator=aggregator;
-                                                       }
-                                               }
-                                       }
-                               }
-                       } else {
-                               best_aggregator=aggregator;
-                       }
-               }
-               aggregator->is_active = 0; // mark all aggregators as not active anymore
-       } while ((aggregator = __get_next_agg(aggregator)));
-
-       // if we have new aggregator selected, don't replace the old aggregator if it has an answering partner,
-       // or if both old aggregator and new aggregator don't have answering partner
-       if (best_aggregator) {
-               if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled &&
-                   (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) ||   // partner answers OR
-                    (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) &&      // both old and new
-                     !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr))))     // partner do not answer
-                  ) {
-                       // if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing)
-                       // -> don't replace otherwise.
-                       if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) {
-                               best_aggregator=NULL;
-                               last_active_aggregator->is_active = 1; // don't replace good old aggregator
+       }
 
-                       }
-               }
+       if (best && (best == active)) {
+               best = NULL;
+               active->is_active = 1;
        }
 
        // if there is new best aggregator, activate it
-       if (best_aggregator) {
-               for (aggregator = __get_first_agg(best_aggregator->lag_ports);
-                   aggregator;
-                   aggregator = __get_next_agg(aggregator)) {
-
-                       dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
-                                       aggregator->aggregator_identifier, aggregator->num_of_ports,
-                                       aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key,
-                                       aggregator->is_individual, aggregator->is_active);
+       if (best) {
+               pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+                        best->aggregator_identifier, best->num_of_ports,
+                        best->actor_oper_aggregator_key,
+                        best->partner_oper_aggregator_key,
+                        best->is_individual, best->is_active);
+               pr_debug("best ports %p slave %p %s\n",
+                        best->lag_ports, best->slave,
+                        best->slave ? best->slave->dev->name : "NULL");
+
+               for (agg = __get_first_agg(best->lag_ports); agg;
+                    agg = __get_next_agg(agg)) {
+
+                       pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+                                agg->aggregator_identifier, agg->num_of_ports,
+                                agg->actor_oper_aggregator_key,
+                                agg->partner_oper_aggregator_key,
+                                agg->is_individual, agg->is_active);
                }
 
                // check if any partner replys
-               if (best_aggregator->is_individual) {
-                       printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner "
-                                       "for any adapters in the bond\n");
+               if (best->is_individual) {
+                       pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
+                                  best->slave ? best->slave->dev->master->name : "NULL");
                }
 
-               // check if there are more than one aggregator
-               if (num_of_aggs > 1) {
-                       dprintk("Warning: More than one Link Aggregation Group was "
-                               "found in the bond. Only one group will function in the bond\n");
-               }
-
-               best_aggregator->is_active = 1;
-               dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier);
-               dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n",
-                               best_aggregator->aggregator_identifier, best_aggregator->num_of_ports,
-                               best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key,
-                               best_aggregator->is_individual, best_aggregator->is_active);
+               best->is_active = 1;
+               pr_debug("LAG %d chosen as the active LAG\n",
+                        best->aggregator_identifier);
+               pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n",
+                        best->aggregator_identifier, best->num_of_ports,
+                        best->actor_oper_aggregator_key,
+                        best->partner_oper_aggregator_key,
+                        best->is_individual, best->is_active);
 
                // disable the ports that were related to the former active_aggregator
-               if (last_active_aggregator) {
-                       for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+               if (active) {
+                       for (port = active->lag_ports; port;
+                            port = port->next_port_in_aggregator) {
                                __disable_port(port);
                        }
                }
        }
 
-       // if the selected aggregator is of join individuals(partner_system is NULL), enable their ports
-       active_aggregator = __get_active_agg(origin_aggregator);
+       /*
+        * if the selected aggregator is of join individuals
+        * (partner_system is NULL), enable their ports
+        */
+       active = __get_active_agg(origin);
 
-       if (active_aggregator) {
-               if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) {
-                       for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) {
+       if (active) {
+               if (!__agg_has_partner(active)) {
+                       for (port = active->lag_ports; port;
+                            port = port->next_port_in_aggregator) {
                                __enable_port(port);
                        }
                }
        }
+
+       if (origin->slave) {
+               struct bonding *bond;
+
+               bond = bond_get_bond_by_slave(origin->slave);
+               if (bond)
+                       bond_3ad_set_carrier(bond);
+       }
 }
 
 /**
@@ -1627,7 +1630,7 @@ static void ad_agg_selection_logic(struct aggregator *aggregator)
 static void ad_clear_agg(struct aggregator *aggregator)
 {
        if (aggregator) {
-               aggregator->is_individual = 0;
+               aggregator->is_individual = false;
                aggregator->actor_admin_aggregator_key = 0;
                aggregator->actor_oper_aggregator_key = 0;
                aggregator->partner_system = null_mac_addr;
@@ -1638,7 +1641,8 @@ static void ad_clear_agg(struct aggregator *aggregator)
                aggregator->lag_ports = NULL;
                aggregator->is_active = 0;
                aggregator->num_of_ports = 0;
-               dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier);
+               pr_debug("LAG %d was cleared\n",
+                        aggregator->aggregator_identifier);
        }
 }
 
@@ -1666,35 +1670,44 @@ static void ad_initialize_agg(struct aggregator *aggregator)
  */
 static void ad_initialize_port(struct port *port, int lacp_fast)
 {
+       static const struct port_params tmpl = {
+               .system_priority = 0xffff,
+               .key             = 1,
+               .port_number     = 1,
+               .port_priority   = 0xff,
+               .port_state      = 1,
+       };
+       static const struct lacpdu lacpdu = {
+               .subtype                = 0x01,
+               .version_number = 0x01,
+               .tlv_type_actor_info = 0x01,
+               .actor_information_length = 0x14,
+               .tlv_type_partner_info = 0x02,
+               .partner_information_length = 0x14,
+               .tlv_type_collector_info = 0x03,
+               .collector_information_length = 0x10,
+               .collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY),
+       };
+
        if (port) {
                port->actor_port_number = 1;
                port->actor_port_priority = 0xff;
                port->actor_system = null_mac_addr;
                port->actor_system_priority = 0xffff;
                port->actor_port_aggregator_identifier = 0;
-               port->ntt = 0;
+               port->ntt = false;
                port->actor_admin_port_key = 1;
                port->actor_oper_port_key  = 1;
                port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
                port->actor_oper_port_state  = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
 
-               if (lacp_fast) {
+               if (lacp_fast)
                        port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
-               }
 
-               port->partner_admin_system = null_mac_addr;
-               port->partner_oper_system  = null_mac_addr;
-               port->partner_admin_system_priority = 0xffff;
-               port->partner_oper_system_priority  = 0xffff;
-               port->partner_admin_key = 1;
-               port->partner_oper_key  = 1;
-               port->partner_admin_port_number = 1;
-               port->partner_oper_port_number  = 1;
-               port->partner_admin_port_priority = 0xff;
-               port->partner_oper_port_priority  = 0xff;
-               port->partner_admin_port_state = 1;
-               port->partner_oper_port_state  = 1;
-               port->is_enabled = 1;
+               memcpy(&port->partner_admin, &tmpl, sizeof(tmpl));
+               memcpy(&port->partner_oper, &tmpl, sizeof(tmpl));
+
+               port->is_enabled = true;
                // ****** private parameters ******
                port->sm_vars = 0x3;
                port->sm_rx_state = 0;
@@ -1710,7 +1723,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
                port->next_port_in_aggregator = NULL;
                port->transaction_id = 0;
 
-               ad_initialize_lacpdu(&(port->lacpdu));
+               memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu));
        }
 }
 
@@ -1723,7 +1736,9 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
 static void ad_enable_collecting_distributing(struct port *port)
 {
        if (port->aggregator->is_active) {
-               dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+               pr_debug("Enabling port %d(LAG %d)\n",
+                        port->actor_port_number,
+                        port->aggregator->aggregator_identifier);
                __enable_port(port);
        }
 }
@@ -1736,7 +1751,9 @@ static void ad_enable_collecting_distributing(struct port *port)
 static void ad_disable_collecting_distributing(struct port *port)
 {
        if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) {
-               dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier);
+               pr_debug("Disabling port %d(LAG %d)\n",
+                        port->actor_port_number,
+                        port->aggregator->aggregator_identifier);
                __disable_port(port);
        }
 }
@@ -1752,7 +1769,7 @@ static void ad_disable_collecting_distributing(struct port *port)
  */
 static void ad_marker_info_send(struct port *port)
 {
-       struct marker marker;
+       struct bond_marker marker;
        u16 index;
 
        // fill the marker PDU with the appropriate values
@@ -1764,17 +1781,21 @@ static void ad_marker_info_send(struct port *port)
        marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8));
        marker.requester_system = port->actor_system;
        // convert requester_port(u32) to Big Endian
-       marker.requester_transaction_id = (((++port->transaction_id & 0xFF) << 24) |((port->transaction_id & 0xFF00) << 8) |((port->transaction_id & 0xFF0000) >> 8) |((port->transaction_id & 0xFF000000) >> 24));
+       marker.requester_transaction_id =
+               (((++port->transaction_id & 0xFF) << 24)
+                | ((port->transaction_id & 0xFF00) << 8)
+                | ((port->transaction_id & 0xFF0000) >> 8)
+                | ((port->transaction_id & 0xFF000000) >> 24));
        marker.pad = 0;
        marker.tlv_type_terminator = 0x00;
        marker.terminator_length = 0x00;
-       for (index=0; index<90; index++) {
-               marker.reserved_90[index]=0;
-       }
+       for (index = 0; index < 90; index++)
+               marker.reserved_90[index] = 0;
 
        // send the marker information
        if (ad_marker_send(port, &marker) >= 0) {
-               dprintk("Sent Marker Information on port %d\n", port->actor_port_number);
+               pr_debug("Sent Marker Information on port %d\n",
+                        port->actor_port_number);
        }
 }
 #endif
@@ -1785,19 +1806,21 @@ static void ad_marker_info_send(struct port *port)
  * @port: the port we're looking at
  *
  */
-static void ad_marker_info_received(struct marker *marker_info,struct port *port)
+static void ad_marker_info_received(struct bond_marker *marker_info,
+       struct port *port)
 {
-       struct marker marker;
+       struct bond_marker marker;
 
        // copy the received marker data to the response marker
        //marker = *marker_info;
-       memcpy(&marker, marker_info, sizeof(struct marker));
+       memcpy(&marker, marker_info, sizeof(struct bond_marker));
        // change the marker subtype to marker response
-       marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE;
+       marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE;
        // send the marker response
 
        if (ad_marker_send(port, &marker) >= 0) {
-               dprintk("Sent Marker Response on port %d\n", port->actor_port_number);
+               pr_debug("Sent Marker Response on port %d\n",
+                        port->actor_port_number);
        }
 }
 
@@ -1810,60 +1833,14 @@ static void ad_marker_info_received(struct marker *marker_info,struct port *port
  * response for marker PDU's, in this stage, but only to respond to marker
  * information.
  */
-static void ad_marker_response_received(struct marker *marker, struct port *port)
+static void ad_marker_response_received(struct bond_marker *marker,
+       struct port *port)
 {
-       marker=NULL; // just to satisfy the compiler
-       port=NULL;  // just to satisfy the compiler
+       marker = NULL; /* just to satisfy the compiler */
+       port = NULL;  /* just to satisfy the compiler */
        // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW
 }
 
-/**
- * ad_initialize_lacpdu - initialize a given lacpdu structure
- * @lacpdu: lacpdu structure to initialize
- *
- */
-static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
-{
-       u16 index;
-
-       // initialize lacpdu data
-       lacpdu->subtype = 0x01;
-       lacpdu->version_number = 0x01;
-       lacpdu->tlv_type_actor_info = 0x01;
-       lacpdu->actor_information_length = 0x14;
-       // lacpdu->actor_system_priority    updated on send
-       // lacpdu->actor_system             updated on send
-       // lacpdu->actor_key                updated on send
-       // lacpdu->actor_port_priority      updated on send
-       // lacpdu->actor_port               updated on send
-       // lacpdu->actor_state              updated on send
-       lacpdu->tlv_type_partner_info = 0x02;
-       lacpdu->partner_information_length = 0x14;
-       for (index=0; index<=2; index++) {
-               lacpdu->reserved_3_1[index]=0;
-       }
-       // lacpdu->partner_system_priority  updated on send
-       // lacpdu->partner_system           updated on send
-       // lacpdu->partner_key              updated on send
-       // lacpdu->partner_port_priority    updated on send
-       // lacpdu->partner_port             updated on send
-       // lacpdu->partner_state            updated on send
-       for (index=0; index<=2; index++) {
-               lacpdu->reserved_3_2[index]=0;
-       }
-       lacpdu->tlv_type_collector_info = 0x03;
-       lacpdu->collector_information_length= 0x10;
-       lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
-       for (index=0; index<=11; index++) {
-               lacpdu->reserved_12[index]=0;
-       }
-       lacpdu->tlv_type_terminator = 0x00;
-       lacpdu->terminator_length = 0;
-       for (index=0; index<=49; index++) {
-               lacpdu->reserved_50[index]=0;
-       }
-}
-
 //////////////////////////////////////////////////////////////////////////////////////
 // ================= AD exported functions to the main bonding code ==================
 //////////////////////////////////////////////////////////////////////////////////////
@@ -1871,6 +1848,19 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
 // Check aggregators status in team every T seconds
 #define AD_AGGREGATOR_SELECTION_TIMER  8
 
+/*
+ * bond_3ad_initiate_agg_selection(struct bonding *bond)
+ *
+ * Set the aggregation selection timer, to initiate an agg selection in
+ * the very near future.  Called during first initialization, and during
+ * any down to up transitions of the bond.
+ */
+void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
+{
+       BOND_AD_INFO(bond).agg_select_timer = timeout;
+       BOND_AD_INFO(bond).agg_select_mode = bond->params.ad_select;
+}
+
 static u16 aggregator_identifier;
 
 /**
@@ -1882,9 +1872,10 @@ static u16 aggregator_identifier;
  * Can be called only after the mac address of the bond is set.
  */
 void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast)
-{                         
+{
        // check that the bond is not initialized yet
-       if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) {
+       if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr),
+                               bond->dev->dev_addr)) {
 
                aggregator_identifier = 0;
 
@@ -1895,9 +1886,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas
                // initialize how many times this module is called in one second(should be about every 100ms)
                ad_ticks_per_sec = tick_resolution;
 
-               // initialize the aggregator selection timer(to activate an aggregation selection after initialize)
-               BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec);
-               BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH;
+               bond_3ad_initiate_agg_selection(bond,
+                                               AD_AGGREGATOR_SELECTION_TIMER *
+                                               ad_ticks_per_sec);
        }
 }
 
@@ -1915,11 +1906,12 @@ int bond_3ad_bind_slave(struct slave *slave)
        struct aggregator *aggregator;
 
        if (bond == NULL) {
-               printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name);
+               pr_err("%s: The slave %s is not attached to its bond\n",
+                      slave->dev->master->name, slave->dev->name);
                return -1;
        }
 
-       //check that the slave has not been intialized yet.
+       //check that the slave has not been initialized yet.
        if (SLAVE_AD_INFO(slave).port.slave != slave) {
 
                // port initialization
@@ -1939,9 +1931,8 @@ int bond_3ad_bind_slave(struct slave *slave)
                port->actor_admin_port_key |= (__get_link_speed(port) << 1);
                port->actor_oper_port_key = port->actor_admin_port_key;
                // if the port is not full duplex, then the port should be not lacp Enabled
-               if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) {
+               if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS))
                        port->sm_vars &= ~AD_PORT_LACP_ENABLED;
-               }
                // actor system is the bond's system
                port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
                // tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second)
@@ -1981,7 +1972,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
        struct port *port, *prev_port, *temp_port;
        struct aggregator *aggregator, *new_aggregator, *temp_aggregator;
        int select_new_active_agg = 0;
-       
+
        // find the aggregator related to this slave
        aggregator = &(SLAVE_AD_INFO(slave).aggregator);
 
@@ -1990,11 +1981,13 @@ void bond_3ad_unbind_slave(struct slave *slave)
 
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
-               printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name);
+               pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
+                          slave->dev->master->name, slave->dev->name);
                return;
        }
 
-       dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier);
+       pr_debug("Unbinding Link Aggregation Group %d\n",
+                aggregator->aggregator_identifier);
 
        /* Tell the partner that this port is not suitable for aggregation */
        port->actor_oper_port_state &= ~AD_STATE_AGGREGATION;
@@ -2010,18 +2003,22 @@ void bond_3ad_unbind_slave(struct slave *slave)
                        // find new aggregator for the related port(s)
                        new_aggregator = __get_first_agg(port);
                        for (; new_aggregator; new_aggregator = __get_next_agg(new_aggregator)) {
-                               // if the new aggregator is empty, or it connected to to our port only
-                               if (!new_aggregator->lag_ports || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator)) {
+                               // if the new aggregator is empty, or it is connected to our port only
+                               if (!new_aggregator->lag_ports
+                                   || ((new_aggregator->lag_ports == port)
+                                       && !new_aggregator->lag_ports->next_port_in_aggregator))
                                        break;
-                               }
                        }
                        // if new aggregator found, copy the aggregator's parameters
                        // and connect the related lag_ports to the new aggregator
                        if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
-                               dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier);
+                               pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n",
+                                        aggregator->aggregator_identifier,
+                                        new_aggregator->aggregator_identifier);
 
                                if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
-                                       printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n");
+                                       pr_info("%s: Removing an active aggregator\n",
+                                               aggregator->slave->dev->master->name);
                                        // select new active aggregator
                                         select_new_active_agg = 1;
                                }
@@ -2039,53 +2036,56 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                new_aggregator->num_of_ports = aggregator->num_of_ports;
 
                                // update the information that is written on the ports about the aggregator
-                               for (temp_port=aggregator->lag_ports; temp_port; temp_port=temp_port->next_port_in_aggregator) {
-                                       temp_port->aggregator=new_aggregator;
+                               for (temp_port = aggregator->lag_ports; temp_port;
+                                    temp_port = temp_port->next_port_in_aggregator) {
+                                       temp_port->aggregator = new_aggregator;
                                        temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
                                }
 
                                // clear the aggregator
                                ad_clear_agg(aggregator);
-                               
-                               if (select_new_active_agg) {
+
+                               if (select_new_active_agg)
                                        ad_agg_selection_logic(__get_first_agg(port));
-                               }
                        } else {
-                               printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, "
-                                      "and could not find a new aggregator for its ports\n");
+                               pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
+                                          slave->dev->master->name);
                        }
                } else { // in case that the only port related to this aggregator is the one we want to remove
                        select_new_active_agg = aggregator->is_active;
                        // clear the aggregator
                        ad_clear_agg(aggregator);
                        if (select_new_active_agg) {
-                               printk(KERN_INFO "Removing an active aggregator\n");
+                               pr_info("%s: Removing an active aggregator\n",
+                                       slave->dev->master->name);
                                // select new active aggregator
                                ad_agg_selection_logic(__get_first_agg(port));
                        }
                }
        }
 
-       dprintk("Unbinding port %d\n", port->actor_port_number);
+       pr_debug("Unbinding port %d\n", port->actor_port_number);
        // find the aggregator that this port is connected to
        temp_aggregator = __get_first_agg(port);
        for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) {
                prev_port = NULL;
                // search the port in the aggregator's related ports
-               for (temp_port=temp_aggregator->lag_ports; temp_port; prev_port=temp_port, temp_port=temp_port->next_port_in_aggregator) {
+               for (temp_port = temp_aggregator->lag_ports; temp_port;
+                    prev_port = temp_port,
+                            temp_port = temp_port->next_port_in_aggregator) {
                        if (temp_port == port) { // the aggregator found - detach the port from this aggregator
-                               if (prev_port) {
+                               if (prev_port)
                                        prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator;
-                               } else {
+                               else
                                        temp_aggregator->lag_ports = temp_port->next_port_in_aggregator;
-                               }
                                temp_aggregator->num_of_ports--;
-                               if (temp_aggregator->num_of_ports==0) {
+                               if (temp_aggregator->num_of_ports == 0) {
                                        select_new_active_agg = temp_aggregator->is_active;
                                        // clear the aggregator
                                        ad_clear_agg(temp_aggregator);
                                        if (select_new_active_agg) {
-                                               printk(KERN_INFO "Removing an active aggregator\n");
+                                               pr_info("%s: Removing an active aggregator\n",
+                                                       slave->dev->master->name);
                                                // select new active aggregator
                                                ad_agg_selection_logic(__get_first_agg(port));
                                        }
@@ -2094,7 +2094,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
                        }
                }
        }
-       port->slave=NULL;       
+       port->slave = NULL;
 }
 
 /**
@@ -2110,43 +2110,52 @@ void bond_3ad_unbind_slave(struct slave *slave)
  * times out, and it selects an aggregator for the ports that are yet not
  * related to any aggregator, and selects the active aggregator for a bond.
  */
-void bond_3ad_state_machine_handler(struct bonding *bond)
+void bond_3ad_state_machine_handler(struct work_struct *work)
 {
+       struct bonding *bond = container_of(work, struct bonding,
+                                           ad_work.work);
        struct port *port;
        struct aggregator *aggregator;
 
        read_lock(&bond->lock);
 
-       if (bond->kill_timers) {
+       if (bond->kill_timers)
                goto out;
-       }
 
        //check if there are any slaves
-       if (bond->slave_cnt == 0) {
+       if (bond->slave_cnt == 0)
                goto re_arm;
-       }
 
        // check if agg_select_timer timer after initialize is timed out
        if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) {
                // select the active aggregator for the bond
                if ((port = __get_first_port(bond))) {
                        if (!port->slave) {
-                               printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n");
+                               pr_warning("%s: Warning: bond's first port is uninitialized\n",
+                                          bond->dev->name);
                                goto re_arm;
                        }
 
                        aggregator = __get_first_agg(port);
                        ad_agg_selection_logic(aggregator);
                }
+               bond_3ad_set_carrier(bond);
        }
 
        // for each port run the state machines
        for (port = __get_first_port(bond); port; port = __get_next_port(port)) {
                if (!port->slave) {
-                       printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n");
+                       pr_warning("%s: Warning: Found an uninitialized port\n",
+                                  bond->dev->name);
                        goto re_arm;
                }
 
+               /* Lock around state machines to protect data accessed
+                * by all (e.g., port->sm_vars).  ad_rx_machine may run
+                * concurrently due to incoming LACPDU.
+                */
+               __get_state_machine_lock(port);
+
                ad_rx_machine(NULL, port);
                ad_periodic_machine(port);
                ad_port_selection_logic(port);
@@ -2154,13 +2163,14 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
                ad_tx_machine(port);
 
                // turn off the BEGIN bit, since we already handled it
-               if (port->sm_vars & AD_PORT_BEGIN) {
+               if (port->sm_vars & AD_PORT_BEGIN)
                        port->sm_vars &= ~AD_PORT_BEGIN;
-               }
+
+               __release_state_machine_lock(port);
        }
 
 re_arm:
-       mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks);
+       queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
 out:
        read_unlock(&bond->lock);
 }
@@ -2184,33 +2194,40 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
                port = &(SLAVE_AD_INFO(slave).port);
 
                if (!port->slave) {
-                       printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name);
+                       pr_warning("%s: Warning: port of slave %s is uninitialized\n",
+                                  slave->dev->name, slave->dev->master->name);
                        return;
                }
 
                switch (lacpdu->subtype) {
                case AD_TYPE_LACPDU:
-                       __ntohs_lacpdu(lacpdu);
-                       dprintk("Received LACPDU on port %d\n", port->actor_port_number);
+                       pr_debug("Received LACPDU on port %d\n",
+                                port->actor_port_number);
+                       /* Protect against concurrent state machines */
+                       __get_state_machine_lock(port);
                        ad_rx_machine(lacpdu, port);
+                       __release_state_machine_lock(port);
                        break;
 
                case AD_TYPE_MARKER:
                        // No need to convert fields to Little Endian since we don't use the marker's fields.
 
-                       switch (((struct marker *)lacpdu)->tlv_type) {
+                       switch (((struct bond_marker *)lacpdu)->tlv_type) {
                        case AD_MARKER_INFORMATION_SUBTYPE:
-                               dprintk("Received Marker Information on port %d\n", port->actor_port_number);
-                               ad_marker_info_received((struct marker *)lacpdu, port);
+                               pr_debug("Received Marker Information on port %d\n",
+                                        port->actor_port_number);
+                               ad_marker_info_received((struct bond_marker *)lacpdu, port);
                                break;
 
                        case AD_MARKER_RESPONSE_SUBTYPE:
-                               dprintk("Received Marker Response on port %d\n", port->actor_port_number);
-                               ad_marker_response_received((struct marker *)lacpdu, port);
+                               pr_debug("Received Marker Response on port %d\n",
+                                        port->actor_port_number);
+                               ad_marker_response_received((struct bond_marker *)lacpdu, port);
                                break;
 
                        default:
-                               dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number);
+                               pr_debug("Received an unknown Marker subtype on slot %d\n",
+                                        port->actor_port_number);
                        }
                }
        }
@@ -2230,14 +2247,15 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
 
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
-               printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n",
-                      slave->dev->name);
+               pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
+                          slave->dev->master->name, slave->dev->name);
                return;
        }
 
        port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
-       port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
-       dprintk("Port %d changed speed\n", port->actor_port_number);
+       port->actor_oper_port_key = port->actor_admin_port_key |=
+               (__get_link_speed(port) << 1);
+       pr_debug("Port %d changed speed\n", port->actor_port_number);
        // there is no need to reselect a new aggregator, just signal the
        // state machines to reinitialize
        port->sm_vars |= AD_PORT_BEGIN;
@@ -2253,18 +2271,19 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
 {
        struct port *port;
 
-       port=&(SLAVE_AD_INFO(slave).port);
+       port = &(SLAVE_AD_INFO(slave).port);
 
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
-               printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n",
-                      slave->dev->name);
+               pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
+                          slave->dev->master->name, slave->dev->name);
                return;
        }
 
        port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
-       port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
-       dprintk("Port %d changed duplex\n", port->actor_port_number);
+       port->actor_oper_port_key = port->actor_admin_port_key |=
+               __get_duplex(port);
+       pr_debug("Port %d changed duplex\n", port->actor_port_number);
        // there is no need to reselect a new aggregator, just signal the
        // state machines to reinitialize
        port->sm_vars |= AD_PORT_BEGIN;
@@ -2285,24 +2304,27 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
 
        // if slave is null, the whole port is not initialized
        if (!port->slave) {
-               printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n",
-                       slave->dev->name);
+               pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
+                          slave->dev->master->name, slave->dev->name);
                return;
        }
 
        // on link down we are zeroing duplex and speed since some of the adaptors(ce1000.lan) report full duplex/speed instead of N/A(duplex) / 0(speed)
        // on link up we are forcing recheck on the duplex and speed since some of he adaptors(ce1000.lan) report
        if (link == BOND_LINK_UP) {
-               port->is_enabled = 1;
+               port->is_enabled = true;
                port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
-               port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port);
+               port->actor_oper_port_key = port->actor_admin_port_key |=
+                       __get_duplex(port);
                port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS;
-               port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1);
+               port->actor_oper_port_key = port->actor_admin_port_key |=
+                       (__get_link_speed(port) << 1);
        } else {
                /* link has failed */
-               port->is_enabled = 0;
+               port->is_enabled = false;
                port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS;
-               port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS);
+               port->actor_oper_port_key = (port->actor_admin_port_key &=
+                                            ~AD_SPEED_KEY_BITS);
        }
        //BOND_PRINT_DBG(("Port %d changed link status to %s", port->actor_port_number, ((link == BOND_LINK_UP)?"UP":"DOWN")));
        // there is no need to reselect a new aggregator, just signal the
@@ -2310,6 +2332,33 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
        port->sm_vars |= AD_PORT_BEGIN;
 }
 
+/*
+ * set link state for bonding master: if we have an active
+ * aggregator, we're up, if not, we're down.  Presumes that we cannot
+ * have an active aggregator if there are no slaves with link up.
+ *
+ * This behavior complies with IEEE 802.3 section 43.3.9.
+ *
+ * Called by bond_set_carrier(). Return zero if carrier state does not
+ * change, nonzero if it does.
+ */
+int bond_3ad_set_carrier(struct bonding *bond)
+{
+       if (__get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator))) {
+               if (!netif_carrier_ok(bond->dev)) {
+                       netif_carrier_on(bond->dev);
+                       return 1;
+               }
+               return 0;
+       }
+
+       if (netif_carrier_ok(bond->dev)) {
+               netif_carrier_off(bond->dev);
+               return 1;
+       }
+       return 0;
+}
+
 /**
  * bond_3ad_get_active_agg_info - get information of the active aggregator
  * @bond: bonding struct to work on
@@ -2345,8 +2394,7 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
 int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 {
        struct slave *slave, *start_at;
-       struct bonding *bond = dev->priv;
-       struct ethhdr *data = (struct ethhdr *)skb->data;
+       struct bonding *bond = netdev_priv(dev);
        int slave_agg_no;
        int slaves_in_agg;
        int agg_id;
@@ -2359,12 +2407,12 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
         */
        read_lock(&bond->lock);
 
-       if (!BOND_IS_OK(bond)) {
+       if (!BOND_IS_OK(bond))
                goto out;
-       }
 
        if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
-               printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n");
+               pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n",
+                        dev->name);
                goto out;
        }
 
@@ -2373,25 +2421,25 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 
        if (slaves_in_agg == 0) {
                /*the aggregator is empty*/
-               printk(KERN_DEBUG "ERROR: active aggregator is empty\n");
+               pr_debug("%s: Error: active aggregator is empty\n", dev->name);
                goto out;
        }
 
-       slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg;
+       slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
 
        bond_for_each_slave(bond, slave, i) {
                struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
                if (agg && (agg->aggregator_identifier == agg_id)) {
                        slave_agg_no--;
-                       if (slave_agg_no < 0) {
+                       if (slave_agg_no < 0)
                                break;
-                       }
                }
        }
 
        if (slave_agg_no >= 0) {
-               printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id);
+               pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n",
+                      dev->name, agg_id);
                goto out;
        }
 
@@ -2401,9 +2449,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
                int slave_agg_id = 0;
                struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
-               if (agg) {
+               if (agg)
                        slave_agg_id = agg->aggregator_identifier;
-               }
 
                if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
                        res = bond_dev_queue_xmit(bond, skb, slave->dev);
@@ -2417,25 +2464,29 @@ out:
                dev_kfree_skb(skb);
        }
        read_unlock(&bond->lock);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype)
+int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
 {
-       struct bonding *bond = dev->priv;
+       struct bonding *bond = netdev_priv(dev);
        struct slave *slave = NULL;
        int ret = NET_RX_DROP;
 
-       if (!(dev->flags & IFF_MASTER)) {
+       if (!(dev->flags & IFF_MASTER))
+               goto out;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
+       if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
                goto out;
-       }
 
        read_lock(&bond->lock);
-       slave = bond_get_slave_by_dev((struct bonding *)dev->priv,
-                                     skb->real_dev);
-       if (slave == NULL) {
+       slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev);
+       if (!slave)
                goto out_unlock;
-       }
 
        bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
 
@@ -2448,4 +2499,3 @@ out:
 
        return ret;
 }
-