xref: /xnu-10063.141.1/bsd/net/if_bond.c (revision d8b80295118ef25ac3a784134bcf95cd8e88109f)
1 /*
2  * Copyright (c) 2004-2021 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * if_bond.c
31  * - bond/failover interface
32  * - implements IEEE 802.3ad Link Aggregation
33  */
34 
35 /*
36  * Modification History:
37  *
38  * April 29, 2004	Dieter Siegmund ([email protected])
39  * - created
40  */
41 
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 #include <sys/kern_event.h>
52 #include <net/bpf.h>
53 #include <net/ethernet.h>
54 #include <net/if.h>
55 #include <net/kpi_interface.h>
56 #include <net/kpi_interfacefilter.h>
57 #include <net/if_arp.h>
58 #include <net/if_dl.h>
59 #include <net/if_ether.h>
60 #include <net/if_types.h>
61 #include <net/if_bond_var.h>
62 #include <net/ieee8023ad.h>
63 #include <net/lacp.h>
64 #include <net/dlil.h>
65 #include <sys/time.h>
66 #include <net/devtimer.h>
67 #include <net/if_vlan_var.h>
68 #include <net/kpi_protocol.h>
69 #include <sys/protosw.h>
70 #include <kern/locks.h>
71 #include <kern/zalloc.h>
72 #include <os/refcnt.h>
73 
74 #include <netinet/in.h>
75 #include <netinet/if_ether.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/ip6.h>
79 
80 #include <net/if_media.h>
81 #include <net/multicast_list.h>
82 
83 #include <net/sockaddr_utils.h>
84 
85 SYSCTL_DECL(_net_link);
86 SYSCTL_NODE(_net_link, OID_AUTO, bond, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
87     "Bond interface");
88 
89 static int if_bond_debug = 0;
90 SYSCTL_INT(_net_link_bond, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED,
91     &if_bond_debug, 0, "Bond interface debug logs");
92 
93 static struct ether_addr slow_proto_multicast = {
94 	.octet = IEEE8023AD_SLOW_PROTO_MULTICAST
95 };
96 
97 typedef struct ifbond_s ifbond, * ifbond_ref;
98 typedef struct bondport_s bondport, * bondport_ref;
99 
100 #define BOND_MAXUNIT            128
101 #define BOND_ZONE_MAX_ELEM      MIN(IFNETS_MAX, BOND_MAXUNIT)
102 #define BONDNAME                "bond"
103 
104 #define EA_FORMAT       "%x:%x:%x:%x:%x:%x"
105 #define EA_CH(e, i)     ((u_char)((u_char *)(e))[(i)])
106 #define EA_LIST(ea)     EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
107 
108 #define timestamp_printf        printf
109 
110 /**
111 ** bond locks
112 **/
113 
114 static LCK_GRP_DECLARE(bond_lck_grp, "if_bond");
115 static LCK_MTX_DECLARE(bond_lck_mtx, &bond_lck_grp);
116 
117 static __inline__ void
bond_assert_lock_held(void)118 bond_assert_lock_held(void)
119 {
120 	LCK_MTX_ASSERT(&bond_lck_mtx, LCK_MTX_ASSERT_OWNED);
121 }
122 
123 static __inline__ void
bond_assert_lock_not_held(void)124 bond_assert_lock_not_held(void)
125 {
126 	LCK_MTX_ASSERT(&bond_lck_mtx, LCK_MTX_ASSERT_NOTOWNED);
127 }
128 
129 static __inline__ void
bond_lock(void)130 bond_lock(void)
131 {
132 	lck_mtx_lock(&bond_lck_mtx);
133 }
134 
135 static __inline__ void
bond_unlock(void)136 bond_unlock(void)
137 {
138 	lck_mtx_unlock(&bond_lck_mtx);
139 }
140 
141 /**
142 ** bond structures, types
143 **/
144 
145 struct LAG_info_s {
146 	lacp_system                 li_system;
147 	lacp_system_priority        li_system_priority;
148 	lacp_key                    li_key;
149 };
150 typedef struct LAG_info_s LAG_info, * LAG_info_ref;
151 
152 struct bondport_s;
153 TAILQ_HEAD(port_list, bondport_s);
154 struct ifbond_s;
155 TAILQ_HEAD(ifbond_list, ifbond_s);
156 struct LAG_s;
157 TAILQ_HEAD(lag_list, LAG_s);
158 
159 typedef struct ifbond_s ifbond, * ifbond_ref;
160 typedef struct bondport_s bondport, * bondport_ref;
161 
162 struct LAG_s {
163 	TAILQ_ENTRY(LAG_s)          lag_list;
164 	struct port_list            lag_port_list;
165 	short                       lag_port_count;
166 	short                       lag_selected_port_count;
167 	int                         lag_active_media;
168 	LAG_info                    lag_info;
169 };
170 typedef struct LAG_s LAG, * LAG_ref;
171 
172 typedef struct partner_state_s {
173 	LAG_info                    ps_lag_info;
174 	lacp_port                   ps_port;
175 	lacp_port_priority          ps_port_priority;
176 	lacp_actor_partner_state    ps_state;
177 } partner_state, * partner_state_ref;
178 
179 struct ifbond_s {
180 	TAILQ_ENTRY(ifbond_s)       ifb_bond_list;
181 	int                         ifb_flags;
182 	struct os_refcnt            ifb_retain_count;
183 	char                        ifb_name[IFNAMSIZ];
184 	struct ifnet *              ifb_ifp;
185 	bpf_packet_func             ifb_bpf_input;
186 	bpf_packet_func             ifb_bpf_output;
187 	int                         ifb_altmtu;
188 	struct port_list            ifb_port_list;
189 	short                       ifb_port_count;
190 	struct lag_list             ifb_lag_list;
191 	lacp_key                    ifb_key;
192 	short                       ifb_max_active;/* 0 == unlimited */
193 	LAG_ref                     ifb_active_lag;
194 	struct ifmultiaddr *        ifb_ifma_slow_proto;
195 	bondport_ref *              ifb_distributing_array;
196 	int                         ifb_distributing_count;
197 	int                         ifb_distributing_max;
198 	int                         ifb_last_link_event;
199 	int                         ifb_mode;/* LACP, STATIC */
200 };
201 
202 struct media_info {
203 	int         mi_active;
204 	int         mi_status;
205 };
206 
207 enum {
208 	ReceiveState_none = 0,
209 	ReceiveState_INITIALIZE = 1,
210 	ReceiveState_PORT_DISABLED = 2,
211 	ReceiveState_EXPIRED = 3,
212 	ReceiveState_LACP_DISABLED = 4,
213 	ReceiveState_DEFAULTED = 5,
214 	ReceiveState_CURRENT = 6,
215 };
216 
217 typedef u_char ReceiveState;
218 
219 enum {
220 	SelectedState_UNSELECTED = IF_BOND_STATUS_SELECTED_STATE_UNSELECTED,
221 	SelectedState_SELECTED = IF_BOND_STATUS_SELECTED_STATE_SELECTED,
222 	SelectedState_STANDBY = IF_BOND_STATUS_SELECTED_STATE_STANDBY
223 };
224 typedef u_char SelectedState;
225 
226 static __inline__ const char *
SelectedStateString(SelectedState s)227 SelectedStateString(SelectedState s)
228 {
229 	static const char * names[] = { "UNSELECTED", "SELECTED", "STANDBY" };
230 
231 	if (s <= SelectedState_STANDBY) {
232 		return names[s];
233 	}
234 	return "<unknown>";
235 }
236 
237 enum {
238 	MuxState_none = 0,
239 	MuxState_DETACHED = 1,
240 	MuxState_WAITING = 2,
241 	MuxState_ATTACHED = 3,
242 	MuxState_COLLECTING_DISTRIBUTING = 4,
243 };
244 
245 typedef u_char MuxState;
246 
247 #define PORT_CONTROL_FLAGS_IN_LIST               0x01
248 #define PORT_CONTROL_FLAGS_PROTO_ATTACHED        0x02
249 #define PORT_CONTROL_FLAGS_FILTER_ATTACHED       0x04
250 #define PORT_CONTROL_FLAGS_LLADDR_SET            0x08
251 #define PORT_CONTROL_FLAGS_MTU_SET               0x10
252 #define PORT_CONTROL_FLAGS_PROMISCUOUS_SET       0x20
253 #define PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET  0x40
254 
255 
256 static inline bool
uint32_bit_is_set(uint32_t flags,uint32_t flags_to_test)257 uint32_bit_is_set(uint32_t flags, uint32_t flags_to_test)
258 {
259 	return (flags & flags_to_test) != 0;
260 }
261 
262 static inline void
uint32_bit_set(uint32_t * flags_p,uint32_t flags_to_set)263 uint32_bit_set(uint32_t * flags_p, uint32_t flags_to_set)
264 {
265 	*flags_p |= flags_to_set;
266 }
267 
268 static inline void
uint32_bit_clear(uint32_t * flags_p,uint32_t flags_to_clear)269 uint32_bit_clear(uint32_t * flags_p, uint32_t flags_to_clear)
270 {
271 	*flags_p &= ~flags_to_clear;
272 }
273 
274 struct bondport_s {
275 	TAILQ_ENTRY(bondport_s)     po_port_list;
276 	ifbond_ref                  po_bond;
277 	struct multicast_list       po_multicast;
278 	struct ifnet *              po_ifp;
279 	struct ether_addr           po_saved_addr;
280 	int                         po_enabled;
281 	char                        po_name[IFNAMSIZ];
282 	struct ifdevmtu             po_devmtu;
283 	uint32_t                    po_control_flags;
284 	interface_filter_t          po_filter;
285 
286 	/* LACP */
287 	TAILQ_ENTRY(bondport_s)     po_lag_port_list;
288 	devtimer_ref                po_current_while_timer;
289 	devtimer_ref                po_periodic_timer;
290 	devtimer_ref                po_wait_while_timer;
291 	devtimer_ref                po_transmit_timer;
292 	partner_state               po_partner_state;
293 	lacp_port_priority          po_priority;
294 	lacp_actor_partner_state    po_actor_state;
295 	u_char                      po_flags;
296 	u_char                      po_periodic_interval;
297 	u_char                      po_n_transmit;
298 	ReceiveState                po_receive_state;
299 	MuxState                    po_mux_state;
300 	SelectedState               po_selected;
301 	int32_t                     po_last_transmit_secs;
302 	struct media_info           po_media_info;
303 	uint64_t                    po_force_link_event_time;
304 	LAG_ref                     po_lag;
305 };
306 
307 #define IFBF_PROMISC            0x1     /* promiscuous mode */
308 #define IFBF_IF_DETACHING       0x2     /* interface is detaching */
309 #define IFBF_LLADDR             0x4     /* specific link address requested */
310 #define IFBF_CHANGE_IN_PROGRESS 0x8     /* interface add/remove in progress */
311 
312 static int bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p,
313     user_addr_t datap);
314 
315 static __inline__ bool
ifbond_flags_if_detaching(ifbond_ref ifb)316 ifbond_flags_if_detaching(ifbond_ref ifb)
317 {
318 	return (ifb->ifb_flags & IFBF_IF_DETACHING) != 0;
319 }
320 
321 static __inline__ void
ifbond_flags_set_if_detaching(ifbond_ref ifb)322 ifbond_flags_set_if_detaching(ifbond_ref ifb)
323 {
324 	ifb->ifb_flags |= IFBF_IF_DETACHING;
325 	return;
326 }
327 
328 static __inline__ bool
ifbond_flags_lladdr(ifbond_ref ifb)329 ifbond_flags_lladdr(ifbond_ref ifb)
330 {
331 	return (ifb->ifb_flags & IFBF_LLADDR) != 0;
332 }
333 
334 static __inline__ bool
ifbond_flags_change_in_progress(ifbond_ref ifb)335 ifbond_flags_change_in_progress(ifbond_ref ifb)
336 {
337 	return (ifb->ifb_flags & IFBF_CHANGE_IN_PROGRESS) != 0;
338 }
339 
340 static __inline__ void
ifbond_flags_set_change_in_progress(ifbond_ref ifb)341 ifbond_flags_set_change_in_progress(ifbond_ref ifb)
342 {
343 	ifb->ifb_flags |= IFBF_CHANGE_IN_PROGRESS;
344 	return;
345 }
346 
347 static __inline__ void
ifbond_flags_clear_change_in_progress(ifbond_ref ifb)348 ifbond_flags_clear_change_in_progress(ifbond_ref ifb)
349 {
350 	ifb->ifb_flags &= ~IFBF_CHANGE_IN_PROGRESS;
351 	return;
352 }
353 
354 static __inline__ bool
ifbond_flags_promisc(ifbond_ref ifb)355 ifbond_flags_promisc(ifbond_ref ifb)
356 {
357 	return (ifb->ifb_flags & IFBF_PROMISC) != 0;
358 }
359 
360 static __inline__ void
ifbond_flags_set_promisc(ifbond_ref ifb)361 ifbond_flags_set_promisc(ifbond_ref ifb)
362 {
363 	ifb->ifb_flags |= IFBF_PROMISC;
364 	return;
365 }
366 
367 static __inline__ void
ifbond_flags_clear_promisc(ifbond_ref ifb)368 ifbond_flags_clear_promisc(ifbond_ref ifb)
369 {
370 	ifb->ifb_flags &= ~IFBF_PROMISC;
371 	return;
372 }
373 
374 /*
375  * bondport_ref->po_flags bits
376  */
377 #define BONDPORT_FLAGS_NTT              0x01
378 #define BONDPORT_FLAGS_READY            0x02
379 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
380 #define BONDPORT_FLAGS_MUX_ATTACHED     0x08
381 #define BONDPORT_FLAGS_DISTRIBUTING     0x10
382 #define BONDPORT_FLAGS_UNUSED2          0x20
383 #define BONDPORT_FLAGS_UNUSED3          0x40
384 #define BONDPORT_FLAGS_UNUSED4          0x80
385 
386 static __inline__ void
bondport_flags_set_ntt(bondport_ref p)387 bondport_flags_set_ntt(bondport_ref p)
388 {
389 	p->po_flags |= BONDPORT_FLAGS_NTT;
390 	return;
391 }
392 
393 static __inline__ void
bondport_flags_clear_ntt(bondport_ref p)394 bondport_flags_clear_ntt(bondport_ref p)
395 {
396 	p->po_flags &= ~BONDPORT_FLAGS_NTT;
397 	return;
398 }
399 
400 static __inline__ int
bondport_flags_ntt(bondport_ref p)401 bondport_flags_ntt(bondport_ref p)
402 {
403 	return (p->po_flags & BONDPORT_FLAGS_NTT) != 0;
404 }
405 
406 static __inline__ void
bondport_flags_set_ready(bondport_ref p)407 bondport_flags_set_ready(bondport_ref p)
408 {
409 	p->po_flags |= BONDPORT_FLAGS_READY;
410 	return;
411 }
412 
413 static __inline__ void
bondport_flags_clear_ready(bondport_ref p)414 bondport_flags_clear_ready(bondport_ref p)
415 {
416 	p->po_flags &= ~BONDPORT_FLAGS_READY;
417 	return;
418 }
419 
420 static __inline__ int
bondport_flags_ready(bondport_ref p)421 bondport_flags_ready(bondport_ref p)
422 {
423 	return (p->po_flags & BONDPORT_FLAGS_READY) != 0;
424 }
425 
426 static __inline__ void
bondport_flags_set_selected_changed(bondport_ref p)427 bondport_flags_set_selected_changed(bondport_ref p)
428 {
429 	p->po_flags |= BONDPORT_FLAGS_SELECTED_CHANGED;
430 	return;
431 }
432 
433 static __inline__ void
bondport_flags_clear_selected_changed(bondport_ref p)434 bondport_flags_clear_selected_changed(bondport_ref p)
435 {
436 	p->po_flags &= ~BONDPORT_FLAGS_SELECTED_CHANGED;
437 	return;
438 }
439 
440 static __inline__ int
bondport_flags_selected_changed(bondport_ref p)441 bondport_flags_selected_changed(bondport_ref p)
442 {
443 	return (p->po_flags & BONDPORT_FLAGS_SELECTED_CHANGED) != 0;
444 }
445 
446 static __inline__ void
bondport_flags_set_mux_attached(bondport_ref p)447 bondport_flags_set_mux_attached(bondport_ref p)
448 {
449 	p->po_flags |= BONDPORT_FLAGS_MUX_ATTACHED;
450 	return;
451 }
452 
453 static __inline__ void
bondport_flags_clear_mux_attached(bondport_ref p)454 bondport_flags_clear_mux_attached(bondport_ref p)
455 {
456 	p->po_flags &= ~BONDPORT_FLAGS_MUX_ATTACHED;
457 	return;
458 }
459 
460 static __inline__ int
bondport_flags_mux_attached(bondport_ref p)461 bondport_flags_mux_attached(bondport_ref p)
462 {
463 	return (p->po_flags & BONDPORT_FLAGS_MUX_ATTACHED) != 0;
464 }
465 
466 static __inline__ void
bondport_flags_set_distributing(bondport_ref p)467 bondport_flags_set_distributing(bondport_ref p)
468 {
469 	p->po_flags |= BONDPORT_FLAGS_DISTRIBUTING;
470 	return;
471 }
472 
473 static __inline__ void
bondport_flags_clear_distributing(bondport_ref p)474 bondport_flags_clear_distributing(bondport_ref p)
475 {
476 	p->po_flags &= ~BONDPORT_FLAGS_DISTRIBUTING;
477 	return;
478 }
479 
480 static __inline__ int
bondport_flags_distributing(bondport_ref p)481 bondport_flags_distributing(bondport_ref p)
482 {
483 	return (p->po_flags & BONDPORT_FLAGS_DISTRIBUTING) != 0;
484 }
485 
486 typedef struct bond_globals_s {
487 	struct ifbond_list          ifbond_list;
488 	lacp_system                 system;
489 	lacp_system_priority        system_priority;
490 } * bond_globals_ref;
491 
492 static bond_globals_ref g_bond;
493 
494 /**
495 ** packet_buffer routines
496 ** - thin wrapper for mbuf
497 **/
498 
499 typedef struct mbuf * packet_buffer_ref;
500 
501 static packet_buffer_ref
packet_buffer_allocate(int length)502 packet_buffer_allocate(int length)
503 {
504 	packet_buffer_ref   m;
505 	int                 size;
506 
507 	/* leave room for ethernet header */
508 	size = length + sizeof(struct ether_header);
509 	if (size > (int)MHLEN) {
510 		if (size > (int)MCLBYTES) {
511 			printf("bond: packet_buffer_allocate size %d > max %u\n",
512 			    size, MCLBYTES);
513 			return NULL;
514 		}
515 		m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
516 	} else {
517 		m = m_gethdr(M_WAITOK, MT_DATA);
518 	}
519 	if (m == NULL) {
520 		return NULL;
521 	}
522 	m->m_len = size;
523 	m->m_pkthdr.len = size;
524 	return m;
525 }
526 
527 static void *
packet_buffer_byteptr(packet_buffer_ref buf)528 packet_buffer_byteptr(packet_buffer_ref buf)
529 {
530 	return m_mtod_current(buf) + sizeof(struct ether_header);
531 }
532 
533 typedef enum {
534 	LAEventStart,
535 	LAEventTimeout,
536 	LAEventPacket,
537 	LAEventMediaChange,
538 	LAEventSelectedChange,
539 	LAEventPortMoved,
540 	LAEventReady
541 } LAEvent;
542 
543 /**
544 ** Receive machine
545 **/
546 static void
547 bondport_receive_machine(bondport_ref p, LAEvent event,
548     void * event_data);
549 /**
550 ** Periodic Transmission machine
551 **/
552 static void
553 bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
554     void * event_data);
555 
556 /**
557 ** Transmit machine
558 **/
559 #define TRANSMIT_MACHINE_TX_IMMEDIATE   ((void *)1)
560 
561 static void
562 bondport_transmit_machine(bondport_ref p, LAEvent event,
563     void * event_data);
564 
565 /**
566 ** Mux machine
567 **/
568 static void
569 bondport_mux_machine(bondport_ref p, LAEvent event,
570     void * event_data);
571 
572 /**
573 ** bond, LAG
574 **/
575 static void
576 ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media);
577 
578 static void
579 ifbond_deactivate_LAG(ifbond_ref bond, LAG_ref lag);
580 
581 static int
582 ifbond_all_ports_ready(ifbond_ref bond);
583 
584 static LAG_ref
585 ifbond_find_best_LAG(ifbond_ref bond, int * active_media);
586 
587 static int
588 LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media);
589 
590 static int
591 ifbond_selection(ifbond_ref bond);
592 
593 static void
594 bond_handle_event(struct ifnet * port_ifp, int event_code);
595 
596 /**
597 ** bondport
598 **/
599 
600 static void
601 bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p);
602 
603 static void
604 bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf);
605 
606 static bondport_ref
607 bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
608     int active, int short_timeout, int * error);
609 static void
610 bondport_start(bondport_ref p);
611 
612 static void
613 bondport_free(bondport_ref p);
614 
615 static int
616 bondport_aggregatable(bondport_ref p);
617 
618 static int
619 bondport_remove_from_LAG(bondport_ref p);
620 
621 static void
622 bondport_set_selected(bondport_ref p, SelectedState s);
623 
624 static int
625 bondport_matches_LAG(bondport_ref p, LAG_ref lag);
626 
627 static void
628 bondport_link_status_changed(bondport_ref p);
629 
630 static void
631 bondport_enable_distributing(bondport_ref p);
632 
633 static void
634 bondport_disable_distributing(bondport_ref p);
635 
636 static __inline__ int
bondport_collecting(bondport_ref p)637 bondport_collecting(bondport_ref p)
638 {
639 	if (p->po_bond->ifb_mode == IF_BOND_MODE_LACP) {
640 		return lacp_actor_partner_state_collecting(p->po_actor_state);
641 	}
642 	return TRUE;
643 }
644 
645 /**
646 ** bond interface/dlil specific routines
647 **/
648 static int bond_clone_create(struct if_clone *, u_int32_t, void *);
649 static int bond_clone_destroy(struct ifnet *);
650 static int bond_output(struct ifnet *ifp, struct mbuf *m);
651 static int bond_ioctl(struct ifnet *ifp, u_long cmd, void * addr);
652 static int bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode,
653     bpf_packet_func func);
654 static int bond_attach_protocol(struct ifnet *ifp);
655 static int bond_detach_protocol(struct ifnet *ifp);
656 static errno_t bond_iff_input(void *cookie, ifnet_t ifp,
657     protocol_family_t protocol, mbuf_t *data, char **frame_ptr);
658 static int bond_attach_filter(struct ifnet *ifp, interface_filter_t * filter_p);
659 static int bond_setmulti(struct ifnet *ifp);
660 static int bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp);
661 static int bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp);
662 static void bond_if_free(struct ifnet * ifp);
663 static void interface_link_event(struct ifnet * ifp, u_int32_t event_code);
664 
665 static struct if_clone bond_cloner = IF_CLONE_INITIALIZER(BONDNAME,
666     bond_clone_create,
667     bond_clone_destroy,
668     0,
669     BOND_MAXUNIT);
670 
671 static int
siocsifmtu(struct ifnet * ifp,int mtu)672 siocsifmtu(struct ifnet * ifp, int mtu)
673 {
674 	struct ifreq        ifr;
675 
676 	bzero(&ifr, sizeof(ifr));
677 	ifr.ifr_mtu = mtu;
678 	return ifnet_ioctl(ifp, 0, SIOCSIFMTU, &ifr);
679 }
680 
681 static int
siocgifdevmtu(struct ifnet * ifp,struct ifdevmtu * ifdm_p)682 siocgifdevmtu(struct ifnet * ifp, struct ifdevmtu * ifdm_p)
683 {
684 	struct ifreq        ifr;
685 	int                 error;
686 
687 	bzero(&ifr, sizeof(ifr));
688 	error = ifnet_ioctl(ifp, 0, SIOCGIFDEVMTU, &ifr);
689 	if (error == 0) {
690 		*ifdm_p = ifr.ifr_devmtu;
691 	}
692 	return error;
693 }
694 
695 static __inline__ void
ether_addr_copy(void * dest,const void * source)696 ether_addr_copy(void * dest, const void * source)
697 {
698 	bcopy(source, dest, ETHER_ADDR_LEN);
699 	return;
700 }
701 
702 static __inline__ void
ifbond_retain(ifbond_ref ifb)703 ifbond_retain(ifbond_ref ifb)
704 {
705 	os_ref_retain(&ifb->ifb_retain_count);
706 }
707 
708 static __inline__ void
ifbond_release(ifbond_ref ifb)709 ifbond_release(ifbond_ref ifb)
710 {
711 	if (os_ref_release(&ifb->ifb_retain_count) != 0) {
712 		return;
713 	}
714 
715 	if (if_bond_debug) {
716 		printf("ifbond_release(%s)\n", ifb->ifb_name);
717 	}
718 	if (ifb->ifb_ifma_slow_proto != NULL) {
719 		if (if_bond_debug) {
720 			printf("ifbond_release(%s) removing multicast\n",
721 			    ifb->ifb_name);
722 		}
723 		(void) if_delmulti_anon(ifb->ifb_ifma_slow_proto->ifma_ifp,
724 		    ifb->ifb_ifma_slow_proto->ifma_addr);
725 		IFMA_REMREF(ifb->ifb_ifma_slow_proto);
726 	}
727 	kfree_type(bondport_ref, ifb->ifb_distributing_max,
728 	    ifb->ifb_distributing_array);
729 	kfree_type(struct ifbond_s, ifb);
730 }
731 
732 /*
733  * Function: ifbond_wait
734  * Purpose:
735  *   Allows a single thread to gain exclusive access to the ifbond
736  *   data structure.  Some operations take a long time to complete,
737  *   and some have side-effects that we can't predict.  Holding the
738  *   bond_lock() across such operations is not possible.
739  *
740  *   For example:
741  *   1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
742  *      complete.  Simply holding the bond_lock() would freeze all other
743  *      data structure accesses during that time.
744  *   2) When we attach our protocol to the interface, a dlil event is
745  *      generated and invokes our bond_event() function.  bond_event()
746  *      needs to take the bond_lock(), but we're already holding it, so
747  *      we're deadlocked against ourselves.
748  * Notes:
749  *   Before calling, you must be holding the bond_lock and have taken
750  *   a reference on the ifbond_ref.
751  */
752 static void
ifbond_wait(ifbond_ref ifb,const char * msg)753 ifbond_wait(ifbond_ref ifb, const char * msg)
754 {
755 	int         waited = 0;
756 
757 	/* other add/remove in progress */
758 	while (ifbond_flags_change_in_progress(ifb)) {
759 		if (if_bond_debug) {
760 			printf("%s: %s msleep\n", ifb->ifb_name, msg);
761 		}
762 		waited = 1;
763 		(void)msleep(ifb, &bond_lck_mtx, PZERO, msg, 0);
764 	}
765 	/* prevent other bond list remove/add from taking place */
766 	ifbond_flags_set_change_in_progress(ifb);
767 	if (if_bond_debug && waited) {
768 		printf("%s: %s woke up\n", ifb->ifb_name, msg);
769 	}
770 	return;
771 }
772 
773 /*
774  * Function: ifbond_signal
775  * Purpose:
776  *   Allows the thread that previously invoked ifbond_wait() to
777  *   give up exclusive access to the ifbond data structure, and wake up
778  *   any other threads waiting to access
779  * Notes:
780  *   Before calling, you must be holding the bond_lock and have taken
781  *   a reference on the ifbond_ref.
782  */
783 static void
ifbond_signal(ifbond_ref ifb,const char * msg)784 ifbond_signal(ifbond_ref ifb, const char * msg)
785 {
786 	ifbond_flags_clear_change_in_progress(ifb);
787 	wakeup((caddr_t)ifb);
788 	if (if_bond_debug) {
789 		printf("%s: %s wakeup\n", ifb->ifb_name, msg);
790 	}
791 	return;
792 }
793 
794 /**
795 ** Media information
796 **/
797 
798 static int
link_speed(int active)799 link_speed(int active)
800 {
801 	switch (IFM_SUBTYPE(active)) {
802 	case IFM_AUTO:
803 	case IFM_MANUAL:
804 	case IFM_NONE:
805 		return 0;
806 	case IFM_10_T:
807 	case IFM_10_2:
808 	case IFM_10_5:
809 	case IFM_10_STP:
810 	case IFM_10_FL:
811 		return 10;
812 	case IFM_100_TX:
813 	case IFM_100_FX:
814 	case IFM_100_T4:
815 	case IFM_100_VG:
816 	case IFM_100_T2:
817 		return 100;
818 	case IFM_1000_SX:
819 	case IFM_1000_LX:
820 	case IFM_1000_CX:
821 	case IFM_1000_TX:
822 	case IFM_1000_CX_SGMII:
823 	case IFM_1000_KX:
824 		return 1000;
825 	case IFM_HPNA_1:
826 		return 1;
827 	default:
828 	/* assume that new defined types are going to be at least 10GigE */
829 	case IFM_10G_SR:
830 	case IFM_10G_LR:
831 	case IFM_10G_KX4:
832 	case IFM_10G_KR:
833 	case IFM_10G_CR1:
834 	case IFM_10G_ER:
835 		return 10000;
836 	case IFM_2500_T:
837 		return 2500;
838 	case IFM_5000_T:
839 		return 5000;
840 	case IFM_20G_KR2:
841 		return 20000;
842 	case IFM_25G_CR:
843 	case IFM_25G_KR:
844 	case IFM_25G_SR:
845 	case IFM_25G_LR:
846 		return 25000;
847 	case IFM_40G_CR4:
848 	case IFM_40G_SR4:
849 	case IFM_40G_LR4:
850 	case IFM_40G_KR4:
851 		return 40000;
852 	case IFM_50G_CR2:
853 	case IFM_50G_KR2:
854 	case IFM_50G_SR2:
855 	case IFM_50G_LR2:
856 		return 50000;
857 	case IFM_56G_R4:
858 		return 56000;
859 	case IFM_100G_CR4:
860 	case IFM_100G_SR4:
861 	case IFM_100G_KR4:
862 	case IFM_100G_LR4:
863 		return 100000;
864 	}
865 }
866 
867 static __inline__ int
media_active(const struct media_info * mi)868 media_active(const struct media_info * mi)
869 {
870 	if ((mi->mi_status & IFM_AVALID) == 0) {
871 		return 1;
872 	}
873 	return (mi->mi_status & IFM_ACTIVE) != 0;
874 }
875 
876 static __inline__ int
media_full_duplex(const struct media_info * mi)877 media_full_duplex(const struct media_info * mi)
878 {
879 	return (mi->mi_active & IFM_FDX) != 0;
880 }
881 
882 static __inline__ int
media_type_unknown(const struct media_info * mi)883 media_type_unknown(const struct media_info * mi)
884 {
885 	int unknown;
886 
887 	switch (IFM_SUBTYPE(mi->mi_active)) {
888 	case IFM_AUTO:
889 	case IFM_MANUAL:
890 	case IFM_NONE:
891 		unknown = 1;
892 		break;
893 	default:
894 		unknown = 0;
895 		break;
896 	}
897 	return unknown;
898 }
899 
900 static __inline__ int
media_ok(const struct media_info * mi)901 media_ok(const struct media_info * mi)
902 {
903 	return media_full_duplex(mi) || media_type_unknown(mi);
904 }
905 
906 static __inline__ int
media_speed(const struct media_info * mi)907 media_speed(const struct media_info * mi)
908 {
909 	return link_speed(mi->mi_active);
910 }
911 
912 static struct media_info
interface_media_info(struct ifnet * ifp)913 interface_media_info(struct ifnet * ifp)
914 {
915 	struct ifmediareq   ifmr;
916 	struct media_info   mi;
917 
918 	bzero(&mi, sizeof(mi));
919 	bzero(&ifmr, sizeof(ifmr));
920 	if (ifnet_ioctl(ifp, 0, SIOCGIFMEDIA, &ifmr) == 0) {
921 		if (ifmr.ifm_count != 0) {
922 			mi.mi_status = ifmr.ifm_status;
923 			mi.mi_active = ifmr.ifm_active;
924 		}
925 	}
926 	return mi;
927 }
928 
929 static int
if_siflladdr(struct ifnet * ifp,const struct ether_addr * ea_p)930 if_siflladdr(struct ifnet * ifp, const struct ether_addr * ea_p)
931 {
932 	struct ifreq        ifr;
933 
934 	/*
935 	 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
936 	 * currently expects it that way
937 	 */
938 	ifr.ifr_addr.sa_family = AF_UNSPEC;
939 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
940 	ether_addr_copy(ifr.ifr_addr.sa_data, ea_p);
941 	return ifnet_ioctl(ifp, 0, SIOCSIFLLADDR, &ifr);
942 }
943 
944 /**
945 ** bond_globals
946 **/
947 static bond_globals_ref
bond_globals_create(lacp_system_priority sys_pri,lacp_system_ref sys)948 bond_globals_create(lacp_system_priority sys_pri,
949     lacp_system_ref sys)
950 {
951 	bond_globals_ref    b;
952 
953 	b = kalloc_type(struct bond_globals_s, Z_WAITOK | Z_ZERO | Z_NOFAIL);
954 	TAILQ_INIT(&b->ifbond_list);
955 	b->system = *sys;
956 	b->system_priority = sys_pri;
957 	return b;
958 }
959 
960 static int
bond_globals_init(void)961 bond_globals_init(void)
962 {
963 	bond_globals_ref    b;
964 	int                 i;
965 	struct ifnet *      ifp;
966 
967 	bond_assert_lock_not_held();
968 
969 	if (g_bond != NULL) {
970 		return 0;
971 	}
972 
973 	/*
974 	 * use en0's ethernet address as the system identifier, and if it's not
975 	 * there, use en1 .. en3
976 	 */
977 	ifp = NULL;
978 	for (i = 0; i < 4; i++) {
979 		char            ifname[IFNAMSIZ + 1];
980 		snprintf(ifname, sizeof(ifname), "en%d", i);
981 		ifp = ifunit(ifname);
982 		if (ifp != NULL) {
983 			break;
984 		}
985 	}
986 	b = NULL;
987 	if (ifp != NULL) {
988 		b = bond_globals_create(0x8000, (lacp_system_ref)IF_LLADDR(ifp));
989 	}
990 	bond_lock();
991 	if (g_bond != NULL) {
992 		bond_unlock();
993 		kfree_type(struct bond_globals_s, b);
994 		return 0;
995 	}
996 	g_bond = b;
997 	bond_unlock();
998 	if (ifp == NULL) {
999 		return ENXIO;
1000 	}
1001 	if (b == NULL) {
1002 		return ENOMEM;
1003 	}
1004 	return 0;
1005 }
1006 
1007 static void
bond_bpf_vlan(struct ifnet * ifp,struct mbuf * m,const struct ether_header * eh_p,u_int16_t vlan_tag,bpf_packet_func func)1008 bond_bpf_vlan(struct ifnet * ifp, struct mbuf * m,
1009     const struct ether_header * eh_p,
1010     u_int16_t vlan_tag, bpf_packet_func func)
1011 {
1012 	struct ether_vlan_header *  vlh_p;
1013 	struct mbuf *               vl_m;
1014 
1015 	vl_m = m_get(M_DONTWAIT, MT_DATA);
1016 	if (vl_m == NULL) {
1017 		return;
1018 	}
1019 	/* populate a new mbuf containing the vlan ethernet header */
1020 	vl_m->m_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1021 	vlh_p = mtod(vl_m, struct ether_vlan_header *);
1022 	bcopy(eh_p, vlh_p, offsetof(struct ether_header, ether_type));
1023 	vlh_p->evl_encap_proto = htons(ETHERTYPE_VLAN);
1024 	vlh_p->evl_tag = htons(vlan_tag);
1025 	vlh_p->evl_proto = eh_p->ether_type;
1026 	vl_m->m_next = m;
1027 	(*func)(ifp, vl_m);
1028 	vl_m->m_next = NULL;
1029 	m_free(vl_m);
1030 	return;
1031 }
1032 
1033 static __inline__ void
bond_bpf_output(struct ifnet * ifp,struct mbuf * m,bpf_packet_func func)1034 bond_bpf_output(struct ifnet * ifp, struct mbuf * m,
1035     bpf_packet_func func)
1036 {
1037 	if (func != NULL) {
1038 		if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1039 			const struct ether_header * eh_p;
1040 			eh_p = mtod(m, const struct ether_header *);
1041 			m->m_data += ETHER_HDR_LEN;
1042 			m->m_len -= ETHER_HDR_LEN;
1043 			bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
1044 			m->m_data -= ETHER_HDR_LEN;
1045 			m->m_len += ETHER_HDR_LEN;
1046 		} else {
1047 			(*func)(ifp, m);
1048 		}
1049 	}
1050 	return;
1051 }
1052 
1053 static __inline__ void
bond_bpf_input(ifnet_t ifp,mbuf_t m,const struct ether_header * eh_p,bpf_packet_func func)1054 bond_bpf_input(ifnet_t ifp, mbuf_t m, const struct ether_header * eh_p,
1055     bpf_packet_func func)
1056 {
1057 	if (func != NULL) {
1058 		if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1059 			bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
1060 		} else {
1061 			/* restore the header */
1062 			m->m_data -= ETHER_HDR_LEN;
1063 			m->m_len += ETHER_HDR_LEN;
1064 			(*func)(ifp, m);
1065 			m->m_data += ETHER_HDR_LEN;
1066 			m->m_len -= ETHER_HDR_LEN;
1067 		}
1068 	}
1069 	return;
1070 }
1071 
1072 /*
1073  * Function: bond_setmulti
1074  * Purpose:
1075  *   Enable multicast reception on "our" interface by enabling multicasts on
1076  *   each of the member ports.
1077  */
1078 static int
bond_setmulti(struct ifnet * ifp)1079 bond_setmulti(struct ifnet * ifp)
1080 {
1081 	ifbond_ref          ifb;
1082 	int                 error;
1083 	int                 result = 0;
1084 	bondport_ref        p;
1085 
1086 	bond_lock();
1087 	ifb = ifnet_softc(ifp);
1088 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1089 	    || TAILQ_EMPTY(&ifb->ifb_port_list)) {
1090 		bond_unlock();
1091 		return 0;
1092 	}
1093 	ifbond_retain(ifb);
1094 	ifbond_wait(ifb, "bond_setmulti");
1095 
1096 	if (ifbond_flags_if_detaching(ifb)) {
1097 		/* someone destroyed the bond while we were waiting */
1098 		result = EBUSY;
1099 		goto signal_done;
1100 	}
1101 	bond_unlock();
1102 
1103 	/* ifbond_wait() let's us safely walk the list without holding the lock */
1104 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1105 		struct ifnet *  port_ifp = p->po_ifp;
1106 
1107 		error = multicast_list_program(&p->po_multicast,
1108 		    ifp, port_ifp);
1109 		if (error != 0) {
1110 			printf("bond_setmulti(%s): "
1111 			    "multicast_list_program(%s%d) failed, %d\n",
1112 			    ifb->ifb_name, ifnet_name(port_ifp),
1113 			    ifnet_unit(port_ifp), error);
1114 			result = error;
1115 		}
1116 	}
1117 	bond_lock();
1118 signal_done:
1119 	ifbond_signal(ifb, __func__);
1120 	bond_unlock();
1121 	ifbond_release(ifb);
1122 	return result;
1123 }
1124 
1125 static int
bond_clone_attach(void)1126 bond_clone_attach(void)
1127 {
1128 	int error;
1129 
1130 	if ((error = if_clone_attach(&bond_cloner)) != 0) {
1131 		return error;
1132 	}
1133 	return 0;
1134 }
1135 
1136 static int
ifbond_add_slow_proto_multicast(ifbond_ref ifb)1137 ifbond_add_slow_proto_multicast(ifbond_ref ifb)
1138 {
1139 	int                         error;
1140 	struct ifmultiaddr *        ifma = NULL;
1141 	struct sockaddr_dl          sdl;
1142 
1143 	bond_assert_lock_not_held();
1144 
1145 	SOCKADDR_ZERO(&sdl, sizeof(sdl));
1146 	sdl.sdl_len = sizeof(sdl);
1147 	sdl.sdl_family = AF_LINK;
1148 	sdl.sdl_type = IFT_ETHER;
1149 	sdl.sdl_nlen = 0;
1150 	sdl.sdl_alen = sizeof(slow_proto_multicast);
1151 	bcopy(&slow_proto_multicast, sdl.sdl_data, sizeof(slow_proto_multicast));
1152 	error = if_addmulti_anon(ifb->ifb_ifp, SA(&sdl), &ifma);
1153 	if (error == 0) {
1154 		ifb->ifb_ifma_slow_proto = ifma;
1155 	}
1156 	return error;
1157 }
1158 
1159 static int
bond_clone_create(struct if_clone * ifc,u_int32_t unit,__unused void * params)1160 bond_clone_create(struct if_clone * ifc, u_int32_t unit, __unused void *params)
1161 {
1162 	int                                             error;
1163 	ifbond_ref                                      ifb;
1164 	ifnet_t                                         ifp;
1165 	struct ifnet_init_eparams       bond_init;
1166 
1167 	error = bond_globals_init();
1168 	if (error != 0) {
1169 		return error;
1170 	}
1171 
1172 	ifb = kalloc_type(struct ifbond_s, Z_WAITOK_ZERO_NOFAIL);
1173 	os_ref_init(&ifb->ifb_retain_count, NULL);
1174 	TAILQ_INIT(&ifb->ifb_port_list);
1175 	TAILQ_INIT(&ifb->ifb_lag_list);
1176 	ifb->ifb_key = unit + 1;
1177 
1178 	/* use the interface name as the unique id for ifp recycle */
1179 	if ((u_int32_t)snprintf(ifb->ifb_name, sizeof(ifb->ifb_name), "%s%d",
1180 	    ifc->ifc_name, unit) >= sizeof(ifb->ifb_name)) {
1181 		ifbond_release(ifb);
1182 		return EINVAL;
1183 	}
1184 
1185 	bzero(&bond_init, sizeof(bond_init));
1186 	bond_init.ver = IFNET_INIT_CURRENT_VERSION;
1187 	bond_init.len = sizeof(bond_init);
1188 	bond_init.flags = IFNET_INIT_LEGACY;
1189 	bond_init.uniqueid = ifb->ifb_name;
1190 	bond_init.uniqueid_len = strlen(ifb->ifb_name);
1191 	bond_init.name = ifc->ifc_name;
1192 	bond_init.unit = unit;
1193 	bond_init.family = IFNET_FAMILY_BOND;
1194 	bond_init.type = IFT_IEEE8023ADLAG;
1195 	bond_init.output = bond_output;
1196 	bond_init.demux = ether_demux;
1197 	bond_init.add_proto = ether_add_proto;
1198 	bond_init.del_proto = ether_del_proto;
1199 	bond_init.check_multi = ether_check_multi;
1200 	bond_init.framer_extended = ether_frameout_extended;
1201 	bond_init.ioctl = bond_ioctl;
1202 	bond_init.set_bpf_tap = bond_set_bpf_tap;
1203 	bond_init.detach = bond_if_free;
1204 	bond_init.broadcast_addr = etherbroadcastaddr;
1205 	bond_init.broadcast_len = ETHER_ADDR_LEN;
1206 	bond_init.softc = ifb;
1207 	error = ifnet_allocate_extended(&bond_init, &ifp);
1208 
1209 	if (error) {
1210 		ifbond_release(ifb);
1211 		return error;
1212 	}
1213 
1214 	ifb->ifb_ifp = ifp;
1215 	ifnet_set_offload(ifp, 0);
1216 	ifnet_set_addrlen(ifp, ETHER_ADDR_LEN); /* XXX ethernet specific */
1217 	ifnet_set_flags(ifp, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX, 0xffff);
1218 	ifnet_set_mtu(ifp, ETHERMTU);
1219 
1220 	error = ifnet_attach(ifp, NULL);
1221 	if (error != 0) {
1222 		ifnet_release(ifp);
1223 		ifbond_release(ifb);
1224 		return error;
1225 	}
1226 	error = ifbond_add_slow_proto_multicast(ifb);
1227 	if (error != 0) {
1228 		printf("bond_clone_create(%s): "
1229 		    "failed to add slow_proto multicast, %d\n",
1230 		    ifb->ifb_name, error);
1231 	}
1232 
1233 	/* attach as ethernet */
1234 	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
1235 
1236 	bond_lock();
1237 	TAILQ_INSERT_HEAD(&g_bond->ifbond_list, ifb, ifb_bond_list);
1238 	bond_unlock();
1239 
1240 	return 0;
1241 }
1242 
1243 static void
bond_remove_all_interfaces(ifbond_ref ifb)1244 bond_remove_all_interfaces(ifbond_ref ifb)
1245 {
1246 	bondport_ref        p;
1247 
1248 	bond_assert_lock_held();
1249 
1250 	/*
1251 	 * do this in reverse order to avoid re-programming the mac address
1252 	 * as each head interface is removed
1253 	 */
1254 	while ((p = TAILQ_LAST(&ifb->ifb_port_list, port_list)) != NULL) {
1255 		bond_remove_interface(ifb, p->po_ifp);
1256 	}
1257 	return;
1258 }
1259 
1260 static void
bond_remove(ifbond_ref ifb)1261 bond_remove(ifbond_ref ifb)
1262 {
1263 	bond_assert_lock_held();
1264 	ifbond_flags_set_if_detaching(ifb);
1265 	TAILQ_REMOVE(&g_bond->ifbond_list, ifb, ifb_bond_list);
1266 	bond_remove_all_interfaces(ifb);
1267 	return;
1268 }
1269 
1270 static void
bond_if_detach(struct ifnet * ifp)1271 bond_if_detach(struct ifnet * ifp)
1272 {
1273 	int         error;
1274 
1275 	error = ifnet_detach(ifp);
1276 	if (error) {
1277 		printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1278 		    ifnet_name(ifp), ifnet_unit(ifp), error);
1279 	}
1280 
1281 	return;
1282 }
1283 
1284 static int
bond_clone_destroy(struct ifnet * ifp)1285 bond_clone_destroy(struct ifnet * ifp)
1286 {
1287 	ifbond_ref ifb;
1288 
1289 	bond_lock();
1290 	ifb = ifnet_softc(ifp);
1291 	if (ifb == NULL || ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
1292 		bond_unlock();
1293 		return 0;
1294 	}
1295 	if (ifbond_flags_if_detaching(ifb)) {
1296 		bond_unlock();
1297 		return 0;
1298 	}
1299 	bond_remove(ifb);
1300 	bond_unlock();
1301 	bond_if_detach(ifp);
1302 	return 0;
1303 }
1304 
1305 static int
bond_set_bpf_tap(struct ifnet * ifp,bpf_tap_mode mode,bpf_packet_func func)1306 bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode, bpf_packet_func func)
1307 {
1308 	ifbond_ref  ifb;
1309 
1310 	bond_lock();
1311 	ifb = ifnet_softc(ifp);
1312 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
1313 		bond_unlock();
1314 		return ENODEV;
1315 	}
1316 	switch (mode) {
1317 	case BPF_TAP_DISABLE:
1318 		ifb->ifb_bpf_input = ifb->ifb_bpf_output = NULL;
1319 		break;
1320 
1321 	case BPF_TAP_INPUT:
1322 		ifb->ifb_bpf_input = func;
1323 		break;
1324 
1325 	case BPF_TAP_OUTPUT:
1326 		ifb->ifb_bpf_output = func;
1327 		break;
1328 
1329 	case BPF_TAP_INPUT_OUTPUT:
1330 		ifb->ifb_bpf_input = ifb->ifb_bpf_output = func;
1331 		break;
1332 	default:
1333 		break;
1334 	}
1335 	bond_unlock();
1336 	return 0;
1337 }
1338 
1339 static uint32_t
ether_header_hash(struct ether_header * eh_p)1340 ether_header_hash(struct ether_header * eh_p)
1341 {
1342 	uint32_t    h;
1343 
1344 	/* get 32-bits from destination ether and ether type */
1345 	h = (*((uint16_t *)&eh_p->ether_dhost[4]) << 16)
1346 	    | eh_p->ether_type;
1347 	h ^= *((uint32_t *)&eh_p->ether_dhost[0]);
1348 	return h;
1349 }
1350 
1351 static struct mbuf *
S_mbuf_skip_to_offset(struct mbuf * m,int32_t * offset)1352 S_mbuf_skip_to_offset(struct mbuf * m, int32_t * offset)
1353 {
1354 	int                 len;
1355 
1356 	len = m->m_len;
1357 	while (*offset >= len) {
1358 		*offset -= len;
1359 		m = m->m_next;
1360 		if (m == NULL) {
1361 			break;
1362 		}
1363 		len = m->m_len;
1364 	}
1365 	return m;
1366 }
1367 
1368 #if BYTE_ORDER == BIG_ENDIAN
1369 static __inline__ uint32_t
make_uint32(u_char c0,u_char c1,u_char c2,u_char c3)1370 make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1371 {
1372 	return ((uint32_t)c0 << 24) | ((uint32_t)c1 << 16)
1373 	       | ((uint32_t)c2 << 8) | (uint32_t)c3;
1374 }
1375 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1376 static __inline__ uint32_t
make_uint32(u_char c0,u_char c1,u_char c2,u_char c3)1377 make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1378 {
1379 	return ((uint32_t)c3 << 24) | ((uint32_t)c2 << 16)
1380 	       | ((uint32_t)c1 << 8) | (uint32_t)c0;
1381 }
1382 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1383 
1384 static int
S_mbuf_copy_uint32(struct mbuf * m,int32_t offset,uint32_t * val)1385 S_mbuf_copy_uint32(struct mbuf * m, int32_t offset, uint32_t * val)
1386 {
1387 	struct mbuf *       current;
1388 	u_char *            current_data;
1389 	struct mbuf *       next;
1390 	u_char *            next_data;
1391 	int                 space_current;
1392 
1393 	current = S_mbuf_skip_to_offset(m, &offset);
1394 	if (current == NULL) {
1395 		return 1;
1396 	}
1397 	current_data = mtod(current, u_char *) + offset;
1398 	space_current = current->m_len - offset;
1399 	if (space_current >= (int)sizeof(uint32_t)) {
1400 		*val = *((uint32_t *)current_data);
1401 		return 0;
1402 	}
1403 	next = current->m_next;
1404 	if (next == NULL || (next->m_len + space_current) < (int)sizeof(uint32_t)) {
1405 		return 1;
1406 	}
1407 	next_data = mtod(next, u_char *);
1408 	switch (space_current) {
1409 	case 1:
1410 		*val = make_uint32(current_data[0], next_data[0],
1411 		    next_data[1], next_data[2]);
1412 		break;
1413 	case 2:
1414 		*val = make_uint32(current_data[0], current_data[1],
1415 		    next_data[0], next_data[1]);
1416 		break;
1417 	default:
1418 		*val = make_uint32(current_data[0], current_data[1],
1419 		    current_data[2], next_data[0]);
1420 		break;
1421 	}
1422 	return 0;
1423 }
1424 
1425 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1426 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1427 
1428 static uint32_t
ip_header_hash(struct mbuf * m)1429 ip_header_hash(struct mbuf * m)
1430 {
1431 	u_char *            data;
1432 	struct in_addr      ip_dst;
1433 	struct in_addr      ip_src;
1434 	u_char              ip_p;
1435 	int32_t             offset;
1436 	struct mbuf *       orig_m = m;
1437 
1438 	/* find the IP protocol field relative to the start of the packet */
1439 	offset = offsetof(struct ip, ip_p) + sizeof(struct ether_header);
1440 	m = S_mbuf_skip_to_offset(m, &offset);
1441 	if (m == NULL || m->m_len < 1) {
1442 		goto bad_ip_packet;
1443 	}
1444 	data = mtod(m, u_char *) + offset;
1445 	ip_p = *data;
1446 
1447 	/* find the IP src relative to the IP protocol */
1448 	if ((m->m_len - offset)
1449 	    >= (int)(IP_SRC_OFFSET + sizeof(struct in_addr) * 2)) {
1450 		/* this should be the normal case */
1451 		ip_src = *(struct in_addr *)(data + IP_SRC_OFFSET);
1452 		ip_dst = *(struct in_addr *)(data + IP_DST_OFFSET);
1453 	} else {
1454 		if (S_mbuf_copy_uint32(m, offset + IP_SRC_OFFSET,
1455 		    (uint32_t *)&ip_src.s_addr)) {
1456 			goto bad_ip_packet;
1457 		}
1458 		if (S_mbuf_copy_uint32(m, offset + IP_DST_OFFSET,
1459 		    (uint32_t *)&ip_dst.s_addr)) {
1460 			goto bad_ip_packet;
1461 		}
1462 	}
1463 	return ntohl(ip_dst.s_addr) ^ ntohl(ip_src.s_addr) ^ ((uint32_t)ip_p);
1464 
1465 bad_ip_packet:
1466 	return ether_header_hash(mtod(orig_m, struct ether_header *));
1467 }
1468 
1469 #define IP6_ADDRS_LEN   (sizeof(struct in6_addr) * 2)
1470 static uint32_t
ipv6_header_hash(struct mbuf * m)1471 ipv6_header_hash(struct mbuf * m)
1472 {
1473 	u_char *            data;
1474 	int                 i;
1475 	int32_t             offset;
1476 	struct mbuf *       orig_m = m;
1477 	uint32_t *          scan;
1478 	uint32_t            val;
1479 
1480 	/* find the IP protocol field relative to the start of the packet */
1481 	offset = offsetof(struct ip6_hdr, ip6_src) + sizeof(struct ether_header);
1482 	m = S_mbuf_skip_to_offset(m, &offset);
1483 	if (m == NULL) {
1484 		goto bad_ipv6_packet;
1485 	}
1486 	data = mtod(m, u_char *) + offset;
1487 	val = 0;
1488 	if ((m->m_len - offset) >= (int)IP6_ADDRS_LEN) {
1489 		/* this should be the normal case */
1490 		for (i = 0, scan = (uint32_t *)data;
1491 		    i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t));
1492 		    i++, scan++) {
1493 			val ^= *scan;
1494 		}
1495 	} else {
1496 		for (i = 0; i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t)); i++) {
1497 			uint32_t    tmp;
1498 			if (S_mbuf_copy_uint32(m, offset + i * sizeof(uint32_t),
1499 			    (uint32_t *)&tmp)) {
1500 				goto bad_ipv6_packet;
1501 			}
1502 			val ^= tmp;
1503 		}
1504 	}
1505 	return ntohl(val);
1506 
1507 bad_ipv6_packet:
1508 	return ether_header_hash(mtod(orig_m, struct ether_header *));
1509 }
1510 
1511 static int
bond_output(struct ifnet * ifp,struct mbuf * m)1512 bond_output(struct ifnet * ifp, struct mbuf * m)
1513 {
1514 	bpf_packet_func             bpf_func;
1515 	uint32_t                    h;
1516 	ifbond_ref                  ifb;
1517 	struct ifnet *              port_ifp = NULL;
1518 	int                         err;
1519 	struct flowadv              adv = { .code = FADV_SUCCESS };
1520 
1521 	if (m == 0) {
1522 		return 0;
1523 	}
1524 	if ((m->m_flags & M_PKTHDR) == 0) {
1525 		m_freem(m);
1526 		return 0;
1527 	}
1528 	if (m->m_pkthdr.pkt_flowid != 0) {
1529 		h = m->m_pkthdr.pkt_flowid;
1530 	} else {
1531 		struct ether_header *   eh_p;
1532 
1533 		eh_p = mtod(m, struct ether_header *);
1534 		switch (ntohs(eh_p->ether_type)) {
1535 		case ETHERTYPE_IP:
1536 			h = ip_header_hash(m);
1537 			break;
1538 		case ETHERTYPE_IPV6:
1539 			h = ipv6_header_hash(m);
1540 			break;
1541 		default:
1542 			h = ether_header_hash(eh_p);
1543 			break;
1544 		}
1545 	}
1546 	bond_lock();
1547 	ifb = ifnet_softc(ifp);
1548 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1549 	    || ifb->ifb_distributing_count == 0) {
1550 		goto done;
1551 	}
1552 	h %= ifb->ifb_distributing_count;
1553 	port_ifp = ifb->ifb_distributing_array[h]->po_ifp;
1554 	bpf_func = ifb->ifb_bpf_output;
1555 	bond_unlock();
1556 
1557 	if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1558 		(void)ifnet_stat_increment_out(ifp, 1,
1559 		    m->m_pkthdr.len + ETHER_VLAN_ENCAP_LEN,
1560 		    0);
1561 	} else {
1562 		(void)ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
1563 	}
1564 	bond_bpf_output(ifp, m, bpf_func);
1565 
1566 	err = dlil_output(port_ifp, PF_BOND, m, NULL, NULL, 1, &adv);
1567 
1568 	if (err == 0) {
1569 		if (adv.code == FADV_FLOW_CONTROLLED) {
1570 			err = EQFULL;
1571 		} else if (adv.code == FADV_SUSPENDED) {
1572 			err = EQSUSPENDED;
1573 		}
1574 	}
1575 
1576 	return err;
1577 
1578 done:
1579 	bond_unlock();
1580 	m_freem(m);
1581 	return 0;
1582 }
1583 
1584 static bondport_ref
ifbond_lookup_port(ifbond_ref ifb,struct ifnet * port_ifp)1585 ifbond_lookup_port(ifbond_ref ifb, struct ifnet * port_ifp)
1586 {
1587 	bondport_ref        p;
1588 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1589 		if (p->po_ifp == port_ifp) {
1590 			return p;
1591 		}
1592 	}
1593 	return NULL;
1594 }
1595 
1596 static bondport_ref
bond_lookup_port(struct ifnet * port_ifp)1597 bond_lookup_port(struct ifnet * port_ifp)
1598 {
1599 	ifbond_ref          ifb;
1600 	bondport_ref        port;
1601 
1602 	TAILQ_FOREACH(ifb, &g_bond->ifbond_list, ifb_bond_list) {
1603 		port = ifbond_lookup_port(ifb, port_ifp);
1604 		if (port != NULL) {
1605 			return port;
1606 		}
1607 	}
1608 	return NULL;
1609 }
1610 
1611 static void
bond_receive_lacpdu(struct mbuf * m,struct ifnet * port_ifp)1612 bond_receive_lacpdu(struct mbuf * m, struct ifnet * port_ifp)
1613 {
1614 	struct ifnet *              bond_ifp = NULL;
1615 	ifbond_ref                  ifb;
1616 	int                         event_code = 0;
1617 	bool                        need_link_update = false;
1618 	bondport_ref                p;
1619 
1620 	bond_lock();
1621 	if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1622 		goto done;
1623 	}
1624 	p = bond_lookup_port(port_ifp);
1625 	if (p == NULL) {
1626 		goto done;
1627 	}
1628 	if (p->po_enabled == 0) {
1629 		goto done;
1630 	}
1631 	ifb = p->po_bond;
1632 	if (ifb->ifb_mode != IF_BOND_MODE_LACP) {
1633 		goto done;
1634 	}
1635 	/*
1636 	 * Work-around for rdar://problem/51372042
1637 	 * Sometimes, the link comes up but the driver doesn't report the
1638 	 * negotiated medium at that time. When we receive an LACPDU packet,
1639 	 * and the medium is unknown, force a link status check. Don't force
1640 	 * the link status check more often than _FORCE_LINK_EVENT_INTERVAL
1641 	 * seconds.
1642 	 */
1643 #define _FORCE_LINK_EVENT_INTERVAL      1
1644 	if (media_type_unknown(&p->po_media_info)) {
1645 		uint64_t        now = net_uptime();
1646 
1647 		if ((now - p->po_force_link_event_time) >=
1648 		    _FORCE_LINK_EVENT_INTERVAL) {
1649 			need_link_update = true;
1650 			p->po_force_link_event_time = now;
1651 		}
1652 	}
1653 	bondport_receive_lacpdu(p, (lacpdu_ref)m_mtod_current(m));
1654 	if (ifbond_selection(ifb)) {
1655 		event_code = (ifb->ifb_active_lag == NULL)
1656 		    ? KEV_DL_LINK_OFF
1657 		    : KEV_DL_LINK_ON;
1658 		/* XXX need to take a reference on bond_ifp */
1659 		bond_ifp = ifb->ifb_ifp;
1660 		ifb->ifb_last_link_event = event_code;
1661 	} else {
1662 		event_code = (ifb->ifb_active_lag == NULL)
1663 		    ? KEV_DL_LINK_OFF
1664 		    : KEV_DL_LINK_ON;
1665 		if (event_code != ifb->ifb_last_link_event) {
1666 			if (if_bond_debug) {
1667 				timestamp_printf("%s: (receive) generating LINK event\n",
1668 				    ifb->ifb_name);
1669 			}
1670 			bond_ifp = ifb->ifb_ifp;
1671 			ifb->ifb_last_link_event = event_code;
1672 		}
1673 	}
1674 
1675 done:
1676 	bond_unlock();
1677 	if (bond_ifp != NULL) {
1678 		interface_link_event(bond_ifp, event_code);
1679 	}
1680 	m_freem(m);
1681 	if (need_link_update) {
1682 		if (if_bond_debug != 0) {
1683 			printf("bond: simulating link status changed event");
1684 		}
1685 		bond_handle_event(port_ifp, KEV_DL_LINK_ON);
1686 	}
1687 	return;
1688 }
1689 
1690 static void
bond_receive_la_marker_pdu(struct mbuf * m,struct ifnet * port_ifp)1691 bond_receive_la_marker_pdu(struct mbuf * m, struct ifnet * port_ifp)
1692 {
1693 	la_marker_pdu_ref           marker_p;
1694 	bondport_ref                p;
1695 
1696 	marker_p = (la_marker_pdu_ref)(m_mtod_current(m) + ETHER_HDR_LEN);
1697 	if (marker_p->lm_marker_tlv_type != LA_MARKER_TLV_TYPE_MARKER) {
1698 		goto failed;
1699 	}
1700 	bond_lock();
1701 	if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1702 		bond_unlock();
1703 		goto failed;
1704 	}
1705 	p = bond_lookup_port(port_ifp);
1706 	if (p == NULL || p->po_enabled == 0
1707 	    || p->po_bond->ifb_mode != IF_BOND_MODE_LACP) {
1708 		bond_unlock();
1709 		goto failed;
1710 	}
1711 	/* echo back the same packet as a marker response */
1712 	marker_p->lm_marker_tlv_type = LA_MARKER_TLV_TYPE_MARKER_RESPONSE;
1713 	bondport_slow_proto_transmit(p, (packet_buffer_ref)m);
1714 	bond_unlock();
1715 	return;
1716 
1717 failed:
1718 	m_freem(m);
1719 	return;
1720 }
1721 
1722 static void
bond_input(ifnet_t port_ifp,mbuf_t m,char * frame_header)1723 bond_input(ifnet_t port_ifp, mbuf_t m, char *frame_header)
1724 {
1725 	bpf_packet_func             bpf_func;
1726 	const struct ether_header * eh_p;
1727 	ifbond_ref                  ifb;
1728 	struct ifnet *              ifp;
1729 	bondport_ref                p;
1730 
1731 	eh_p = (const struct ether_header *)frame_header;
1732 	if ((m->m_flags & M_MCAST) != 0
1733 	    && bcmp(eh_p->ether_dhost, &slow_proto_multicast,
1734 	    sizeof(eh_p->ether_dhost)) == 0
1735 	    && ntohs(eh_p->ether_type) == IEEE8023AD_SLOW_PROTO_ETHERTYPE) {
1736 		u_char  subtype = *mtod(m, u_char *);
1737 
1738 		if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP) {
1739 			if (m->m_pkthdr.len < (int)offsetof(lacpdu, la_reserved)) {
1740 				m_freem(m);
1741 				return;
1742 			}
1743 			/* send to lacp */
1744 			if (m->m_len < (int)offsetof(lacpdu, la_reserved)) {
1745 				m = m_pullup(m, offsetof(lacpdu, la_reserved));
1746 				if (m == NULL) {
1747 					return;
1748 				}
1749 			}
1750 			bond_receive_lacpdu(m, port_ifp);
1751 			return;
1752 		} else if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL) {
1753 			int         min_size;
1754 
1755 			/* restore the ethernet header pointer in the mbuf */
1756 			m->m_pkthdr.len += ETHER_HDR_LEN;
1757 			m->m_data -= ETHER_HDR_LEN;
1758 			m->m_len += ETHER_HDR_LEN;
1759 			min_size = ETHER_HDR_LEN + offsetof(la_marker_pdu, lm_reserved);
1760 			if (m->m_pkthdr.len < min_size) {
1761 				m_freem(m);
1762 				return;
1763 			}
1764 			/* send to lacp */
1765 			if (m->m_len < min_size) {
1766 				m = m_pullup(m, min_size);
1767 				if (m == NULL) {
1768 					return;
1769 				}
1770 			}
1771 			/* send to marker responder */
1772 			bond_receive_la_marker_pdu(m, port_ifp);
1773 			return;
1774 		} else if (subtype == 0
1775 		    || subtype > IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END) {
1776 			/* invalid subtype, discard the frame */
1777 			m_freem(m);
1778 			return;
1779 		}
1780 	}
1781 	bond_lock();
1782 	if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1783 		goto done;
1784 	}
1785 	p = bond_lookup_port(port_ifp);
1786 	if (p == NULL || bondport_collecting(p) == 0) {
1787 		goto done;
1788 	}
1789 
1790 	ifb = p->po_bond;
1791 	ifp = ifb->ifb_ifp;
1792 	bpf_func = ifb->ifb_bpf_input;
1793 	bond_unlock();
1794 
1795 	/*
1796 	 * Need to clear the promiscous flags otherwise it will be
1797 	 * dropped by DLIL after processing filters
1798 	 */
1799 	if ((mbuf_flags(m) & MBUF_PROMISC)) {
1800 		mbuf_setflags_mask(m, 0, MBUF_PROMISC);
1801 	}
1802 
1803 	if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1804 		(void)ifnet_stat_increment_in(ifp, 1,
1805 		    (m->m_pkthdr.len + ETHER_HDR_LEN
1806 		    + ETHER_VLAN_ENCAP_LEN), 0);
1807 	} else {
1808 		(void)ifnet_stat_increment_in(ifp, 1,
1809 		    (m->m_pkthdr.len + ETHER_HDR_LEN), 0);
1810 	}
1811 
1812 	/* make the packet appear as if it arrived on the bonded interface */
1813 	m->m_pkthdr.rcvif = ifp;
1814 	bond_bpf_input(ifp, m, eh_p, bpf_func);
1815 	m->m_pkthdr.pkt_hdr = frame_header;
1816 	dlil_input_packet_list(ifp, m);
1817 	return;
1818 
1819 done:
1820 	bond_unlock();
1821 	m_freem(m);
1822 	return;
1823 }
1824 
1825 static errno_t
bond_iff_input(void * cookie,ifnet_t port_ifp,protocol_family_t protocol,mbuf_t * data,char ** frame_header_ptr)1826 bond_iff_input(void *cookie, ifnet_t port_ifp, protocol_family_t protocol,
1827     mbuf_t *data, char **frame_header_ptr)
1828 {
1829 #pragma unused(cookie)
1830 #pragma unused(protocol)
1831 	mbuf_t                      m = *data;
1832 	char *                      frame_header = *frame_header_ptr;
1833 
1834 	bond_input(port_ifp, m, frame_header);
1835 	return EJUSTRETURN;
1836 }
1837 
1838 static __inline__ const char *
bondport_get_name(bondport_ref p)1839 bondport_get_name(bondport_ref p)
1840 {
1841 	return p->po_name;
1842 }
1843 
1844 static __inline__ int
bondport_get_index(bondport_ref p)1845 bondport_get_index(bondport_ref p)
1846 {
1847 	return ifnet_index(p->po_ifp);
1848 }
1849 
1850 static void
bondport_slow_proto_transmit(bondport_ref p,packet_buffer_ref buf)1851 bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf)
1852 {
1853 	struct ether_header *       eh_p;
1854 	int                         error;
1855 
1856 	/* packet_buffer_allocate leaves room for ethernet header */
1857 	eh_p = mtod(buf, struct ether_header *);
1858 	bcopy(&slow_proto_multicast, &eh_p->ether_dhost, sizeof(eh_p->ether_dhost));
1859 	bcopy(&p->po_saved_addr, eh_p->ether_shost, sizeof(eh_p->ether_shost));
1860 	eh_p->ether_type = htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE);
1861 	error = ifnet_output_raw(p->po_ifp, PF_BOND, buf);
1862 	if (error != 0) {
1863 		printf("bondport_slow_proto_transmit(%s) failed %d\n",
1864 		    bondport_get_name(p), error);
1865 	}
1866 	return;
1867 }
1868 
1869 static void
bondport_timer_process_func(devtimer_ref timer,devtimer_process_func_event event)1870 bondport_timer_process_func(devtimer_ref timer,
1871     devtimer_process_func_event event)
1872 {
1873 	bondport_ref        p;
1874 
1875 	switch (event) {
1876 	case devtimer_process_func_event_lock:
1877 		bond_lock();
1878 		devtimer_retain(timer);
1879 		break;
1880 	case devtimer_process_func_event_unlock:
1881 		if (devtimer_valid(timer)) {
1882 			/* as long as the devtimer is valid, we can look at arg0 */
1883 			int                 event_code = 0;
1884 			struct ifnet *      bond_ifp = NULL;
1885 
1886 			p = (bondport_ref)devtimer_arg0(timer);
1887 			if (ifbond_selection(p->po_bond)) {
1888 				event_code = (p->po_bond->ifb_active_lag == NULL)
1889 				    ? KEV_DL_LINK_OFF
1890 				    : KEV_DL_LINK_ON;
1891 				/* XXX need to take a reference on bond_ifp */
1892 				bond_ifp = p->po_bond->ifb_ifp;
1893 				p->po_bond->ifb_last_link_event = event_code;
1894 			} else {
1895 				event_code = (p->po_bond->ifb_active_lag == NULL)
1896 				    ? KEV_DL_LINK_OFF
1897 				    : KEV_DL_LINK_ON;
1898 				if (event_code != p->po_bond->ifb_last_link_event) {
1899 					if (if_bond_debug) {
1900 						timestamp_printf("%s: (timer) generating LINK event\n",
1901 						    p->po_bond->ifb_name);
1902 					}
1903 					bond_ifp = p->po_bond->ifb_ifp;
1904 					p->po_bond->ifb_last_link_event = event_code;
1905 				}
1906 			}
1907 			devtimer_release(timer);
1908 			bond_unlock();
1909 			if (bond_ifp != NULL) {
1910 				interface_link_event(bond_ifp, event_code);
1911 			}
1912 		} else {
1913 			/* timer is going away */
1914 			devtimer_release(timer);
1915 			bond_unlock();
1916 		}
1917 		break;
1918 	default:
1919 		break;
1920 	}
1921 }
1922 
1923 static bondport_ref
bondport_create(struct ifnet * port_ifp,lacp_port_priority priority,int active,int short_timeout,int * ret_error)1924 bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
1925     int active, int short_timeout, int * ret_error)
1926 {
1927 	int                         error = 0;
1928 	bondport_ref                p = NULL;
1929 	lacp_actor_partner_state    s;
1930 
1931 	*ret_error = 0;
1932 	p = kalloc_type(struct bondport_s, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1933 	multicast_list_init(&p->po_multicast);
1934 	if ((u_int32_t)snprintf(p->po_name, sizeof(p->po_name), "%s%d",
1935 	    ifnet_name(port_ifp), ifnet_unit(port_ifp))
1936 	    >= sizeof(p->po_name)) {
1937 		printf("if_bond: name too large\n");
1938 		*ret_error = EINVAL;
1939 		goto failed;
1940 	}
1941 	error = siocgifdevmtu(port_ifp, &p->po_devmtu);
1942 	if (error != 0) {
1943 		printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1944 		    bondport_get_name(p), error);
1945 		goto failed;
1946 	}
1947 	/* remember the current interface MTU so it can be restored */
1948 	p->po_devmtu.ifdm_current = ifnet_mtu(port_ifp);
1949 	p->po_ifp = port_ifp;
1950 	p->po_media_info = interface_media_info(port_ifp);
1951 	p->po_current_while_timer = devtimer_create(bondport_timer_process_func, p);
1952 	if (p->po_current_while_timer == NULL) {
1953 		*ret_error = ENOMEM;
1954 		goto failed;
1955 	}
1956 	p->po_periodic_timer = devtimer_create(bondport_timer_process_func, p);
1957 	if (p->po_periodic_timer == NULL) {
1958 		*ret_error = ENOMEM;
1959 		goto failed;
1960 	}
1961 	p->po_wait_while_timer = devtimer_create(bondport_timer_process_func, p);
1962 	if (p->po_wait_while_timer == NULL) {
1963 		*ret_error = ENOMEM;
1964 		goto failed;
1965 	}
1966 	p->po_transmit_timer = devtimer_create(bondport_timer_process_func, p);
1967 	if (p->po_transmit_timer == NULL) {
1968 		*ret_error = ENOMEM;
1969 		goto failed;
1970 	}
1971 	p->po_receive_state = ReceiveState_none;
1972 	p->po_mux_state = MuxState_none;
1973 	p->po_priority = priority;
1974 	s = 0;
1975 	s = lacp_actor_partner_state_set_aggregatable(s);
1976 	if (short_timeout) {
1977 		s = lacp_actor_partner_state_set_short_timeout(s);
1978 	}
1979 	if (active) {
1980 		s = lacp_actor_partner_state_set_active_lacp(s);
1981 	}
1982 	p->po_actor_state = s;
1983 	return p;
1984 
1985 failed:
1986 	bondport_free(p);
1987 	return NULL;
1988 }
1989 
1990 static void
bondport_start(bondport_ref p)1991 bondport_start(bondport_ref p)
1992 {
1993 	bondport_receive_machine(p, LAEventStart, NULL);
1994 	bondport_mux_machine(p, LAEventStart, NULL);
1995 	bondport_periodic_transmit_machine(p, LAEventStart, NULL);
1996 	bondport_transmit_machine(p, LAEventStart, NULL);
1997 	return;
1998 }
1999 
2000 /*
2001  * Function: bondport_invalidate_timers
2002  * Purpose:
2003  *   Invalidate all of the timers for the bondport.
2004  */
2005 static void
bondport_invalidate_timers(bondport_ref p)2006 bondport_invalidate_timers(bondport_ref p)
2007 {
2008 	devtimer_invalidate(p->po_current_while_timer);
2009 	devtimer_invalidate(p->po_periodic_timer);
2010 	devtimer_invalidate(p->po_wait_while_timer);
2011 	devtimer_invalidate(p->po_transmit_timer);
2012 }
2013 
2014 /*
2015  * Function: bondport_cancel_timers
2016  * Purpose:
2017  *   Cancel all of the timers for the bondport.
2018  */
2019 static void
bondport_cancel_timers(bondport_ref p)2020 bondport_cancel_timers(bondport_ref p)
2021 {
2022 	devtimer_cancel(p->po_current_while_timer);
2023 	devtimer_cancel(p->po_periodic_timer);
2024 	devtimer_cancel(p->po_wait_while_timer);
2025 	devtimer_cancel(p->po_transmit_timer);
2026 }
2027 
2028 static void
bondport_free(bondport_ref p)2029 bondport_free(bondport_ref p)
2030 {
2031 	multicast_list_remove(&p->po_multicast);
2032 	devtimer_release(p->po_current_while_timer);
2033 	devtimer_release(p->po_periodic_timer);
2034 	devtimer_release(p->po_wait_while_timer);
2035 	devtimer_release(p->po_transmit_timer);
2036 	kfree_type(struct bondport_s, p);
2037 	return;
2038 }
2039 
2040 static __inline__ int
bond_device_mtu(struct ifnet * ifp,ifbond_ref ifb)2041 bond_device_mtu(struct ifnet * ifp, ifbond_ref ifb)
2042 {
2043 	return ((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
2044 	       ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu;
2045 }
2046 
2047 static int
bond_add_interface(struct ifnet * ifp,struct ifnet * port_ifp)2048 bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp)
2049 {
2050 	u_int32_t                   eflags;
2051 	uint32_t                    control_flags = 0;
2052 	int                         devmtu;
2053 	int                         error = 0;
2054 	int                         event_code = 0;
2055 	interface_filter_t          filter = NULL;
2056 	int                         first = FALSE;
2057 	ifbond_ref                  ifb;
2058 	bondport_ref *              new_array = NULL;
2059 	bondport_ref *              old_array = NULL;
2060 	bondport_ref                p;
2061 	int                         old_max = 0;
2062 	int                         new_max = 0;
2063 
2064 	if (IFNET_IS_INTCOPROC(port_ifp) || IFNET_IS_MANAGEMENT(port_ifp)) {
2065 		return EINVAL;
2066 	}
2067 
2068 	/* pre-allocate space for new port */
2069 	p = bondport_create(port_ifp, 0x8000, 1, 0, &error);
2070 	if (p == NULL) {
2071 		return error;
2072 	}
2073 	bond_lock();
2074 	ifb = (ifbond_ref)ifnet_softc(ifp);
2075 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2076 		bond_unlock();
2077 		bondport_free(p);
2078 		return ifb == NULL ? EOPNOTSUPP : EBUSY;
2079 	}
2080 
2081 	/* make sure this interface can handle our current MTU */
2082 	devmtu = bond_device_mtu(ifp, ifb);
2083 	if (devmtu != 0
2084 	    && (devmtu > p->po_devmtu.ifdm_max || devmtu < p->po_devmtu.ifdm_min)) {
2085 		bond_unlock();
2086 		printf("if_bond: interface %s doesn't support mtu %d",
2087 		    bondport_get_name(p), devmtu);
2088 		bondport_free(p);
2089 		return EINVAL;
2090 	}
2091 
2092 	/* make sure ifb doesn't get de-allocated while we wait */
2093 	ifbond_retain(ifb);
2094 
2095 	/* wait for other add or remove to complete */
2096 	ifbond_wait(ifb, __func__);
2097 
2098 	if (ifbond_flags_if_detaching(ifb)) {
2099 		/* someone destroyed the bond while we were waiting */
2100 		error = EBUSY;
2101 		goto signal_done;
2102 	}
2103 	if (bond_lookup_port(port_ifp) != NULL) {
2104 		/* port is already part of a bond */
2105 		error = EBUSY;
2106 		goto signal_done;
2107 	}
2108 	if ((ifnet_eflags(port_ifp) & (IFEF_VLAN | IFEF_BOND)) != 0) {
2109 		/* interface already has VLAN's, or is part of bond */
2110 		error = EBUSY;
2111 		goto signal_done;
2112 	}
2113 
2114 	/* mark the interface busy */
2115 	eflags = if_set_eflags(port_ifp, IFEF_BOND);
2116 	if ((eflags & IFEF_VLAN) != 0) {
2117 		/* vlan got in ahead of us */
2118 		if_clear_eflags(port_ifp, IFEF_BOND);
2119 		error = EBUSY;
2120 		goto signal_done;
2121 	}
2122 
2123 	if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2124 		ifnet_set_offload(ifp, ifnet_offload(port_ifp));
2125 		ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
2126 		if (ifbond_flags_lladdr(ifb) == FALSE) {
2127 			first = TRUE;
2128 		}
2129 	} else {
2130 		ifnet_offload_t         ifp_offload;
2131 		ifnet_offload_t         port_ifp_offload;
2132 
2133 		ifp_offload = ifnet_offload(ifp);
2134 		port_ifp_offload = ifnet_offload(port_ifp);
2135 		if (ifp_offload != port_ifp_offload) {
2136 			ifnet_offload_t     offload;
2137 
2138 			offload = ifp_offload & port_ifp_offload;
2139 			printf("%s(%s, %s)  "
2140 			    "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n",
2141 			    __func__,
2142 			    ifb->ifb_name, bondport_get_name(p),
2143 			    ifp_offload, port_ifp_offload, offload);
2144 			/*
2145 			 * XXX
2146 			 * if the bond has VLAN's, we can't simply change the hwassist
2147 			 * field behind its back: this needs work
2148 			 */
2149 			ifnet_set_offload(ifp, offload);
2150 		}
2151 	}
2152 	p->po_bond = ifb;
2153 
2154 	/* remember the port's ethernet address so it can be restored */
2155 	ether_addr_copy(&p->po_saved_addr, IF_LLADDR(port_ifp));
2156 
2157 	/* add it to the list of ports */
2158 	TAILQ_INSERT_TAIL(&ifb->ifb_port_list, p, po_port_list);
2159 	ifb->ifb_port_count++;
2160 
2161 	bond_unlock();
2162 
2163 
2164 	/* first port added to bond determines bond's ethernet address */
2165 	if (first) {
2166 		ifnet_set_lladdr_and_type(ifp, IF_LLADDR(port_ifp), ETHER_ADDR_LEN,
2167 		    IFT_ETHER);
2168 	}
2169 	uint32_bit_set(&control_flags, PORT_CONTROL_FLAGS_IN_LIST);
2170 
2171 	/* allocate a larger distributing array */
2172 	new_max = ifb->ifb_port_count;
2173 	new_array = kalloc_type(bondport_ref, new_max, Z_WAITOK);
2174 	if (new_array == NULL) {
2175 		error = ENOMEM;
2176 		goto failed;
2177 	}
2178 
2179 	/* attach our BOND "protocol" to the interface */
2180 	error = bond_attach_protocol(port_ifp);
2181 	if (error) {
2182 		goto failed;
2183 	}
2184 	uint32_bit_set(&control_flags, PORT_CONTROL_FLAGS_PROTO_ATTACHED);
2185 
2186 	/* attach our BOND interface filter */
2187 	error = bond_attach_filter(port_ifp, &filter);
2188 	if (error != 0) {
2189 		goto failed;
2190 	}
2191 	uint32_bit_set(&control_flags, PORT_CONTROL_FLAGS_FILTER_ATTACHED);
2192 
2193 	/* set the interface MTU */
2194 	devmtu = bond_device_mtu(ifp, ifb);
2195 	error = siocsifmtu(port_ifp, devmtu);
2196 	if (error != 0) {
2197 		printf("%s(%s, %s):"
2198 		    " SIOCSIFMTU %d failed %d\n",
2199 		    __func__,
2200 		    ifb->ifb_name, bondport_get_name(p), devmtu, error);
2201 		goto failed;
2202 	}
2203 	uint32_bit_set(&control_flags, PORT_CONTROL_FLAGS_MTU_SET);
2204 
2205 	/* program the port with our multicast addresses */
2206 	error = multicast_list_program(&p->po_multicast, ifp, port_ifp);
2207 	if (error) {
2208 		printf("%s(%s, %s): multicast_list_program failed %d\n",
2209 		    __func__,
2210 		    ifb->ifb_name, bondport_get_name(p), error);
2211 		goto failed;
2212 	}
2213 
2214 	/* mark the interface up */
2215 	ifnet_set_flags(port_ifp, IFF_UP, IFF_UP);
2216 
2217 	error = ifnet_ioctl(port_ifp, 0, SIOCSIFFLAGS, NULL);
2218 	if (error != 0) {
2219 		printf("%s(%s, %s): SIOCSIFFLAGS failed %d\n",
2220 		    __func__,
2221 		    ifb->ifb_name, bondport_get_name(p), error);
2222 		goto failed;
2223 	}
2224 
2225 	/* re-program the port's ethernet address */
2226 	error = if_siflladdr(port_ifp,
2227 	    (const struct ether_addr *)IF_LLADDR(ifp));
2228 	if (error == 0) {
2229 		if (memcmp(IF_LLADDR(ifp), IF_LLADDR(port_ifp), ETHER_ADDR_LEN)
2230 		    != 0) {
2231 			/* it lied, it really doesn't support setting lladdr */
2232 			error = EOPNOTSUPP;
2233 		}
2234 	}
2235 	if (error != 0) {
2236 		/* port doesn't support setting the link address */
2237 		printf("%s(%s, %s): if_siflladdr failed %d\n",
2238 		    __func__,
2239 		    ifb->ifb_name, bondport_get_name(p), error);
2240 		error = ifnet_set_promiscuous(port_ifp, 1);
2241 		if (error != 0) {
2242 			/* port doesn't support setting promiscuous mode */
2243 			printf("%s(%s, %s): set promiscuous failed %d\n",
2244 			    __func__,
2245 			    ifb->ifb_name, bondport_get_name(p), error);
2246 			goto failed;
2247 		}
2248 		uint32_bit_set(&control_flags,
2249 		    PORT_CONTROL_FLAGS_PROMISCUOUS_SET);
2250 	} else {
2251 		uint32_bit_set(&control_flags,
2252 		    PORT_CONTROL_FLAGS_LLADDR_SET);
2253 	}
2254 
2255 	/* if we're in promiscuous mode, enable that as well */
2256 	if (ifbond_flags_promisc(ifb)) {
2257 		error = ifnet_set_promiscuous(port_ifp, 1);
2258 		if (error != 0) {
2259 			/* port doesn't support setting promiscuous mode */
2260 			printf("%s(%s, %s): set promiscuous failed %d\n",
2261 			    __func__,
2262 			    ifb->ifb_name, bondport_get_name(p), error);
2263 			goto failed;
2264 		}
2265 		uint32_bit_set(&control_flags,
2266 		    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET);
2267 	}
2268 
2269 	bond_lock();
2270 
2271 	/* no failures past this point */
2272 	p->po_enabled = 1;
2273 	p->po_control_flags = control_flags;
2274 
2275 	/* copy the contents of the existing distributing array */
2276 	if (ifb->ifb_distributing_count) {
2277 		bcopy(ifb->ifb_distributing_array, new_array,
2278 		    sizeof(*new_array) * ifb->ifb_distributing_count);
2279 	}
2280 	old_array = ifb->ifb_distributing_array;
2281 	old_max = ifb->ifb_distributing_max;
2282 	ifb->ifb_distributing_array = new_array;
2283 	ifb->ifb_distributing_max = new_max;
2284 
2285 	if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2286 		bondport_start(p);
2287 
2288 		/* check if we need to generate a link status event */
2289 		if (ifbond_selection(ifb)) {
2290 			event_code = (ifb->ifb_active_lag == NULL)
2291 			    ? KEV_DL_LINK_OFF
2292 			    : KEV_DL_LINK_ON;
2293 			ifb->ifb_last_link_event = event_code;
2294 		}
2295 	} else {
2296 		/* are we adding the first distributing interface? */
2297 		if (media_active(&p->po_media_info)) {
2298 			if (ifb->ifb_distributing_count == 0) {
2299 				ifb->ifb_last_link_event = event_code = KEV_DL_LINK_ON;
2300 			}
2301 			bondport_enable_distributing(p);
2302 		} else {
2303 			bondport_disable_distributing(p);
2304 		}
2305 	}
2306 	p->po_filter = filter;
2307 
2308 	/* clear the busy state, and wakeup anyone waiting */
2309 	ifbond_signal(ifb, __func__);
2310 	bond_unlock();
2311 	if (event_code != 0) {
2312 		interface_link_event(ifp, event_code);
2313 	}
2314 	kfree_type(bondport_ref, old_max, old_array);
2315 	return 0;
2316 
2317 failed:
2318 	bond_assert_lock_not_held();
2319 
2320 	/* if this was the first port to be added, clear our address */
2321 	if (first) {
2322 		ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2323 	}
2324 
2325 	kfree_type(bondport_ref, new_max, new_array);
2326 	if (uint32_bit_is_set(control_flags,
2327 	    PORT_CONTROL_FLAGS_LLADDR_SET)) {
2328 		int     error1;
2329 
2330 		error1 = if_siflladdr(port_ifp, &p->po_saved_addr);
2331 		if (error1 != 0) {
2332 			printf("%s(%s, %s): if_siflladdr restore failed %d\n",
2333 			    __func__,
2334 			    ifb->ifb_name, bondport_get_name(p), error1);
2335 		}
2336 	}
2337 	if (uint32_bit_is_set(control_flags,
2338 	    PORT_CONTROL_FLAGS_PROMISCUOUS_SET)) {
2339 		int     error1;
2340 
2341 		error1 = ifnet_set_promiscuous(port_ifp, 0);
2342 		if (error1 != 0) {
2343 			printf("%s(%s, %s): promiscous mode disable failed %d\n",
2344 			    __func__,
2345 			    ifb->ifb_name, bondport_get_name(p), error1);
2346 		}
2347 	}
2348 	if (uint32_bit_is_set(control_flags,
2349 	    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET)) {
2350 		int     error1;
2351 
2352 		error1 = ifnet_set_promiscuous(port_ifp, 0);
2353 		if (error1 != 0) {
2354 			printf("%s(%s, %s): promiscous mode disable failed %d\n",
2355 			    __func__,
2356 			    ifb->ifb_name, bondport_get_name(p), error1);
2357 		}
2358 	}
2359 	if (uint32_bit_is_set(control_flags,
2360 	    PORT_CONTROL_FLAGS_PROTO_ATTACHED)) {
2361 		(void)bond_detach_protocol(port_ifp);
2362 	}
2363 	if (uint32_bit_is_set(control_flags,
2364 	    PORT_CONTROL_FLAGS_FILTER_ATTACHED)) {
2365 		iflt_detach(filter);
2366 	}
2367 	if (uint32_bit_is_set(control_flags,
2368 	    PORT_CONTROL_FLAGS_MTU_SET)) {
2369 		int error1;
2370 
2371 		error1 = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2372 		if (error1 != 0) {
2373 			printf("%s(%s, %s): SIOCSIFMTU %d failed %d\n",
2374 			    __func__,
2375 			    ifb->ifb_name, bondport_get_name(p),
2376 			    p->po_devmtu.ifdm_current, error1);
2377 		}
2378 	}
2379 	bond_lock();
2380 	if (uint32_bit_is_set(control_flags,
2381 	    PORT_CONTROL_FLAGS_IN_LIST)) {
2382 		TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2383 		ifb->ifb_port_count--;
2384 	}
2385 	if_clear_eflags(ifp, IFEF_BOND);
2386 	if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2387 		ifb->ifb_altmtu = 0;
2388 		ifnet_set_mtu(ifp, ETHERMTU);
2389 		ifnet_set_offload(ifp, 0);
2390 	}
2391 
2392 signal_done:
2393 	ifbond_signal(ifb, __func__);
2394 	bond_unlock();
2395 	ifbond_release(ifb);
2396 	bondport_free(p);
2397 	return error;
2398 }
2399 
2400 static int
bond_remove_interface(ifbond_ref ifb,struct ifnet * port_ifp)2401 bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp)
2402 {
2403 	int                         active_lag = 0;
2404 	int                         error = 0;
2405 	int                         event_code = 0;
2406 	bondport_ref                head_port;
2407 	struct ifnet *              ifp;
2408 	interface_filter_t          filter;
2409 	int                         last = FALSE;
2410 	int                         new_link_address = FALSE;
2411 	bondport_ref                p;
2412 	lacp_actor_partner_state    s;
2413 	int                         was_distributing;
2414 
2415 	bond_assert_lock_held();
2416 
2417 	ifbond_retain(ifb);
2418 	ifbond_wait(ifb, "bond_remove_interface");
2419 
2420 	p = ifbond_lookup_port(ifb, port_ifp);
2421 	if (p == NULL) {
2422 		error = ENXIO;
2423 		/* it got removed by another thread */
2424 		goto signal_done;
2425 	}
2426 
2427 	/* de-select it and remove it from the lists */
2428 	was_distributing = bondport_flags_distributing(p);
2429 	bondport_disable_distributing(p);
2430 	if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2431 		bondport_set_selected(p, SelectedState_UNSELECTED);
2432 		active_lag = bondport_remove_from_LAG(p);
2433 		/* invalidate timers here while holding the bond_lock */
2434 		bondport_invalidate_timers(p);
2435 
2436 		/* announce that we're Individual now */
2437 		s = p->po_actor_state;
2438 		s = lacp_actor_partner_state_set_individual(s);
2439 		s = lacp_actor_partner_state_set_not_collecting(s);
2440 		s = lacp_actor_partner_state_set_not_distributing(s);
2441 		s = lacp_actor_partner_state_set_out_of_sync(s);
2442 		p->po_actor_state = s;
2443 		bondport_flags_set_ntt(p);
2444 	}
2445 
2446 	TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2447 	ifb->ifb_port_count--;
2448 
2449 	ifp = ifb->ifb_ifp;
2450 	head_port = TAILQ_FIRST(&ifb->ifb_port_list);
2451 	if (head_port == NULL) {
2452 		ifnet_set_flags(ifp, 0, IFF_RUNNING);
2453 		if (ifbond_flags_lladdr(ifb) == FALSE) {
2454 			last = TRUE;
2455 		}
2456 		ifnet_set_offload(ifp, 0);
2457 		ifnet_set_mtu(ifp, ETHERMTU);
2458 		ifb->ifb_altmtu = 0;
2459 	} else if (ifbond_flags_lladdr(ifb) == FALSE
2460 	    && bcmp(&p->po_saved_addr, IF_LLADDR(ifp),
2461 	    ETHER_ADDR_LEN) == 0) {
2462 		new_link_address = TRUE;
2463 	}
2464 	/* check if we need to generate a link status event */
2465 	if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2466 		if (ifbond_selection(ifb) || active_lag) {
2467 			event_code = (ifb->ifb_active_lag == NULL)
2468 			    ? KEV_DL_LINK_OFF
2469 			    : KEV_DL_LINK_ON;
2470 			ifb->ifb_last_link_event = event_code;
2471 		}
2472 		bondport_transmit_machine(p, LAEventStart,
2473 		    TRANSMIT_MACHINE_TX_IMMEDIATE);
2474 	} else {
2475 		/* are we removing the last distributing interface? */
2476 		if (was_distributing && ifb->ifb_distributing_count == 0) {
2477 			ifb->ifb_last_link_event = event_code = KEV_DL_LINK_OFF;
2478 		}
2479 	}
2480 	filter = p->po_filter;
2481 	bond_unlock();
2482 
2483 	if (last) {
2484 		ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2485 	} else if (new_link_address) {
2486 		struct ifnet *  scan_ifp;
2487 		bondport_ref    scan_port;
2488 
2489 		/* ifbond_wait() allows port list traversal without holding the lock */
2490 
2491 		/* this port gave the bond its ethernet address, switch to new one */
2492 		ifnet_set_lladdr_and_type(ifp,
2493 		    &head_port->po_saved_addr, ETHER_ADDR_LEN,
2494 		    IFT_ETHER);
2495 
2496 		/* re-program each port with the new link address */
2497 		TAILQ_FOREACH(scan_port, &ifb->ifb_port_list, po_port_list) {
2498 			scan_ifp = scan_port->po_ifp;
2499 
2500 			if (!uint32_bit_is_set(scan_port->po_control_flags,
2501 			    PORT_CONTROL_FLAGS_LLADDR_SET)) {
2502 				/* port doesn't support setting lladdr */
2503 				continue;
2504 			}
2505 			error = if_siflladdr(scan_ifp,
2506 			    (const struct ether_addr *) IF_LLADDR(ifp));
2507 			if (error != 0) {
2508 				printf("%s(%s, %s): "
2509 				    "if_siflladdr (%s) failed %d\n",
2510 				    __func__,
2511 				    ifb->ifb_name, bondport_get_name(p),
2512 				    bondport_get_name(scan_port), error);
2513 			}
2514 		}
2515 	}
2516 
2517 	/* restore the port's ethernet address */
2518 	if (uint32_bit_is_set(p->po_control_flags,
2519 	    PORT_CONTROL_FLAGS_LLADDR_SET)) {
2520 		error = if_siflladdr(port_ifp, &p->po_saved_addr);
2521 		if (error != 0) {
2522 			printf("%s(%s, %s): if_siflladdr failed %d\n",
2523 			    __func__,
2524 			    ifb->ifb_name, bondport_get_name(p), error);
2525 		}
2526 	}
2527 
2528 	/* disable promiscous mode (if we enabled it) */
2529 	if (uint32_bit_is_set(p->po_control_flags,
2530 	    PORT_CONTROL_FLAGS_PROMISCUOUS_SET)) {
2531 		error = ifnet_set_promiscuous(port_ifp, 0);
2532 		if (error != 0) {
2533 			printf("%s(%s, %s): disable promiscuous failed %d\n",
2534 			    __func__,
2535 			    ifb->ifb_name, bondport_get_name(p), error);
2536 		}
2537 	}
2538 
2539 	/* disable promiscous mode from bond (if we enabled it) */
2540 	if (uint32_bit_is_set(p->po_control_flags,
2541 	    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET)) {
2542 		error = ifnet_set_promiscuous(port_ifp, 0);
2543 		if (error != 0) {
2544 			printf("%s(%s, %s): disable promiscuous failed %d\n",
2545 			    __func__,
2546 			    ifb->ifb_name, bondport_get_name(p), error);
2547 		}
2548 	}
2549 
2550 	/* restore the port's MTU */
2551 	error = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2552 	if (error != 0) {
2553 		printf("%s(%s, %s): SIOCSIFMTU %d failed %d\n",
2554 		    __func__,
2555 		    ifb->ifb_name, bondport_get_name(p),
2556 		    p->po_devmtu.ifdm_current, error);
2557 	}
2558 
2559 	/* remove the bond "protocol" */
2560 	bond_detach_protocol(port_ifp);
2561 
2562 	/* detach the filter */
2563 	if (filter != NULL) {
2564 		iflt_detach(filter);
2565 	}
2566 
2567 	/* generate link event */
2568 	if (event_code != 0) {
2569 		interface_link_event(ifp, event_code);
2570 	}
2571 
2572 	bond_lock();
2573 	bondport_free(p);
2574 	if_clear_eflags(port_ifp, IFEF_BOND);
2575 	/* release this bondport's reference to the ifbond */
2576 	ifbond_release(ifb);
2577 
2578 signal_done:
2579 	ifbond_signal(ifb, __func__);
2580 	ifbond_release(ifb);
2581 	return error;
2582 }
2583 
2584 static void
bond_set_lacp_mode(ifbond_ref ifb)2585 bond_set_lacp_mode(ifbond_ref ifb)
2586 {
2587 	bondport_ref                p;
2588 
2589 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2590 		bondport_disable_distributing(p);
2591 		bondport_start(p);
2592 	}
2593 	return;
2594 }
2595 
2596 static void
bond_set_static_mode(ifbond_ref ifb)2597 bond_set_static_mode(ifbond_ref ifb)
2598 {
2599 	bondport_ref                p;
2600 	lacp_actor_partner_state    s;
2601 
2602 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2603 		bondport_disable_distributing(p);
2604 		bondport_set_selected(p, SelectedState_UNSELECTED);
2605 		(void)bondport_remove_from_LAG(p);
2606 		bondport_cancel_timers(p);
2607 
2608 		/* announce that we're Individual now */
2609 		s = p->po_actor_state;
2610 		s = lacp_actor_partner_state_set_individual(s);
2611 		s = lacp_actor_partner_state_set_not_collecting(s);
2612 		s = lacp_actor_partner_state_set_not_distributing(s);
2613 		s = lacp_actor_partner_state_set_out_of_sync(s);
2614 		p->po_actor_state = s;
2615 		bondport_flags_set_ntt(p);
2616 		bondport_transmit_machine(p, LAEventStart,
2617 		    TRANSMIT_MACHINE_TX_IMMEDIATE);
2618 		/* clear state */
2619 		p->po_actor_state = 0;
2620 		bzero(&p->po_partner_state, sizeof(p->po_partner_state));
2621 
2622 		if (media_active(&p->po_media_info)) {
2623 			bondport_enable_distributing(p);
2624 		} else {
2625 			bondport_disable_distributing(p);
2626 		}
2627 	}
2628 	return;
2629 }
2630 
2631 static int
bond_set_mode(struct ifnet * ifp,int mode)2632 bond_set_mode(struct ifnet * ifp, int mode)
2633 {
2634 	int                         error = 0;
2635 	int                         event_code = 0;
2636 	ifbond_ref                  ifb;
2637 
2638 	bond_lock();
2639 	ifb = (ifbond_ref)ifnet_softc(ifp);
2640 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2641 		bond_unlock();
2642 		return (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2643 	}
2644 	if (ifb->ifb_mode == mode) {
2645 		bond_unlock();
2646 		return 0;
2647 	}
2648 
2649 	ifbond_retain(ifb);
2650 	ifbond_wait(ifb, "bond_set_mode");
2651 
2652 	/* verify (again) that the mode is actually different */
2653 	if (ifb->ifb_mode == mode) {
2654 		/* nothing to do */
2655 		goto signal_done;
2656 	}
2657 
2658 	ifb->ifb_mode = mode;
2659 	if (mode == IF_BOND_MODE_LACP) {
2660 		bond_set_lacp_mode(ifb);
2661 
2662 		/* check if we need to generate a link status event */
2663 		if (ifbond_selection(ifb)) {
2664 			event_code = (ifb->ifb_active_lag == NULL)
2665 			    ? KEV_DL_LINK_OFF
2666 			    : KEV_DL_LINK_ON;
2667 		}
2668 	} else {
2669 		bond_set_static_mode(ifb);
2670 		event_code = (ifb->ifb_distributing_count == 0)
2671 		    ? KEV_DL_LINK_OFF
2672 		    : KEV_DL_LINK_ON;
2673 	}
2674 	ifb->ifb_last_link_event = event_code;
2675 
2676 signal_done:
2677 	ifbond_signal(ifb, __func__);
2678 	bond_unlock();
2679 	ifbond_release(ifb);
2680 
2681 	if (event_code != 0) {
2682 		interface_link_event(ifp, event_code);
2683 	}
2684 	return error;
2685 }
2686 
2687 static int
bond_get_status(ifbond_ref ifb,struct if_bond_req * ibr_p,user_addr_t datap)2688 bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap)
2689 {
2690 	int                         count;
2691 	user_addr_t                 dst;
2692 	int                         error = 0;
2693 	struct if_bond_status_req * ibsr;
2694 	struct if_bond_status       ibs;
2695 	bondport_ref                port;
2696 
2697 	ibsr = &(ibr_p->ibr_ibru.ibru_status);
2698 	if (ibsr->ibsr_version != IF_BOND_STATUS_REQ_VERSION) {
2699 		return EINVAL;
2700 	}
2701 	ibsr->ibsr_key = ifb->ifb_key;
2702 	ibsr->ibsr_mode = ifb->ifb_mode;
2703 	ibsr->ibsr_total = ifb->ifb_port_count;
2704 	dst = proc_is64bit(current_proc())
2705 	    ? ibsr->ibsr_ibsru.ibsru_buffer64
2706 	    : CAST_USER_ADDR_T(ibsr->ibsr_ibsru.ibsru_buffer);
2707 	if (dst == USER_ADDR_NULL) {
2708 		/* just want to know how many there are */
2709 		goto done;
2710 	}
2711 	if (ibsr->ibsr_count < 0) {
2712 		return EINVAL;
2713 	}
2714 	count = (ifb->ifb_port_count < ibsr->ibsr_count)
2715 	    ? ifb->ifb_port_count : ibsr->ibsr_count;
2716 	TAILQ_FOREACH(port, &ifb->ifb_port_list, po_port_list) {
2717 		struct if_bond_partner_state *  ibps_p;
2718 		partner_state_ref               ps;
2719 
2720 		if (count == 0) {
2721 			break;
2722 		}
2723 		bzero(&ibs, sizeof(ibs));
2724 		strlcpy(ibs.ibs_if_name, port->po_name, sizeof(ibs.ibs_if_name));
2725 		ibs.ibs_port_priority = port->po_priority;
2726 		if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2727 			ibs.ibs_state = port->po_actor_state;
2728 			ibs.ibs_selected_state = port->po_selected;
2729 			ps = &port->po_partner_state;
2730 			ibps_p = &ibs.ibs_partner_state;
2731 			ibps_p->ibps_system = ps->ps_lag_info.li_system;
2732 			ibps_p->ibps_system_priority = ps->ps_lag_info.li_system_priority;
2733 			ibps_p->ibps_key = ps->ps_lag_info.li_key;
2734 			ibps_p->ibps_port = ps->ps_port;
2735 			ibps_p->ibps_port_priority = ps->ps_port_priority;
2736 			ibps_p->ibps_state = ps->ps_state;
2737 		} else {
2738 			/* fake the selected information */
2739 			ibs.ibs_selected_state = bondport_flags_distributing(port)
2740 			    ? SelectedState_SELECTED : SelectedState_UNSELECTED;
2741 		}
2742 		error = copyout(&ibs, dst, sizeof(ibs));
2743 		if (error != 0) {
2744 			break;
2745 		}
2746 		dst += sizeof(ibs);
2747 		count--;
2748 	}
2749 
2750 done:
2751 	if (error == 0) {
2752 		error = copyout(ibr_p, datap, sizeof(*ibr_p));
2753 	} else {
2754 		(void)copyout(ibr_p, datap, sizeof(*ibr_p));
2755 	}
2756 	return error;
2757 }
2758 
2759 static int
bond_set_promisc(struct ifnet * ifp)2760 bond_set_promisc(struct ifnet * ifp)
2761 {
2762 	int                 error = 0;
2763 	ifbond_ref          ifb;
2764 	bool                is_promisc;
2765 	bondport_ref        p;
2766 	int                 val;
2767 
2768 	is_promisc = (ifnet_flags(ifp) & IFF_PROMISC) != 0;
2769 
2770 	/* determine whether promiscuous state needs to be changed */
2771 	bond_lock();
2772 	ifb = (ifbond_ref)ifnet_softc(ifp);
2773 	if (ifb == NULL) {
2774 		bond_unlock();
2775 		error = EBUSY;
2776 		goto done;
2777 	}
2778 	if (is_promisc == ifbond_flags_promisc(ifb)) {
2779 		/* already in the right state */
2780 		bond_unlock();
2781 		goto done;
2782 	}
2783 	ifbond_retain(ifb);
2784 	ifbond_wait(ifb, __func__);
2785 	if (ifbond_flags_if_detaching(ifb)) {
2786 		/* someone destroyed the bond while we were waiting */
2787 		error = EBUSY;
2788 		goto signal_done;
2789 	}
2790 	bond_unlock();
2791 
2792 	/* update the promiscuous state of each memeber */
2793 	val = is_promisc ? 1 : 0;
2794 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2795 		struct ifnet *  port_ifp = p->po_ifp;
2796 		bool            port_is_promisc;
2797 
2798 		port_is_promisc = uint32_bit_is_set(p->po_control_flags,
2799 		    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET);
2800 		if (port_is_promisc == is_promisc) {
2801 			/* already in the right state */
2802 			continue;
2803 		}
2804 		error = ifnet_set_promiscuous(port_ifp, val);
2805 		if (error != 0) {
2806 			printf("%s: ifnet_set_promiscuous(%s, %d): failed %d",
2807 			    ifb->ifb_name, port_ifp->if_xname, val, error);
2808 			continue;
2809 		}
2810 		printf("%s: ifnet_set_promiscuous(%s, %d): succeeded",
2811 		    ifb->ifb_name, port_ifp->if_xname, val);
2812 		if (is_promisc) {
2813 			/* remember that we set it */
2814 			uint32_bit_set(&p->po_control_flags,
2815 			    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET);
2816 		} else {
2817 			uint32_bit_clear(&p->po_control_flags,
2818 			    PORT_CONTROL_FLAGS_BOND_PROMISCUOUS_SET);
2819 		}
2820 	}
2821 
2822 	/* assume that updating promiscuous state succeeded */
2823 	error = 0;
2824 	bond_lock();
2825 
2826 	/* update our internal state */
2827 	if (is_promisc) {
2828 		ifbond_flags_set_promisc(ifb);
2829 	} else {
2830 		ifbond_flags_clear_promisc(ifb);
2831 	}
2832 
2833 signal_done:
2834 	ifbond_signal(ifb, __func__);
2835 	bond_unlock();
2836 	ifbond_release(ifb);
2837 
2838 done:
2839 	return error;
2840 }
2841 
2842 static void
bond_get_mtu_values(ifbond_ref ifb,int * ret_min,int * ret_max)2843 bond_get_mtu_values(ifbond_ref ifb, int * ret_min, int * ret_max)
2844 {
2845 	int                         mtu_min = 0;
2846 	int                         mtu_max = 0;
2847 	bondport_ref                p;
2848 
2849 	if (TAILQ_FIRST(&ifb->ifb_port_list) != NULL) {
2850 		mtu_min = IF_MINMTU;
2851 	}
2852 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2853 		struct ifdevmtu *       devmtu_p = &p->po_devmtu;
2854 
2855 		if (devmtu_p->ifdm_min > mtu_min) {
2856 			mtu_min = devmtu_p->ifdm_min;
2857 		}
2858 		if (mtu_max == 0 || devmtu_p->ifdm_max < mtu_max) {
2859 			mtu_max = devmtu_p->ifdm_max;
2860 		}
2861 	}
2862 	*ret_min = mtu_min;
2863 	*ret_max = mtu_max;
2864 	return;
2865 }
2866 
2867 static int
bond_set_mtu_on_ports(ifbond_ref ifb,int mtu)2868 bond_set_mtu_on_ports(ifbond_ref ifb, int mtu)
2869 {
2870 	int                         error = 0;
2871 	bondport_ref                p;
2872 
2873 	TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2874 		error = siocsifmtu(p->po_ifp, mtu);
2875 		if (error != 0) {
2876 			printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2877 			    ifb->ifb_name, bondport_get_name(p), error);
2878 			break;
2879 		}
2880 	}
2881 	return error;
2882 }
2883 
2884 static int
bond_set_mtu(struct ifnet * ifp,int mtu,int isdevmtu)2885 bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu)
2886 {
2887 	int                 error = 0;
2888 	ifbond_ref          ifb;
2889 	int                 mtu_min;
2890 	int                 mtu_max;
2891 	int                 new_max;
2892 	int                 old_max;
2893 
2894 	bond_lock();
2895 	ifb = (ifbond_ref)ifnet_softc(ifp);
2896 	if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2897 		error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2898 		goto done;
2899 	}
2900 	ifbond_retain(ifb);
2901 	ifbond_wait(ifb, "bond_set_mtu");
2902 
2903 	/* check again */
2904 	if (ifnet_softc(ifp) == NULL || ifbond_flags_if_detaching(ifb)) {
2905 		error = EBUSY;
2906 		goto signal_done;
2907 	}
2908 	bond_get_mtu_values(ifb, &mtu_min, &mtu_max);
2909 	if (mtu > mtu_max) {
2910 		error = EINVAL;
2911 		goto signal_done;
2912 	}
2913 	if (mtu < mtu_min && (isdevmtu == 0 || mtu != 0)) {
2914 		/* allow SIOCSIFALTMTU to set the mtu to 0 */
2915 		error = EINVAL;
2916 		goto signal_done;
2917 	}
2918 	if (isdevmtu) {
2919 		new_max = (mtu > (int)ifnet_mtu(ifp)) ? mtu : (int)ifnet_mtu(ifp);
2920 	} else {
2921 		new_max = (mtu > ifb->ifb_altmtu) ? mtu : ifb->ifb_altmtu;
2922 	}
2923 	old_max = ((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
2924 	    ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu;
2925 	if (new_max != old_max) {
2926 		/* we can safely walk the list of port without the lock held */
2927 		bond_unlock();
2928 		error = bond_set_mtu_on_ports(ifb, new_max);
2929 		if (error != 0) {
2930 			/* try our best to back out of it */
2931 			(void)bond_set_mtu_on_ports(ifb, old_max);
2932 		}
2933 		bond_lock();
2934 	}
2935 	if (error == 0) {
2936 		if (isdevmtu) {
2937 			ifb->ifb_altmtu = mtu;
2938 		} else {
2939 			ifnet_set_mtu(ifp, mtu);
2940 		}
2941 	}
2942 
2943 signal_done:
2944 	ifbond_signal(ifb, __func__);
2945 	ifbond_release(ifb);
2946 
2947 done:
2948 	bond_unlock();
2949 	return error;
2950 }
2951 
2952 static int
bond_ioctl(struct ifnet * ifp,u_long cmd,void * data)2953 bond_ioctl(struct ifnet *ifp, u_long cmd, void * data)
2954 {
2955 	int                 error = 0;
2956 	struct if_bond_req  ibr;
2957 	struct ifaddr *     ifa;
2958 	ifbond_ref          ifb;
2959 	struct ifreq *      ifr;
2960 	struct ifmediareq   *ifmr;
2961 	struct ifnet *      port_ifp = NULL;
2962 	user_addr_t         user_addr;
2963 
2964 	if (ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
2965 		return EOPNOTSUPP;
2966 	}
2967 	ifr = (struct ifreq *)data;
2968 	ifa = (struct ifaddr *)data;
2969 
2970 	switch (cmd) {
2971 	case SIOCSIFADDR:
2972 		ifnet_set_flags(ifp, IFF_UP, IFF_UP);
2973 		break;
2974 
2975 	case SIOCGIFMEDIA32:
2976 	case SIOCGIFMEDIA64:
2977 		bond_lock();
2978 		ifb = (ifbond_ref)ifnet_softc(ifp);
2979 		if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2980 			bond_unlock();
2981 			return ifb == NULL ? EOPNOTSUPP : EBUSY;
2982 		}
2983 		ifmr = (struct ifmediareq *)data;
2984 		ifmr->ifm_current = IFM_ETHER;
2985 		ifmr->ifm_mask = 0;
2986 		ifmr->ifm_status = IFM_AVALID;
2987 		ifmr->ifm_active = IFM_ETHER;
2988 		ifmr->ifm_count = 1;
2989 		if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2990 			if (ifb->ifb_active_lag != NULL) {
2991 				ifmr->ifm_active = ifb->ifb_active_lag->lag_active_media;
2992 				ifmr->ifm_status |= IFM_ACTIVE;
2993 			}
2994 		} else if (ifb->ifb_distributing_count > 0) {
2995 			ifmr->ifm_active
2996 			        = ifb->ifb_distributing_array[0]->po_media_info.mi_active;
2997 			ifmr->ifm_status |= IFM_ACTIVE;
2998 		}
2999 		bond_unlock();
3000 		user_addr = (cmd == SIOCGIFMEDIA64) ?
3001 		    ((struct ifmediareq64 *)ifmr)->ifmu_ulist :
3002 		    CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
3003 		if (user_addr != USER_ADDR_NULL) {
3004 			error = copyout(&ifmr->ifm_current,
3005 			    user_addr,
3006 			    sizeof(int));
3007 		}
3008 		break;
3009 
3010 	case SIOCSIFMEDIA:
3011 		/* XXX send the SIFMEDIA to all children?  Or force autoselect? */
3012 		error = EINVAL;
3013 		break;
3014 
3015 	case SIOCGIFDEVMTU:
3016 		bond_lock();
3017 		ifb = (ifbond_ref)ifnet_softc(ifp);
3018 		if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
3019 			bond_unlock();
3020 			error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
3021 			break;
3022 		}
3023 		ifr->ifr_devmtu.ifdm_current = bond_device_mtu(ifp, ifb);
3024 		bond_get_mtu_values(ifb, &ifr->ifr_devmtu.ifdm_min,
3025 		    &ifr->ifr_devmtu.ifdm_max);
3026 		bond_unlock();
3027 		break;
3028 
3029 	case SIOCGIFALTMTU:
3030 		bond_lock();
3031 		ifb = (ifbond_ref)ifnet_softc(ifp);
3032 		if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
3033 			bond_unlock();
3034 			error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
3035 			break;
3036 		}
3037 		ifr->ifr_mtu = ifb->ifb_altmtu;
3038 		bond_unlock();
3039 		break;
3040 
3041 	case SIOCSIFALTMTU:
3042 		error = bond_set_mtu(ifp, ifr->ifr_mtu, 1);
3043 		break;
3044 
3045 	case SIOCSIFMTU:
3046 		error = bond_set_mtu(ifp, ifr->ifr_mtu, 0);
3047 		break;
3048 
3049 	case SIOCSIFBOND:
3050 		user_addr = proc_is64bit(current_proc())
3051 		    ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
3052 		error = copyin(user_addr, &ibr, sizeof(ibr));
3053 		if (error) {
3054 			break;
3055 		}
3056 		switch (ibr.ibr_op) {
3057 		case IF_BOND_OP_ADD_INTERFACE:
3058 		case IF_BOND_OP_REMOVE_INTERFACE:
3059 			port_ifp = ifunit(ibr.ibr_ibru.ibru_if_name);
3060 			if (port_ifp == NULL) {
3061 				error = ENXIO;
3062 				break;
3063 			}
3064 			if (ifnet_type(port_ifp) != IFT_ETHER) {
3065 				error = EPROTONOSUPPORT;
3066 				break;
3067 			}
3068 			break;
3069 		case IF_BOND_OP_SET_VERBOSE:
3070 		case IF_BOND_OP_SET_MODE:
3071 			break;
3072 		default:
3073 			error = EOPNOTSUPP;
3074 			break;
3075 		}
3076 		if (error != 0) {
3077 			break;
3078 		}
3079 		switch (ibr.ibr_op) {
3080 		case IF_BOND_OP_ADD_INTERFACE:
3081 			error = bond_add_interface(ifp, port_ifp);
3082 			break;
3083 		case IF_BOND_OP_REMOVE_INTERFACE:
3084 			bond_lock();
3085 			ifb = (ifbond_ref)ifnet_softc(ifp);
3086 			if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
3087 				bond_unlock();
3088 				return ifb == NULL ? EOPNOTSUPP : EBUSY;
3089 			}
3090 			error = bond_remove_interface(ifb, port_ifp);
3091 			bond_unlock();
3092 			break;
3093 		case IF_BOND_OP_SET_VERBOSE:
3094 			bond_lock();
3095 			if_bond_debug = ibr.ibr_ibru.ibru_int_val;
3096 			bond_unlock();
3097 			break;
3098 		case IF_BOND_OP_SET_MODE:
3099 			switch (ibr.ibr_ibru.ibru_int_val) {
3100 			case IF_BOND_MODE_LACP:
3101 			case IF_BOND_MODE_STATIC:
3102 				break;
3103 			default:
3104 				error = EINVAL;
3105 				break;
3106 			}
3107 			if (error != 0) {
3108 				break;
3109 			}
3110 			error = bond_set_mode(ifp, ibr.ibr_ibru.ibru_int_val);
3111 			break;
3112 		}
3113 		break; /* SIOCSIFBOND */
3114 
3115 	case SIOCGIFBOND:
3116 		user_addr = proc_is64bit(current_proc())
3117 		    ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
3118 		error = copyin(user_addr, &ibr, sizeof(ibr));
3119 		if (error) {
3120 			break;
3121 		}
3122 		switch (ibr.ibr_op) {
3123 		case IF_BOND_OP_GET_STATUS:
3124 			break;
3125 		default:
3126 			error = EOPNOTSUPP;
3127 			break;
3128 		}
3129 		if (error != 0) {
3130 			break;
3131 		}
3132 		bond_lock();
3133 		ifb = (ifbond_ref)ifnet_softc(ifp);
3134 		if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
3135 			bond_unlock();
3136 			return ifb == NULL ? EOPNOTSUPP : EBUSY;
3137 		}
3138 		switch (ibr.ibr_op) {
3139 		case IF_BOND_OP_GET_STATUS:
3140 			error = bond_get_status(ifb, &ibr, user_addr);
3141 			break;
3142 		}
3143 		bond_unlock();
3144 		break; /* SIOCGIFBOND */
3145 
3146 	case SIOCSIFLLADDR:
3147 		error = EOPNOTSUPP;
3148 		break;
3149 
3150 	case SIOCSIFFLAGS:
3151 		/* enable promiscuous mode on members */
3152 		error = bond_set_promisc(ifp);
3153 		break;
3154 
3155 	case SIOCADDMULTI:
3156 	case SIOCDELMULTI:
3157 		error = bond_setmulti(ifp);
3158 		break;
3159 	default:
3160 		error = EOPNOTSUPP;
3161 	}
3162 	return error;
3163 }
3164 
3165 static void
bond_if_free(struct ifnet * ifp)3166 bond_if_free(struct ifnet * ifp)
3167 {
3168 	ifbond_ref  ifb;
3169 
3170 	if (ifp == NULL) {
3171 		return;
3172 	}
3173 	bond_lock();
3174 	ifb = (ifbond_ref)ifnet_softc(ifp);
3175 	if (ifb == NULL) {
3176 		bond_unlock();
3177 		return;
3178 	}
3179 	ifbond_release(ifb);
3180 	bond_unlock();
3181 	ifnet_release(ifp);
3182 	return;
3183 }
3184 
3185 static void
bond_handle_event(struct ifnet * port_ifp,int event_code)3186 bond_handle_event(struct ifnet * port_ifp, int event_code)
3187 {
3188 	struct ifnet *      bond_ifp = NULL;
3189 	ifbond_ref          ifb;
3190 	int                 old_distributing_count;
3191 	bondport_ref        p;
3192 	struct media_info   media_info = { .mi_active = 0, .mi_status = 0 };
3193 
3194 	switch (event_code) {
3195 	case KEV_DL_IF_DETACHED:
3196 	case KEV_DL_IF_DETACHING:
3197 		break;
3198 	case KEV_DL_LINK_OFF:
3199 	case KEV_DL_LINK_ON:
3200 		media_info = interface_media_info(port_ifp);
3201 		break;
3202 	default:
3203 		return;
3204 	}
3205 	bond_lock();
3206 	p = bond_lookup_port(port_ifp);
3207 	if (p == NULL) {
3208 		bond_unlock();
3209 		return;
3210 	}
3211 	ifb = p->po_bond;
3212 	old_distributing_count = ifb->ifb_distributing_count;
3213 	switch (event_code) {
3214 	case KEV_DL_IF_DETACHED:
3215 	case KEV_DL_IF_DETACHING:
3216 		bond_remove_interface(ifb, p->po_ifp);
3217 		break;
3218 	case KEV_DL_LINK_OFF:
3219 	case KEV_DL_LINK_ON:
3220 		p->po_media_info = media_info;
3221 		if (p->po_enabled) {
3222 			bondport_link_status_changed(p);
3223 		}
3224 		break;
3225 	}
3226 	/* generate a link-event */
3227 	if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
3228 		if (ifbond_selection(ifb)) {
3229 			event_code = (ifb->ifb_active_lag == NULL)
3230 			    ? KEV_DL_LINK_OFF
3231 			    : KEV_DL_LINK_ON;
3232 			/* XXX need to take a reference on bond_ifp */
3233 			bond_ifp = ifb->ifb_ifp;
3234 			ifb->ifb_last_link_event = event_code;
3235 		} else {
3236 			event_code = (ifb->ifb_active_lag == NULL)
3237 			    ? KEV_DL_LINK_OFF
3238 			    : KEV_DL_LINK_ON;
3239 			if (event_code != ifb->ifb_last_link_event) {
3240 				if (if_bond_debug) {
3241 					timestamp_printf("%s: (event) generating LINK event\n",
3242 					    ifb->ifb_name);
3243 				}
3244 				bond_ifp = ifb->ifb_ifp;
3245 				ifb->ifb_last_link_event = event_code;
3246 			}
3247 		}
3248 	} else {
3249 		/*
3250 		 * if the distributing array membership changed from 0 <-> !0
3251 		 * generate a link event
3252 		 */
3253 		if (old_distributing_count == 0
3254 		    && ifb->ifb_distributing_count != 0) {
3255 			event_code = KEV_DL_LINK_ON;
3256 		} else if (old_distributing_count != 0
3257 		    && ifb->ifb_distributing_count == 0) {
3258 			event_code = KEV_DL_LINK_OFF;
3259 		}
3260 		if (event_code != 0 && event_code != ifb->ifb_last_link_event) {
3261 			bond_ifp = ifb->ifb_ifp;
3262 			ifb->ifb_last_link_event = event_code;
3263 		}
3264 	}
3265 
3266 	bond_unlock();
3267 	if (bond_ifp != NULL) {
3268 		interface_link_event(bond_ifp, event_code);
3269 	}
3270 	return;
3271 }
3272 
3273 static void
bond_iff_event(__unused void * cookie,ifnet_t port_ifp,__unused protocol_family_t protocol,const struct kev_msg * event)3274 bond_iff_event(__unused void *cookie, ifnet_t port_ifp,
3275     __unused protocol_family_t protocol,
3276     const struct kev_msg *event)
3277 {
3278 	int         event_code;
3279 
3280 	if (event->vendor_code != KEV_VENDOR_APPLE
3281 	    || event->kev_class != KEV_NETWORK_CLASS
3282 	    || event->kev_subclass != KEV_DL_SUBCLASS) {
3283 		return;
3284 	}
3285 	event_code = event->event_code;
3286 	switch (event_code) {
3287 	case KEV_DL_LINK_OFF:
3288 	case KEV_DL_LINK_ON:
3289 	case KEV_DL_IF_DETACHING:
3290 	case KEV_DL_IF_DETACHED:
3291 		bond_handle_event(port_ifp, event_code);
3292 		break;
3293 	default:
3294 		break;
3295 	}
3296 	return;
3297 }
3298 
3299 static void
bond_iff_detached(__unused void * cookie,ifnet_t port_ifp)3300 bond_iff_detached(__unused void *cookie, ifnet_t port_ifp)
3301 {
3302 	bond_handle_event(port_ifp, KEV_DL_IF_DETACHED);
3303 	return;
3304 }
3305 
3306 static void
interface_link_event(struct ifnet * ifp,u_int32_t event_code)3307 interface_link_event(struct ifnet * ifp, u_int32_t event_code)
3308 {
3309 	struct event {
3310 		u_int32_t ifnet_family;
3311 		u_int32_t unit;
3312 		char if_name[IFNAMSIZ];
3313 	};
3314 	_Alignas(struct kern_event_msg) char message[sizeof(struct kern_event_msg) + sizeof(struct event)] = { 0 };
3315 	struct kern_event_msg *header = (struct kern_event_msg*)message;
3316 	struct event *data = (struct event *)(header + 1);
3317 
3318 	header->total_size   = sizeof(message);
3319 	header->vendor_code  = KEV_VENDOR_APPLE;
3320 	header->kev_class    = KEV_NETWORK_CLASS;
3321 	header->kev_subclass = KEV_DL_SUBCLASS;
3322 	header->event_code   = event_code;
3323 	data->ifnet_family   = ifnet_family(ifp);
3324 	data->unit           = (u_int32_t)ifnet_unit(ifp);
3325 	strlcpy(data->if_name, ifnet_name(ifp), IFNAMSIZ);
3326 	ifnet_event(ifp, header);
3327 }
3328 
3329 static errno_t
bond_proto_input(ifnet_t ifp,protocol_family_t protocol,mbuf_t packet,char * header)3330 bond_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
3331     char *header)
3332 {
3333 #pragma unused(protocol, packet, header)
3334 	if (if_bond_debug != 0) {
3335 		printf("%s: unexpected packet from %s\n", __func__,
3336 		    ifp->if_xname);
3337 	}
3338 	return 0;
3339 }
3340 
3341 
3342 /*
3343  * Function: bond_attach_protocol
3344  * Purpose:
3345  *   Attach a DLIL protocol to the interface.
3346  *
3347  *   The ethernet demux special cases to always return PF_BOND if the
3348  *   interface is bonded.  That means we receive all traffic from that
3349  *   interface without passing any of the traffic to any other attached
3350  *   protocol.
3351  */
3352 static int
bond_attach_protocol(struct ifnet * ifp)3353 bond_attach_protocol(struct ifnet *ifp)
3354 {
3355 	int                                                         error;
3356 	struct ifnet_attach_proto_param     reg;
3357 
3358 	bzero(&reg, sizeof(reg));
3359 	reg.input = bond_proto_input;
3360 
3361 	error = ifnet_attach_protocol(ifp, PF_BOND, &reg);
3362 	if (error) {
3363 		printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3364 		    ifnet_name(ifp), ifnet_unit(ifp), error);
3365 	}
3366 	return error;
3367 }
3368 
3369 /*
3370  * Function: bond_detach_protocol
3371  * Purpose:
3372  *   Detach our DLIL protocol from an interface
3373  */
3374 static int
bond_detach_protocol(struct ifnet * ifp)3375 bond_detach_protocol(struct ifnet *ifp)
3376 {
3377 	int         error;
3378 
3379 	error = ifnet_detach_protocol(ifp, PF_BOND);
3380 	if (error) {
3381 		printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3382 		    ifnet_name(ifp), ifnet_unit(ifp), error);
3383 	}
3384 	return error;
3385 }
3386 
3387 /*
3388  * Function: bond_attach_filter
3389  * Purpose:
3390  *   Attach our DLIL interface filter.
3391  */
3392 static int
bond_attach_filter(struct ifnet * ifp,interface_filter_t * filter_p)3393 bond_attach_filter(struct ifnet *ifp, interface_filter_t * filter_p)
3394 {
3395 	int                     error;
3396 	struct iff_filter       iff;
3397 
3398 	/*
3399 	 * install an interface filter
3400 	 */
3401 	memset(&iff, 0, sizeof(struct iff_filter));
3402 	iff.iff_name = "com.apple.kernel.bsd.net.if_bond";
3403 	iff.iff_input = bond_iff_input;
3404 	iff.iff_event = bond_iff_event;
3405 	iff.iff_detached = bond_iff_detached;
3406 	error = dlil_attach_filter(ifp, &iff, filter_p,
3407 	    DLIL_IFF_TSO | DLIL_IFF_INTERNAL);
3408 	if (error != 0) {
3409 		printf("%s: dlil_attach_filter failed %d\n", __func__, error);
3410 	}
3411 	return error;
3412 }
3413 
3414 
3415 /*
3416  * DLIL interface family functions
3417  */
3418 extern int ether_attach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3419 extern void ether_detach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3420 extern int ether_attach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3421 extern void ether_detach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3422 extern int ether_attach_at(ifnet_t ifp, protocol_family_t protocol_family);
3423 extern void ether_detach_at(ifnet_t ifp, protocol_family_t protocol_family);
3424 
3425 __private_extern__ int
bond_family_init(void)3426 bond_family_init(void)
3427 {
3428 	int error = 0;
3429 
3430 	error = proto_register_plumber(PF_INET, APPLE_IF_FAM_BOND,
3431 	    ether_attach_inet,
3432 	    ether_detach_inet);
3433 	if (error != 0) {
3434 		printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
3435 		    error);
3436 		goto done;
3437 	}
3438 	error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_BOND,
3439 	    ether_attach_inet6,
3440 	    ether_detach_inet6);
3441 	if (error != 0) {
3442 		printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3443 		    error);
3444 		goto done;
3445 	}
3446 	error = bond_clone_attach();
3447 	if (error != 0) {
3448 		printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n",
3449 		    error);
3450 		goto done;
3451 	}
3452 
3453 done:
3454 	return error;
3455 }
3456 /**
3457 **
3458 ** LACP routines:
3459 **
3460 **/
3461 
3462 /**
3463 ** LACP ifbond_list routines
3464 **/
3465 static bondport_ref
ifbond_list_find_moved_port(bondport_ref rx_port,const lacp_actor_partner_tlv_ref atlv)3466 ifbond_list_find_moved_port(bondport_ref rx_port,
3467     const lacp_actor_partner_tlv_ref atlv)
3468 {
3469 	ifbond_ref          bond;
3470 	bondport_ref        p;
3471 	partner_state_ref   ps;
3472 	LAG_info_ref        ps_li;
3473 
3474 	TAILQ_FOREACH(bond, &g_bond->ifbond_list, ifb_bond_list) {
3475 		TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3476 			if (rx_port == p) {
3477 				/* no point in comparing against ourselves */
3478 				continue;
3479 			}
3480 			if (p->po_receive_state != ReceiveState_PORT_DISABLED) {
3481 				/* it's not clear that we should be checking this */
3482 				continue;
3483 			}
3484 			ps = &p->po_partner_state;
3485 			if (lacp_actor_partner_state_defaulted(ps->ps_state)) {
3486 				continue;
3487 			}
3488 			ps_li = &ps->ps_lag_info;
3489 			if (ps->ps_port == lacp_actor_partner_tlv_get_port(atlv)
3490 			    && bcmp(&ps_li->li_system, atlv->lap_system,
3491 			    sizeof(ps_li->li_system)) == 0) {
3492 				if (if_bond_debug) {
3493 					timestamp_printf("System " EA_FORMAT
3494 					    " Port 0x%x moved from %s to %s\n",
3495 					    EA_LIST(&ps_li->li_system), ps->ps_port,
3496 					    bondport_get_name(p),
3497 					    bondport_get_name(rx_port));
3498 				}
3499 				return p;
3500 			}
3501 		}
3502 	}
3503 	return NULL;
3504 }
3505 
3506 /**
3507 ** LACP ifbond, LAG routines
3508 **/
3509 
3510 static int
ifbond_selection(ifbond_ref bond)3511 ifbond_selection(ifbond_ref bond)
3512 {
3513 	int                 all_ports_ready = 0;
3514 	int                 active_media = 0;
3515 	LAG_ref             lag = NULL;
3516 	int                 lag_changed = 0;
3517 	bondport_ref        p;
3518 	int                 port_speed = 0;
3519 
3520 	lag = ifbond_find_best_LAG(bond, &active_media);
3521 	if (lag != bond->ifb_active_lag) {
3522 		if (bond->ifb_active_lag != NULL) {
3523 			ifbond_deactivate_LAG(bond, bond->ifb_active_lag);
3524 			bond->ifb_active_lag = NULL;
3525 		}
3526 		bond->ifb_active_lag = lag;
3527 		if (lag != NULL) {
3528 			ifbond_activate_LAG(bond, lag, active_media);
3529 		}
3530 		lag_changed = 1;
3531 	} else if (lag != NULL) {
3532 		if (lag->lag_active_media != active_media) {
3533 			if (if_bond_debug) {
3534 				timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3535 				    link_speed(lag->lag_active_media),
3536 				    link_speed(active_media));
3537 			}
3538 			ifbond_deactivate_LAG(bond, lag);
3539 			ifbond_activate_LAG(bond, lag, active_media);
3540 			lag_changed = 1;
3541 		}
3542 	}
3543 	if (lag != NULL) {
3544 		port_speed = link_speed(active_media);
3545 		all_ports_ready = ifbond_all_ports_ready(bond);
3546 	}
3547 	TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3548 		if (lag != NULL && p->po_lag == lag
3549 		    && media_speed(&p->po_media_info) == port_speed
3550 		    && (p->po_mux_state == MuxState_DETACHED
3551 		    || p->po_selected == SelectedState_SELECTED
3552 		    || p->po_selected == SelectedState_STANDBY)
3553 		    && bondport_aggregatable(p)) {
3554 			if (bond->ifb_max_active > 0) {
3555 				if (lag->lag_selected_port_count < bond->ifb_max_active) {
3556 					if (p->po_selected == SelectedState_STANDBY
3557 					    || p->po_selected == SelectedState_UNSELECTED) {
3558 						bondport_set_selected(p, SelectedState_SELECTED);
3559 					}
3560 				} else if (p->po_selected == SelectedState_UNSELECTED) {
3561 					bondport_set_selected(p, SelectedState_STANDBY);
3562 				}
3563 			} else {
3564 				bondport_set_selected(p, SelectedState_SELECTED);
3565 			}
3566 		}
3567 		if (bondport_flags_selected_changed(p)) {
3568 			bondport_flags_clear_selected_changed(p);
3569 			bondport_mux_machine(p, LAEventSelectedChange, NULL);
3570 		}
3571 		if (all_ports_ready
3572 		    && bondport_flags_ready(p)
3573 		    && p->po_mux_state == MuxState_WAITING) {
3574 			bondport_mux_machine(p, LAEventReady, NULL);
3575 		}
3576 		bondport_transmit_machine(p, LAEventStart, NULL);
3577 	}
3578 	return lag_changed;
3579 }
3580 
3581 static LAG_ref
ifbond_find_best_LAG(ifbond_ref bond,int * active_media)3582 ifbond_find_best_LAG(ifbond_ref bond, int * active_media)
3583 {
3584 	int                 best_active = 0;
3585 	LAG_ref             best_lag = NULL;
3586 	int                 best_count = 0;
3587 	int                 best_speed = 0;
3588 	LAG_ref             lag;
3589 
3590 	if (bond->ifb_active_lag != NULL) {
3591 		best_lag = bond->ifb_active_lag;
3592 		best_count = LAG_get_aggregatable_port_count(best_lag, &best_active);
3593 		if (bond->ifb_max_active > 0
3594 		    && best_count > bond->ifb_max_active) {
3595 			best_count = bond->ifb_max_active;
3596 		}
3597 		best_speed = link_speed(best_active);
3598 	}
3599 	TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3600 		int     active;
3601 		int     count;
3602 		int     speed;
3603 
3604 		if (lag == bond->ifb_active_lag) {
3605 			/* we've already computed it */
3606 			continue;
3607 		}
3608 		count = LAG_get_aggregatable_port_count(lag, &active);
3609 		if (count == 0) {
3610 			continue;
3611 		}
3612 		if (bond->ifb_max_active > 0
3613 		    && count > bond->ifb_max_active) {
3614 			/* if there's a limit, don't count extra links */
3615 			count = bond->ifb_max_active;
3616 		}
3617 		speed = link_speed(active);
3618 		if ((count * speed) > (best_count * best_speed)) {
3619 			best_count = count;
3620 			best_speed = speed;
3621 			best_active = active;
3622 			best_lag = lag;
3623 		}
3624 	}
3625 	if (best_count == 0) {
3626 		return NULL;
3627 	}
3628 	*active_media = best_active;
3629 	return best_lag;
3630 }
3631 
3632 static void
ifbond_deactivate_LAG(__unused ifbond_ref bond,LAG_ref lag)3633 ifbond_deactivate_LAG(__unused ifbond_ref bond, LAG_ref lag)
3634 {
3635 	bondport_ref        p;
3636 
3637 	TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3638 		bondport_set_selected(p, SelectedState_UNSELECTED);
3639 	}
3640 	return;
3641 }
3642 
3643 static void
ifbond_activate_LAG(ifbond_ref bond,LAG_ref lag,int active_media)3644 ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media)
3645 {
3646 	int                 need = 0;
3647 	bondport_ref        p;
3648 
3649 	if (bond->ifb_max_active > 0) {
3650 		need = bond->ifb_max_active;
3651 	}
3652 	lag->lag_active_media = active_media;
3653 	TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3654 		if (bondport_aggregatable(p) == 0) {
3655 			bondport_set_selected(p, SelectedState_UNSELECTED);
3656 		} else if (media_speed(&p->po_media_info) != link_speed(active_media)) {
3657 			bondport_set_selected(p, SelectedState_UNSELECTED);
3658 		} else if (p->po_mux_state == MuxState_DETACHED) {
3659 			if (bond->ifb_max_active > 0) {
3660 				if (need > 0) {
3661 					bondport_set_selected(p, SelectedState_SELECTED);
3662 					need--;
3663 				} else {
3664 					bondport_set_selected(p, SelectedState_STANDBY);
3665 				}
3666 			} else {
3667 				bondport_set_selected(p, SelectedState_SELECTED);
3668 			}
3669 		} else {
3670 			bondport_set_selected(p, SelectedState_UNSELECTED);
3671 		}
3672 	}
3673 	return;
3674 }
3675 
3676 #if 0
3677 static void
3678 ifbond_set_max_active(ifbond_ref bond, int max_active)
3679 {
3680 	LAG_ref     lag = bond->ifb_active_lag;
3681 
3682 	bond->ifb_max_active = max_active;
3683 	if (bond->ifb_max_active <= 0 || lag == NULL) {
3684 		return;
3685 	}
3686 	if (lag->lag_selected_port_count > bond->ifb_max_active) {
3687 		bondport_ref    p;
3688 		int                     remove_count;
3689 
3690 		remove_count = lag->lag_selected_port_count - bond->ifb_max_active;
3691 		TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3692 			if (p->po_selected == SelectedState_SELECTED) {
3693 				bondport_set_selected(p, SelectedState_UNSELECTED);
3694 				remove_count--;
3695 				if (remove_count == 0) {
3696 					break;
3697 				}
3698 			}
3699 		}
3700 	}
3701 	return;
3702 }
3703 #endif
3704 
3705 static int
ifbond_all_ports_ready(ifbond_ref bond)3706 ifbond_all_ports_ready(ifbond_ref bond)
3707 {
3708 	int                 ready = 0;
3709 	bondport_ref        p;
3710 
3711 	if (bond->ifb_active_lag == NULL) {
3712 		return 0;
3713 	}
3714 	TAILQ_FOREACH(p, &bond->ifb_active_lag->lag_port_list, po_lag_port_list) {
3715 		if (p->po_mux_state == MuxState_WAITING
3716 		    && p->po_selected == SelectedState_SELECTED) {
3717 			if (bondport_flags_ready(p) == 0) {
3718 				return 0;
3719 			}
3720 		}
3721 		/* note that there was at least one ready port */
3722 		ready = 1;
3723 	}
3724 	return ready;
3725 }
3726 
3727 static int
ifbond_all_ports_attached(ifbond_ref bond,bondport_ref this_port)3728 ifbond_all_ports_attached(ifbond_ref bond, bondport_ref this_port)
3729 {
3730 	bondport_ref        p;
3731 
3732 	TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3733 		if (this_port == p) {
3734 			continue;
3735 		}
3736 		if (bondport_flags_mux_attached(p) == 0) {
3737 			return 0;
3738 		}
3739 	}
3740 	return 1;
3741 }
3742 
3743 static LAG_ref
ifbond_get_LAG_matching_port(ifbond_ref bond,bondport_ref p)3744 ifbond_get_LAG_matching_port(ifbond_ref bond, bondport_ref p)
3745 {
3746 	LAG_ref     lag;
3747 
3748 	TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3749 		if (bcmp(&lag->lag_info, &p->po_partner_state.ps_lag_info,
3750 		    sizeof(lag->lag_info)) == 0) {
3751 			return lag;
3752 		}
3753 	}
3754 	return NULL;
3755 }
3756 
3757 static int
LAG_get_aggregatable_port_count(LAG_ref lag,int * active_media)3758 LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media)
3759 {
3760 	int                 active;
3761 	int                 count;
3762 	bondport_ref        p;
3763 	int                 speed;
3764 
3765 	active = 0;
3766 	count = 0;
3767 	speed = 0;
3768 	TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3769 		if (bondport_aggregatable(p)) {
3770 			int this_speed;
3771 
3772 			this_speed = media_speed(&p->po_media_info);
3773 			if (this_speed == 0) {
3774 				continue;
3775 			}
3776 			if (this_speed > speed) {
3777 				active = p->po_media_info.mi_active;
3778 				speed = this_speed;
3779 				count = 1;
3780 			} else if (this_speed == speed) {
3781 				count++;
3782 			}
3783 		}
3784 	}
3785 	*active_media = active;
3786 	return count;
3787 }
3788 
3789 
3790 /**
3791 ** LACP bondport routines
3792 **/
3793 static void
bondport_link_status_changed(bondport_ref p)3794 bondport_link_status_changed(bondport_ref p)
3795 {
3796 	ifbond_ref  bond = p->po_bond;
3797 
3798 	if (if_bond_debug) {
3799 		if (media_active(&p->po_media_info)) {
3800 			const char * duplex_string;
3801 
3802 			if (media_full_duplex(&p->po_media_info)) {
3803 				duplex_string = "full";
3804 			} else if (media_type_unknown(&p->po_media_info)) {
3805 				duplex_string = "unknown";
3806 			} else {
3807 				duplex_string = "half";
3808 			}
3809 			timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3810 			    bondport_get_name(p),
3811 			    media_speed(&p->po_media_info),
3812 			    duplex_string);
3813 		} else {
3814 			timestamp_printf("[%s] Link DOWN\n",
3815 			    bondport_get_name(p));
3816 		}
3817 	}
3818 	if (bond->ifb_mode == IF_BOND_MODE_LACP) {
3819 		if (media_active(&p->po_media_info)
3820 		    && bond->ifb_active_lag != NULL
3821 		    && p->po_lag == bond->ifb_active_lag
3822 		    && p->po_selected != SelectedState_UNSELECTED) {
3823 			if (media_speed(&p->po_media_info) != p->po_lag->lag_active_media) {
3824 				if (if_bond_debug) {
3825 					timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3826 					    bondport_get_name(p),
3827 					    media_speed(&p->po_media_info),
3828 					    link_speed(p->po_lag->lag_active_media));
3829 				}
3830 				bondport_set_selected(p, SelectedState_UNSELECTED);
3831 			}
3832 		}
3833 		bondport_receive_machine(p, LAEventMediaChange, NULL);
3834 		bondport_mux_machine(p, LAEventMediaChange, NULL);
3835 		bondport_periodic_transmit_machine(p, LAEventMediaChange, NULL);
3836 	} else {
3837 		if (media_active(&p->po_media_info)) {
3838 			bondport_enable_distributing(p);
3839 		} else {
3840 			bondport_disable_distributing(p);
3841 		}
3842 	}
3843 	return;
3844 }
3845 
3846 static int
bondport_aggregatable(bondport_ref p)3847 bondport_aggregatable(bondport_ref p)
3848 {
3849 	partner_state_ref   ps = &p->po_partner_state;
3850 
3851 	if (lacp_actor_partner_state_aggregatable(p->po_actor_state) == 0
3852 	    || lacp_actor_partner_state_aggregatable(ps->ps_state) == 0) {
3853 		/* we and/or our partner are individual */
3854 		return 0;
3855 	}
3856 	if (p->po_lag == NULL) {
3857 		return 0;
3858 	}
3859 	switch (p->po_receive_state) {
3860 	default:
3861 		if (if_bond_debug) {
3862 			timestamp_printf("[%s] Port is not selectable\n",
3863 			    bondport_get_name(p));
3864 		}
3865 		return 0;
3866 	case ReceiveState_CURRENT:
3867 	case ReceiveState_EXPIRED:
3868 		break;
3869 	}
3870 	return 1;
3871 }
3872 
3873 static int
bondport_matches_LAG(bondport_ref p,LAG_ref lag)3874 bondport_matches_LAG(bondport_ref p, LAG_ref lag)
3875 {
3876 	LAG_info_ref        lag_li;
3877 	partner_state_ref   ps;
3878 	LAG_info_ref        ps_li;
3879 
3880 	ps = &p->po_partner_state;
3881 	ps_li = &ps->ps_lag_info;
3882 	lag_li = &lag->lag_info;
3883 	if (ps_li->li_system_priority == lag_li->li_system_priority
3884 	    && ps_li->li_key == lag_li->li_key
3885 	    && (bcmp(&ps_li->li_system, &lag_li->li_system,
3886 	    sizeof(lag_li->li_system))
3887 	    == 0)) {
3888 		return 1;
3889 	}
3890 	return 0;
3891 }
3892 
3893 static int
bondport_remove_from_LAG(bondport_ref p)3894 bondport_remove_from_LAG(bondport_ref p)
3895 {
3896 	int         active_lag = 0;
3897 	ifbond_ref  bond = p->po_bond;
3898 	LAG_ref     lag = p->po_lag;
3899 
3900 	if (lag == NULL) {
3901 		return 0;
3902 	}
3903 	TAILQ_REMOVE(&lag->lag_port_list, p, po_lag_port_list);
3904 	if (if_bond_debug) {
3905 		timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3906 		    ",0x%04x)\n",
3907 		    bondport_get_name(p),
3908 		    lag->lag_info.li_system_priority,
3909 		    EA_LIST(&lag->lag_info.li_system),
3910 		    lag->lag_info.li_key);
3911 	}
3912 	p->po_lag = NULL;
3913 	lag->lag_port_count--;
3914 	if (lag->lag_port_count > 0) {
3915 		return bond->ifb_active_lag == lag;
3916 	}
3917 	if (if_bond_debug) {
3918 		timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3919 		    ",0x%04x)\n",
3920 		    bond->ifb_key,
3921 		    lag->lag_info.li_system_priority,
3922 		    EA_LIST(&lag->lag_info.li_system),
3923 		    lag->lag_info.li_key);
3924 	}
3925 	TAILQ_REMOVE(&bond->ifb_lag_list, lag, lag_list);
3926 	if (bond->ifb_active_lag == lag) {
3927 		bond->ifb_active_lag = NULL;
3928 		active_lag = 1;
3929 	}
3930 	kfree_type(struct LAG_s, lag);
3931 	return active_lag;
3932 }
3933 
3934 static void
bondport_add_to_LAG(bondport_ref p,LAG_ref lag)3935 bondport_add_to_LAG(bondport_ref p, LAG_ref lag)
3936 {
3937 	TAILQ_INSERT_TAIL(&lag->lag_port_list, p, po_lag_port_list);
3938 	p->po_lag = lag;
3939 	lag->lag_port_count++;
3940 	if (if_bond_debug) {
3941 		timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT "0x%04x)\n",
3942 		    bondport_get_name(p),
3943 		    lag->lag_info.li_system_priority,
3944 		    EA_LIST(&lag->lag_info.li_system),
3945 		    lag->lag_info.li_key);
3946 	}
3947 	return;
3948 }
3949 
3950 static void
bondport_assign_to_LAG(bondport_ref p)3951 bondport_assign_to_LAG(bondport_ref p)
3952 {
3953 	ifbond_ref  bond = p->po_bond;
3954 	LAG_ref     lag;
3955 
3956 	if (lacp_actor_partner_state_defaulted(p->po_actor_state)) {
3957 		bondport_remove_from_LAG(p);
3958 		return;
3959 	}
3960 	lag = p->po_lag;
3961 	if (lag != NULL) {
3962 		if (bondport_matches_LAG(p, lag)) {
3963 			/* still OK */
3964 			return;
3965 		}
3966 		bondport_remove_from_LAG(p);
3967 	}
3968 	lag = ifbond_get_LAG_matching_port(bond, p);
3969 	if (lag != NULL) {
3970 		bondport_add_to_LAG(p, lag);
3971 		return;
3972 	}
3973 	lag = kalloc_type(struct LAG_s, Z_WAITOK);
3974 	TAILQ_INIT(&lag->lag_port_list);
3975 	lag->lag_port_count = 0;
3976 	lag->lag_selected_port_count = 0;
3977 	lag->lag_info = p->po_partner_state.ps_lag_info;
3978 	TAILQ_INSERT_TAIL(&bond->ifb_lag_list, lag, lag_list);
3979 	if (if_bond_debug) {
3980 		timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3981 		    ",0x%04x)\n",
3982 		    bond->ifb_key,
3983 		    lag->lag_info.li_system_priority,
3984 		    EA_LIST(&lag->lag_info.li_system),
3985 		    lag->lag_info.li_key);
3986 	}
3987 	bondport_add_to_LAG(p, lag);
3988 	return;
3989 }
3990 
3991 static void
bondport_receive_lacpdu(bondport_ref p,lacpdu_ref in_lacpdu_p)3992 bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p)
3993 {
3994 	bondport_ref                moved_port;
3995 
3996 	moved_port
3997 	        = ifbond_list_find_moved_port(p, (const lacp_actor_partner_tlv_ref)
3998 	    &in_lacpdu_p->la_actor_tlv);
3999 	if (moved_port != NULL) {
4000 		bondport_receive_machine(moved_port, LAEventPortMoved, NULL);
4001 	}
4002 	bondport_receive_machine(p, LAEventPacket, in_lacpdu_p);
4003 	bondport_mux_machine(p, LAEventPacket, in_lacpdu_p);
4004 	bondport_periodic_transmit_machine(p, LAEventPacket, in_lacpdu_p);
4005 	return;
4006 }
4007 
4008 static void
bondport_set_selected(bondport_ref p,SelectedState s)4009 bondport_set_selected(bondport_ref p, SelectedState s)
4010 {
4011 	if (s != p->po_selected) {
4012 		ifbond_ref      bond = p->po_bond;
4013 		LAG_ref         lag = p->po_lag;
4014 
4015 		bondport_flags_set_selected_changed(p);
4016 		if (lag != NULL && bond->ifb_active_lag == lag) {
4017 			if (p->po_selected == SelectedState_SELECTED) {
4018 				lag->lag_selected_port_count--;
4019 			} else if (s == SelectedState_SELECTED) {
4020 				lag->lag_selected_port_count++;
4021 			}
4022 			if (if_bond_debug) {
4023 				timestamp_printf("[%s] SetSelected: %s (was %s)\n",
4024 				    bondport_get_name(p),
4025 				    SelectedStateString(s),
4026 				    SelectedStateString(p->po_selected));
4027 			}
4028 		}
4029 	}
4030 	p->po_selected = s;
4031 	return;
4032 }
4033 
4034 /**
4035 ** Receive machine
4036 **/
4037 
4038 static void
bondport_UpdateDefaultSelected(bondport_ref p)4039 bondport_UpdateDefaultSelected(bondport_ref p)
4040 {
4041 	bondport_set_selected(p, SelectedState_UNSELECTED);
4042 	return;
4043 }
4044 
4045 static void
bondport_RecordDefault(bondport_ref p)4046 bondport_RecordDefault(bondport_ref p)
4047 {
4048 	bzero(&p->po_partner_state, sizeof(p->po_partner_state));
4049 	p->po_actor_state
4050 	        = lacp_actor_partner_state_set_defaulted(p->po_actor_state);
4051 	bondport_assign_to_LAG(p);
4052 	return;
4053 }
4054 
4055 static void
bondport_UpdateSelected(bondport_ref p,lacpdu_ref lacpdu_p)4056 bondport_UpdateSelected(bondport_ref p, lacpdu_ref lacpdu_p)
4057 {
4058 	lacp_actor_partner_tlv_ref  actor;
4059 	partner_state_ref           ps;
4060 	LAG_info_ref                ps_li;
4061 
4062 	/* compare the PDU's Actor information to our Partner state */
4063 	actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
4064 	ps = &p->po_partner_state;
4065 	ps_li = &ps->ps_lag_info;
4066 	if (lacp_actor_partner_tlv_get_port(actor) != ps->ps_port
4067 	    || (lacp_actor_partner_tlv_get_port_priority(actor)
4068 	    != ps->ps_port_priority)
4069 	    || bcmp(actor->lap_system, &ps_li->li_system, sizeof(ps_li->li_system))
4070 	    || (lacp_actor_partner_tlv_get_system_priority(actor)
4071 	    != ps_li->li_system_priority)
4072 	    || (lacp_actor_partner_tlv_get_key(actor) != ps_li->li_key)
4073 	    || (lacp_actor_partner_state_aggregatable(actor->lap_state)
4074 	    != lacp_actor_partner_state_aggregatable(ps->ps_state))) {
4075 		bondport_set_selected(p, SelectedState_UNSELECTED);
4076 		if (if_bond_debug) {
4077 			timestamp_printf("[%s] updateSelected UNSELECTED\n",
4078 			    bondport_get_name(p));
4079 		}
4080 	}
4081 	return;
4082 }
4083 
4084 static void
bondport_RecordPDU(bondport_ref p,lacpdu_ref lacpdu_p)4085 bondport_RecordPDU(bondport_ref p, lacpdu_ref lacpdu_p)
4086 {
4087 	lacp_actor_partner_tlv_ref  actor;
4088 	ifbond_ref                  bond = p->po_bond;
4089 	int                         lacp_maintain = 0;
4090 	partner_state_ref           ps;
4091 	lacp_actor_partner_tlv_ref  partner;
4092 	LAG_info_ref                ps_li;
4093 
4094 	/* copy the PDU's Actor information into our Partner state */
4095 	actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
4096 	ps = &p->po_partner_state;
4097 	ps_li = &ps->ps_lag_info;
4098 	ps->ps_port = lacp_actor_partner_tlv_get_port(actor);
4099 	ps->ps_port_priority = lacp_actor_partner_tlv_get_port_priority(actor);
4100 	ps_li->li_system = *((lacp_system_ref)actor->lap_system);
4101 	ps_li->li_system_priority
4102 	        = lacp_actor_partner_tlv_get_system_priority(actor);
4103 	ps_li->li_key = lacp_actor_partner_tlv_get_key(actor);
4104 	ps->ps_state = lacp_actor_partner_state_set_out_of_sync(actor->lap_state);
4105 	p->po_actor_state
4106 	        = lacp_actor_partner_state_set_not_defaulted(p->po_actor_state);
4107 
4108 	/* compare the PDU's Partner information to our own information */
4109 	partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
4110 
4111 	if (lacp_actor_partner_state_active_lacp(ps->ps_state)
4112 	    || (lacp_actor_partner_state_active_lacp(p->po_actor_state)
4113 	    && lacp_actor_partner_state_active_lacp(partner->lap_state))) {
4114 		if (if_bond_debug) {
4115 			timestamp_printf("[%s] recordPDU: LACP will maintain\n",
4116 			    bondport_get_name(p));
4117 		}
4118 		lacp_maintain = 1;
4119 	}
4120 	if ((lacp_actor_partner_tlv_get_port(partner)
4121 	    == bondport_get_index(p))
4122 	    && lacp_actor_partner_tlv_get_port_priority(partner) == p->po_priority
4123 	    && bcmp(partner->lap_system, &g_bond->system,
4124 	    sizeof(g_bond->system)) == 0
4125 	    && (lacp_actor_partner_tlv_get_system_priority(partner)
4126 	    == g_bond->system_priority)
4127 	    && lacp_actor_partner_tlv_get_key(partner) == bond->ifb_key
4128 	    && (lacp_actor_partner_state_aggregatable(partner->lap_state)
4129 	    == lacp_actor_partner_state_aggregatable(p->po_actor_state))
4130 	    && lacp_actor_partner_state_in_sync(actor->lap_state)
4131 	    && lacp_maintain) {
4132 		ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
4133 		if (if_bond_debug) {
4134 			timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
4135 			    bondport_get_name(p));
4136 		}
4137 	} else if (lacp_actor_partner_state_aggregatable(actor->lap_state) == 0
4138 	    && lacp_actor_partner_state_in_sync(actor->lap_state)
4139 	    && lacp_maintain) {
4140 		ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
4141 		if (if_bond_debug) {
4142 			timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
4143 			    bondport_get_name(p));
4144 		}
4145 	}
4146 	bondport_assign_to_LAG(p);
4147 	return;
4148 }
4149 
4150 static __inline__ lacp_actor_partner_state
updateNTTBits(lacp_actor_partner_state s)4151 updateNTTBits(lacp_actor_partner_state s)
4152 {
4153 	return s & (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
4154 	       | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
4155 	       | LACP_ACTOR_PARTNER_STATE_AGGREGATION
4156 	       | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION);
4157 }
4158 
4159 static void
bondport_UpdateNTT(bondport_ref p,lacpdu_ref lacpdu_p)4160 bondport_UpdateNTT(bondport_ref p, lacpdu_ref lacpdu_p)
4161 {
4162 	ifbond_ref                  bond = p->po_bond;
4163 	lacp_actor_partner_tlv_ref  partner;
4164 
4165 	/* compare the PDU's Actor information to our Partner state */
4166 	partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
4167 	if ((lacp_actor_partner_tlv_get_port(partner) != bondport_get_index(p))
4168 	    || lacp_actor_partner_tlv_get_port_priority(partner) != p->po_priority
4169 	    || bcmp(partner->lap_system, &g_bond->system, sizeof(g_bond->system))
4170 	    || (lacp_actor_partner_tlv_get_system_priority(partner)
4171 	    != g_bond->system_priority)
4172 	    || lacp_actor_partner_tlv_get_key(partner) != bond->ifb_key
4173 	    || (updateNTTBits(partner->lap_state)
4174 	    != updateNTTBits(p->po_actor_state))) {
4175 		bondport_flags_set_ntt(p);
4176 		if (if_bond_debug) {
4177 			timestamp_printf("[%s] updateNTT: Need To Transmit\n",
4178 			    bondport_get_name(p));
4179 		}
4180 	}
4181 	return;
4182 }
4183 
4184 static void
bondport_AttachMuxToAggregator(bondport_ref p)4185 bondport_AttachMuxToAggregator(bondport_ref p)
4186 {
4187 	if (bondport_flags_mux_attached(p) == 0) {
4188 		if (if_bond_debug) {
4189 			timestamp_printf("[%s] Attached Mux To Aggregator\n",
4190 			    bondport_get_name(p));
4191 		}
4192 		bondport_flags_set_mux_attached(p);
4193 	}
4194 	return;
4195 }
4196 
4197 static void
bondport_DetachMuxFromAggregator(bondport_ref p)4198 bondport_DetachMuxFromAggregator(bondport_ref p)
4199 {
4200 	if (bondport_flags_mux_attached(p)) {
4201 		if (if_bond_debug) {
4202 			timestamp_printf("[%s] Detached Mux From Aggregator\n",
4203 			    bondport_get_name(p));
4204 		}
4205 		bondport_flags_clear_mux_attached(p);
4206 	}
4207 	return;
4208 }
4209 
4210 static void
bondport_enable_distributing(bondport_ref p)4211 bondport_enable_distributing(bondport_ref p)
4212 {
4213 	if (bondport_flags_distributing(p) == 0) {
4214 		ifbond_ref      bond = p->po_bond;
4215 
4216 		bond->ifb_distributing_array[bond->ifb_distributing_count++] = p;
4217 		if (if_bond_debug) {
4218 			timestamp_printf("[%s] Distribution Enabled\n",
4219 			    bondport_get_name(p));
4220 		}
4221 		bondport_flags_set_distributing(p);
4222 	}
4223 	return;
4224 }
4225 
4226 static void
bondport_disable_distributing(bondport_ref p)4227 bondport_disable_distributing(bondport_ref p)
4228 {
4229 	if (bondport_flags_distributing(p)) {
4230 		bondport_ref *  array;
4231 		ifbond_ref      bond;
4232 		int             count;
4233 		int             i;
4234 
4235 		bond = p->po_bond;
4236 		array = bond->ifb_distributing_array;
4237 		count = bond->ifb_distributing_count;
4238 		for (i = 0; i < count; i++) {
4239 			if (array[i] == p) {
4240 				int     j;
4241 
4242 				for (j = i; j < (count - 1); j++) {
4243 					array[j] = array[j + 1];
4244 				}
4245 				break;
4246 			}
4247 		}
4248 		bond->ifb_distributing_count--;
4249 		if (if_bond_debug) {
4250 			timestamp_printf("[%s] Distribution Disabled\n",
4251 			    bondport_get_name(p));
4252 		}
4253 		bondport_flags_clear_distributing(p);
4254 	}
4255 	return;
4256 }
4257 
4258 /**
4259 ** Receive machine functions
4260 **/
4261 static void
4262 bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
4263     void * event_data);
4264 static void
4265 bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
4266     void * event_data);
4267 static void
4268 bondport_receive_machine_expired(bondport_ref p, LAEvent event,
4269     void * event_data);
4270 static void
4271 bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
4272     void * event_data);
4273 static void
4274 bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
4275     void * event_data);
4276 static void
4277 bondport_receive_machine_current(bondport_ref p, LAEvent event,
4278     void * event_data);
4279 
4280 static void
bondport_receive_machine_event(bondport_ref p,LAEvent event,void * event_data)4281 bondport_receive_machine_event(bondport_ref p, LAEvent event,
4282     void * event_data)
4283 {
4284 	switch (p->po_receive_state) {
4285 	case ReceiveState_none:
4286 		bondport_receive_machine_initialize(p, LAEventStart, NULL);
4287 		break;
4288 	case ReceiveState_INITIALIZE:
4289 		bondport_receive_machine_initialize(p, event, event_data);
4290 		break;
4291 	case ReceiveState_PORT_DISABLED:
4292 		bondport_receive_machine_port_disabled(p, event, event_data);
4293 		break;
4294 	case ReceiveState_EXPIRED:
4295 		bondport_receive_machine_expired(p, event, event_data);
4296 		break;
4297 	case ReceiveState_LACP_DISABLED:
4298 		bondport_receive_machine_lacp_disabled(p, event, event_data);
4299 		break;
4300 	case ReceiveState_DEFAULTED:
4301 		bondport_receive_machine_defaulted(p, event, event_data);
4302 		break;
4303 	case ReceiveState_CURRENT:
4304 		bondport_receive_machine_current(p, event, event_data);
4305 		break;
4306 	default:
4307 		break;
4308 	}
4309 	return;
4310 }
4311 
4312 static void
bondport_receive_machine(bondport_ref p,LAEvent event,void * event_data)4313 bondport_receive_machine(bondport_ref p, LAEvent event,
4314     void * event_data)
4315 {
4316 	switch (event) {
4317 	case LAEventPacket:
4318 		if (p->po_receive_state != ReceiveState_LACP_DISABLED) {
4319 			bondport_receive_machine_current(p, event, event_data);
4320 		}
4321 		break;
4322 	case LAEventMediaChange:
4323 		if (media_active(&p->po_media_info)) {
4324 			switch (p->po_receive_state) {
4325 			case ReceiveState_PORT_DISABLED:
4326 			case ReceiveState_LACP_DISABLED:
4327 				bondport_receive_machine_port_disabled(p, LAEventMediaChange, NULL);
4328 				break;
4329 			default:
4330 				break;
4331 			}
4332 		} else {
4333 			bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4334 		}
4335 		break;
4336 	default:
4337 		bondport_receive_machine_event(p, event, event_data);
4338 		break;
4339 	}
4340 	return;
4341 }
4342 
4343 static void
bondport_receive_machine_initialize(bondport_ref p,LAEvent event,__unused void * event_data)4344 bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
4345     __unused void * event_data)
4346 {
4347 	switch (event) {
4348 	case LAEventStart:
4349 		devtimer_cancel(p->po_current_while_timer);
4350 		if (if_bond_debug) {
4351 			timestamp_printf("[%s] Receive INITIALIZE\n",
4352 			    bondport_get_name(p));
4353 		}
4354 		p->po_receive_state = ReceiveState_INITIALIZE;
4355 		bondport_set_selected(p, SelectedState_UNSELECTED);
4356 		bondport_RecordDefault(p);
4357 		p->po_actor_state
4358 		        = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4359 		bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4360 		break;
4361 	default:
4362 		break;
4363 	}
4364 	return;
4365 }
4366 
4367 static void
bondport_receive_machine_port_disabled(bondport_ref p,LAEvent event,__unused void * event_data)4368 bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
4369     __unused void * event_data)
4370 {
4371 	partner_state_ref   ps;
4372 
4373 	switch (event) {
4374 	case LAEventStart:
4375 		devtimer_cancel(p->po_current_while_timer);
4376 		if (if_bond_debug) {
4377 			timestamp_printf("[%s] Receive PORT_DISABLED\n",
4378 			    bondport_get_name(p));
4379 		}
4380 		p->po_receive_state = ReceiveState_PORT_DISABLED;
4381 		ps = &p->po_partner_state;
4382 		ps->ps_state = lacp_actor_partner_state_set_out_of_sync(ps->ps_state);
4383 		OS_FALLTHROUGH;
4384 	case LAEventMediaChange:
4385 		if (media_active(&p->po_media_info)) {
4386 			if (media_ok(&p->po_media_info)) {
4387 				bondport_receive_machine_expired(p, LAEventStart, NULL);
4388 			} else {
4389 				bondport_receive_machine_lacp_disabled(p, LAEventStart, NULL);
4390 			}
4391 		} else if (p->po_selected == SelectedState_SELECTED) {
4392 			struct timeval      tv;
4393 
4394 			if (if_bond_debug) {
4395 				timestamp_printf("[%s] Receive PORT_DISABLED: "
4396 				    "link timer started\n",
4397 				    bondport_get_name(p));
4398 			}
4399 			tv.tv_sec = 1;
4400 			tv.tv_usec = 0;
4401 			devtimer_set_relative(p->po_current_while_timer, tv,
4402 			    (devtimer_timeout_func)(void (*)(void))
4403 			    bondport_receive_machine_port_disabled,
4404 			    (void *)LAEventTimeout, NULL);
4405 		} else if (p->po_selected == SelectedState_STANDBY) {
4406 			bondport_set_selected(p, SelectedState_UNSELECTED);
4407 		}
4408 		break;
4409 	case LAEventTimeout:
4410 		if (p->po_selected == SelectedState_SELECTED) {
4411 			if (if_bond_debug) {
4412 				timestamp_printf("[%s] Receive PORT_DISABLED: "
4413 				    "link timer completed, marking UNSELECTED\n",
4414 				    bondport_get_name(p));
4415 			}
4416 			bondport_set_selected(p, SelectedState_UNSELECTED);
4417 		}
4418 		break;
4419 	case LAEventPortMoved:
4420 		bondport_receive_machine_initialize(p, LAEventStart, NULL);
4421 		break;
4422 	default:
4423 		break;
4424 	}
4425 	return;
4426 }
4427 
4428 static void
bondport_receive_machine_expired(bondport_ref p,LAEvent event,__unused void * event_data)4429 bondport_receive_machine_expired(bondport_ref p, LAEvent event,
4430     __unused void * event_data)
4431 {
4432 	lacp_actor_partner_state    s;
4433 	struct timeval              tv;
4434 
4435 	switch (event) {
4436 	case LAEventStart:
4437 		devtimer_cancel(p->po_current_while_timer);
4438 		if (if_bond_debug) {
4439 			timestamp_printf("[%s] Receive EXPIRED\n",
4440 			    bondport_get_name(p));
4441 		}
4442 		p->po_receive_state = ReceiveState_EXPIRED;
4443 		s = p->po_partner_state.ps_state;
4444 		s = lacp_actor_partner_state_set_out_of_sync(s);
4445 		s = lacp_actor_partner_state_set_short_timeout(s);
4446 		p->po_partner_state.ps_state = s;
4447 		p->po_actor_state
4448 		        = lacp_actor_partner_state_set_expired(p->po_actor_state);
4449 		/* start current_while timer */
4450 		tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4451 		tv.tv_usec = 0;
4452 		devtimer_set_relative(p->po_current_while_timer, tv,
4453 		    (devtimer_timeout_func)(void (*)(void))
4454 		    bondport_receive_machine_expired,
4455 		    (void *)LAEventTimeout, NULL);
4456 
4457 		break;
4458 	case LAEventTimeout:
4459 		bondport_receive_machine_defaulted(p, LAEventStart, NULL);
4460 		break;
4461 	default:
4462 		break;
4463 	}
4464 	return;
4465 }
4466 
4467 static void
bondport_receive_machine_lacp_disabled(bondport_ref p,LAEvent event,__unused void * event_data)4468 bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
4469     __unused void * event_data)
4470 {
4471 	partner_state_ref   ps;
4472 	switch (event) {
4473 	case LAEventStart:
4474 		devtimer_cancel(p->po_current_while_timer);
4475 		if (if_bond_debug) {
4476 			timestamp_printf("[%s] Receive LACP_DISABLED\n",
4477 			    bondport_get_name(p));
4478 		}
4479 		p->po_receive_state = ReceiveState_LACP_DISABLED;
4480 		bondport_set_selected(p, SelectedState_UNSELECTED);
4481 		bondport_RecordDefault(p);
4482 		ps = &p->po_partner_state;
4483 		ps->ps_state = lacp_actor_partner_state_set_individual(ps->ps_state);
4484 		p->po_actor_state
4485 		        = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4486 		break;
4487 	default:
4488 		break;
4489 	}
4490 	return;
4491 }
4492 
4493 static void
bondport_receive_machine_defaulted(bondport_ref p,LAEvent event,__unused void * event_data)4494 bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
4495     __unused void * event_data)
4496 {
4497 	switch (event) {
4498 	case LAEventStart:
4499 		devtimer_cancel(p->po_current_while_timer);
4500 		if (if_bond_debug) {
4501 			timestamp_printf("[%s] Receive DEFAULTED\n",
4502 			    bondport_get_name(p));
4503 		}
4504 		p->po_receive_state = ReceiveState_DEFAULTED;
4505 		bondport_UpdateDefaultSelected(p);
4506 		bondport_RecordDefault(p);
4507 		p->po_actor_state
4508 		        = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4509 		break;
4510 	default:
4511 		break;
4512 	}
4513 	return;
4514 }
4515 
4516 static void
bondport_receive_machine_current(bondport_ref p,LAEvent event,void * event_data)4517 bondport_receive_machine_current(bondport_ref p, LAEvent event,
4518     void * event_data)
4519 {
4520 	partner_state_ref   ps;
4521 	struct timeval      tv;
4522 
4523 	switch (event) {
4524 	case LAEventPacket:
4525 		devtimer_cancel(p->po_current_while_timer);
4526 		if (if_bond_debug) {
4527 			timestamp_printf("[%s] Receive CURRENT\n",
4528 			    bondport_get_name(p));
4529 		}
4530 		p->po_receive_state = ReceiveState_CURRENT;
4531 		bondport_UpdateSelected(p, event_data);
4532 		bondport_UpdateNTT(p, event_data);
4533 		bondport_RecordPDU(p, event_data);
4534 		p->po_actor_state
4535 		        = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4536 		bondport_assign_to_LAG(p);
4537 		/* start current_while timer */
4538 		ps = &p->po_partner_state;
4539 		if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4540 			tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4541 		} else {
4542 			tv.tv_sec = LACP_LONG_TIMEOUT_TIME;
4543 		}
4544 		tv.tv_usec = 0;
4545 		devtimer_set_relative(p->po_current_while_timer, tv,
4546 		    (devtimer_timeout_func)(void (*)(void))
4547 		    bondport_receive_machine_current,
4548 		    (void *)LAEventTimeout, NULL);
4549 		break;
4550 	case LAEventTimeout:
4551 		bondport_receive_machine_expired(p, LAEventStart, NULL);
4552 		break;
4553 	default:
4554 		break;
4555 	}
4556 	return;
4557 }
4558 
4559 /**
4560 ** Periodic Transmission machine
4561 **/
4562 
4563 static void
bondport_periodic_transmit_machine(bondport_ref p,LAEvent event,__unused void * event_data)4564 bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
4565     __unused void * event_data)
4566 {
4567 	int                 interval;
4568 	partner_state_ref   ps;
4569 	struct timeval      tv;
4570 
4571 	switch (event) {
4572 	case LAEventStart:
4573 		if (if_bond_debug) {
4574 			timestamp_printf("[%s] periodic_transmit Start\n",
4575 			    bondport_get_name(p));
4576 		}
4577 		OS_FALLTHROUGH;
4578 	case LAEventMediaChange:
4579 		devtimer_cancel(p->po_periodic_timer);
4580 		p->po_periodic_interval = 0;
4581 		if (media_active(&p->po_media_info) == 0
4582 		    || media_ok(&p->po_media_info) == 0) {
4583 			break;
4584 		}
4585 		OS_FALLTHROUGH;
4586 	case LAEventPacket:
4587 		/* Neither Partner nor Actor are LACP Active, no periodic tx */
4588 		ps = &p->po_partner_state;
4589 		if (lacp_actor_partner_state_active_lacp(p->po_actor_state) == 0
4590 		    && (lacp_actor_partner_state_active_lacp(ps->ps_state)
4591 		    == 0)) {
4592 			devtimer_cancel(p->po_periodic_timer);
4593 			p->po_periodic_interval = 0;
4594 			break;
4595 		}
4596 		if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4597 			interval = LACP_FAST_PERIODIC_TIME;
4598 		} else {
4599 			interval = LACP_SLOW_PERIODIC_TIME;
4600 		}
4601 		if (p->po_periodic_interval != interval) {
4602 			if (interval == LACP_FAST_PERIODIC_TIME
4603 			    && p->po_periodic_interval == LACP_SLOW_PERIODIC_TIME) {
4604 				if (if_bond_debug) {
4605 					timestamp_printf("[%s] periodic_transmit:"
4606 					    " Need To Transmit\n",
4607 					    bondport_get_name(p));
4608 				}
4609 				bondport_flags_set_ntt(p);
4610 			}
4611 			p->po_periodic_interval = interval;
4612 			tv.tv_usec = 0;
4613 			tv.tv_sec = interval;
4614 			devtimer_set_relative(p->po_periodic_timer, tv,
4615 			    (devtimer_timeout_func)(void (*)(void))
4616 			    bondport_periodic_transmit_machine,
4617 			    (void *)LAEventTimeout, NULL);
4618 			if (if_bond_debug) {
4619 				timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4620 				    bondport_get_name(p),
4621 				    p->po_periodic_interval);
4622 			}
4623 		}
4624 		break;
4625 	case LAEventTimeout:
4626 		bondport_flags_set_ntt(p);
4627 		tv.tv_sec = p->po_periodic_interval;
4628 		tv.tv_usec = 0;
4629 		devtimer_set_relative(p->po_periodic_timer, tv, (devtimer_timeout_func)(void (*)(void))
4630 		    bondport_periodic_transmit_machine,
4631 		    (void *)LAEventTimeout, NULL);
4632 		if (if_bond_debug > 1) {
4633 			timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4634 			    bondport_get_name(p), p->po_periodic_interval);
4635 		}
4636 		break;
4637 	default:
4638 		break;
4639 	}
4640 	return;
4641 }
4642 
4643 /**
4644 ** Transmit machine
4645 **/
4646 static int
bondport_can_transmit(bondport_ref p,int32_t current_secs,__darwin_time_t * next_secs)4647 bondport_can_transmit(bondport_ref p, int32_t current_secs,
4648     __darwin_time_t * next_secs)
4649 {
4650 	if (p->po_last_transmit_secs != current_secs) {
4651 		p->po_last_transmit_secs = current_secs;
4652 		p->po_n_transmit = 0;
4653 	}
4654 	if (p->po_n_transmit < LACP_PACKET_RATE) {
4655 		p->po_n_transmit++;
4656 		return 1;
4657 	}
4658 	if (next_secs != NULL) {
4659 		*next_secs = current_secs + 1;
4660 	}
4661 	return 0;
4662 }
4663 
4664 static void
bondport_transmit_machine(bondport_ref p,LAEvent event,void * event_data)4665 bondport_transmit_machine(bondport_ref p, LAEvent event,
4666     void * event_data)
4667 {
4668 	lacp_actor_partner_tlv_ref  aptlv;
4669 	lacp_collector_tlv_ref      ctlv;
4670 	struct timeval              next_tick_time = {.tv_sec = 0, .tv_usec = 0};
4671 	lacpdu_ref          out_lacpdu_p;
4672 	packet_buffer_ref           pkt;
4673 	partner_state_ref           ps;
4674 	LAG_info_ref                ps_li;
4675 
4676 	switch (event) {
4677 	case LAEventTimeout:
4678 	case LAEventStart:
4679 		if (p->po_periodic_interval == 0 || bondport_flags_ntt(p) == 0) {
4680 			break;
4681 		}
4682 		if (event_data == TRANSMIT_MACHINE_TX_IMMEDIATE) {
4683 			/* we're going away, transmit the packet no matter what */
4684 		} else if (bondport_can_transmit(p, devtimer_current_secs(),
4685 		    &next_tick_time.tv_sec) == 0) {
4686 			if (devtimer_enabled(p->po_transmit_timer)) {
4687 				if (if_bond_debug > 0) {
4688 					timestamp_printf("[%s] Transmit Timer Already Set\n",
4689 					    bondport_get_name(p));
4690 				}
4691 			} else {
4692 				devtimer_set_absolute(p->po_transmit_timer, next_tick_time,
4693 				    (devtimer_timeout_func)(void (*)(void))
4694 				    bondport_transmit_machine,
4695 				    (void *)LAEventTimeout, NULL);
4696 				if (if_bond_debug > 0) {
4697 					timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4698 					    bondport_get_name(p),
4699 					    (int)next_tick_time.tv_sec);
4700 				}
4701 			}
4702 			break;
4703 		}
4704 		if (if_bond_debug > 0) {
4705 			if (event == LAEventTimeout) {
4706 				timestamp_printf("[%s] Transmit Timer Complete\n",
4707 				    bondport_get_name(p));
4708 			}
4709 		}
4710 		pkt = packet_buffer_allocate(sizeof(*out_lacpdu_p));
4711 		if (pkt == NULL) {
4712 			printf("[%s] Transmit: failed to allocate packet buffer\n",
4713 			    bondport_get_name(p));
4714 			break;
4715 		}
4716 		out_lacpdu_p = (lacpdu_ref)packet_buffer_byteptr(pkt);
4717 		bzero(out_lacpdu_p, sizeof(*out_lacpdu_p));
4718 		out_lacpdu_p->la_subtype = IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP;
4719 		out_lacpdu_p->la_version = LACPDU_VERSION_1;
4720 
4721 		/* Actor */
4722 		aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_actor_tlv;
4723 		aptlv->lap_tlv_type = LACPDU_TLV_TYPE_ACTOR;
4724 		aptlv->lap_length = LACPDU_ACTOR_TLV_LENGTH;
4725 		*((lacp_system_ref)aptlv->lap_system) = g_bond->system;
4726 		lacp_actor_partner_tlv_set_system_priority(aptlv,
4727 		    g_bond->system_priority);
4728 		lacp_actor_partner_tlv_set_port_priority(aptlv, p->po_priority);
4729 		lacp_actor_partner_tlv_set_port(aptlv, bondport_get_index(p));
4730 		lacp_actor_partner_tlv_set_key(aptlv, p->po_bond->ifb_key);
4731 		aptlv->lap_state = p->po_actor_state;
4732 
4733 		/* Partner */
4734 		aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_partner_tlv;
4735 		aptlv->lap_tlv_type = LACPDU_TLV_TYPE_PARTNER;
4736 		aptlv->lap_length = LACPDU_PARTNER_TLV_LENGTH;
4737 		ps = &p->po_partner_state;
4738 		ps_li = &ps->ps_lag_info;
4739 		lacp_actor_partner_tlv_set_port(aptlv, ps->ps_port);
4740 		lacp_actor_partner_tlv_set_port_priority(aptlv, ps->ps_port_priority);
4741 		*((lacp_system_ref)aptlv->lap_system) = ps_li->li_system;
4742 		lacp_actor_partner_tlv_set_system_priority(aptlv,
4743 		    ps_li->li_system_priority);
4744 		lacp_actor_partner_tlv_set_key(aptlv, ps_li->li_key);
4745 		aptlv->lap_state = ps->ps_state;
4746 
4747 		/* Collector */
4748 		ctlv = (lacp_collector_tlv_ref)out_lacpdu_p->la_collector_tlv;
4749 		ctlv->lac_tlv_type = LACPDU_TLV_TYPE_COLLECTOR;
4750 		ctlv->lac_length = LACPDU_COLLECTOR_TLV_LENGTH;
4751 
4752 		bondport_slow_proto_transmit(p, pkt);
4753 		bondport_flags_clear_ntt(p);
4754 		if (if_bond_debug > 0) {
4755 			timestamp_printf("[%s] Transmit Packet %d\n",
4756 			    bondport_get_name(p), p->po_n_transmit);
4757 		}
4758 		break;
4759 	default:
4760 		break;
4761 	}
4762 	return;
4763 }
4764 
4765 /**
4766 ** Mux machine functions
4767 **/
4768 
4769 static void
4770 bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4771     void * event_data);
4772 static void
4773 bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4774     void * event_data);
4775 static void
4776 bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4777     void * event_data);
4778 
4779 static void
4780 bondport_mux_machine_collecting_distributing(bondport_ref p, LAEvent event,
4781     void * event_data);
4782 
4783 static void
bondport_mux_machine(bondport_ref p,LAEvent event,void * event_data)4784 bondport_mux_machine(bondport_ref p, LAEvent event, void * event_data)
4785 {
4786 	switch (p->po_mux_state) {
4787 	case MuxState_none:
4788 		bondport_mux_machine_detached(p, LAEventStart, NULL);
4789 		break;
4790 	case MuxState_DETACHED:
4791 		bondport_mux_machine_detached(p, event, event_data);
4792 		break;
4793 	case MuxState_WAITING:
4794 		bondport_mux_machine_waiting(p, event, event_data);
4795 		break;
4796 	case MuxState_ATTACHED:
4797 		bondport_mux_machine_attached(p, event, event_data);
4798 		break;
4799 	case MuxState_COLLECTING_DISTRIBUTING:
4800 		bondport_mux_machine_collecting_distributing(p, event, event_data);
4801 		break;
4802 	default:
4803 		break;
4804 	}
4805 	return;
4806 }
4807 
4808 static void
bondport_mux_machine_detached(bondport_ref p,LAEvent event,__unused void * event_data)4809 bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4810     __unused void * event_data)
4811 {
4812 	lacp_actor_partner_state    s;
4813 
4814 	switch (event) {
4815 	case LAEventStart:
4816 		devtimer_cancel(p->po_wait_while_timer);
4817 		if (if_bond_debug) {
4818 			timestamp_printf("[%s] Mux DETACHED\n",
4819 			    bondport_get_name(p));
4820 		}
4821 		p->po_mux_state = MuxState_DETACHED;
4822 		bondport_flags_clear_ready(p);
4823 		bondport_DetachMuxFromAggregator(p);
4824 		bondport_disable_distributing(p);
4825 		s = p->po_actor_state;
4826 		s = lacp_actor_partner_state_set_out_of_sync(s);
4827 		s = lacp_actor_partner_state_set_not_collecting(s);
4828 		s = lacp_actor_partner_state_set_not_distributing(s);
4829 		p->po_actor_state = s;
4830 		bondport_flags_set_ntt(p);
4831 		break;
4832 	case LAEventSelectedChange:
4833 	case LAEventPacket:
4834 	case LAEventMediaChange:
4835 		if (p->po_selected == SelectedState_SELECTED
4836 		    || p->po_selected == SelectedState_STANDBY) {
4837 			bondport_mux_machine_waiting(p, LAEventStart, NULL);
4838 		}
4839 		break;
4840 	default:
4841 		break;
4842 	}
4843 	return;
4844 }
4845 
4846 static void
bondport_mux_machine_waiting(bondport_ref p,LAEvent event,__unused void * event_data)4847 bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4848     __unused void * event_data)
4849 {
4850 	struct timeval      tv;
4851 
4852 	switch (event) {
4853 	case LAEventStart:
4854 		devtimer_cancel(p->po_wait_while_timer);
4855 		if (if_bond_debug) {
4856 			timestamp_printf("[%s] Mux WAITING\n",
4857 			    bondport_get_name(p));
4858 		}
4859 		p->po_mux_state = MuxState_WAITING;
4860 		OS_FALLTHROUGH;
4861 	default:
4862 	case LAEventSelectedChange:
4863 		if (p->po_selected == SelectedState_UNSELECTED) {
4864 			bondport_mux_machine_detached(p, LAEventStart, NULL);
4865 			break;
4866 		}
4867 		if (p->po_selected == SelectedState_STANDBY) {
4868 			devtimer_cancel(p->po_wait_while_timer);
4869 			/* wait until state changes to SELECTED */
4870 			if (if_bond_debug) {
4871 				timestamp_printf("[%s] Mux WAITING: Standby\n",
4872 				    bondport_get_name(p));
4873 			}
4874 			break;
4875 		}
4876 		if (bondport_flags_ready(p)) {
4877 			if (if_bond_debug) {
4878 				timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4879 				    bondport_get_name(p));
4880 			}
4881 			break;
4882 		}
4883 		if (devtimer_enabled(p->po_wait_while_timer)) {
4884 			if (if_bond_debug) {
4885 				timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4886 				    bondport_get_name(p));
4887 			}
4888 			break;
4889 		}
4890 		if (ifbond_all_ports_attached(p->po_bond, p)) {
4891 			devtimer_cancel(p->po_wait_while_timer);
4892 			if (if_bond_debug) {
4893 				timestamp_printf("[%s] Mux WAITING: No waiting\n",
4894 				    bondport_get_name(p));
4895 			}
4896 			bondport_flags_set_ready(p);
4897 			goto no_waiting;
4898 		}
4899 		if (if_bond_debug) {
4900 			timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4901 			    bondport_get_name(p));
4902 		}
4903 		tv.tv_sec = LACP_AGGREGATE_WAIT_TIME;
4904 		tv.tv_usec = 0;
4905 		devtimer_set_relative(p->po_wait_while_timer, tv,
4906 		    (devtimer_timeout_func)(void (*)(void))
4907 		    bondport_mux_machine_waiting,
4908 		    (void *)LAEventTimeout, NULL);
4909 		break;
4910 	case LAEventTimeout:
4911 		if (if_bond_debug) {
4912 			timestamp_printf("[%s] Mux WAITING: Ready\n",
4913 			    bondport_get_name(p));
4914 		}
4915 		bondport_flags_set_ready(p);
4916 		break;
4917 	case LAEventReady:
4918 no_waiting:
4919 		if (bondport_flags_ready(p)) {
4920 			if (if_bond_debug) {
4921 				timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4922 				    bondport_get_name(p));
4923 			}
4924 			bondport_mux_machine_attached(p, LAEventStart, NULL);
4925 			break;
4926 		}
4927 		break;
4928 	}
4929 	return;
4930 }
4931 
4932 static void
bondport_mux_machine_attached(bondport_ref p,LAEvent event,__unused void * event_data)4933 bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4934     __unused void * event_data)
4935 {
4936 	lacp_actor_partner_state    s;
4937 
4938 	switch (event) {
4939 	case LAEventStart:
4940 		devtimer_cancel(p->po_wait_while_timer);
4941 		if (if_bond_debug) {
4942 			timestamp_printf("[%s] Mux ATTACHED\n",
4943 			    bondport_get_name(p));
4944 		}
4945 		p->po_mux_state = MuxState_ATTACHED;
4946 		bondport_AttachMuxToAggregator(p);
4947 		s = p->po_actor_state;
4948 		s = lacp_actor_partner_state_set_in_sync(s);
4949 		s = lacp_actor_partner_state_set_not_collecting(s);
4950 		s = lacp_actor_partner_state_set_not_distributing(s);
4951 		bondport_disable_distributing(p);
4952 		p->po_actor_state = s;
4953 		bondport_flags_set_ntt(p);
4954 		OS_FALLTHROUGH;
4955 	default:
4956 		switch (p->po_selected) {
4957 		case SelectedState_SELECTED:
4958 			s = p->po_partner_state.ps_state;
4959 			if (lacp_actor_partner_state_in_sync(s)) {
4960 				bondport_mux_machine_collecting_distributing(p, LAEventStart,
4961 				    NULL);
4962 			}
4963 			break;
4964 		default:
4965 			bondport_mux_machine_detached(p, LAEventStart, NULL);
4966 			break;
4967 		}
4968 		break;
4969 	}
4970 	return;
4971 }
4972 
4973 static void
bondport_mux_machine_collecting_distributing(bondport_ref p,LAEvent event,__unused void * event_data)4974 bondport_mux_machine_collecting_distributing(bondport_ref p,
4975     LAEvent event,
4976     __unused void * event_data)
4977 {
4978 	lacp_actor_partner_state    s;
4979 
4980 	switch (event) {
4981 	case LAEventStart:
4982 		devtimer_cancel(p->po_wait_while_timer);
4983 		if (if_bond_debug) {
4984 			timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4985 			    bondport_get_name(p));
4986 		}
4987 		p->po_mux_state = MuxState_COLLECTING_DISTRIBUTING;
4988 		bondport_enable_distributing(p);
4989 		s = p->po_actor_state;
4990 		s = lacp_actor_partner_state_set_collecting(s);
4991 		s = lacp_actor_partner_state_set_distributing(s);
4992 		p->po_actor_state = s;
4993 		bondport_flags_set_ntt(p);
4994 		OS_FALLTHROUGH;
4995 	default:
4996 		s = p->po_partner_state.ps_state;
4997 		if (lacp_actor_partner_state_in_sync(s) == 0) {
4998 			bondport_mux_machine_attached(p, LAEventStart, NULL);
4999 			break;
5000 		}
5001 		switch (p->po_selected) {
5002 		case SelectedState_UNSELECTED:
5003 		case SelectedState_STANDBY:
5004 			bondport_mux_machine_attached(p, LAEventStart, NULL);
5005 			break;
5006 		default:
5007 			break;
5008 		}
5009 		break;
5010 	}
5011 	return;
5012 }
5013