Home | History | Annotate | Download | only in aggr
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * IEEE 802.3ad Link Aggregation - LACP & Marker Protocol processing.
     28  */
     29 
     30 #include <sys/types.h>
     31 #include <sys/sysmacros.h>
     32 #include <sys/callb.h>
     33 #include <sys/conf.h>
     34 #include <sys/cmn_err.h>
     35 #include <sys/disp.h>
     36 #include <sys/list.h>
     37 #include <sys/ksynch.h>
     38 #include <sys/kmem.h>
     39 #include <sys/stream.h>
     40 #include <sys/modctl.h>
     41 #include <sys/ddi.h>
     42 #include <sys/sunddi.h>
     43 #include <sys/atomic.h>
     44 #include <sys/stat.h>
     45 #include <sys/byteorder.h>
     46 #include <sys/strsun.h>
     47 #include <sys/isa_defs.h>
     48 #include <sys/sdt.h>
     49 
     50 #include <sys/aggr.h>
     51 #include <sys/aggr_impl.h>
     52 
     53 static struct ether_addr	etherzeroaddr = {
     54 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     55 };
     56 
     57 /*
     58  * Slow_Protocol_Multicast address, as per IEEE 802.3ad spec.
     59  */
     60 static struct ether_addr   slow_multicast_addr = {
     61 	0x01, 0x80, 0xc2, 0x00, 0x00, 0x02
     62 };
     63 
     64 #ifdef DEBUG
     65 /* LACP state machine debugging support */
     66 static uint32_t aggr_lacp_debug = 0;
     67 #define	AGGR_LACP_DBG(x)	if (aggr_lacp_debug) { (void) printf x; }
     68 #else
     69 #define	AGGR_LACP_DBG(x)	{}
     70 #endif /* DEBUG */
     71 
     72 #define	NSECS_PER_SEC   1000000000ll
     73 
     74 /* used by lacp_misconfig_walker() */
     75 typedef struct lacp_misconfig_check_state_s {
     76 	aggr_port_t *cs_portp;
     77 	boolean_t cs_found;
     78 } lacp_misconfig_check_state_t;
     79 
     80 static const char *lacp_receive_str[] = LACP_RECEIVE_STATE_STRINGS;
     81 static const char *lacp_periodic_str[] = LACP_PERIODIC_STRINGS;
     82 static const char *lacp_mux_str[] = LACP_MUX_STRINGS;
     83 
     84 static uint16_t lacp_port_priority = 0x1000;
     85 static uint16_t lacp_system_priority = 0x1000;
     86 
     87 /*
     88  * Maintains a list of all ports in ATTACHED state. This information
     89  * is used to detect misconfiguration.
     90  */
     91 typedef struct lacp_sel_ports {
     92 	datalink_id_t sp_grp_linkid;
     93 	datalink_id_t sp_linkid;
     94 	/* Note: sp_partner_system must be 2-byte aligned */
     95 	struct ether_addr sp_partner_system;
     96 	uint32_t sp_partner_key;
     97 	struct lacp_sel_ports *sp_next;
     98 } lacp_sel_ports_t;
     99 
    100 static lacp_sel_ports_t *sel_ports = NULL;
    101 static kmutex_t lacp_sel_lock;
    102 
    103 static void periodic_timer_pop(void *);
    104 static void periodic_timer_pop_handler(aggr_port_t *);
    105 static void lacp_xmit_sm(aggr_port_t *);
    106 static void lacp_periodic_sm(aggr_port_t *);
    107 static void fill_lacp_pdu(aggr_port_t *, lacp_t *);
    108 static void fill_lacp_ether(aggr_port_t *, struct ether_header *);
    109 static void lacp_on(aggr_port_t *);
    110 static void lacp_off(aggr_port_t *);
    111 static boolean_t valid_lacp_pdu(aggr_port_t *, lacp_t *);
    112 static void lacp_receive_sm(aggr_port_t *, lacp_t *);
    113 static void aggr_set_coll_dist(aggr_port_t *, boolean_t);
    114 static void start_wait_while_timer(aggr_port_t *);
    115 static void stop_wait_while_timer(aggr_port_t *);
    116 static void lacp_reset_port(aggr_port_t *);
    117 static void stop_current_while_timer(aggr_port_t *);
    118 static void current_while_timer_pop(void *);
    119 static void current_while_timer_pop_handler(aggr_port_t *);
    120 static void update_default_selected(aggr_port_t *);
    121 static boolean_t update_selected(aggr_port_t *, lacp_t *);
    122 static boolean_t lacp_sel_ports_add(aggr_port_t *);
    123 static void lacp_sel_ports_del(aggr_port_t *);
    124 static void wait_while_timer_pop(void *);
    125 static void wait_while_timer_pop_handler(aggr_port_t *);
    126 
    127 void
    128 aggr_lacp_init(void)
    129 {
    130 	mutex_init(&lacp_sel_lock, NULL, MUTEX_DEFAULT, NULL);
    131 }
    132 
    133 void
    134 aggr_lacp_fini(void)
    135 {
    136 	mutex_destroy(&lacp_sel_lock);
    137 }
    138 
    139 /*
    140  * The following functions are used for handling LACP timers.
    141  *
    142  * Note that we cannot fully rely on the aggr's mac perimeter in the timeout
    143  * handler routine, otherwise it may cause deadlock with the untimeout() call
    144  * which is usually called with the mac perimeter held. Instead, a
    145  * lacp_timer_lock mutex is introduced, which protects a bitwise flag
    146  * (lacp_timer_bits). This flag is set/cleared by timeout()/stop_timer()
    147  * routines and is checked by a dedicated thread, that executes the real
    148  * timeout operation.
    149  */
    150 static void
    151 aggr_port_timer_thread(void *arg)
    152 {
    153 	aggr_port_t		*port = arg;
    154 	aggr_lacp_port_t	*pl = &port->lp_lacp;
    155 	aggr_grp_t		*grp = port->lp_grp;
    156 	uint32_t		lacp_timer_bits;
    157 	mac_perim_handle_t	mph;
    158 	callb_cpr_t		cprinfo;
    159 
    160 	CALLB_CPR_INIT(&cprinfo, &pl->lacp_timer_lock, callb_generic_cpr,
    161 	    "aggr_port_timer_thread");
    162 
    163 	mutex_enter(&pl->lacp_timer_lock);
    164 
    165 	for (;;) {
    166 
    167 		if ((lacp_timer_bits = pl->lacp_timer_bits) == 0) {
    168 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
    169 			cv_wait(&pl->lacp_timer_cv, &pl->lacp_timer_lock);
    170 			CALLB_CPR_SAFE_END(&cprinfo, &pl->lacp_timer_lock);
    171 			continue;
    172 		}
    173 		pl->lacp_timer_bits = 0;
    174 
    175 		if (lacp_timer_bits & LACP_THREAD_EXIT)
    176 			break;
    177 
    178 		if (lacp_timer_bits & LACP_PERIODIC_TIMEOUT)
    179 			pl->periodic_timer.id = 0;
    180 		if (lacp_timer_bits & LACP_WAIT_WHILE_TIMEOUT)
    181 			pl->wait_while_timer.id = 0;
    182 		if (lacp_timer_bits & LACP_CURRENT_WHILE_TIMEOUT)
    183 			pl->current_while_timer.id = 0;
    184 
    185 		mutex_exit(&pl->lacp_timer_lock);
    186 
    187 		mac_perim_enter_by_mh(grp->lg_mh, &mph);
    188 		if (port->lp_closing) {
    189 			mac_perim_exit(mph);
    190 			mutex_enter(&pl->lacp_timer_lock);
    191 			break;
    192 		}
    193 
    194 		if (lacp_timer_bits & LACP_PERIODIC_TIMEOUT)
    195 			periodic_timer_pop_handler(port);
    196 		if (lacp_timer_bits & LACP_WAIT_WHILE_TIMEOUT)
    197 			wait_while_timer_pop_handler(port);
    198 		if (lacp_timer_bits & LACP_CURRENT_WHILE_TIMEOUT)
    199 			current_while_timer_pop_handler(port);
    200 		mac_perim_exit(mph);
    201 
    202 		mutex_enter(&pl->lacp_timer_lock);
    203 		if (pl->lacp_timer_bits & LACP_THREAD_EXIT)
    204 			break;
    205 	}
    206 
    207 	pl->lacp_timer_bits = 0;
    208 	pl->lacp_timer_thread = NULL;
    209 	cv_broadcast(&pl->lacp_timer_cv);
    210 
    211 	/* CALLB_CPR_EXIT drops the lock */
    212 	CALLB_CPR_EXIT(&cprinfo);
    213 
    214 	/*
    215 	 * Release the reference of the grp so aggr_grp_delete() can call
    216 	 * mac_unregister() safely.
    217 	 */
    218 	aggr_grp_port_rele(port);
    219 	thread_exit();
    220 }
    221 
    222 /*
    223  * Set the port LACP state to SELECTED. Returns B_FALSE if the operation
    224  * could not be performed due to a memory allocation error, B_TRUE otherwise.
    225  */
    226 static boolean_t
    227 lacp_port_select(aggr_port_t *portp)
    228 {
    229 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    230 
    231 	if (!lacp_sel_ports_add(portp))
    232 		return (B_FALSE);
    233 	portp->lp_lacp.sm.selected = AGGR_SELECTED;
    234 	return (B_TRUE);
    235 }
    236 
    237 /*
    238  * Set the port LACP state to UNSELECTED.
    239  */
    240 static void
    241 lacp_port_unselect(aggr_port_t *portp)
    242 {
    243 	aggr_grp_t	*grp = portp->lp_grp;
    244 
    245 	ASSERT((grp->lg_mh == NULL) || MAC_PERIM_HELD(grp->lg_mh));
    246 
    247 	lacp_sel_ports_del(portp);
    248 	portp->lp_lacp.sm.selected = AGGR_UNSELECTED;
    249 }
    250 
    251 /*
    252  * Initialize group specific LACP state and parameters.
    253  */
    254 void
    255 aggr_lacp_init_grp(aggr_grp_t *aggrp)
    256 {
    257 	aggrp->aggr.PeriodicTimer = AGGR_LACP_TIMER_SHORT;
    258 	aggrp->aggr.ActorSystemPriority = (uint16_t)lacp_system_priority;
    259 	aggrp->aggr.CollectorMaxDelay = 10;
    260 	aggrp->lg_lacp_mode = AGGR_LACP_OFF;
    261 	aggrp->aggr.ready = B_FALSE;
    262 }
    263 
    264 /*
    265  * Complete LACP info initialization at port creation time.
    266  */
    267 void
    268 aggr_lacp_init_port(aggr_port_t *portp)
    269 {
    270 	aggr_grp_t *aggrp = portp->lp_grp;
    271 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    272 
    273 	ASSERT(aggrp->lg_mh == NULL || MAC_PERIM_HELD(aggrp->lg_mh));
    274 	ASSERT(MAC_PERIM_HELD(portp->lp_mh));
    275 
    276 	/* actor port # */
    277 	pl->ActorPortNumber = portp->lp_portid;
    278 	AGGR_LACP_DBG(("aggr_lacp_init_port(%d): "
    279 	    "ActorPortNumber = 0x%x\n", portp->lp_linkid,
    280 	    pl->ActorPortNumber));
    281 
    282 	pl->ActorPortPriority = (uint16_t)lacp_port_priority;
    283 	pl->ActorPortAggrId = 0;	/* aggregator id - not used */
    284 	pl->NTT = B_FALSE;			/* need to transmit */
    285 
    286 	pl->ActorAdminPortKey = aggrp->lg_key;
    287 	pl->ActorOperPortKey = pl->ActorAdminPortKey;
    288 	AGGR_LACP_DBG(("aggr_lacp_init_port(%d) "
    289 	    "ActorAdminPortKey = 0x%x, ActorAdminPortKey = 0x%x\n",
    290 	    portp->lp_linkid, pl->ActorAdminPortKey, pl->ActorOperPortKey));
    291 
    292 	/* Actor admin. port state */
    293 	pl->ActorAdminPortState.bit.activity = B_FALSE;
    294 	pl->ActorAdminPortState.bit.timeout = B_TRUE;
    295 	pl->ActorAdminPortState.bit.aggregation = B_TRUE;
    296 	pl->ActorAdminPortState.bit.sync = B_FALSE;
    297 	pl->ActorAdminPortState.bit.collecting = B_FALSE;
    298 	pl->ActorAdminPortState.bit.distributing = B_FALSE;
    299 	pl->ActorAdminPortState.bit.defaulted = B_FALSE;
    300 	pl->ActorAdminPortState.bit.expired = B_FALSE;
    301 	pl->ActorOperPortState = pl->ActorAdminPortState;
    302 
    303 	/*
    304 	 * Partner Administrative Information
    305 	 * (All initialized to zero except for the following)
    306 	 * Fast Timeouts.
    307 	 */
    308 	pl->PartnerAdminPortState.bit.timeout =
    309 	    pl->PartnerOperPortState.bit.timeout = B_TRUE;
    310 
    311 	pl->PartnerCollectorMaxDelay = 0; /* tens of microseconds */
    312 
    313 	/*
    314 	 * State machine information.
    315 	 */
    316 	pl->sm.lacp_on = B_FALSE;		/* LACP Off default */
    317 	pl->sm.begin = B_TRUE;		/* Prevents transmissions */
    318 	pl->sm.lacp_enabled = B_FALSE;
    319 	pl->sm.port_enabled = B_FALSE;		/* Link Down */
    320 	pl->sm.actor_churn = B_FALSE;
    321 	pl->sm.partner_churn = B_FALSE;
    322 	pl->sm.ready_n = B_FALSE;
    323 	pl->sm.port_moved = B_FALSE;
    324 
    325 	lacp_port_unselect(portp);
    326 
    327 	pl->sm.periodic_state = LACP_NO_PERIODIC;
    328 	pl->sm.receive_state = LACP_INITIALIZE;
    329 	pl->sm.mux_state = LACP_DETACHED;
    330 	pl->sm.churn_state = LACP_NO_ACTOR_CHURN;
    331 
    332 	/*
    333 	 * Timer information.
    334 	 */
    335 	pl->current_while_timer.id = 0;
    336 	pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
    337 
    338 	pl->periodic_timer.id = 0;
    339 	pl->periodic_timer.val = FAST_PERIODIC_TIME;
    340 
    341 	pl->wait_while_timer.id = 0;
    342 	pl->wait_while_timer.val = AGGREGATE_WAIT_TIME;
    343 
    344 	pl->lacp_timer_bits = 0;
    345 
    346 	mutex_init(&pl->lacp_timer_lock, NULL, MUTEX_DRIVER, NULL);
    347 	cv_init(&pl->lacp_timer_cv, NULL, CV_DRIVER, NULL);
    348 
    349 	pl->lacp_timer_thread = thread_create(NULL, 0, aggr_port_timer_thread,
    350 	    portp, 0, &p0, TS_RUN, minclsyspri);
    351 
    352 	/*
    353 	 * Hold a reference of the grp and the port and this reference will
    354 	 * be release when the thread exits.
    355 	 *
    356 	 * The reference on the port is used for aggr_port_delete() to
    357 	 * continue without waiting for the thread to exit; the reference
    358 	 * on the grp is used for aggr_grp_delete() to wait for the thread
    359 	 * to exit before calling mac_unregister().
    360 	 */
    361 	aggr_grp_port_hold(portp);
    362 }
    363 
    364 /*
    365  * Port initialization when we need to
    366  * turn LACP on/off, etc. Not everything is
    367  * reset like in the above routine.
    368  *		Do NOT modify things like link status.
    369  */
    370 static void
    371 lacp_reset_port(aggr_port_t *portp)
    372 {
    373 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    374 
    375 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    376 
    377 	pl->NTT = B_FALSE;			/* need to transmit */
    378 
    379 	/* reset operational port state */
    380 	pl->ActorOperPortState.bit.timeout =
    381 	    pl->ActorAdminPortState.bit.timeout;
    382 
    383 	pl->ActorOperPortState.bit.sync = B_FALSE;
    384 	pl->ActorOperPortState.bit.collecting = B_FALSE;
    385 	pl->ActorOperPortState.bit.distributing = B_FALSE;
    386 	pl->ActorOperPortState.bit.defaulted = B_TRUE;
    387 	pl->ActorOperPortState.bit.expired = B_FALSE;
    388 
    389 	pl->PartnerOperPortState.bit.timeout = B_TRUE;	/* fast t/o */
    390 	pl->PartnerCollectorMaxDelay = 0; /* tens of microseconds */
    391 
    392 	/*
    393 	 * State machine information.
    394 	 */
    395 	pl->sm.begin = B_TRUE;		/* Prevents transmissions */
    396 	pl->sm.actor_churn = B_FALSE;
    397 	pl->sm.partner_churn = B_FALSE;
    398 	pl->sm.ready_n = B_FALSE;
    399 
    400 	lacp_port_unselect(portp);
    401 
    402 	pl->sm.periodic_state = LACP_NO_PERIODIC;
    403 	pl->sm.receive_state = LACP_INITIALIZE;
    404 	pl->sm.mux_state = LACP_DETACHED;
    405 	pl->sm.churn_state = LACP_NO_ACTOR_CHURN;
    406 
    407 	/*
    408 	 * Timer information.
    409 	 */
    410 	pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
    411 	pl->periodic_timer.val = FAST_PERIODIC_TIME;
    412 }
    413 
    414 static void
    415 aggr_lacp_mcast_on(aggr_port_t *port)
    416 {
    417 	ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
    418 	ASSERT(MAC_PERIM_HELD(port->lp_mh));
    419 
    420 	if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
    421 		return;
    422 
    423 	(void) aggr_port_multicst(port, B_TRUE,
    424 	    (uchar_t *)&slow_multicast_addr);
    425 }
    426 
    427 static void
    428 aggr_lacp_mcast_off(aggr_port_t *port)
    429 {
    430 	ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
    431 	ASSERT(MAC_PERIM_HELD(port->lp_mh));
    432 
    433 	if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
    434 		return;
    435 
    436 	(void) aggr_port_multicst(port, B_FALSE,
    437 	    (uchar_t *)&slow_multicast_addr);
    438 }
    439 
    440 static void
    441 start_periodic_timer(aggr_port_t *portp)
    442 {
    443 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    444 
    445 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    446 
    447 	mutex_enter(&pl->lacp_timer_lock);
    448 	if (pl->periodic_timer.id == 0) {
    449 		pl->periodic_timer.id = timeout(periodic_timer_pop, portp,
    450 		    drv_usectohz(1000000 * portp->lp_lacp.periodic_timer.val));
    451 	}
    452 	mutex_exit(&pl->lacp_timer_lock);
    453 }
    454 
    455 static void
    456 stop_periodic_timer(aggr_port_t *portp)
    457 {
    458 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    459 	timeout_id_t id;
    460 
    461 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    462 
    463 	mutex_enter(&pl->lacp_timer_lock);
    464 	if ((id = pl->periodic_timer.id) != 0) {
    465 		pl->lacp_timer_bits &= ~LACP_PERIODIC_TIMEOUT;
    466 		pl->periodic_timer.id = 0;
    467 	}
    468 	mutex_exit(&pl->lacp_timer_lock);
    469 
    470 	if (id != 0)
    471 		(void) untimeout(id);
    472 }
    473 
    474 /*
    475  * When the timer pops, we arrive here to
    476  * clear out LACPDU count as well as transmit an
    477  * LACPDU. We then set the periodic state and let
    478  * the periodic state machine restart the timer.
    479  */
    480 static void
    481 periodic_timer_pop(void *data)
    482 {
    483 	aggr_port_t *portp = data;
    484 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    485 
    486 	mutex_enter(&pl->lacp_timer_lock);
    487 	pl->lacp_timer_bits |= LACP_PERIODIC_TIMEOUT;
    488 	cv_broadcast(&pl->lacp_timer_cv);
    489 	mutex_exit(&pl->lacp_timer_lock);
    490 }
    491 
    492 /*
    493  * When the timer pops, we arrive here to
    494  * clear out LACPDU count as well as transmit an
    495  * LACPDU. We then set the periodic state and let
    496  * the periodic state machine restart the timer.
    497  */
    498 static void
    499 periodic_timer_pop_handler(aggr_port_t *portp)
    500 {
    501 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    502 
    503 	portp->lp_lacp_stats.LACPDUsTx = 0;
    504 
    505 	/* current timestamp */
    506 	portp->lp_lacp.time = gethrtime();
    507 	portp->lp_lacp.NTT = B_TRUE;
    508 	lacp_xmit_sm(portp);
    509 
    510 	/*
    511 	 * Set Periodic State machine state based on the
    512 	 * value of the Partner Operation Port State timeout
    513 	 * bit.
    514 	 */
    515 	if (portp->lp_lacp.PartnerOperPortState.bit.timeout) {
    516 		portp->lp_lacp.periodic_timer.val = FAST_PERIODIC_TIME;
    517 		portp->lp_lacp.sm.periodic_state = LACP_FAST_PERIODIC;
    518 	} else {
    519 		portp->lp_lacp.periodic_timer.val = SLOW_PERIODIC_TIME;
    520 		portp->lp_lacp.sm.periodic_state = LACP_SLOW_PERIODIC;
    521 	}
    522 
    523 	lacp_periodic_sm(portp);
    524 }
    525 
    526 /*
    527  * Invoked from:
    528  *	- startup upon aggregation
    529  *	- when the periodic timer pops
    530  *	- when the periodic timer value is changed
    531  *	- when the port is attached or detached
    532  *	- when LACP mode is changed.
    533  */
    534 static void
    535 lacp_periodic_sm(aggr_port_t *portp)
    536 {
    537 	lacp_periodic_state_t oldstate = portp->lp_lacp.sm.periodic_state;
    538 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    539 
    540 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    541 
    542 	/* LACP_OFF state not in specification so check here.  */
    543 	if (!pl->sm.lacp_on) {
    544 		/* Stop timer whether it is running or not */
    545 		stop_periodic_timer(portp);
    546 		pl->sm.periodic_state = LACP_NO_PERIODIC;
    547 		pl->NTT = B_FALSE;
    548 		AGGR_LACP_DBG(("lacp_periodic_sm(%d):NO LACP "
    549 		    "%s--->%s\n", portp->lp_linkid,
    550 		    lacp_periodic_str[oldstate],
    551 		    lacp_periodic_str[pl->sm.periodic_state]));
    552 		return;
    553 	}
    554 
    555 	if (pl->sm.begin || !pl->sm.lacp_enabled ||
    556 	    !pl->sm.port_enabled ||
    557 	    !pl->ActorOperPortState.bit.activity &&
    558 	    !pl->PartnerOperPortState.bit.activity) {
    559 
    560 		/* Stop timer whether it is running or not */
    561 		stop_periodic_timer(portp);
    562 		pl->sm.periodic_state = LACP_NO_PERIODIC;
    563 		pl->NTT = B_FALSE;
    564 		AGGR_LACP_DBG(("lacp_periodic_sm(%d):STOP %s--->%s\n",
    565 		    portp->lp_linkid, lacp_periodic_str[oldstate],
    566 		    lacp_periodic_str[pl->sm.periodic_state]));
    567 		return;
    568 	}
    569 
    570 	/*
    571 	 * Startup with FAST_PERIODIC_TIME if no previous LACPDU
    572 	 * has been received. Then after we timeout, then it is
    573 	 * possible to go to SLOW_PERIODIC_TIME.
    574 	 */
    575 	if (pl->sm.periodic_state == LACP_NO_PERIODIC) {
    576 		pl->periodic_timer.val = FAST_PERIODIC_TIME;
    577 		pl->sm.periodic_state = LACP_FAST_PERIODIC;
    578 	} else if ((pl->sm.periodic_state == LACP_SLOW_PERIODIC) &&
    579 	    pl->PartnerOperPortState.bit.timeout) {
    580 		/*
    581 		 * If we receive a bit indicating we are going to
    582 		 * fast periodic from slow periodic, stop the timer
    583 		 * and let the periodic_timer_pop routine deal
    584 		 * with reseting the periodic state and transmitting
    585 		 * a LACPDU.
    586 		 */
    587 		stop_periodic_timer(portp);
    588 		periodic_timer_pop_handler(portp);
    589 	}
    590 
    591 	/* Rearm timer with value provided by partner */
    592 	start_periodic_timer(portp);
    593 }
    594 
    595 /*
    596  * This routine transmits an LACPDU if lacp_enabled
    597  * is TRUE and if NTT is set.
    598  */
    599 static void
    600 lacp_xmit_sm(aggr_port_t *portp)
    601 {
    602 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    603 	size_t	len;
    604 	mblk_t  *mp;
    605 	hrtime_t now, elapsed;
    606 
    607 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    608 
    609 	/* LACP_OFF state not in specification so check here.  */
    610 	if (!pl->sm.lacp_on || !pl->NTT || !portp->lp_started)
    611 		return;
    612 
    613 	/*
    614 	 * Do nothing if LACP has been turned off or if the
    615 	 * periodic state machine is not enabled.
    616 	 */
    617 	if ((pl->sm.periodic_state == LACP_NO_PERIODIC) ||
    618 	    !pl->sm.lacp_enabled || pl->sm.begin) {
    619 		pl->NTT = B_FALSE;
    620 		return;
    621 	}
    622 
    623 	/*
    624 	 * If we have sent 5 Slow packets in the last second, avoid
    625 	 * sending any more here. No more than three LACPDUs may be transmitted
    626 	 * in any Fast_Periodic_Time interval.
    627 	 */
    628 	if (portp->lp_lacp_stats.LACPDUsTx >= 3) {
    629 		/*
    630 		 * Grab the current time value and see if
    631 		 * more than 1 second has passed. If so,
    632 		 * reset the timestamp and clear the count.
    633 		 */
    634 		now = gethrtime();
    635 		elapsed = now - pl->time;
    636 		if (elapsed > NSECS_PER_SEC) {
    637 			portp->lp_lacp_stats.LACPDUsTx = 0;
    638 			pl->time = now;
    639 		} else {
    640 			return;
    641 		}
    642 	}
    643 
    644 	len = sizeof (lacp_t) + sizeof (struct ether_header);
    645 	mp = allocb(len, BPRI_MED);
    646 	if (mp == NULL)
    647 		return;
    648 
    649 	mp->b_wptr = mp->b_rptr + len;
    650 	bzero(mp->b_rptr, len);
    651 
    652 	fill_lacp_ether(portp, (struct ether_header *)mp->b_rptr);
    653 	fill_lacp_pdu(portp,
    654 	    (lacp_t *)(mp->b_rptr + sizeof (struct ether_header)));
    655 
    656 	(void) mac_tx(portp->lp_mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL);
    657 
    658 	pl->NTT = B_FALSE;
    659 	portp->lp_lacp_stats.LACPDUsTx++;
    660 }
    661 
    662 /*
    663  * Initialize the ethernet header of a LACP packet sent from the specified
    664  * port.
    665  */
    666 static void
    667 fill_lacp_ether(aggr_port_t *port, struct ether_header *ether)
    668 {
    669 	bcopy(port->lp_addr, (uint8_t *)&(ether->ether_shost), ETHERADDRL);
    670 	bcopy(&slow_multicast_addr, (uint8_t *)&(ether->ether_dhost),
    671 	    ETHERADDRL);
    672 	ether->ether_type = htons(ETHERTYPE_SLOW);
    673 }
    674 
    675 static void
    676 fill_lacp_pdu(aggr_port_t *portp, lacp_t *lacp)
    677 {
    678 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    679 	aggr_grp_t *aggrp = portp->lp_grp;
    680 	mac_perim_handle_t pmph;
    681 
    682 	ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
    683 	mac_perim_enter_by_mh(portp->lp_mh, &pmph);
    684 
    685 	lacp->subtype = LACP_SUBTYPE;
    686 	lacp->version = LACP_VERSION;
    687 
    688 	/*
    689 	 * Actor Information
    690 	 */
    691 	lacp->actor_info.tlv_type = ACTOR_TLV;
    692 	lacp->actor_info.information_len = sizeof (link_info_t);
    693 	lacp->actor_info.system_priority =
    694 	    htons(aggrp->aggr.ActorSystemPriority);
    695 	bcopy(aggrp->lg_addr, (uchar_t *)&lacp->actor_info.system_id,
    696 	    ETHERADDRL);
    697 	lacp->actor_info.key = htons(pl->ActorOperPortKey);
    698 	lacp->actor_info.port_priority = htons(pl->ActorPortPriority);
    699 	lacp->actor_info.port = htons(pl->ActorPortNumber);
    700 	lacp->actor_info.state.state = pl->ActorOperPortState.state;
    701 
    702 	/*
    703 	 * Partner Information
    704 	 */
    705 	lacp->partner_info.tlv_type = PARTNER_TLV;
    706 	lacp->partner_info.information_len = sizeof (link_info_t);
    707 	lacp->partner_info.system_priority =
    708 	    htons(pl->PartnerOperSysPriority);
    709 	lacp->partner_info.system_id = pl->PartnerOperSystem;
    710 	lacp->partner_info.key = htons(pl->PartnerOperKey);
    711 	lacp->partner_info.port_priority =
    712 	    htons(pl->PartnerOperPortPriority);
    713 	lacp->partner_info.port = htons(pl->PartnerOperPortNum);
    714 	lacp->partner_info.state.state = pl->PartnerOperPortState.state;
    715 
    716 	/* Collector Information */
    717 	lacp->tlv_collector = COLLECTOR_TLV;
    718 	lacp->collector_len = 0x10;
    719 	lacp->collector_max_delay = htons(aggrp->aggr.CollectorMaxDelay);
    720 
    721 	/* Termination Information */
    722 	lacp->tlv_terminator = TERMINATOR_TLV;
    723 	lacp->terminator_len = 0x0;
    724 
    725 	mac_perim_exit(pmph);
    726 }
    727 
    728 /*
    729  * lacp_mux_sm - LACP mux state machine
    730  *		This state machine is invoked from:
    731  *			- startup upon aggregation
    732  *			- from the Selection logic
    733  *			- when the wait_while_timer pops
    734  *			- when the aggregation MAC address is changed
    735  *			- when receiving DL_NOTE_LINK_UP/DOWN
    736  *			- when receiving DL_NOTE_AGGR_AVAIL/UNAVAIL
    737  *			- when LACP mode is changed.
    738  *			- when a DL_NOTE_SPEED is received
    739  */
    740 static void
    741 lacp_mux_sm(aggr_port_t *portp)
    742 {
    743 	aggr_grp_t *aggrp = portp->lp_grp;
    744 	boolean_t NTT_updated = B_FALSE;
    745 	aggr_lacp_port_t *pl = &portp->lp_lacp;
    746 	lacp_mux_state_t oldstate = pl->sm.mux_state;
    747 
    748 	ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
    749 
    750 	/* LACP_OFF state not in specification so check here.  */
    751 	if (!pl->sm.lacp_on) {
    752 		pl->sm.mux_state = LACP_DETACHED;
    753 		pl->ActorOperPortState.bit.sync = B_FALSE;
    754 
    755 		if (pl->ActorOperPortState.bit.collecting ||
    756 		    pl->ActorOperPortState.bit.distributing) {
    757 			AGGR_LACP_DBG(("trunk link: (%d): "
    758 			    "Collector_Distributor Disabled.\n",
    759 			    portp->lp_linkid));
    760 		}
    761 
    762 		pl->ActorOperPortState.bit.collecting =
    763 		    pl->ActorOperPortState.bit.distributing = B_FALSE;
    764 		return;
    765 	}
    766 
    767 	if (pl->sm.begin || !pl->sm.lacp_enabled)
    768 		pl->sm.mux_state = LACP_DETACHED;
    769 
    770 again:
    771 	/* determine next state, or return if state unchanged */
    772 	switch (pl->sm.mux_state) {
    773 	case LACP_DETACHED:
    774 		if (pl->sm.begin) {
    775 			break;
    776 		}
    777 
    778 		if ((pl->sm.selected == AGGR_SELECTED) ||
    779 		    (pl->sm.selected == AGGR_STANDBY)) {
    780 			pl->sm.mux_state = LACP_WAITING;
    781 			break;
    782 		}
    783 		return;
    784 
    785 	case LACP_WAITING:
    786 		if (pl->sm.selected == AGGR_UNSELECTED) {
    787 			pl->sm.mux_state = LACP_DETACHED;
    788 			break;
    789 		}
    790 
    791 		if ((pl->sm.selected == AGGR_SELECTED) && aggrp->aggr.ready) {
    792 			pl->sm.mux_state = LACP_ATTACHED;
    793 			break;
    794 		}
    795 		return;
    796 
    797 	case LACP_ATTACHED:
    798 		if ((pl->sm.selected == AGGR_UNSELECTED) ||
    799 		    (pl->sm.selected == AGGR_STANDBY)) {
    800 			pl->sm.mux_state = LACP_DETACHED;
    801 			break;
    802 		}
    803 
    804 		if ((pl->sm.selected == AGGR_SELECTED) &&
    805 		    pl->PartnerOperPortState.bit.sync) {
    806 			pl->sm.mux_state = LACP_COLLECTING_DISTRIBUTING;
    807 			break;
    808 		}
    809 		return;
    810 
    811 	case LACP_COLLECTING_DISTRIBUTING:
    812 		if ((pl->sm.selected == AGGR_UNSELECTED) ||
    813 		    (pl->sm.selected == AGGR_STANDBY) ||
    814 		    !pl->PartnerOperPortState.bit.sync) {
    815 			pl->sm.mux_state = LACP_ATTACHED;
    816 			break;
    817 		}
    818 		return;
    819 	}
    820 
    821 	AGGR_LACP_DBG(("lacp_mux_sm(%d):%s--->%s\n",
    822 	    portp->lp_linkid, lacp_mux_str[oldstate],
    823 	    lacp_mux_str[pl->sm.mux_state]));
    824 
    825 	/* perform actions on entering a new state */
    826 	switch (pl->sm.mux_state) {
    827 	case LACP_DETACHED:
    828 		if (pl->ActorOperPortState.bit.collecting ||
    829 		    pl->ActorOperPortState.bit.distributing) {
    830 			AGGR_LACP_DBG(("trunk link: (%d): "
    831 			    "Collector_Distributor Disabled.\n",
    832 			    portp->lp_linkid));
    833 		}
    834 
    835 		pl->ActorOperPortState.bit.sync =
    836 		    pl->ActorOperPortState.bit.collecting = B_FALSE;
    837 
    838 		/* Turn OFF Collector_Distributor */
    839 		aggr_set_coll_dist(portp, B_FALSE);
    840 
    841 		pl->ActorOperPortState.bit.distributing = B_FALSE;
    842 		NTT_updated = B_TRUE;
    843 		break;
    844 
    845 	case LACP_WAITING:
    846 		start_wait_while_timer(portp);
    847 		break;
    848 
    849 	case LACP_ATTACHED:
    850 		if (pl->ActorOperPortState.bit.collecting ||
    851 		    pl->ActorOperPortState.bit.distributing) {
    852 			AGGR_LACP_DBG(("trunk link: (%d): "
    853 			    "Collector_Distributor Disabled.\n",
    854 			    portp->lp_linkid));
    855 		}
    856 
    857 		pl->ActorOperPortState.bit.sync = B_TRUE;
    858 		pl->ActorOperPortState.bit.collecting = B_FALSE;
    859 
    860 		/* Turn OFF Collector_Distributor */
    861 		aggr_set_coll_dist(portp, B_FALSE);
    862 
    863 		pl->ActorOperPortState.bit.distributing = B_FALSE;
    864 		NTT_updated = B_TRUE;
    865 		if (pl->PartnerOperPortState.bit.sync) {
    866 			/*
    867 			 * We had already received an updated sync from
    868 			 * the partner. Attempt to transition to
    869 			 * collecting/distributing now.
    870 			 */
    871 			goto again;
    872 		}
    873 		break;
    874 
    875 	case LACP_COLLECTING_DISTRIBUTING:
    876 		if (!pl->ActorOperPortState.bit.collecting &&
    877 		    !pl->ActorOperPortState.bit.distributing) {
    878 			AGGR_LACP_DBG(("trunk link: (%d): "
    879 			    "Collector_Distributor Enabled.\n",
    880 			    portp->lp_linkid));
    881 		}
    882 		pl->ActorOperPortState.bit.distributing = B_TRUE;
    883 
    884 		/* Turn Collector_Distributor back ON */
    885 		aggr_set_coll_dist(portp, B_TRUE);
    886 
    887 		pl->ActorOperPortState.bit.collecting = B_TRUE;
    888 		NTT_updated = B_TRUE;
    889 		break;
    890 	}
    891 
    892 	/*
    893 	 * If we updated the state of the NTT variable, then
    894 	 * initiate a LACPDU transmission.
    895 	 */
    896 	if (NTT_updated) {
    897 		pl->NTT = B_TRUE;
    898 		lacp_xmit_sm(portp);
    899 	}
    900 } /* lacp_mux_sm */
    901 
    902 
    903 static int
    904 receive_marker_pdu(aggr_port_t *portp, mblk_t *mp)
    905 {
    906 	marker_pdu_t		*markerp = (marker_pdu_t *)mp->b_rptr;
    907 
    908 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
    909 
    910 	AGGR_LACP_DBG(("trunk link: (%d): MARKER PDU received:\n",
    911 	    portp->lp_linkid));
    912 
    913 	/* LACP_OFF state not in specification so check here.  */
    914 	if (!portp->lp_lacp.sm.lacp_on)
    915 		return (-1);
    916 
    917 	if (MBLKL(mp) < sizeof (marker_pdu_t))
    918 		return (-1);
    919 
    920 	if (markerp->version != MARKER_VERSION) {
    921 		AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
    922 		    "version = %d does not match s/w version %d\n",
    923 		    portp->lp_linkid, markerp->version, MARKER_VERSION));
    924 		return (-1);
    925 	}
    926 
    927 	if (markerp->tlv_marker == MARKER_RESPONSE_TLV) {
    928 		/* We do not yet send out MARKER info PDUs */
    929 		AGGR_LACP_DBG(("trunk link (%d): MARKER RESPONSE PDU: "
    930 		    " MARKER TLV = %d - We don't send out info type!\n",
    931 		    portp->lp_linkid, markerp->tlv_marker));
    932 		return (-1);
    933 	}
    934 
    935 	if (markerp->tlv_marker != MARKER_INFO_TLV) {
    936 		AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
    937 		    " MARKER TLV = %d \n", portp->lp_linkid,
    938 		    markerp->tlv_marker));
    939 		return (-1);
    940 	}
    941 
    942 	if (markerp->marker_len != MARKER_INFO_RESPONSE_LENGTH) {
    943 		AGGR_LACP_DBG(("trunk link (%d): Malformed MARKER PDU: "
    944 		    " MARKER length = %d \n", portp->lp_linkid,
    945 		    markerp->marker_len));
    946 		return (-1);
    947 	}
    948 
    949 	if (markerp->requestor_port != portp->lp_lacp.PartnerOperPortNum) {
    950 		AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: "
    951 		    " MARKER Port %d not equal to Partner port %d\n",
    952 		    portp->lp_linkid, markerp->requestor_port,
    953 		    portp->lp_lacp.PartnerOperPortNum));
    954 		return (-1);
    955 	}
    956 
    957 	if (ether_cmp(&markerp->system_id,
    958 	    &portp->lp_lacp.PartnerOperSystem) != 0) {
    959 		AGGR_LACP_DBG(("trunk link (%d): MARKER PDU: "
    960 		    " MARKER MAC not equal to Partner MAC\n",
    961 		    portp->lp_linkid));
    962 		return (-1);
    963 	}
    964 
    965 	/*
    966 	 * Turn into Marker Response PDU
    967 	 * and return mblk to sending system
    968 	 */
    969 	markerp->tlv_marker = MARKER_RESPONSE_TLV;
    970 
    971 	/* reuse the space that was used by received ethernet header */
    972 	ASSERT(MBLKHEAD(mp) >= sizeof (struct ether_header));
    973 	mp->b_rptr -= sizeof (struct ether_header);
    974 	fill_lacp_ether(portp, (struct ether_header *)mp->b_rptr);
    975 	return (0);
    976 }
    977 
    978 /*
    979  * Update the LACP mode (off, active, or passive) of the specified group.
    980  */
    981 void
    982 aggr_lacp_update_mode(aggr_grp_t *grp, aggr_lacp_mode_t mode)
    983 {
    984 	aggr_lacp_mode_t old_mode = grp->lg_lacp_mode;
    985 	aggr_port_t *port;
    986 
    987 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
    988 	ASSERT(!grp->lg_closing);
    989 
    990 	if (mode == old_mode)
    991 		return;
    992 
    993 	grp->lg_lacp_mode = mode;
    994 
    995 	for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
    996 		port->lp_lacp.ActorAdminPortState.bit.activity =
    997 		    port->lp_lacp.ActorOperPortState.bit.activity =
    998 		    (mode == AGGR_LACP_ACTIVE);
    999 
   1000 		if (old_mode == AGGR_LACP_OFF) {
   1001 			/* OFF -> {PASSIVE,ACTIVE} */
   1002 			/* turn OFF Collector_Distributor */
   1003 			aggr_set_coll_dist(port, B_FALSE);
   1004 			lacp_on(port);
   1005 		} else if (mode == AGGR_LACP_OFF) {
   1006 			/* {PASSIVE,ACTIVE} -> OFF */
   1007 			lacp_off(port);
   1008 			/* Turn ON Collector_Distributor */
   1009 			aggr_set_coll_dist(port, B_TRUE);
   1010 		} else {
   1011 			/* PASSIVE->ACTIVE or ACTIVE->PASSIVE */
   1012 			port->lp_lacp.sm.begin = B_TRUE;
   1013 			lacp_mux_sm(port);
   1014 			lacp_periodic_sm(port);
   1015 
   1016 			/* kick off state machines */
   1017 			lacp_receive_sm(port, NULL);
   1018 			lacp_mux_sm(port);
   1019 		}
   1020 	}
   1021 }
   1022 
   1023 
   1024 /*
   1025  * Update the LACP timer (short or long) of the specified group.
   1026  */
   1027 void
   1028 aggr_lacp_update_timer(aggr_grp_t *grp, aggr_lacp_timer_t timer)
   1029 {
   1030 	aggr_port_t *port;
   1031 
   1032 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
   1033 
   1034 	if (timer == grp->aggr.PeriodicTimer)
   1035 		return;
   1036 
   1037 	grp->aggr.PeriodicTimer = timer;
   1038 
   1039 	for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
   1040 		port->lp_lacp.ActorAdminPortState.bit.timeout =
   1041 		    port->lp_lacp.ActorOperPortState.bit.timeout =
   1042 		    (timer == AGGR_LACP_TIMER_SHORT);
   1043 	}
   1044 }
   1045 
   1046 void
   1047 aggr_port_lacp_set_mode(aggr_grp_t *grp, aggr_port_t *port)
   1048 {
   1049 	aggr_lacp_mode_t	mode;
   1050 	aggr_lacp_timer_t	timer;
   1051 
   1052 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
   1053 
   1054 	mode = grp->lg_lacp_mode;
   1055 	timer = grp->aggr.PeriodicTimer;
   1056 
   1057 	port->lp_lacp.ActorAdminPortState.bit.activity =
   1058 	    port->lp_lacp.ActorOperPortState.bit.activity =
   1059 	    (mode == AGGR_LACP_ACTIVE);
   1060 
   1061 	port->lp_lacp.ActorAdminPortState.bit.timeout =
   1062 	    port->lp_lacp.ActorOperPortState.bit.timeout =
   1063 	    (timer == AGGR_LACP_TIMER_SHORT);
   1064 
   1065 	if (mode == AGGR_LACP_OFF) {
   1066 		/* Turn ON Collector_Distributor */
   1067 		aggr_set_coll_dist(port, B_TRUE);
   1068 	} else { /* LACP_ACTIVE/PASSIVE */
   1069 		lacp_on(port);
   1070 	}
   1071 }
   1072 
   1073 /*
   1074  * Sets the initial LACP mode (off, active, passive) and LACP timer
   1075  * (short, long) of the specified group.
   1076  */
   1077 void
   1078 aggr_lacp_set_mode(aggr_grp_t *grp, aggr_lacp_mode_t mode,
   1079     aggr_lacp_timer_t timer)
   1080 {
   1081 	aggr_port_t *port;
   1082 
   1083 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
   1084 
   1085 	grp->lg_lacp_mode = mode;
   1086 	grp->aggr.PeriodicTimer = timer;
   1087 
   1088 	for (port = grp->lg_ports; port != NULL; port = port->lp_next)
   1089 		aggr_port_lacp_set_mode(grp, port);
   1090 }
   1091 
   1092 /*
   1093  * Verify that the Partner MAC and Key recorded by the specified
   1094  * port are not found in other ports that are not part of our
   1095  * aggregation. Returns B_TRUE if such a port is found, B_FALSE
   1096  * otherwise.
   1097  */
   1098 static boolean_t
   1099 lacp_misconfig_check(aggr_port_t *portp)
   1100 {
   1101 	aggr_grp_t *grp = portp->lp_grp;
   1102 	lacp_sel_ports_t *cport;
   1103 
   1104 	mutex_enter(&lacp_sel_lock);
   1105 
   1106 	for (cport = sel_ports; cport != NULL; cport = cport->sp_next) {
   1107 
   1108 		/* skip entries of the group of the port being checked */
   1109 		if (cport->sp_grp_linkid == grp->lg_linkid)
   1110 			continue;
   1111 
   1112 		if ((ether_cmp(&cport->sp_partner_system,
   1113 		    &grp->aggr.PartnerSystem) == 0) &&
   1114 		    (cport->sp_partner_key == grp->aggr.PartnerOperAggrKey)) {
   1115 			char mac_str[ETHERADDRL*3];
   1116 			struct ether_addr *mac = &cport->sp_partner_system;
   1117 
   1118 			/*
   1119 			 * The Partner port information is already in use
   1120 			 * by ports in another aggregation so disable this
   1121 			 * port.
   1122 			 */
   1123 
   1124 			(void) snprintf(mac_str, sizeof (mac_str),
   1125 			    "%x:%x:%x:%x:%x:%x",
   1126 			    mac->ether_addr_octet[0], mac->ether_addr_octet[1],
   1127 			    mac->ether_addr_octet[2], mac->ether_addr_octet[3],
   1128 			    mac->ether_addr_octet[4], mac->ether_addr_octet[5]);
   1129 
   1130 			portp->lp_lacp.sm.selected = AGGR_UNSELECTED;
   1131 
   1132 			cmn_err(CE_NOTE, "aggr %d port %d: Port Partner "
   1133 			    "MAC %s and key %d in use on aggregation %d "
   1134 			    "port %d\n", grp->lg_linkid, portp->lp_linkid,
   1135 			    mac_str, portp->lp_lacp.PartnerOperKey,
   1136 			    cport->sp_grp_linkid, cport->sp_linkid);
   1137 			break;
   1138 		}
   1139 	}
   1140 
   1141 	mutex_exit(&lacp_sel_lock);
   1142 	return (cport != NULL);
   1143 }
   1144 
   1145 /*
   1146  * Remove the specified port from the list of selected ports.
   1147  */
   1148 static void
   1149 lacp_sel_ports_del(aggr_port_t *portp)
   1150 {
   1151 	lacp_sel_ports_t *cport, **prev = NULL;
   1152 
   1153 	mutex_enter(&lacp_sel_lock);
   1154 
   1155 	prev = &sel_ports;
   1156 	for (cport = sel_ports; cport != NULL; prev = &cport->sp_next,
   1157 	    cport = cport->sp_next) {
   1158 		if (portp->lp_linkid == cport->sp_linkid)
   1159 			break;
   1160 	}
   1161 
   1162 	if (cport == NULL) {
   1163 		mutex_exit(&lacp_sel_lock);
   1164 		return;
   1165 	}
   1166 
   1167 	*prev = cport->sp_next;
   1168 	kmem_free(cport, sizeof (*cport));
   1169 
   1170 	mutex_exit(&lacp_sel_lock);
   1171 }
   1172 
   1173 /*
   1174  * Add the specified port to the list of selected ports. Returns B_FALSE
   1175  * if the operation could not be performed due to an memory allocation
   1176  * error.
   1177  */
   1178 static boolean_t
   1179 lacp_sel_ports_add(aggr_port_t *portp)
   1180 {
   1181 	lacp_sel_ports_t *new_port;
   1182 	lacp_sel_ports_t *cport, **last;
   1183 
   1184 	mutex_enter(&lacp_sel_lock);
   1185 
   1186 	/* check if port is already in the list */
   1187 	last = &sel_ports;
   1188 	for (cport = sel_ports; cport != NULL;
   1189 	    last = &cport->sp_next, cport = cport->sp_next) {
   1190 		if (portp->lp_linkid == cport->sp_linkid) {
   1191 			ASSERT(cport->sp_partner_key ==
   1192 			    portp->lp_lacp.PartnerOperKey);
   1193 			ASSERT(ether_cmp(&cport->sp_partner_system,
   1194 			    &portp->lp_lacp.PartnerOperSystem) == 0);
   1195 
   1196 			mutex_exit(&lacp_sel_lock);
   1197 			return (B_TRUE);
   1198 		}
   1199 	}
   1200 
   1201 	/* create and initialize new entry */
   1202 	new_port = kmem_zalloc(sizeof (lacp_sel_ports_t), KM_NOSLEEP);
   1203 	if (new_port == NULL) {
   1204 		mutex_exit(&lacp_sel_lock);
   1205 		return (B_FALSE);
   1206 	}
   1207 
   1208 	new_port->sp_grp_linkid = portp->lp_grp->lg_linkid;
   1209 	bcopy(&portp->lp_lacp.PartnerOperSystem,
   1210 	    &new_port->sp_partner_system, sizeof (new_port->sp_partner_system));
   1211 	new_port->sp_partner_key = portp->lp_lacp.PartnerOperKey;
   1212 	new_port->sp_linkid = portp->lp_linkid;
   1213 
   1214 	*last = new_port;
   1215 
   1216 	mutex_exit(&lacp_sel_lock);
   1217 	return (B_TRUE);
   1218 }
   1219 
   1220 /*
   1221  * lacp_selection_logic - LACP selection logic
   1222  *		Sets the selected variable on a per port basis
   1223  *		and sets Ready when all waiting ports are ready
   1224  *		to go online.
   1225  *
   1226  * parameters:
   1227  *      - portp - instance this applies to.
   1228  *
   1229  * invoked:
   1230  *    - when initialization is needed
   1231  *    - when UNSELECTED is set from the lacp_receive_sm() in LACP_CURRENT state
   1232  *    - When the lacp_receive_sm goes to the LACP_DEFAULTED state
   1233  *    - every time the wait_while_timer pops
   1234  *    - everytime we turn LACP on/off
   1235  */
   1236 static void
   1237 lacp_selection_logic(aggr_port_t *portp)
   1238 {
   1239 	aggr_port_t *tpp;
   1240 	aggr_grp_t *aggrp = portp->lp_grp;
   1241 	int ports_waiting;
   1242 	boolean_t reset_mac = B_FALSE;
   1243 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1244 
   1245 	ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
   1246 
   1247 	/* LACP_OFF state not in specification so check here.  */
   1248 	if (!pl->sm.lacp_on) {
   1249 		lacp_port_unselect(portp);
   1250 		aggrp->aggr.ready = B_FALSE;
   1251 		lacp_mux_sm(portp);
   1252 		return;
   1253 	}
   1254 
   1255 	if (pl->sm.begin || !pl->sm.lacp_enabled ||
   1256 	    (portp->lp_state != AGGR_PORT_STATE_ATTACHED)) {
   1257 
   1258 		AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
   1259 		    "selected %d-->%d (begin=%d, lacp_enabled = %d, "
   1260 		    "lp_state=%d)\n", portp->lp_linkid, pl->sm.selected,
   1261 		    AGGR_UNSELECTED, pl->sm.begin, pl->sm.lacp_enabled,
   1262 		    portp->lp_state));
   1263 
   1264 		lacp_port_unselect(portp);
   1265 		aggrp->aggr.ready = B_FALSE;
   1266 		lacp_mux_sm(portp);
   1267 		return;
   1268 	}
   1269 
   1270 	/*
   1271 	 * If LACP is not enabled then selected is never set.
   1272 	 */
   1273 	if (!pl->sm.lacp_enabled) {
   1274 		AGGR_LACP_DBG(("lacp_selection_logic:(%d): selected %d-->%d\n",
   1275 		    portp->lp_linkid, pl->sm.selected, AGGR_UNSELECTED));
   1276 
   1277 		lacp_port_unselect(portp);
   1278 		lacp_mux_sm(portp);
   1279 		return;
   1280 	}
   1281 
   1282 	/*
   1283 	 * Check if the Partner MAC or Key are zero. If so, we have
   1284 	 * not received any LACP info or it has expired and the
   1285 	 * receive machine is in the LACP_DEFAULTED state.
   1286 	 */
   1287 	if (ether_cmp(&pl->PartnerOperSystem, &etherzeroaddr) == 0 ||
   1288 	    (pl->PartnerOperKey == 0)) {
   1289 
   1290 		for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
   1291 			if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
   1292 			    &etherzeroaddr) != 0 &&
   1293 			    (tpp->lp_lacp.PartnerOperKey != 0))
   1294 				break;
   1295 		}
   1296 
   1297 		/*
   1298 		 * If all ports have no key or aggregation address,
   1299 		 * then clear the negotiated Partner MAC and key.
   1300 		 */
   1301 		if (tpp == NULL) {
   1302 			/* Clear the aggregation Partner MAC and key */
   1303 			aggrp->aggr.PartnerSystem = etherzeroaddr;
   1304 			aggrp->aggr.PartnerOperAggrKey = 0;
   1305 		}
   1306 
   1307 		return;
   1308 	}
   1309 
   1310 	/*
   1311 	 * Insure that at least one port in the aggregation
   1312 	 * matches the Partner aggregation MAC and key. If not,
   1313 	 * then clear the aggregation MAC and key. Later we will
   1314 	 * set the Partner aggregation MAC and key to that of the
   1315 	 * current port's Partner MAC and key.
   1316 	 */
   1317 	if (ether_cmp(&pl->PartnerOperSystem,
   1318 	    &aggrp->aggr.PartnerSystem) != 0 ||
   1319 	    (pl->PartnerOperKey != aggrp->aggr.PartnerOperAggrKey)) {
   1320 
   1321 		for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
   1322 			if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
   1323 			    &aggrp->aggr.PartnerSystem) == 0 &&
   1324 			    (tpp->lp_lacp.PartnerOperKey ==
   1325 			    aggrp->aggr.PartnerOperAggrKey))
   1326 				break;
   1327 		}
   1328 
   1329 		if (tpp == NULL) {
   1330 			/* Clear the aggregation Partner MAC and key */
   1331 			aggrp->aggr.PartnerSystem = etherzeroaddr;
   1332 			aggrp->aggr.PartnerOperAggrKey = 0;
   1333 			reset_mac = B_TRUE;
   1334 		}
   1335 	}
   1336 
   1337 	/*
   1338 	 * If our Actor MAC is found in the Partner MAC
   1339 	 * on this port then we have a loopback misconfiguration.
   1340 	 */
   1341 	if (ether_cmp(&pl->PartnerOperSystem,
   1342 	    (struct ether_addr *)&aggrp->lg_addr) == 0) {
   1343 		cmn_err(CE_NOTE, "trunk link: (%d): Loopback condition.\n",
   1344 		    portp->lp_linkid);
   1345 
   1346 		lacp_port_unselect(portp);
   1347 		lacp_mux_sm(portp);
   1348 		return;
   1349 	}
   1350 
   1351 	/*
   1352 	 * If our Partner MAC and Key are found on any other
   1353 	 * ports that are not in our aggregation, we have
   1354 	 * a misconfiguration.
   1355 	 */
   1356 	if (lacp_misconfig_check(portp)) {
   1357 		lacp_mux_sm(portp);
   1358 		return;
   1359 	}
   1360 
   1361 	/*
   1362 	 * If the Aggregation Partner MAC and Key have not been
   1363 	 * set, then this is either the first port or the aggregation
   1364 	 * MAC and key have been reset. In either case we must set
   1365 	 * the values of the Partner MAC and key.
   1366 	 */
   1367 	if (ether_cmp(&aggrp->aggr.PartnerSystem, &etherzeroaddr) == 0 &&
   1368 	    (aggrp->aggr.PartnerOperAggrKey == 0)) {
   1369 		/* Set aggregation Partner MAC and key */
   1370 		aggrp->aggr.PartnerSystem = pl->PartnerOperSystem;
   1371 		aggrp->aggr.PartnerOperAggrKey = pl->PartnerOperKey;
   1372 
   1373 		/*
   1374 		 * If we reset Partner aggregation MAC, then restart
   1375 		 * selection_logic on ports that match new MAC address.
   1376 		 */
   1377 		if (reset_mac) {
   1378 			for (tpp = aggrp->lg_ports; tpp; tpp =
   1379 			    tpp->lp_next) {
   1380 				if (tpp == portp)
   1381 					continue;
   1382 				if (ether_cmp(&tpp->lp_lacp.PartnerOperSystem,
   1383 				    &aggrp->aggr.PartnerSystem) == 0 &&
   1384 				    (tpp->lp_lacp.PartnerOperKey ==
   1385 				    aggrp->aggr.PartnerOperAggrKey))
   1386 					lacp_selection_logic(tpp);
   1387 			}
   1388 		}
   1389 	} else if (ether_cmp(&pl->PartnerOperSystem,
   1390 	    &aggrp->aggr.PartnerSystem) != 0 ||
   1391 	    (pl->PartnerOperKey != aggrp->aggr.PartnerOperAggrKey)) {
   1392 		/*
   1393 		 * The Partner port information does not match
   1394 		 * that of the other ports in the aggregation
   1395 		 * so disable this port.
   1396 		 */
   1397 		lacp_port_unselect(portp);
   1398 
   1399 		cmn_err(CE_NOTE, "trunk link: (%d): Port Partner MAC "
   1400 		    "or key (%d) incompatible with Aggregation Partner "
   1401 		    "MAC or key (%d)\n", portp->lp_linkid, pl->PartnerOperKey,
   1402 		    aggrp->aggr.PartnerOperAggrKey);
   1403 
   1404 		lacp_mux_sm(portp);
   1405 		return;
   1406 	}
   1407 
   1408 	/* If we get to here, automatically set selected */
   1409 	if (pl->sm.selected != AGGR_SELECTED) {
   1410 		AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
   1411 		    "selected %d-->%d\n", portp->lp_linkid,
   1412 		    pl->sm.selected, AGGR_SELECTED));
   1413 		if (!lacp_port_select(portp))
   1414 			return;
   1415 		lacp_mux_sm(portp);
   1416 	}
   1417 
   1418 	/*
   1419 	 * From this point onward we have selected the port
   1420 	 * and are simply checking if the Ready flag should
   1421 	 * be set.
   1422 	 */
   1423 
   1424 	/*
   1425 	 * If at least two ports are waiting to aggregate
   1426 	 * and ready_n is set on all ports waiting to aggregate
   1427 	 * then set READY for the aggregation.
   1428 	 */
   1429 
   1430 	ports_waiting = 0;
   1431 
   1432 	if (!aggrp->aggr.ready) {
   1433 		/*
   1434 		 * If all ports in the aggregation have received compatible
   1435 		 * partner information and they match up correctly with the
   1436 		 * switch, there is no need to wait for all the
   1437 		 * wait_while_timers to pop.
   1438 		 */
   1439 		for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next) {
   1440 			if (((tpp->lp_lacp.sm.mux_state == LACP_WAITING) ||
   1441 			    tpp->lp_lacp.sm.begin) &&
   1442 			    !tpp->lp_lacp.PartnerOperPortState.bit.sync) {
   1443 				/* Add up ports uninitialized or waiting */
   1444 				ports_waiting++;
   1445 				if (!tpp->lp_lacp.sm.ready_n) {
   1446 					DTRACE_PROBE1(port___not__ready,
   1447 					    aggr_port_t *, tpp);
   1448 					return;
   1449 				}
   1450 			}
   1451 		}
   1452 	}
   1453 
   1454 	if (aggrp->aggr.ready) {
   1455 		AGGR_LACP_DBG(("lacp_selection_logic:(%d): "
   1456 		    "aggr.ready already set\n", portp->lp_linkid));
   1457 		lacp_mux_sm(portp);
   1458 	} else {
   1459 		AGGR_LACP_DBG(("lacp_selection_logic:(%d): Ready %d-->%d\n",
   1460 		    portp->lp_linkid, aggrp->aggr.ready, B_TRUE));
   1461 		aggrp->aggr.ready = B_TRUE;
   1462 
   1463 		for (tpp = aggrp->lg_ports; tpp; tpp = tpp->lp_next)
   1464 			lacp_mux_sm(tpp);
   1465 	}
   1466 
   1467 }
   1468 
   1469 /*
   1470  * wait_while_timer_pop - When the timer pops, we arrive here to
   1471  *			set ready_n and trigger the selection logic.
   1472  */
   1473 static void
   1474 wait_while_timer_pop(void *data)
   1475 {
   1476 	aggr_port_t *portp = data;
   1477 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1478 
   1479 	mutex_enter(&pl->lacp_timer_lock);
   1480 	pl->lacp_timer_bits |= LACP_WAIT_WHILE_TIMEOUT;
   1481 	cv_broadcast(&pl->lacp_timer_cv);
   1482 	mutex_exit(&pl->lacp_timer_lock);
   1483 }
   1484 
   1485 /*
   1486  * wait_while_timer_pop_handler - When the timer pops, we arrive here to
   1487  *			set ready_n and trigger the selection logic.
   1488  */
   1489 static void
   1490 wait_while_timer_pop_handler(aggr_port_t *portp)
   1491 {
   1492 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1493 
   1494 	AGGR_LACP_DBG(("trunk link:(%d): wait_while_timer pop \n",
   1495 	    portp->lp_linkid));
   1496 	portp->lp_lacp.sm.ready_n = B_TRUE;
   1497 
   1498 	lacp_selection_logic(portp);
   1499 }
   1500 
   1501 static void
   1502 start_wait_while_timer(aggr_port_t *portp)
   1503 {
   1504 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1505 
   1506 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1507 
   1508 	mutex_enter(&pl->lacp_timer_lock);
   1509 	if (pl->wait_while_timer.id == 0) {
   1510 		pl->wait_while_timer.id =
   1511 		    timeout(wait_while_timer_pop, portp,
   1512 		    drv_usectohz(1000000 *
   1513 		    portp->lp_lacp.wait_while_timer.val));
   1514 	}
   1515 	mutex_exit(&pl->lacp_timer_lock);
   1516 }
   1517 
   1518 
   1519 static void
   1520 stop_wait_while_timer(aggr_port_t *portp)
   1521 {
   1522 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1523 	timeout_id_t id;
   1524 
   1525 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1526 
   1527 	mutex_enter(&pl->lacp_timer_lock);
   1528 	if ((id = pl->wait_while_timer.id) != 0) {
   1529 		pl->lacp_timer_bits &= ~LACP_WAIT_WHILE_TIMEOUT;
   1530 		pl->wait_while_timer.id = 0;
   1531 	}
   1532 	mutex_exit(&pl->lacp_timer_lock);
   1533 
   1534 	if (id != 0)
   1535 		(void) untimeout(id);
   1536 }
   1537 
   1538 /*
   1539  * Invoked when a port has been attached to a group.
   1540  * Complete the processing that couldn't be finished from lacp_on()
   1541  * because the port was not started. We know that the link is full
   1542  * duplex and ON, otherwise it wouldn't be attached.
   1543  */
   1544 void
   1545 aggr_lacp_port_attached(aggr_port_t *portp)
   1546 {
   1547 	aggr_grp_t *grp = portp->lp_grp;
   1548 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1549 
   1550 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
   1551 	ASSERT(MAC_PERIM_HELD(portp->lp_mh));
   1552 	ASSERT(portp->lp_state == AGGR_PORT_STATE_ATTACHED);
   1553 
   1554 	AGGR_LACP_DBG(("aggr_lacp_port_attached: port %d\n",
   1555 	    portp->lp_linkid));
   1556 
   1557 	portp->lp_lacp.sm.port_enabled = B_TRUE;	/* link on */
   1558 
   1559 	if (grp->lg_lacp_mode == AGGR_LACP_OFF)
   1560 		return;
   1561 
   1562 	pl->sm.lacp_enabled = B_TRUE;
   1563 	pl->ActorOperPortState.bit.aggregation = B_TRUE;
   1564 	pl->sm.begin = B_TRUE;
   1565 
   1566 	lacp_receive_sm(portp, NULL);
   1567 	lacp_mux_sm(portp);
   1568 
   1569 	/* Enable Multicast Slow Protocol address */
   1570 	aggr_lacp_mcast_on(portp);
   1571 
   1572 	/* periodic_sm is started up from the receive machine */
   1573 	lacp_selection_logic(portp);
   1574 }
   1575 
   1576 /*
   1577  * Invoked when a port has been detached from a group. Turn off
   1578  * LACP processing if it was enabled.
   1579  */
   1580 void
   1581 aggr_lacp_port_detached(aggr_port_t *portp)
   1582 {
   1583 	aggr_grp_t *grp = portp->lp_grp;
   1584 
   1585 	ASSERT(MAC_PERIM_HELD(grp->lg_mh));
   1586 	ASSERT(MAC_PERIM_HELD(portp->lp_mh));
   1587 
   1588 	AGGR_LACP_DBG(("aggr_lacp_port_detached: port %d\n",
   1589 	    portp->lp_linkid));
   1590 
   1591 	portp->lp_lacp.sm.port_enabled = B_FALSE;
   1592 
   1593 	if (grp->lg_lacp_mode == AGGR_LACP_OFF)
   1594 		return;
   1595 
   1596 	portp->lp_lacp.sm.lacp_enabled = B_FALSE;
   1597 	lacp_selection_logic(portp);
   1598 	lacp_mux_sm(portp);
   1599 	lacp_periodic_sm(portp);
   1600 
   1601 	/*
   1602 	 * Disable Slow Protocol Timers.
   1603 	 */
   1604 	stop_periodic_timer(portp);
   1605 	stop_current_while_timer(portp);
   1606 	stop_wait_while_timer(portp);
   1607 
   1608 	/* Disable Multicast Slow Protocol address */
   1609 	aggr_lacp_mcast_off(portp);
   1610 	aggr_set_coll_dist(portp, B_FALSE);
   1611 }
   1612 
   1613 /*
   1614  * Enable Slow Protocol LACP and Marker PDUs.
   1615  */
   1616 static void
   1617 lacp_on(aggr_port_t *portp)
   1618 {
   1619 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1620 	mac_perim_handle_t mph;
   1621 
   1622 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1623 
   1624 	mac_perim_enter_by_mh(portp->lp_mh, &mph);
   1625 
   1626 	/*
   1627 	 * Reset the state machines and Partner operational
   1628 	 * information. Careful to not reset things like
   1629 	 * our link state.
   1630 	 */
   1631 	lacp_reset_port(portp);
   1632 	pl->sm.lacp_on = B_TRUE;
   1633 
   1634 	AGGR_LACP_DBG(("lacp_on:(%d): \n", portp->lp_linkid));
   1635 
   1636 	if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
   1637 		pl->sm.port_enabled = B_TRUE;
   1638 		pl->sm.lacp_enabled = B_TRUE;
   1639 		pl->ActorOperPortState.bit.aggregation = B_TRUE;
   1640 	}
   1641 
   1642 	lacp_receive_sm(portp, NULL);
   1643 	lacp_mux_sm(portp);
   1644 
   1645 	if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
   1646 		/* Enable Multicast Slow Protocol address */
   1647 		aggr_lacp_mcast_on(portp);
   1648 
   1649 		/* periodic_sm is started up from the receive machine */
   1650 		lacp_selection_logic(portp);
   1651 	}
   1652 done:
   1653 	mac_perim_exit(mph);
   1654 } /* lacp_on */
   1655 
   1656 /* Disable Slow Protocol LACP and Marker PDUs */
   1657 static void
   1658 lacp_off(aggr_port_t *portp)
   1659 {
   1660 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1661 	mac_perim_handle_t mph;
   1662 
   1663 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1664 	mac_perim_enter_by_mh(portp->lp_mh, &mph);
   1665 
   1666 	pl->sm.lacp_on = B_FALSE;
   1667 
   1668 	AGGR_LACP_DBG(("lacp_off:(%d): \n", portp->lp_linkid));
   1669 
   1670 	if (portp->lp_state == AGGR_PORT_STATE_ATTACHED) {
   1671 		/*
   1672 		 * Disable Slow Protocol Timers.
   1673 		 */
   1674 		stop_periodic_timer(portp);
   1675 		stop_current_while_timer(portp);
   1676 		stop_wait_while_timer(portp);
   1677 
   1678 		/* Disable Multicast Slow Protocol address */
   1679 		aggr_lacp_mcast_off(portp);
   1680 
   1681 		pl->sm.port_enabled = B_FALSE;
   1682 		pl->sm.lacp_enabled = B_FALSE;
   1683 		pl->ActorOperPortState.bit.aggregation = B_FALSE;
   1684 	}
   1685 
   1686 	lacp_mux_sm(portp);
   1687 	lacp_periodic_sm(portp);
   1688 	lacp_selection_logic(portp);
   1689 
   1690 	/* Turn OFF Collector_Distributor */
   1691 	aggr_set_coll_dist(portp, B_FALSE);
   1692 
   1693 	lacp_reset_port(portp);
   1694 	mac_perim_exit(mph);
   1695 }
   1696 
   1697 
   1698 static boolean_t
   1699 valid_lacp_pdu(aggr_port_t *portp, lacp_t *lacp)
   1700 {
   1701 	/*
   1702 	 * 43.4.12 - "a Receive machine shall not validate
   1703 	 * the Version Number, TLV_type, or Reserved fields in received
   1704 	 * LACPDUs."
   1705 	 * ... "a Receive machine may validate the Actor_Information_Length,
   1706 	 * Partner_Information_Length, Collector_Information_Length,
   1707 	 * or Terminator_Length fields."
   1708 	 */
   1709 	if ((lacp->actor_info.information_len != sizeof (link_info_t)) ||
   1710 	    (lacp->partner_info.information_len != sizeof (link_info_t)) ||
   1711 	    (lacp->collector_len != LACP_COLLECTOR_INFO_LEN) ||
   1712 	    (lacp->terminator_len != LACP_TERMINATOR_INFO_LEN)) {
   1713 		AGGR_LACP_DBG(("trunk link (%d): Malformed LACPDU: "
   1714 		    " Terminator Length = %d \n", portp->lp_linkid,
   1715 		    lacp->terminator_len));
   1716 		return (B_FALSE);
   1717 	}
   1718 
   1719 	return (B_TRUE);
   1720 }
   1721 
   1722 
   1723 static void
   1724 start_current_while_timer(aggr_port_t *portp, uint_t time)
   1725 {
   1726 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1727 
   1728 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1729 
   1730 	mutex_enter(&pl->lacp_timer_lock);
   1731 	if (pl->current_while_timer.id == 0) {
   1732 		if (time > 0)
   1733 			pl->current_while_timer.val = time;
   1734 		else if (pl->ActorOperPortState.bit.timeout)
   1735 			pl->current_while_timer.val = SHORT_TIMEOUT_TIME;
   1736 		else
   1737 			pl->current_while_timer.val = LONG_TIMEOUT_TIME;
   1738 
   1739 		pl->current_while_timer.id =
   1740 		    timeout(current_while_timer_pop, portp,
   1741 		    drv_usectohz((clock_t)1000000 *
   1742 		    (clock_t)portp->lp_lacp.current_while_timer.val));
   1743 	}
   1744 	mutex_exit(&pl->lacp_timer_lock);
   1745 }
   1746 
   1747 
   1748 static void
   1749 stop_current_while_timer(aggr_port_t *portp)
   1750 {
   1751 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1752 	timeout_id_t id;
   1753 
   1754 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1755 
   1756 	mutex_enter(&pl->lacp_timer_lock);
   1757 	if ((id = pl->current_while_timer.id) != 0) {
   1758 		pl->lacp_timer_bits &= ~LACP_CURRENT_WHILE_TIMEOUT;
   1759 		pl->current_while_timer.id = 0;
   1760 	}
   1761 	mutex_exit(&pl->lacp_timer_lock);
   1762 
   1763 	if (id != 0)
   1764 		(void) untimeout(id);
   1765 }
   1766 
   1767 static void
   1768 current_while_timer_pop(void *data)
   1769 {
   1770 	aggr_port_t *portp = (aggr_port_t *)data;
   1771 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1772 
   1773 	mutex_enter(&pl->lacp_timer_lock);
   1774 	pl->lacp_timer_bits |= LACP_CURRENT_WHILE_TIMEOUT;
   1775 	cv_broadcast(&pl->lacp_timer_cv);
   1776 	mutex_exit(&pl->lacp_timer_lock);
   1777 }
   1778 
   1779 static void
   1780 current_while_timer_pop_handler(aggr_port_t *portp)
   1781 {
   1782 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1783 
   1784 	AGGR_LACP_DBG(("trunk link:(%d): current_while_timer "
   1785 	    "pop id=%p\n", portp->lp_linkid,
   1786 	    portp->lp_lacp.current_while_timer.id));
   1787 
   1788 	lacp_receive_sm(portp, NULL);
   1789 }
   1790 
   1791 /*
   1792  * record_Default - Simply copies over administrative values
   1793  * to the partner operational values, and sets our state to indicate we
   1794  * are using defaulted values.
   1795  */
   1796 static void
   1797 record_Default(aggr_port_t *portp)
   1798 {
   1799 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1800 
   1801 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1802 
   1803 	pl->PartnerOperPortNum = pl->PartnerAdminPortNum;
   1804 	pl->PartnerOperPortPriority = pl->PartnerAdminPortPriority;
   1805 	pl->PartnerOperSystem = pl->PartnerAdminSystem;
   1806 	pl->PartnerOperSysPriority = pl->PartnerAdminSysPriority;
   1807 	pl->PartnerOperKey = pl->PartnerAdminKey;
   1808 	pl->PartnerOperPortState.state = pl->PartnerAdminPortState.state;
   1809 
   1810 	pl->ActorOperPortState.bit.defaulted = B_TRUE;
   1811 }
   1812 
   1813 
   1814 /* Returns B_TRUE on sync value changing */
   1815 static boolean_t
   1816 record_PDU(aggr_port_t *portp, lacp_t *lacp)
   1817 {
   1818 	aggr_grp_t *aggrp = portp->lp_grp;
   1819 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1820 	uint8_t save_sync;
   1821 
   1822 	ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
   1823 
   1824 	/*
   1825 	 * Partner Information
   1826 	 */
   1827 	pl->PartnerOperPortNum = ntohs(lacp->actor_info.port);
   1828 	pl->PartnerOperPortPriority =
   1829 	    ntohs(lacp->actor_info.port_priority);
   1830 	pl->PartnerOperSystem = lacp->actor_info.system_id;
   1831 	pl->PartnerOperSysPriority =
   1832 	    htons(lacp->actor_info.system_priority);
   1833 	pl->PartnerOperKey = ntohs(lacp->actor_info.key);
   1834 
   1835 	/* All state info except for Synchronization */
   1836 	save_sync = pl->PartnerOperPortState.bit.sync;
   1837 	pl->PartnerOperPortState.state = lacp->actor_info.state.state;
   1838 
   1839 	/* Defaulted set to FALSE */
   1840 	pl->ActorOperPortState.bit.defaulted = B_FALSE;
   1841 
   1842 	/*
   1843 	 * 43.4.9 - (Partner_Port, Partner_Port_Priority, Partner_system,
   1844 	 *		Partner_System_Priority, Partner_Key, and
   1845 	 *		Partner_State.Aggregation) are compared to the
   1846 	 *		corresponding operations paramters values for
   1847 	 *		the Actor. If these are equal, or if this is
   1848 	 *		an individual link, we are synchronized.
   1849 	 */
   1850 	if (((ntohs(lacp->partner_info.port) == pl->ActorPortNumber) &&
   1851 	    (ntohs(lacp->partner_info.port_priority) ==
   1852 	    pl->ActorPortPriority) &&
   1853 	    (ether_cmp(&lacp->partner_info.system_id,
   1854 	    (struct ether_addr *)&aggrp->lg_addr) == 0) &&
   1855 	    (ntohs(lacp->partner_info.system_priority) ==
   1856 	    aggrp->aggr.ActorSystemPriority) &&
   1857 	    (ntohs(lacp->partner_info.key) == pl->ActorOperPortKey) &&
   1858 	    (lacp->partner_info.state.bit.aggregation ==
   1859 	    pl->ActorOperPortState.bit.aggregation)) ||
   1860 	    (!lacp->actor_info.state.bit.aggregation)) {
   1861 
   1862 		pl->PartnerOperPortState.bit.sync =
   1863 		    lacp->actor_info.state.bit.sync;
   1864 	} else {
   1865 		pl->PartnerOperPortState.bit.sync = B_FALSE;
   1866 	}
   1867 
   1868 	if (save_sync != pl->PartnerOperPortState.bit.sync) {
   1869 		AGGR_LACP_DBG(("record_PDU:(%d): partner sync "
   1870 		    "%d -->%d\n", portp->lp_linkid, save_sync,
   1871 		    pl->PartnerOperPortState.bit.sync));
   1872 		return (B_TRUE);
   1873 	} else {
   1874 		return (B_FALSE);
   1875 	}
   1876 }
   1877 
   1878 
   1879 /*
   1880  * update_selected - If any of the Partner parameters has
   1881  *			changed from a previous value, then
   1882  *			unselect the link from the aggregator.
   1883  */
   1884 static boolean_t
   1885 update_selected(aggr_port_t *portp, lacp_t *lacp)
   1886 {
   1887 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1888 
   1889 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1890 
   1891 	if ((pl->PartnerOperPortNum != ntohs(lacp->actor_info.port)) ||
   1892 	    (pl->PartnerOperPortPriority !=
   1893 	    ntohs(lacp->actor_info.port_priority)) ||
   1894 	    (ether_cmp(&pl->PartnerOperSystem,
   1895 	    &lacp->actor_info.system_id) != 0) ||
   1896 	    (pl->PartnerOperSysPriority !=
   1897 	    ntohs(lacp->actor_info.system_priority)) ||
   1898 	    (pl->PartnerOperKey != ntohs(lacp->actor_info.key)) ||
   1899 	    (pl->PartnerOperPortState.bit.aggregation !=
   1900 	    lacp->actor_info.state.bit.aggregation)) {
   1901 		AGGR_LACP_DBG(("update_selected:(%d): "
   1902 		    "selected  %d-->%d\n", portp->lp_linkid, pl->sm.selected,
   1903 		    AGGR_UNSELECTED));
   1904 
   1905 		lacp_port_unselect(portp);
   1906 		return (B_TRUE);
   1907 	} else {
   1908 		return (B_FALSE);
   1909 	}
   1910 }
   1911 
   1912 
   1913 /*
   1914  * update_default_selected - If any of the operational Partner parameters
   1915  *			is different than that of the administrative values
   1916  *			then unselect the link from the aggregator.
   1917  */
   1918 static void
   1919 update_default_selected(aggr_port_t *portp)
   1920 {
   1921 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1922 
   1923 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   1924 
   1925 	if ((pl->PartnerAdminPortNum != pl->PartnerOperPortNum) ||
   1926 	    (pl->PartnerOperPortPriority != pl->PartnerAdminPortPriority) ||
   1927 	    (ether_cmp(&pl->PartnerOperSystem, &pl->PartnerAdminSystem) != 0) ||
   1928 	    (pl->PartnerOperSysPriority != pl->PartnerAdminSysPriority) ||
   1929 	    (pl->PartnerOperKey != pl->PartnerAdminKey) ||
   1930 	    (pl->PartnerOperPortState.bit.aggregation !=
   1931 	    pl->PartnerAdminPortState.bit.aggregation)) {
   1932 
   1933 		AGGR_LACP_DBG(("update_default_selected:(%d): "
   1934 		    "selected  %d-->%d\n", portp->lp_linkid,
   1935 		    pl->sm.selected, AGGR_UNSELECTED));
   1936 
   1937 		lacp_port_unselect(portp);
   1938 	}
   1939 }
   1940 
   1941 
   1942 /*
   1943  * update_NTT - If any of the Partner values in the received LACPDU
   1944  *			are different than that of the Actor operational
   1945  *			values then set NTT to true.
   1946  */
   1947 static void
   1948 update_NTT(aggr_port_t *portp, lacp_t *lacp)
   1949 {
   1950 	aggr_grp_t *aggrp = portp->lp_grp;
   1951 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1952 
   1953 	ASSERT(MAC_PERIM_HELD(aggrp->lg_mh));
   1954 
   1955 	if ((pl->ActorPortNumber != ntohs(lacp->partner_info.port)) ||
   1956 	    (pl->ActorPortPriority !=
   1957 	    ntohs(lacp->partner_info.port_priority)) ||
   1958 	    (ether_cmp(&aggrp->lg_addr,
   1959 	    &lacp->partner_info.system_id) != 0) ||
   1960 	    (aggrp->aggr.ActorSystemPriority !=
   1961 	    ntohs(lacp->partner_info.system_priority)) ||
   1962 	    (pl->ActorOperPortKey != ntohs(lacp->partner_info.key)) ||
   1963 	    (pl->ActorOperPortState.bit.activity !=
   1964 	    lacp->partner_info.state.bit.activity) ||
   1965 	    (pl->ActorOperPortState.bit.timeout !=
   1966 	    lacp->partner_info.state.bit.timeout) ||
   1967 	    (pl->ActorOperPortState.bit.sync !=
   1968 	    lacp->partner_info.state.bit.sync) ||
   1969 	    (pl->ActorOperPortState.bit.aggregation !=
   1970 	    lacp->partner_info.state.bit.aggregation)) {
   1971 
   1972 		AGGR_LACP_DBG(("update_NTT:(%d): NTT  %d-->%d\n",
   1973 		    portp->lp_linkid, pl->NTT, B_TRUE));
   1974 
   1975 		pl->NTT = B_TRUE;
   1976 	}
   1977 }
   1978 
   1979 /*
   1980  * lacp_receive_sm - LACP receive state machine
   1981  *
   1982  * parameters:
   1983  *      - portp - instance this applies to.
   1984  *      - lacp - pointer in the case of a received LACPDU.
   1985  *                This value is NULL if there is no LACPDU.
   1986  *
   1987  * invoked:
   1988  *    - when initialization is needed
   1989  *    - upon reception of an LACPDU. This is the common case.
   1990  *    - every time the current_while_timer pops
   1991  */
   1992 static void
   1993 lacp_receive_sm(aggr_port_t *portp, lacp_t *lacp)
   1994 {
   1995 	boolean_t sync_updated, selected_updated, save_activity;
   1996 	aggr_lacp_port_t *pl = &portp->lp_lacp;
   1997 	lacp_receive_state_t oldstate = pl->sm.receive_state;
   1998 
   1999 	ASSERT(MAC_PERIM_HELD(portp->lp_grp->lg_mh));
   2000 
   2001 	/* LACP_OFF state not in specification so check here.  */
   2002 	if (!pl->sm.lacp_on)
   2003 		return;
   2004 
   2005 	/* figure next state */
   2006 	if (pl->sm.begin || pl->sm.port_moved) {
   2007 		pl->sm.receive_state = LACP_INITIALIZE;
   2008 	} else if (!pl->sm.port_enabled) {	/* DL_NOTE_LINK_DOWN */
   2009 		pl->sm.receive_state = LACP_PORT_DISABLED;
   2010 	} else if (!pl->sm.lacp_enabled) { /* DL_NOTE_AGGR_UNAVAIL */
   2011 		pl->sm.receive_state =
   2012 		    (pl->sm.receive_state == LACP_PORT_DISABLED) ?
   2013 		    LACP_DISABLED : LACP_PORT_DISABLED;
   2014 	} else if (lacp != NULL) {
   2015 		if ((pl->sm.receive_state == LACP_EXPIRED) ||
   2016 		    (pl->sm.receive_state == LACP_DEFAULTED)) {
   2017 			pl->sm.receive_state = LACP_CURRENT;
   2018 		}
   2019 	} else if ((pl->sm.receive_state == LACP_CURRENT) &&
   2020 	    (pl->current_while_timer.id == 0)) {
   2021 		pl->sm.receive_state = LACP_EXPIRED;
   2022 	} else if ((pl->sm.receive_state == LACP_EXPIRED) &&
   2023 	    (pl->current_while_timer.id == 0)) {
   2024 		pl->sm.receive_state = LACP_DEFAULTED;
   2025 	}
   2026 
   2027 	if (!((lacp && (oldstate == LACP_CURRENT) &&
   2028 	    (pl->sm.receive_state == LACP_CURRENT)))) {
   2029 		AGGR_LACP_DBG(("lacp_receive_sm(%d):%s--->%s\n",
   2030 		    portp->lp_linkid, lacp_receive_str[oldstate],
   2031 		    lacp_receive_str[pl->sm.receive_state]));
   2032 	}
   2033 
   2034 	switch (pl->sm.receive_state) {
   2035 	case LACP_INITIALIZE:
   2036 		lacp_port_unselect(portp);
   2037 		record_Default(portp);
   2038 		pl->ActorOperPortState.bit.expired = B_FALSE;
   2039 		pl->sm.port_moved = B_FALSE;
   2040 		pl->sm.receive_state = LACP_PORT_DISABLED;
   2041 		pl->sm.begin = B_FALSE;
   2042 		lacp_receive_sm(portp, NULL);
   2043 		break;
   2044 
   2045 	case LACP_PORT_DISABLED:
   2046 		pl->PartnerOperPortState.bit.sync = B_FALSE;
   2047 		/*
   2048 		 * Stop current_while_timer in case
   2049 		 * we got here from link down
   2050 		 */
   2051 		stop_current_while_timer(portp);
   2052 
   2053 		if (pl->sm.port_enabled && !pl->sm.lacp_enabled) {
   2054 			pl->sm.receive_state = LACP_DISABLED;
   2055 			lacp_receive_sm(portp, lacp);
   2056 			/* We goto LACP_DISABLED state */
   2057 			break;
   2058 		} else if (pl->sm.port_enabled && pl->sm.lacp_enabled) {
   2059 			pl->sm.receive_state = LACP_EXPIRED;
   2060 			/*
   2061 			 * FALL THROUGH TO LACP_EXPIRED CASE:
   2062 			 * We have no way of knowing if we get into
   2063 			 * lacp_receive_sm() from a  current_while_timer
   2064 			 * expiring as it has never been kicked off yet!
   2065 			 */
   2066 		} else {
   2067 			/* We stay in LACP_PORT_DISABLED state */
   2068 			break;
   2069 		}
   2070 		/* LACP_PORT_DISABLED -> LACP_EXPIRED */
   2071 		/* FALLTHROUGH */
   2072 
   2073 	case LACP_EXPIRED:
   2074 		/*
   2075 		 * Arrives here from LACP_PORT_DISABLED state as well as
   2076 		 * as well as current_while_timer expiring.
   2077 		 */
   2078 		pl->PartnerOperPortState.bit.sync = B_FALSE;
   2079 		pl->PartnerOperPortState.bit.timeout = B_TRUE;
   2080 
   2081 		pl->ActorOperPortState.bit.expired = B_TRUE;
   2082 		start_current_while_timer(portp, SHORT_TIMEOUT_TIME);
   2083 		lacp_periodic_sm(portp);
   2084 		break;
   2085 
   2086 	case LACP_DISABLED:
   2087 		/*
   2088 		 * This is the normal state for recv_sm when LACP_OFF
   2089 		 * is set or the NIC is in half duplex mode.
   2090 		 */
   2091 		lacp_port_unselect(portp);
   2092 		record_Default(portp);
   2093 		pl->PartnerOperPortState.bit.aggregation = B_FALSE;
   2094 		pl->ActorOperPortState.bit.expired = B_FALSE;
   2095 		break;
   2096 
   2097 	case LACP_DEFAULTED:
   2098 		/*
   2099 		 * Current_while_timer expired a second time.
   2100 		 */
   2101 		update_default_selected(portp);
   2102 		record_Default(portp);	/* overwrite Partner Oper val */
   2103 		pl->ActorOperPortState.bit.expired = B_FALSE;
   2104 		pl->PartnerOperPortState.bit.sync = B_TRUE;
   2105 
   2106 		lacp_selection_logic(portp);
   2107 		lacp_mux_sm(portp);
   2108 		break;
   2109 
   2110 	case LACP_CURRENT:
   2111 		/*
   2112 		 * Reception of LACPDU
   2113 		 */
   2114 
   2115 		if (!lacp) /* no LACPDU so current_while_timer popped */
   2116 			break;
   2117 
   2118 		AGGR_LACP_DBG(("lacp_receive_sm: (%d): LACPDU received:\n",
   2119 		    portp->lp_linkid));
   2120 
   2121 		/*
   2122 		 * Validate Actor_Information_Length,
   2123 		 * Partner_Information_Length, Collector_Information_Length,
   2124 		 * and Terminator_Length fields.
   2125 		 */
   2126 		if (!valid_lacp_pdu(portp, lacp)) {
   2127 			AGGR_LACP_DBG(("lacp_receive_sm (%d): "
   2128 			    "Invalid LACPDU received\n",
   2129 			    portp->lp_linkid));
   2130 			break;
   2131 		}
   2132 
   2133 		save_activity = pl->PartnerOperPortState.bit.activity;
   2134 		selected_updated = update_selected(portp, lacp);
   2135 		update_NTT(portp, lacp);
   2136 		sync_updated = record_PDU(portp, lacp);
   2137 
   2138 		pl->ActorOperPortState.bit.expired = B_FALSE;
   2139 
   2140 		if (selected_updated) {
   2141 			lacp_selection_logic(portp);
   2142 			lacp_mux_sm(portp);
   2143 		} else if (sync_updated) {
   2144 			lacp_mux_sm(portp);
   2145 		}
   2146 
   2147 		/*
   2148 		 * If the periodic timer value bit has been modified
   2149 		 * or the partner activity bit has been changed then
   2150 		 * we need to respectively:
   2151 		 *  - restart the timer with the proper timeout value.
   2152 		 *  - possibly enable/disable transmission of LACPDUs.
   2153 		 */
   2154 		if ((pl->PartnerOperPortState.bit.timeout &&
   2155 		    (pl->periodic_timer.val != FAST_PERIODIC_TIME)) ||
   2156 		    (!pl->PartnerOperPortState.bit.timeout &&
   2157 		    (pl->periodic_timer.val != SLOW_PERIODIC_TIME)) ||
   2158 		    (pl->PartnerOperPortState.bit.activity !=
   2159 		    save_activity)) {
   2160 			lacp_periodic_sm(portp);
   2161 		}
   2162 
   2163 		stop_current_while_timer(portp);
   2164 		/* Check if we need to transmit an LACPDU */
   2165 		if (pl->NTT)
   2166 			lacp_xmit_sm(portp);
   2167 		start_current_while_timer(portp, 0);
   2168 
   2169 		break;
   2170 	}
   2171 }
   2172 
   2173 static void
   2174 aggr_set_coll_dist(aggr_port_t *portp, boolean_t enable)
   2175 {
   2176 	mac_perim_handle_t mph;
   2177 
   2178 	AGGR_LACP_DBG(("AGGR_SET_COLL_DIST_TYPE: (%d) %s\n",
   2179 	    portp->lp_linkid, enable ? "ENABLED" : "DISABLED"));
   2180 
   2181 	mac_perim_enter_by_mh(portp->lp_mh, &mph);
   2182 	if (!enable) {
   2183 		/*
   2184 		 * Turn OFF Collector_Distributor.
   2185 		 */
   2186 		portp->lp_collector_enabled = B_FALSE;
   2187 		aggr_send_port_disable(portp);
   2188 		goto done;
   2189 	}
   2190 
   2191 	/*
   2192 	 * Turn ON Collector_Distributor.
   2193 	 */
   2194 
   2195 	if (!portp->lp_lacp.sm.lacp_on || (portp->lp_lacp.sm.lacp_on &&
   2196 	    (portp->lp_lacp.sm.mux_state == LACP_COLLECTING_DISTRIBUTING))) {
   2197 		/* Port is compatible and can be aggregated */
   2198 		portp->lp_collector_enabled = B_TRUE;
   2199 		aggr_send_port_enable(portp);
   2200 	}
   2201 
   2202 done:
   2203 	mac_perim_exit(mph);
   2204 }
   2205 
   2206 /*
   2207  * Because the LACP packet processing needs to enter the aggr's mac perimeter
   2208  * and that would potentially cause a deadlock with the thread in which the
   2209  * grp/port is deleted, we defer the packet process to a worker thread. Here
   2210  * we only enqueue the received Marker or LACPDU for later processing.
   2211  */
   2212 void
   2213 aggr_lacp_rx_enqueue(aggr_port_t *portp, mblk_t *dmp)
   2214 {
   2215 	aggr_grp_t *grp = portp->lp_grp;
   2216 	lacp_t	*lacp;
   2217 
   2218 	dmp->b_rptr += sizeof (struct ether_header);
   2219 
   2220 	if (MBLKL(dmp) < sizeof (lacp_t)) {
   2221 		freemsg(dmp);
   2222 		return;
   2223 	}
   2224 
   2225 	lacp = (lacp_t *)dmp->b_rptr;
   2226 	if (lacp->subtype != LACP_SUBTYPE && lacp->subtype != MARKER_SUBTYPE) {
   2227 		AGGR_LACP_DBG(("aggr_lacp_rx_enqueue: (%d): "
   2228 		    "Unknown Slow Protocol type %d\n",
   2229 		    portp->lp_linkid, lacp->subtype));
   2230 		freemsg(dmp);
   2231 		return;
   2232 	}
   2233 
   2234 	mutex_enter(&grp->lg_lacp_lock);
   2235 
   2236 	/*
   2237 	 * If the lg_lacp_done is set, this aggregation is in the process of
   2238 	 * being deleted, return directly.
   2239 	 */
   2240 	if (grp->lg_lacp_done) {
   2241 		mutex_exit(&grp->lg_lacp_lock);
   2242 		freemsg(dmp);
   2243 		return;
   2244 	}
   2245 
   2246 	if (grp->lg_lacp_tail == NULL) {
   2247 		grp->lg_lacp_head = grp->lg_lacp_tail = dmp;
   2248 	} else {
   2249 		grp->lg_lacp_tail->b_next = dmp;
   2250 		grp->lg_lacp_tail = dmp;
   2251 	}
   2252 
   2253 	/*
   2254 	 * Hold a reference of the port so that the port won't be freed when it
   2255 	 * is removed from the aggr. The b_prev field is borrowed to save the
   2256 	 * port information.
   2257 	 */
   2258 	AGGR_PORT_REFHOLD(portp);
   2259 	dmp->b_prev = (mblk_t *)portp;
   2260 	cv_broadcast(&grp->lg_lacp_cv);
   2261 	mutex_exit(&grp->lg_lacp_lock);
   2262 }
   2263 
   2264 static void
   2265 aggr_lacp_rx(mblk_t *dmp)
   2266 {
   2267 	aggr_port_t *portp = (aggr_port_t *)dmp->b_prev;
   2268 	mac_perim_handle_t mph;
   2269 	lacp_t	*lacp;
   2270 
   2271 	dmp->b_prev = NULL;
   2272 
   2273 	mac_perim_enter_by_mh(portp->lp_grp->lg_mh, &mph);
   2274 	if (portp->lp_closing)
   2275 		goto done;
   2276 
   2277 	lacp = (lacp_t *)dmp->b_rptr;
   2278 	switch (lacp->subtype) {
   2279 	case LACP_SUBTYPE:
   2280 		AGGR_LACP_DBG(("aggr_lacp_rx:(%d): LACPDU received.\n",
   2281 		    portp->lp_linkid));
   2282 
   2283 		if (!portp->lp_lacp.sm.lacp_on) {
   2284 			break;
   2285 		}
   2286 		lacp_receive_sm(portp, lacp);
   2287 		break;
   2288 
   2289 	case MARKER_SUBTYPE:
   2290 		AGGR_LACP_DBG(("aggr_lacp_rx:(%d): Marker Packet received.\n",
   2291 		    portp->lp_linkid));
   2292 
   2293 		if (receive_marker_pdu(portp, dmp) != 0)
   2294 			break;
   2295 
   2296 		(void) mac_tx(portp->lp_mch, dmp, 0, MAC_DROP_ON_NO_DESC, NULL);
   2297 		mac_perim_exit(mph);
   2298 		AGGR_PORT_REFRELE(portp);
   2299 		return;
   2300 	}
   2301 
   2302 done:
   2303 	mac_perim_exit(mph);
   2304 	AGGR_PORT_REFRELE(portp);
   2305 	freemsg(dmp);
   2306 }
   2307 
   2308 void
   2309 aggr_lacp_rx_thread(void *arg)
   2310 {
   2311 	callb_cpr_t	cprinfo;
   2312 	aggr_grp_t	*grp = (aggr_grp_t *)arg;
   2313 	aggr_port_t	*port;
   2314 	mblk_t		*mp, *nextmp;
   2315 
   2316 	CALLB_CPR_INIT(&cprinfo, &grp->lg_lacp_lock, callb_generic_cpr,
   2317 	    "aggr_lacp_rx_thread");
   2318 
   2319 	mutex_enter(&grp->lg_lacp_lock);
   2320 
   2321 	/*
   2322 	 * Quit the thread if the grp is deleted.
   2323 	 */
   2324 	while (!grp->lg_lacp_done) {
   2325 		if ((mp = grp->lg_lacp_head) == NULL) {
   2326 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
   2327 			cv_wait(&grp->lg_lacp_cv, &grp->lg_lacp_lock);
   2328 			CALLB_CPR_SAFE_END(&cprinfo, &grp->lg_lacp_lock);
   2329 			continue;
   2330 		}
   2331 
   2332 		grp->lg_lacp_head = grp->lg_lacp_tail = NULL;
   2333 		mutex_exit(&grp->lg_lacp_lock);
   2334 
   2335 		while (mp != NULL) {
   2336 			nextmp = mp->b_next;
   2337 			mp->b_next = NULL;
   2338 			aggr_lacp_rx(mp);
   2339 			mp = nextmp;
   2340 		}
   2341 		mutex_enter(&grp->lg_lacp_lock);
   2342 	}
   2343 
   2344 	/*
   2345 	 * The grp is being destroyed, simply free all of the LACP messages
   2346 	 * left in the queue which did not have the chance to be processed.
   2347 	 * We cannot use freemsgchain() here since we need to clear the
   2348 	 * b_prev field.
   2349 	 */
   2350 	while ((mp = grp->lg_lacp_head) != NULL) {
   2351 		port = (aggr_port_t *)mp->b_prev;
   2352 		AGGR_PORT_REFRELE(port);
   2353 		nextmp = mp->b_next;
   2354 		mp->b_next = NULL;
   2355 		mp->b_prev = NULL;
   2356 		freemsg(mp);
   2357 		mp = nextmp;
   2358 	}
   2359 
   2360 	grp->lg_lacp_head = grp->lg_lacp_tail = NULL;
   2361 	grp->lg_lacp_rx_thread = NULL;
   2362 	cv_broadcast(&grp->lg_lacp_cv);
   2363 	CALLB_CPR_EXIT(&cprinfo);
   2364 	thread_exit();
   2365 }
   2366