176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Copyright 2004 Linux Networx */
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef PROTO_LACP
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "nic.h"
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "timer.h"
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DEBUG 0
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Structure definitions originally taken from the linux bond_3ad driver */
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_DST_MAC "\x01\x80\xc2\x00\x00\x02"
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char slow_dest[] = SLOW_DST_MAC;
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_SUBTYPE_LACP 1
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_SUBTYPE_MARKER 2
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_header {
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t subtype;
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct lacp_info {
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t system_priority;
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  system[ETH_ALEN];
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t key;
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t port_priority;
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t port;
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  state;
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  reserved[3];
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED;
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_CMP_LEN (2 + 6 + 2 + 2 + 2)
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_CP_LEN  (2 + 6 + 2 + 2 + 2 + 1)
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_lacp {
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  subtype;		       /* = LACP(= 0x01) */
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  version_number;
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type_actor_info;	       /* = actor information(type/length/value) */
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_TERMINATOR 0
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_ACTOR      1
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_PARTNER    2
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TLV_COLLECTOR  3
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  actor_information_length;     /* = 20 */
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct lacp_info actor;
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type_partner_info;        /* = partner information */
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  partner_information_length;   /* = 20 */
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct lacp_info partner;
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type_collector_info;      /* = collector information */
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  collector_information_length; /* = 16 */
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t collector_max_delay;
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  reserved_12[12];
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type_terminator;	       /* = terminator */
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  terminator_length;	       /* = 0 */
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  reserved_50[50];	       /* = 0 */
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct slow_marker {
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  subtype;                      /* = 0x02  (marker PDU) */
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  version_number;	       /* = 0x01 */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type;
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_TERMINATOR 0                /* marker terminator */
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_INFO       1	               /* marker information */
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARKER_TLV_RESPONSE   2	               /* marker response information */
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  marker_length;                /* = 0x16 */
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t requester_port;	       /* The number assigned to the port by the requester */
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  requester_system[ETH_ALEN];   /* The requester's system id */
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t requester_transaction_id;     /* The transaction id allocated by the requester, */
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t pad;		               /* = 0 */
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  tlv_type_terminator;	       /* = 0x00 */
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  terminator_length;	       /* = 0x00 */
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint8_t  reserved_90[90];	       /* = 0 */
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} PACKED;
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanunion slow_union {
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct slow_header header;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct slow_lacp lacp;
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct slow_marker marker;
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define FAST_PERIODIC_TIME   (1*TICKS_PER_SEC)
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SLOW_PERIODIC_TIME   (30*TICKS_PER_SEC)
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SHORT_TIMEOUT_TIME   (3*FAST_PERIODIC_TIME)
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LONG_TIMEOUT_TIME    (3*SLOW_PERIODIC_TIME)
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define CHURN_DETECTION_TIME (60*TICKS_PER_SEC)
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define AGGREGATE_WAIT_TIME  (2*TICKS_PER_SEC)
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_ACTIVITY        (1 << 0)
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_TIMEOUT         (1 << 1)
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_AGGREGATION     (1 << 2)
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_SYNCHRONIZATION (1 << 3)
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_COLLECTING      (1 << 4)
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DISTRIBUTING    (1 << 5)
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_DEFAULTED       (1 << 6)
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_EXPIRED         (1 << 7)
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UNSELECTED 0
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define STANDBY    1
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define SELECTED   2
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct lacp_state {
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct slow_lacp pkt;
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned long current_while_timer; /* Time when the LACP information expires */
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned long periodic_timer; /* Time when I need to send my partner an update */
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct lacp_state lacp;
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 0
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void print_lacp_state(uint8_t state)
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("%hhx", state);
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_ACTIVITY) {
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Activity");
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_TIMEOUT) {
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Timeout");
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_AGGREGATION) {
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Aggregation");
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_SYNCHRONIZATION) {
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Syncronization");
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_COLLECTING) {
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Collecting");
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_DISTRIBUTING) {
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Distributing");
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_DEFAULTED) {
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Defaulted");
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (state & LACP_EXPIRED) {
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf(" Expired");
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\n");
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void print_lacpdu(struct slow_lacp *pkt)
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("subtype version:  %hhx %hhx\n",
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->subtype, pkt->version_number);
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("actor_tlv %hhx", pkt->tlv_type_actor_info);
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" len: %hhx (\n", pkt->actor_information_length);
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" sys_pri: %hx", ntohs(pkt->actor.system_priority));
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" mac: %!", pkt->actor.system);
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" key: %hx", ntohs(pkt->actor.key));
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" port_pri: %hx", ntohs(pkt->actor.port_priority));
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" port: %hx\n", ntohs(pkt->actor.port));
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" state: ");
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	print_lacp_state(pkt->actor.state);
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" reserved:     %hhx %hhx %hhx\n",
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->actor.reserved[0], pkt->actor.reserved[1], pkt->actor.reserved[2]);
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(")\n");
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("partner_tlv: %hhx", pkt->tlv_type_partner_info);
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" len: %hhx (\n", pkt->partner_information_length);
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" sys_pri: %hx", ntohs(pkt->partner.system_priority));
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" mac: %!", pkt->partner.system);
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" key: %hx", ntohs(pkt->partner.key));
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" port_pri: %hx", ntohs(pkt->partner.port_priority));
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" port: %hx\n", ntohs(pkt->partner.port));
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" state: ");
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	print_lacp_state(pkt->partner.state);
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" reserved:     %hhx %hhx %hhx\n",
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->partner.reserved[0], pkt->partner.reserved[1], pkt->partner.reserved[2]);
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(")\n");
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("collector_tlv: %hhx ", pkt->tlv_type_collector_info);
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" len: %hhx (", pkt->collector_information_length);
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" max_delay: %hx", ntohs(pkt->collector_max_delay));
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LACP_DEBUG > 1
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("reserved_12:      %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->reserved_12[0], pkt->reserved_12[1], pkt->reserved_12[2],
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->reserved_12[3], pkt->reserved_12[4], pkt->reserved_12[5],
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->reserved_12[6], pkt->reserved_12[7], pkt->reserved_12[8],
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->reserved_12[9], pkt->reserved_12[10], pkt->reserved_12[11]);
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" )\n");
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("terminator_tlv: %hhx", pkt->tlv_type_terminator);
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" len: %hhx ()\n", pkt->terminator_length);
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline unsigned long lacp_timer_val(unsigned long now, unsigned long when)
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return when?(when - now)/TICKS_PER_SEC : 0;
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void print_lacp(const char *which, struct slow_lacp *pkt, unsigned long now)
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("%s\n", which);
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	print_lacpdu(pkt);
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("timers: c %ds p %ds\n",
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_timer_val(now, lacp.current_while_timer),
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_timer_val(now, lacp.periodic_timer)
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		);
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\n");
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LACP_DEBUG */
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define print_lacp(which, pkt, now) do {} while(0)
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LACP_DEBUG */
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void lacp_init_state(const uint8_t *mac)
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(&lacp, 0, sizeof(lacp));
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Initialize the packet constants */
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.subtype               = 1;
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.version_number        = 1;
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* The default state of my interface */
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.tlv_type_actor_info      = LACP_TLV_ACTOR;
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor_information_length = 0x14;
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.system_priority    = htons(1);
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(lacp.pkt.actor.system, mac, ETH_ALEN);
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.key                = htons(1);
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.port               = htons(1);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.port_priority      = htons(1);
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.state =
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_SYNCHRONIZATION |
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_COLLECTING      |
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_DISTRIBUTING    |
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_DEFAULTED;
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Set my partner defaults */
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.tlv_type_partner_info      = LACP_TLV_PARTNER;
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner_information_length = 0x14;
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.system_priority    = htons(1);
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* memset(lacp.pkt.parnter_system, 0, ETH_ALEN); */
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.key                = htons(1);
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.port               = htons(1);
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.port_priority      = htons(1);
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.state =
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_ACTIVITY        |
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_SYNCHRONIZATION |
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_COLLECTING      |
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_DISTRIBUTING    |
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		LACP_DEFAULTED;
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.tlv_type_collector_info      = LACP_TLV_COLLECTOR;
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.collector_information_length = 0x10;
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.collector_max_delay          = htons(0x8000); /* ???? */
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.tlv_type_terminator          = LACP_TLV_TERMINATOR;
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.terminator_length            = 0;
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define LACP_NTT_MASK (LACP_ACTIVITY | LACP_TIMEOUT | \
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	LACP_SYNCHRONIZATION | LACP_AGGREGATION)
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int lacp_update_ntt(struct slow_lacp *pkt)
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int ntt = 0;
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) != 0) ||
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		((pkt->partner.state & LACP_NTT_MASK) !=
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(lacp.pkt.actor.state & LACP_NTT_MASK)))
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ntt = 1;
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ntt;
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_record_pdu(struct slow_lacp *pkt)
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(&lacp.pkt.partner, &pkt->actor, LACP_CP_LEN);
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.state &= ~LACP_DEFAULTED;
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((memcmp(&pkt->partner, &lacp.pkt.actor, LACP_CMP_LEN) == 0) &&
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		((pkt->partner.state & LACP_AGGREGATION) ==
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(lacp.pkt.actor.state & LACP_AGGREGATION)))
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp.pkt.partner.state  |= LACP_SYNCHRONIZATION;
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!(pkt->actor.state & LACP_AGGREGATION)) {
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp.pkt.partner.state |= LACP_SYNCHRONIZATION;
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* ACTIVITY? */
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int lacp_timer_expired(unsigned long now, unsigned long when)
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return when && (now > when);
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_start_periodic_timer(unsigned long now)
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((lacp.pkt.partner.state & LACP_ACTIVITY) ||
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(lacp.pkt.actor.state & LACP_ACTIVITY)) {
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp.periodic_timer = now +
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			(((lacp.pkt.partner.state & LACP_TIMEOUT)?
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				FAST_PERIODIC_TIME : SLOW_PERIODIC_TIME));
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void lacp_start_current_while_timer(unsigned long now)
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.current_while_timer = now +
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		((lacp.pkt.actor.state & LACP_TIMEOUT) ?
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		SHORT_TIMEOUT_TIME : LONG_TIMEOUT_TIME);
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	lacp.pkt.actor.state &= ~LACP_EXPIRED;
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void send_lacp_reports(unsigned long now, int ntt)
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_init_state(nic.node_addr);
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If the remote information has expired I need to take action */
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (lacp_timer_expired(now, lacp.current_while_timer)) {
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!(lacp.pkt.actor.state & LACP_EXPIRED)) {
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp.pkt.partner.state &= ~LACP_SYNCHRONIZATION;
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp.pkt.partner.state |= LACP_TIMEOUT;
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp.pkt.actor.state |= LACP_EXPIRED;
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp.current_while_timer = now + SHORT_TIMEOUT_TIME;
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			ntt = 1;
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		else {
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp_init_state(nic.node_addr);
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If the periodic timer has expired I need to transmit */
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (lacp_timer_expired(now, lacp.periodic_timer)) {
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ntt = 1;
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Reset by lacp_start_periodic_timer */
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ntt) {
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		eth_transmit(slow_dest, ETH_P_SLOW, sizeof(lacp.pkt), &lacp.pkt);
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Restart the periodic timer */
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_start_periodic_timer(now);
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		print_lacp("Trasmitted", &lacp.pkt, now);
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void send_eth_slow_reports(unsigned long now)
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	send_lacp_reports(now, 0);
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void process_eth_slow(unsigned short ptype, unsigned long now)
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	union slow_union *pkt;
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((ptype != ETH_P_SLOW) ||
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(nic.packetlen < (ETH_HLEN + sizeof(pkt->header)))) {
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pkt = (union slow_union *)&nic.packet[ETH_HLEN];
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((pkt->header.subtype == SLOW_SUBTYPE_LACP) &&
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(nic.packetlen >= ETH_HLEN + sizeof(pkt->lacp))) {
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int ntt;
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (memcmp(nic.node_addr, lacp.pkt.actor.system, ETH_ALEN) != 0) {
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			lacp_init_state(nic.node_addr);
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* As long as nic.packet is 2 byte aligned all is good */
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		print_lacp("Received", &pkt->lacp, now);
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* I don't actually implement the MUX or SELECT
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * machines.
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 *
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * What logically happens when the client and I
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * disagree about an aggregator is the current
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * aggregtator is unselected.  The MUX machine places
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * me in DETACHED.  The SELECT machine runs and
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * reslects the same aggregator.  If I go through
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * these steps fast enough an outside observer can not
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * notice this.
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 *
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * Since the process will not generate any noticeable
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * effect it does not need an implmenetation.  This
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * keeps the code simple and the code and binary
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * size down.
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* lacp_update_selected(&pkt->lacp); */
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ntt = lacp_update_ntt(&pkt->lacp);
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_record_pdu(&pkt->lacp);
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		lacp_start_current_while_timer(now);
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		send_lacp_reports(now, ntt);
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If we receive a marker information packet return it */
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if ((pkt->header.subtype == SLOW_SUBTYPE_MARKER) &&
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(nic.packetlen >= ETH_HLEN + sizeof(pkt->marker)) &&
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(pkt->marker.tlv_type == MARKER_TLV_INFO) &&
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(pkt->marker.marker_length == 0x16))
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pkt->marker.tlv_type = MARKER_TLV_RESPONSE;
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		eth_transmit(slow_dest, ETH_P_SLOW,
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			sizeof(pkt->marker), &pkt->marker);
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman }
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define send_eth_slow_reports(now)    do {} while(0)
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define process_eth_slow(ptype, now)  do {} while(0)
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
407