diff --git a/AUTHORS b/AUTHORS index 8f57d0764f..05379adb19 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1248,6 +1248,10 @@ Loic Tortay { AFS fix } +Steve Housley { + 802.3ad LACP support +} + Alain Magloire was kind enough to give his permission to use his version of snprintf.c. diff --git a/Makefile.am b/Makefile.am index 95eb8e2184..aa3be4f863 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ # Makefile.am # Automake file for Ethereal # -# $Id: Makefile.am,v 1.440 2002/06/07 21:11:22 guy Exp $ +# $Id: Makefile.am,v 1.441 2002/06/13 07:18:47 guy Exp $ # # Ethereal - Network traffic analyzer # By Gerald Combs @@ -275,6 +275,7 @@ DISSECTOR_SRC = \ packet-skinny.c \ packet-slimp3.c \ packet-sll.c \ + packet-slowprotocols.c \ packet-smb.c \ packet-smb-browse.c \ packet-smb-common.c \ diff --git a/Makefile.nmake b/Makefile.nmake index 81ff811a1f..ee72cd6add 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,7 +1,7 @@ ## Makefile for building ethereal.exe with Microsoft C and nmake ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake # -# $Id: Makefile.nmake,v 1.193 2002/06/02 12:32:10 sahlberg Exp $ +# $Id: Makefile.nmake,v 1.194 2002/06/13 07:18:47 guy Exp $ include config.nmake include @@ -216,6 +216,7 @@ DISSECTOR_SRC = \ packet-skinny.c \ packet-slimp3.c \ packet-sll.c \ + packet-slowprotocols.c \ packet-smb.c \ packet-smb-browse.c \ packet-smb-common.c \ diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template index 9393be9086..f7024263e0 100644 --- a/doc/ethereal.pod.template +++ b/doc/ethereal.pod.template @@ -1447,6 +1447,7 @@ B. Martin Gignac John Wells Loic Tortay + Steve Housley Alain Magloire was kind enough to give his permission to use his version of snprintf.c. diff --git a/etypes.h b/etypes.h index a1621b28af..fa2fd9f13f 100644 --- a/etypes.h +++ b/etypes.h @@ -1,12 +1,11 @@ /* etypes.h * Defines ethernet packet types, similar to tcpdump's ethertype.h * - * $Id: etypes.h,v 1.24 2002/03/23 22:02:20 guy Exp $ + * $Id: etypes.h,v 1.25 2002/06/13 07:18:47 guy Exp $ * * Ethereal - Network traffic analyzer - * By Gerald Combs + * By Gerald Combs * Copyright 1998 Gerald Combs - * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -152,6 +151,10 @@ #define ETHERTYPE_IPv6 0x86dd #endif +#ifndef ETHERTYPE_SLOW_PROTOCOLS +#define ETHERTYPE_SLOW_PROTOCOLS 0x8809 +#endif + #ifndef ETHERTYPE_PPP #define ETHERTYPE_PPP 0x880b /* no, this is not PPPoE */ #endif diff --git a/packet-ethertype.c b/packet-ethertype.c index 349d942aed..2ee8b8a10c 100644 --- a/packet-ethertype.c +++ b/packet-ethertype.c @@ -1,7 +1,7 @@ /* ethertype.c * Routines for calling the right protocol for the ethertype. * - * $Id: packet-ethertype.c,v 1.28 2002/04/24 06:03:33 guy Exp $ + * $Id: packet-ethertype.c,v 1.29 2002/06/13 07:18:47 guy Exp $ * * Gilbert Ramirez * @@ -77,6 +77,7 @@ const value_string etype_vals[] = { {ETHERTYPE_DEC_SCA, "DEC LAVC/SCA" }, {ETHERTYPE_ETHBRIDGE, "Transparent Ethernet bridging" }, {ETHERTYPE_CGMP, "Cisco Group Management Protocol" }, + {ETHERTYPE_SLOW_PROTOCOLS, "Slow Protocols" }, /* * NDISWAN on Windows translates Ethernet frames from higher-level diff --git a/packet-slowprotocols.c b/packet-slowprotocols.c new file mode 100644 index 0000000000..97b594febe --- /dev/null +++ b/packet-slowprotocols.c @@ -0,0 +1,827 @@ +/* packet-slowprotocols.c + * Routines for EtherType (0x8809) Slow Protocols disassembly. + * + * $Id: packet-slowprotocols.c,v 1.1 2002/06/13 07:18:47 guy Exp $ + * + * Copyright 2002 Steve Housley + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + /* *** WARNING!! *** Only a dissector for LACPDU (Link Aggregation Control + * Protocol Data Unit) disassembly has currently been implemented. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include +#include +#include +#include "etypes.h" +#include "llcsaps.h" +#include "ppptypes.h" +#include + +/* Offsets of fields within a LACPDU */ + +#define LACPDU_SUBTYPE 0 +#define LACPDU_VERSION_NUMBER 1 + +#define LACPDU_ACTOR_TYPE 2 +#define LACPDU_ACTOR_INFO_LEN 3 +#define LACPDU_ACTOR_SYS_PRIORITY 4 +#define LACPDU_ACTOR_SYSTEM 6 +#define LACPDU_ACTOR_KEY 12 +#define LACPDU_ACTOR_PORT_PRIORITY 14 +#define LACPDU_ACTOR_PORT 16 +#define LACPDU_ACTOR_STATE 18 +#define LACPDU_ACTOR_RESERVED 19 + +#define LACPDU_PARTNER_TYPE 22 +#define LACPDU_PARTNER_INFO_LEN 23 +#define LACPDU_PARTNER_SYS_PRIORITY 24 +#define LACPDU_PARTNER_SYSTEM 26 +#define LACPDU_PARTNER_KEY 32 +#define LACPDU_PARTNER_PORT_PRIORITY 34 +#define LACPDU_PARTNER_PORT 36 +#define LACPDU_PARTNER_STATE 38 +#define LACPDU_PARTNER_RESERVED 39 + +#define LACPDU_COLL_TYPE 42 +#define LACPDU_COLL_INFO_LEN 43 +#define LACPDU_COLL_MAX_DELAY 44 +#define LACPDU_COLL_RESERVED 46 + +#define LACPDU_TERM_TYPE 58 +#define LACPDU_TERM_LEN 59 +#define LACPDU_TERM_RESERVED 60 + +/* Actor and Partner Flag bits */ + +#define LACPDU_FLAGS_ACTIVITY 0x01 +#define LACPDU_FLAGS_TIMEOUT 0x02 +#define LACPDU_FLAGS_AGGREGATION 0x04 +#define LACPDU_FLAGS_SYNC 0x08 +#define LACPDU_FLAGS_COLLECTING 0x10 +#define LACPDU_FLAGS_DISTRIB 0x20 +#define LACPDU_FLAGS_DEFAULTED 0x40 +#define LACPDU_FLAGS_EXPIRED 0x80 + +/* Initialise the protocol and registered fields */ + +static int proto_lacpdu = -1; + +static int hf_lacpdu_subtype = -1; +static int hf_lacpdu_version_number = -1; + +static int hf_lacpdu_actor_type = -1; +static int hf_lacpdu_actor_info_len = -1; +static int hf_lacpdu_actor_sys_priority = -1; +static int hf_lacpdu_actor_sys = -1; +static int hf_lacpdu_actor_key = -1; +static int hf_lacpdu_actor_port_priority = -1; +static int hf_lacpdu_actor_port = -1; +static int hf_lacpdu_actor_state = -1; +static int hf_lacpdu_flags_a_activity = -1; +static int hf_lacpdu_flags_a_timeout = -1; +static int hf_lacpdu_flags_a_aggregation = -1; +static int hf_lacpdu_flags_a_sync = -1; +static int hf_lacpdu_flags_a_collecting = -1; +static int hf_lacpdu_flags_a_distrib = -1; +static int hf_lacpdu_flags_a_defaulted = -1; +static int hf_lacpdu_flags_a_expired = -1; +static int hf_lacpdu_actor_reserved = -1; + +static int hf_lacpdu_partner_type = -1; +static int hf_lacpdu_partner_info_len = -1; +static int hf_lacpdu_partner_sys_priority = -1; +static int hf_lacpdu_partner_sys = -1; +static int hf_lacpdu_partner_key = -1; +static int hf_lacpdu_partner_port_priority = -1; +static int hf_lacpdu_partner_port = -1; +static int hf_lacpdu_partner_state = -1; +static int hf_lacpdu_flags_p_activity = -1; +static int hf_lacpdu_flags_p_timeout = -1; +static int hf_lacpdu_flags_p_aggregation = -1; +static int hf_lacpdu_flags_p_sync = -1; +static int hf_lacpdu_flags_p_collecting = -1; +static int hf_lacpdu_flags_p_distrib = -1; +static int hf_lacpdu_flags_p_defaulted = -1; +static int hf_lacpdu_flags_p_expired = -1; +static int hf_lacpdu_partner_reserved = -1; + +static int hf_lacpdu_coll_type = -1; +static int hf_lacpdu_coll_info_len = -1; +static int hf_lacpdu_coll_max_delay = -1; +static int hf_lacpdu_coll_reserved = -1; + +static int hf_lacpdu_term_type = -1; +static int hf_lacpdu_term_len = -1; +static int hf_lacpdu_term_reserved = -1; + +/* Initialise the subtree pointers */ + +static gint ett_lacpdu = -1; +static gint ett_lacpdu_a_flags = -1; +static gint ett_lacpdu_p_flags = -1; + +/* General declarations and macros */ + +#define LACP_SUBTYPE 0x1 + +static const char initial_sep[] = " ("; +static const char cont_sep[] = ", "; + +#define APPEND_BOOLEAN_FLAG(flag, item, string) \ + if(flag){ \ + if(item) \ + proto_item_append_text(item, string, sep); \ + sep = cont_sep; \ + } + +/* Code to actually dissect the LACPDU packets */ +static void +dissect_lacpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint16 raw_word; + guint8 raw_octet; + + guint8 flags; + + const guint8 *a_sys; + const guint8 *p_sys; + const guint8 *resv_bytes; + + proto_tree *lacpdu_tree; + proto_item *lacpdu_item; + proto_tree *actor_flags_tree; + proto_item *actor_flags_item; + proto_tree *partner_flags_tree; + proto_item *partner_flags_item; + + + const char *sep; + + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LACP"); /* LACP Protocol */ + } + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_clear(pinfo->cinfo, COL_INFO); + } + + if (tree) + { + /* Add LACP Heading */ + lacpdu_item = proto_tree_add_protocol_format(tree, proto_lacpdu, tvb, + 0, -1, "Link Aggregation Control Protocol"); + lacpdu_tree = proto_item_add_subtree(lacpdu_item, ett_lacpdu); + + /* Version Number */ + raw_octet = tvb_get_guint8(tvb, LACPDU_VERSION_NUMBER); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_version_number, tvb, + LACPDU_VERSION_NUMBER, 1, raw_octet); + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "Version %d. ", raw_octet); + } + + /* Actor Type */ + raw_octet = tvb_get_guint8(tvb, LACPDU_ACTOR_TYPE); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_type, tvb, + LACPDU_ACTOR_TYPE, 1, raw_octet); + + /* Actor Info Length */ + raw_octet = tvb_get_guint8(tvb, LACPDU_ACTOR_INFO_LEN); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_info_len, tvb, + LACPDU_ACTOR_INFO_LEN, 1, raw_octet); + + /* Actor System Priority */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_ACTOR_SYS_PRIORITY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_sys_priority, tvb, + LACPDU_ACTOR_SYS_PRIORITY, 2, raw_word); + /* Actor System */ + + a_sys = tvb_get_ptr(tvb, LACPDU_ACTOR_SYSTEM , 6); + proto_tree_add_ether(lacpdu_tree, hf_lacpdu_actor_sys, tvb, + LACPDU_ACTOR_SYSTEM, 6, a_sys); + + /* Actor Key */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_ACTOR_KEY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_key, tvb, + LACPDU_ACTOR_KEY, 2, raw_word); + + /* Actor Port Priority */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_ACTOR_PORT_PRIORITY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_port_priority, tvb, + LACPDU_ACTOR_PORT_PRIORITY, 2, raw_word); + + /* Actor Port */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_ACTOR_PORT); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_port, tvb, + LACPDU_ACTOR_PORT, 2, raw_word); + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "Actor Port = %d ", raw_word); + } + + /* Actor State */ + + flags = tvb_get_guint8(tvb, LACPDU_ACTOR_STATE); + actor_flags_item = proto_tree_add_uint(lacpdu_tree, hf_lacpdu_actor_state, tvb, + LACPDU_ACTOR_STATE, 1, flags); + actor_flags_tree = proto_item_add_subtree(actor_flags_item, ett_lacpdu_a_flags); + + sep = initial_sep; + + /* Activity Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_ACTIVITY, actor_flags_item, + "%sActivity"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_activity, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Timeout Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_TIMEOUT, actor_flags_item, + "%sTimeout"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_timeout, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Aggregation Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_AGGREGATION, actor_flags_item, + "%sAggregation"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_aggregation, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Synchronization Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_SYNC, actor_flags_item, + "%sSynchronization"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_sync, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Collecting Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_COLLECTING, actor_flags_item, + "%sCollecting"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_collecting, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + + /* Distributing Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_DISTRIB, actor_flags_item, + "%sDistributing"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_distrib, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Defaulted Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_DEFAULTED, actor_flags_item, + "%sDefaulted"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_defaulted, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + /* Expired Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_EXPIRED, actor_flags_item, + "%sExpired"); + proto_tree_add_boolean(actor_flags_tree, hf_lacpdu_flags_a_expired, tvb, + LACPDU_ACTOR_STATE, 1, flags); + + sep = cont_sep; + if (sep != initial_sep) + { + /* We put something in; put in the terminating ")" */ + proto_item_append_text(actor_flags_item, ")"); + } + + /* Actor Reserved */ + + resv_bytes = tvb_get_ptr(tvb, LACPDU_ACTOR_RESERVED, 3); + proto_tree_add_bytes(lacpdu_tree, hf_lacpdu_actor_reserved, tvb, + LACPDU_ACTOR_RESERVED, 3, resv_bytes); + + + /* Partner Type */ + raw_octet = tvb_get_guint8(tvb, LACPDU_PARTNER_TYPE); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_type, tvb, + LACPDU_PARTNER_TYPE, 1, raw_octet); + + /* Partner Info Length */ + raw_octet = tvb_get_guint8(tvb, LACPDU_PARTNER_INFO_LEN); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_info_len, tvb, + LACPDU_PARTNER_INFO_LEN, 1, raw_octet); + + /* Partner System Priority */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_PARTNER_SYS_PRIORITY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_sys_priority, tvb, + LACPDU_PARTNER_SYS_PRIORITY, 2, raw_word); + + /* Partner System */ + + p_sys = tvb_get_ptr(tvb, LACPDU_PARTNER_SYSTEM, 6); + proto_tree_add_ether(lacpdu_tree, hf_lacpdu_partner_sys, tvb, + LACPDU_PARTNER_SYSTEM, 6, p_sys); + + /* Partner Key */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_PARTNER_KEY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_key, tvb, + LACPDU_PARTNER_KEY, 2, raw_word); + + /* Partner Port Priority */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_PARTNER_PORT_PRIORITY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_port_priority, tvb, + LACPDU_PARTNER_PORT_PRIORITY, 2, raw_word); + + /* Partner Port */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_PARTNER_PORT); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_port, tvb, + LACPDU_PARTNER_PORT, 2, raw_word); + + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_append_fstr(pinfo->cinfo, COL_INFO, "Partner Port = %d ", raw_word); + } + + /* Partner State */ + + flags = tvb_get_guint8(tvb, LACPDU_PARTNER_STATE); + partner_flags_item = proto_tree_add_uint(lacpdu_tree, hf_lacpdu_partner_state, tvb, + LACPDU_PARTNER_STATE, 1, flags); + partner_flags_tree = proto_item_add_subtree(partner_flags_item, ett_lacpdu_p_flags); + + sep = initial_sep; + + /* Activity Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_ACTIVITY, partner_flags_item, + "%sActivity"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_activity, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Timeout Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_TIMEOUT, partner_flags_item, + "%sTimeout"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_timeout, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Aggregation Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_AGGREGATION, partner_flags_item, + "%sAggregation"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_aggregation, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Synchronization Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_SYNC, partner_flags_item, + "%sSynchronization"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_sync, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Collecting Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_COLLECTING, partner_flags_item, + "%sCollecting"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_collecting, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + + /* Distributing Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_DISTRIB, partner_flags_item, + "%sDistributing"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_distrib, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Defaulted Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_DEFAULTED, partner_flags_item, + "%sDefaulted"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_defaulted, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + /* Expired Flag */ + + APPEND_BOOLEAN_FLAG(flags & LACPDU_FLAGS_EXPIRED, partner_flags_item, + "%sExpired"); + proto_tree_add_boolean(partner_flags_tree, hf_lacpdu_flags_p_expired, tvb, + LACPDU_PARTNER_STATE, 1, flags); + + sep = cont_sep; + if (sep != initial_sep) + { + /* We put something in; put in the terminating ")" */ + proto_item_append_text(partner_flags_item, ")"); + } + + /* Partner Reserved */ + + resv_bytes = tvb_get_ptr(tvb, LACPDU_PARTNER_RESERVED, 3); + proto_tree_add_bytes(lacpdu_tree, hf_lacpdu_partner_reserved, tvb, + LACPDU_PARTNER_RESERVED, 3, resv_bytes); + + + /* Collector Type */ + raw_octet = tvb_get_guint8(tvb, LACPDU_COLL_TYPE); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_coll_type, tvb, + LACPDU_COLL_TYPE, 1, raw_octet); + + /* Collector Info Length */ + raw_octet = tvb_get_guint8(tvb, LACPDU_COLL_INFO_LEN); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_coll_info_len, tvb, + LACPDU_COLL_INFO_LEN, 1, raw_octet); + + /* Collector Max Delay */ + + raw_word = tvb_get_ntohs(tvb, LACPDU_COLL_MAX_DELAY); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_coll_max_delay, tvb, + LACPDU_COLL_MAX_DELAY, 2, raw_word); + + /* Collector Reserved */ + + resv_bytes = tvb_get_ptr(tvb, LACPDU_COLL_RESERVED, 12); + proto_tree_add_bytes(lacpdu_tree, hf_lacpdu_coll_reserved, tvb, + LACPDU_COLL_RESERVED, 12, resv_bytes); + + /* Terminator Type */ + raw_octet = tvb_get_guint8(tvb, LACPDU_TERM_TYPE); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_term_type, tvb, + LACPDU_TERM_TYPE, 1, raw_octet); + + /* Terminator Info Length */ + raw_octet = tvb_get_guint8(tvb, LACPDU_TERM_LEN); + proto_tree_add_uint(lacpdu_tree, hf_lacpdu_term_len, tvb, + LACPDU_TERM_LEN, 1, raw_octet); + + /* Terminator Reserved */ + + resv_bytes = tvb_get_ptr(tvb, LACPDU_TERM_RESERVED, 50); + proto_tree_add_bytes(lacpdu_tree, hf_lacpdu_term_reserved, tvb, + LACPDU_TERM_RESERVED, 50, resv_bytes); + } +} + + +/* Code to dissect the Slow Protocol packets */ +static void +dissect_slow_protocols(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint8 raw_octet; + + if (tree) + { + + /* Get the Slow Protocol Subtype value */ + raw_octet = tvb_get_guint8(tvb, LACPDU_SUBTYPE); + + if (raw_octet != LACP_SUBTYPE) + { + /* This is not a LACPDU. Do not disassemble. */ + /* Requires implementation at a later date. */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Slow Protocols"); /* Slow Protocols */ + } + + /* Display the subtype value to aid the user. */ + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_add_fstr(pinfo->cinfo, COL_INFO, "Subtype = %u.", raw_octet); + } + return; + } + } + + /* This is a LACPDU so decode it! */ + dissect_lacpdu(tvb, pinfo, tree); +} + + + +/* Register the protocol with Ethereal */ + +static const value_string subtype_vals[] = { + { 1, "LACP" }, + { 2, "Marker Protocol" }, + { 0, NULL } +}; + +static const true_false_string yesno = { + "Yes", + "No" +}; + +void +proto_register_lacpdu(void) +{ +/* Setup list of header fields */ + + static hf_register_info hf[] = { + + { &hf_lacpdu_subtype, + { "Subtype", "lacp.subtype", + FT_UINT8, BASE_HEX, VALS(subtype_vals), 0x0, + "The specific Slow Protocol being used", HFILL }}, + + { &hf_lacpdu_version_number, + { "LACP Version Number", "lacp.version", + FT_UINT8, BASE_HEX, NULL, 0x0, + "Identifies the LACP version", HFILL }}, + + { &hf_lacpdu_actor_type, + { "Actor Information", "lacp.actorInfo", + FT_UINT8, BASE_HEX, NULL, 0x0, + "TLV type = Actor", HFILL }}, + + { &hf_lacpdu_actor_info_len, + { "Actor Information Length", "lacp.actorInfoLen", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The length of the Actor TLV", HFILL }}, + + { &hf_lacpdu_actor_sys_priority, + { "Actor System Priority", "lacp.actorSysPriority", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The priority assigned to this System by management or admin", HFILL }}, + + { &hf_lacpdu_actor_sys, + { "Actor System", "lacp.actorSystem", + FT_ETHER, BASE_NONE, NULL, 0x0, + "The Actor's System ID encoded as a MAC address", HFILL }}, + + { &hf_lacpdu_actor_key, + { "Actor Key", "lacp.actorKey", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The operational Key value assigned to the port by the Actor", HFILL }}, + + { &hf_lacpdu_actor_port_priority, + { "Actor Port Priority", "lacp.actorPortPriority", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The priority assigned to the port by the Actor (via Management or Admin)", HFILL }}, + + { &hf_lacpdu_actor_port, + { "Actor Port", "lacp.actorPort", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The port number assigned to the port by the Actor (via Management or Admin)", HFILL }}, + + { &hf_lacpdu_actor_state, + { "Actor State", "lacp.actorState", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The Actor's state variables for the port, encoded as bits within a single octet", HFILL }}, + + { &hf_lacpdu_flags_a_activity, + { "LACP Activity", "lacp.actorState.activity", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_ACTIVITY, + "Activity control value for this link. Active = 1, Passive = 0", HFILL }}, + + { &hf_lacpdu_flags_a_timeout, + { "LACP Timeout", "lacp.actorState.timeout", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_TIMEOUT, + "Timeout control value for this link. Short Timeout = 1, Long Timeout = 0", HFILL }}, + + + { &hf_lacpdu_flags_a_aggregation, + { "Aggregation", "lacp.actorState.aggregation", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_AGGREGATION, + "Aggregatable = 1, Individual = 0", HFILL }}, + + + { &hf_lacpdu_flags_a_sync, + { "Synchronization", "lacp.actorState.synchronization", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_SYNC, + "In Sync = 1, Out of Sync = 0", HFILL }}, + + + { &hf_lacpdu_flags_a_collecting, + { "Collecting", "lacp.actorState.collecting", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_COLLECTING, + "Collection of incoming frames is: Enabled = 1, Disabled = 0", HFILL }}, + + + { &hf_lacpdu_flags_a_distrib, + { "Distributing", "lacp.actorState.distributing", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_DISTRIB, + "Distribution of outgoing frames is: Enabled = 1, Disabled = 0", HFILL }}, + + + + { &hf_lacpdu_flags_a_defaulted, + { "Defaulted", "lacp.actorState.defaulted", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_DEFAULTED, + "1 = Actor Rx machine is using DEFAULT Partner info, 0 = using info in Rx'd LACPDU"}}, + + + { &hf_lacpdu_flags_a_expired, + { "Expired", "lacp.actorState.expired", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_EXPIRED, + "1 = Actor Rx machine is EXPIRED, 0 = is NOT EXPIRED", HFILL }}, + + + { &hf_lacpdu_actor_reserved, + { "Reserved", "lacp.reserved", + FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + { &hf_lacpdu_partner_type, + { "Partner Information", "lacp.partnerInfo", + FT_UINT8, BASE_HEX, NULL, 0x0, + "TLV type = Partner", HFILL }}, + + { &hf_lacpdu_partner_info_len, + { "Partner Information Length", "lacp.partnerInfoLen", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The length of the Partner TLV", HFILL }}, + + { &hf_lacpdu_partner_sys_priority, + { "Partner System Priority", "lacp.partnerSysPriority", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The priority assigned to the Partner System by management or admin", HFILL }}, + + { &hf_lacpdu_partner_sys, + { "Partner System", "lacp.partnerSystem", + FT_ETHER, BASE_NONE, NULL, 0x0, + "The Partner's System ID encoded as a MAC address", HFILL }}, + + { &hf_lacpdu_partner_key, + { "Partner Key", "lacp.partnerKey", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The operational Key value assigned to the port associated with this link by the Partner", HFILL }}, + + { &hf_lacpdu_partner_port_priority, + { "Partner Port Priority", "lacp.partnerPortPriority", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The priority assigned to the port by the Partner (via Management or Admin)", HFILL }}, + + { &hf_lacpdu_partner_port, + { "Partner Port", "lacp.partnerPort", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The port number associated with this link assigned to the port by the Partner (via Management or Admin)", HFILL }}, + + { &hf_lacpdu_partner_state, + { "Partner State", "lacp.partnerState", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The Partner's state variables for the port, encoded as bits within a single octet", HFILL }}, + + { &hf_lacpdu_flags_p_activity, + { "LACP Activity", "lacp.partnerState.activity", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_ACTIVITY, + "Activity control value for this link. Active = 1, Passive = 0", HFILL }}, + + { &hf_lacpdu_flags_p_timeout, + { "LACP Timeout", "lacp.partnerState.timeout", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_TIMEOUT, + "Timeout control value for this link. Short Timeout = 1, Long Timeout = 0", HFILL }}, + + + { &hf_lacpdu_flags_p_aggregation, + { "Aggregation", "lacp.partnerState.aggregation", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_AGGREGATION, + "Aggregatable = 1, Individual = 0", HFILL }}, + + + { &hf_lacpdu_flags_p_sync, + { "Synchronization", "lacp.partnerState.synchronization", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_SYNC, + "In Sync = 1, Out of Sync = 0", HFILL }}, + + + { &hf_lacpdu_flags_p_collecting, + { "Collecting", "lacp.partnerState.collecting", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_COLLECTING, + "Collection of incoming frames is: Enabled = 1, Disabled = 0", HFILL }}, + + + { &hf_lacpdu_flags_p_distrib, + { "Distributing", "lacp.partnerState.distributing", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_DISTRIB, + "Distribution of outgoing frames is: Enabled = 1, Disabled = 0", HFILL }}, + + + + { &hf_lacpdu_flags_p_defaulted, + { "Defaulted", "lacp.partnerState.defaulted", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_DEFAULTED, + "1 = Actor Rx machine is using DEFAULT Partner info, 0 = using info in Rx'd LACPDU"}}, + + + { &hf_lacpdu_flags_p_expired, + { "Expired", "lacp.partnerState.expired", + FT_BOOLEAN, 8, TFS(&yesno), LACPDU_FLAGS_EXPIRED, + "1 = Actor Rx machine is EXPIRED, 0 = is NOT EXPIRED", HFILL }}, + + + { &hf_lacpdu_partner_reserved, + { "Reserved", "lacp.reserved", + FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + { &hf_lacpdu_coll_type, + { "Collector Information", "lacp.collectorInfo", + FT_UINT8, BASE_HEX, NULL, 0x0, + "TLV type = Collector", HFILL }}, + + { &hf_lacpdu_coll_info_len, + { "Collector Information Length", "lacp.collectorInfoLen", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The length of the Collector TLV", HFILL }}, + + { &hf_lacpdu_coll_max_delay, + { "Collector Max Delay", "lacp.collectorMaxDelay", + FT_UINT16, BASE_DEC, NULL, 0x0, + "The max delay of the station tx'ing the LACPDU (in tens of usecs)", HFILL }}, + + { &hf_lacpdu_coll_reserved, + { "Reserved", "lacp.reserved", + FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + + { &hf_lacpdu_term_type, + { "Terminator Information", "lacp.termInfo", + FT_UINT8, BASE_HEX, NULL, 0x0, + "TLV type = Terminator", HFILL }}, + + { &hf_lacpdu_term_len, + { "Terminator Length", "lacp.termLen", + FT_UINT8, BASE_HEX, NULL, 0x0, + "The length of the Terminator TLV", HFILL }}, + + { &hf_lacpdu_term_reserved, + { "Reserved", "lacp.reserved", + FT_BYTES, BASE_NONE, NULL, 0x0, + "", HFILL }}, + + }; + + /* Setup protocol subtree array */ + + static gint *ett[] = { + &ett_lacpdu, + &ett_lacpdu_a_flags, + &ett_lacpdu_p_flags, + }; + + /* Register the protocol name and description */ + + proto_lacpdu = proto_register_protocol("Link Aggregation Control Protocol", "LACP", "lacp"); + + /* Required function calls to register the header fields and subtrees used */ + + proto_register_field_array(proto_lacpdu, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + +} + + +void +proto_reg_handoff_lacpdu(void) +{ + dissector_handle_t slow_protocols_handle; + + slow_protocols_handle = create_dissector_handle(dissect_slow_protocols, proto_lacpdu); + dissector_add("ethertype", ETHERTYPE_SLOW_PROTOCOLS, slow_protocols_handle); +}