xref: /illumos-gate/usr/src/uts/common/io/aggr/aggr_lacp.c (revision aef83d42)
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