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