2 * Routines for PAgP (Port Aggregation Protocol - aka FEC) dissection
3 * Original Author Mark C. Brown <mbrown@hp.com>
4 * Copyright (C) 2004 Hewlett-Packard Development Company, L.P.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Copied from packet-slowprotocols.c
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19 #include <epan/to_str.h>
20 #include <epan/cisco_pid.h>
22 #include <wsutil/array.h>
24 void proto_register_pagp(void);
25 void proto_reg_handoff_pagp(void);
27 static dissector_handle_t pagp_handle
;
29 /* Offsets of fields within a PagP PDU */
31 #define PAGP_VERSION_NUMBER 0
34 #define PAGP_LOCAL_DEVICE_ID 2
35 #define PAGP_LOCAL_LEARN_CAP 8
36 #define PAGP_LOCAL_PORT_PRIORITY 9
37 #define PAGP_LOCAL_SENT_PORT_IFINDEX 10
38 #define PAGP_LOCAL_GROUP_CAPABILITY 14
39 #define PAGP_LOCAL_GROUP_IFINDEX 18
40 #define PAGP_PARTNER_DEVICE_ID 22
41 #define PAGP_PARTNER_LEARN_CAP 28
42 #define PAGP_PARTNER_PORT_PRIORITY 29
43 #define PAGP_PARTNER_SENT_PORT_IFINDEX 30
44 #define PAGP_PARTNER_GROUP_CAPABILITY 34
45 #define PAGP_PARTNER_GROUP_IFINDEX 38
46 #define PAGP_PARTNER_COUNT 42
47 #define PAGP_NUM_TLVS 44
48 #define PAGP_FIRST_TLV 46
50 #define PAGP_FLUSH_LOCAL_DEVICE_ID 2
51 #define PAGP_FLUSH_PARTNER_DEVICE_ID 8
52 #define PAGP_FLUSH_TRANSACTION_ID 14
56 #define PAGP_INFO_PDU 1
57 #define PAGP_FLUSH_PDU 2
61 #define PAGP_FLAGS_SLOW_HELLO 0x01
62 #define PAGP_FLAGS_AUTO_MODE 0x02
63 #define PAGP_FLAGS_CONSISTENT_STATE 0x04
68 #define PAGP_TLV_DEVICE_NAME 1
69 #define PAGP_TLV_PORT_NAME 2
70 #define PAGP_TLV_AGPORT_MAC 3
71 #define PAGP_TLV_RESERVED 4
73 /* Initialise the protocol and registered fields */
75 static int proto_pagp
;
77 static int hf_pagp_version_number
;
79 static int hf_pagp_flags
;
80 static int hf_pagp_flags_slow_hello
;
81 static int hf_pagp_flags_auto_mode
;
82 static int hf_pagp_flags_consistent_state
;
83 static int hf_pagp_local_device_id
;
84 static int hf_pagp_local_learn_cap
;
85 static int hf_pagp_local_port_priority
;
86 static int hf_pagp_local_sent_port_ifindex
;
87 static int hf_pagp_local_group_capability
;
88 static int hf_pagp_local_group_ifindex
;
89 static int hf_pagp_partner_device_id
;
90 static int hf_pagp_partner_learn_cap
;
91 static int hf_pagp_partner_port_priority
;
92 static int hf_pagp_partner_sent_port_ifindex
;
93 static int hf_pagp_partner_group_capability
;
94 static int hf_pagp_partner_group_ifindex
;
95 static int hf_pagp_partner_count
;
96 static int hf_pagp_num_tlvs
;
97 static int hf_pagp_tlv
;
98 static int hf_pagp_tlv_length
;
99 static int hf_pagp_tlv_device_name
;
100 static int hf_pagp_tlv_port_name
;
101 static int hf_pagp_tlv_agport_mac
;
103 static int hf_pagp_flush_local_device_id
;
104 static int hf_pagp_flush_partner_device_id
;
105 static int hf_pagp_flush_transaction_id
;
107 /* Initialise the subtree pointers */
110 static int ett_pagp_flags
;
111 static int ett_pagp_tlvs
;
113 static expert_field ei_pagp_tlv_length
;
115 /* General declarations and macros */
117 static const value_string pdu_vers
[] = {
123 static const value_string learn_cap
[] = {
124 { 1, "Source-based Distribution" },
125 { 2, "Arbitrary Distribution" },
129 static const value_string tlv_types
[] = {
130 { 1, "Device Name TLV" },
131 { 2, "Physical Port Name TLV" },
132 { 3, "Agport MAC Address" },
137 static const true_false_string automode
= {
142 /* Code to actually dissect the PAGP packets */
144 dissect_pagp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
151 uint16_t offset
= PAGP_FIRST_TLV
;
156 proto_tree
*pagp_tree
= NULL
;
157 proto_item
*pagp_item
, *len_item
;
158 proto_tree
*tlv_tree
;
159 static int * const pagp_flags
[] = {
160 &hf_pagp_flags_slow_hello
,
161 &hf_pagp_flags_auto_mode
,
162 &hf_pagp_flags_consistent_state
,
167 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PAGP"); /* PAGP Protocol */
169 col_clear(pinfo
->cinfo
, COL_INFO
);
171 raw_octet
= tvb_get_uint8(tvb
, PAGP_VERSION_NUMBER
);
173 pagp_item
= proto_tree_add_protocol_format(tree
, proto_pagp
, tvb
,
174 0, -1, "Port Aggregation Protocol");
175 pagp_tree
= proto_item_add_subtree(pagp_item
, ett_pagp
);
176 proto_tree_add_uint(pagp_tree
, hf_pagp_version_number
, tvb
,
177 PAGP_VERSION_NUMBER
, 1, raw_octet
);
179 col_append_str(pinfo
->cinfo
, COL_INFO
,
180 val_to_str_const(raw_octet
, pdu_vers
, "Unknown PDU version"));
182 if (raw_octet
== PAGP_FLUSH_PDU
) {
184 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "; Local DevID: %s",
185 tvb_ether_to_str(pinfo
->pool
, tvb
, PAGP_FLUSH_LOCAL_DEVICE_ID
));
187 proto_tree_add_item(pagp_tree
, hf_pagp_flush_local_device_id
, tvb
,
188 PAGP_FLUSH_LOCAL_DEVICE_ID
, 6, ENC_NA
);
190 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Partner DevID: %s",
191 tvb_ether_to_str(pinfo
->pool
, tvb
, PAGP_FLUSH_PARTNER_DEVICE_ID
));
193 proto_tree_add_item(pagp_tree
, hf_pagp_flush_partner_device_id
, tvb
,
194 PAGP_FLUSH_PARTNER_DEVICE_ID
, 6, ENC_NA
);
196 raw_word
= tvb_get_ntohl(tvb
, PAGP_FLUSH_TRANSACTION_ID
);
197 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "; Transaction ID: 0x%x ", raw_word
);
199 proto_tree_add_uint(pagp_tree
, hf_pagp_flush_transaction_id
, tvb
,
200 PAGP_FLUSH_TRANSACTION_ID
, 4, raw_word
);
201 return tvb_captured_length(tvb
);
206 flags
= tvb_get_uint8(tvb
, PAGP_FLAGS
);
207 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "; Flags 0x%x", flags
);
209 proto_tree_add_bitmask(pagp_tree
, tvb
, PAGP_FLAGS
, hf_pagp_flags
, ett_pagp_flags
, pagp_flags
, ENC_NA
);
211 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "; Local DevID: %s",
212 tvb_ether_to_str(pinfo
->pool
, tvb
, PAGP_LOCAL_DEVICE_ID
));
214 proto_tree_add_item(pagp_tree
, hf_pagp_local_device_id
, tvb
,
215 PAGP_LOCAL_DEVICE_ID
, 6, ENC_NA
);
218 proto_tree_add_item(pagp_tree
, hf_pagp_local_learn_cap
, tvb
,
219 PAGP_LOCAL_LEARN_CAP
, 1, ENC_NA
);
221 proto_tree_add_item(pagp_tree
, hf_pagp_local_port_priority
, tvb
,
222 PAGP_LOCAL_PORT_PRIORITY
, 1, ENC_NA
);
224 proto_tree_add_item(pagp_tree
, hf_pagp_local_sent_port_ifindex
, tvb
,
225 PAGP_LOCAL_SENT_PORT_IFINDEX
, 4, ENC_BIG_ENDIAN
);
227 proto_tree_add_item(pagp_tree
, hf_pagp_local_group_capability
, tvb
,
228 PAGP_LOCAL_GROUP_CAPABILITY
, 4, ENC_BIG_ENDIAN
);
230 proto_tree_add_item(pagp_tree
, hf_pagp_local_group_ifindex
, tvb
,
231 PAGP_LOCAL_GROUP_IFINDEX
, 4, ENC_BIG_ENDIAN
);
234 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Partner DevID: %s",
235 tvb_ether_to_str(pinfo
->pool
, tvb
, PAGP_PARTNER_DEVICE_ID
));
237 proto_tree_add_item(pagp_tree
, hf_pagp_partner_device_id
, tvb
,
238 PAGP_PARTNER_DEVICE_ID
, 6, ENC_NA
);
240 proto_tree_add_item(pagp_tree
, hf_pagp_partner_learn_cap
, tvb
,
241 PAGP_PARTNER_LEARN_CAP
, 1, ENC_NA
);
243 proto_tree_add_item(pagp_tree
, hf_pagp_partner_port_priority
, tvb
,
244 PAGP_PARTNER_PORT_PRIORITY
, 1, ENC_NA
);
246 proto_tree_add_item(pagp_tree
, hf_pagp_partner_sent_port_ifindex
, tvb
,
247 PAGP_PARTNER_SENT_PORT_IFINDEX
, 4, ENC_BIG_ENDIAN
);
249 proto_tree_add_item(pagp_tree
, hf_pagp_partner_group_capability
, tvb
,
250 PAGP_PARTNER_GROUP_CAPABILITY
, 4, ENC_BIG_ENDIAN
);
252 proto_tree_add_item(pagp_tree
, hf_pagp_partner_group_ifindex
, tvb
,
253 PAGP_PARTNER_GROUP_IFINDEX
, 4, ENC_BIG_ENDIAN
);
255 proto_tree_add_item(pagp_tree
, hf_pagp_partner_count
, tvb
,
256 PAGP_PARTNER_COUNT
, 2, ENC_BIG_ENDIAN
);
258 num_tlvs
= tvb_get_ntohs(tvb
, PAGP_NUM_TLVS
);
259 proto_tree_add_uint(pagp_tree
, hf_pagp_num_tlvs
, tvb
,
260 PAGP_NUM_TLVS
, 2, num_tlvs
);
262 /* dump TLV entries */
264 for ( ii
= 0; ii
< num_tlvs
; ii
++ ) {
266 tlv
= tvb_get_ntohs(tvb
, offset
);
267 len
= tvb_get_ntohs(tvb
, offset
+ 2);
269 tlv_tree
= proto_tree_add_subtree_format(pagp_tree
, tvb
, offset
, len
,
270 ett_pagp_tlvs
, NULL
, "TLV Entry #%d", ii
+1);
272 proto_tree_add_uint(tlv_tree
, hf_pagp_tlv
, tvb
, offset
, 2, tlv
);
273 len_item
= proto_tree_add_uint(tlv_tree
, hf_pagp_tlv_length
, tvb
, offset
+2, 2, len
);
275 expert_add_info_format(pinfo
, len_item
, &ei_pagp_tlv_length
,
276 "Unknown data - TLV len=0");
279 if ( tvb_reported_length_remaining(tvb
, offset
) < len
) {
280 expert_add_info_format(pinfo
, len_item
, &ei_pagp_tlv_length
,
281 "TLV length too large");
286 case PAGP_TLV_DEVICE_NAME
:
287 proto_tree_add_item(tlv_tree
, hf_pagp_tlv_device_name
,
288 tvb
, offset
+4, len
-4, ENC_NA
|ENC_ASCII
);
290 case PAGP_TLV_PORT_NAME
:
291 proto_tree_add_item(tlv_tree
, hf_pagp_tlv_port_name
,
292 tvb
, offset
+4, len
-4, ENC_NA
|ENC_ASCII
);
294 case PAGP_TLV_AGPORT_MAC
:
295 proto_tree_add_item(tlv_tree
, hf_pagp_tlv_agport_mac
,
296 tvb
, offset
+4, 6, ENC_NA
);
298 case PAGP_TLV_RESERVED
:
305 return tvb_captured_length(tvb
);
309 /* Register the protocol with Wireshark */
312 proto_register_pagp(void)
314 /* Setup list of header fields */
316 static hf_register_info hf
[] = {
318 { &hf_pagp_version_number
,
319 { "Version", "pagp.version",
320 FT_UINT8
, BASE_HEX
, VALS(pdu_vers
), 0x0,
321 "Identifies the PAgP PDU version: 1 = Info, 2 = Flush", HFILL
}},
324 { "Flags", "pagp.flags",
325 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
326 "Information flags", HFILL
}},
328 { &hf_pagp_flags_slow_hello
,
329 { "Slow Hello", "pagp.flags.slowhello",
330 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), PAGP_FLAGS_SLOW_HELLO
,
331 "1 = using Slow Hello, 0 = Slow Hello disabled", HFILL
}},
333 { &hf_pagp_flags_auto_mode
,
334 { "Auto Mode", "pagp.flags.automode",
335 FT_BOOLEAN
, 8, TFS(&automode
), PAGP_FLAGS_AUTO_MODE
,
336 "1 = Auto Mode enabled, 0 = Desirable Mode", HFILL
}},
338 { &hf_pagp_flags_consistent_state
,
339 { "Consistent State", "pagp.flags.state",
340 FT_BOOLEAN
, 8, NULL
, PAGP_FLAGS_CONSISTENT_STATE
,
341 "1 = Consistent State, 0 = Not Ready", HFILL
}},
343 { &hf_pagp_local_device_id
,
344 { "Local Device ID", "pagp.localdevid",
345 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
348 { &hf_pagp_local_learn_cap
,
349 { "Local Learn Capability", "pagp.localearncap",
350 FT_UINT8
, BASE_HEX
, VALS(learn_cap
), 0x0,
353 { &hf_pagp_local_port_priority
,
354 { "Local Port Hot Standby Priority", "pagp.localportpri",
355 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
356 "The local hot standby priority assigned to this port", HFILL
}},
358 { &hf_pagp_local_sent_port_ifindex
,
359 { "Local Sent Port ifindex", "pagp.localsentportifindex",
360 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
361 "The interface index of the local port used to send PDU", HFILL
}},
363 { &hf_pagp_local_group_capability
,
364 { "Local Group Capability", "pagp.localgroupcap",
365 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
366 "The local group capability", HFILL
}},
368 { &hf_pagp_local_group_ifindex
,
369 { "Local Group ifindex", "pagp.localgroupifindex",
370 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
371 "The local group interface index", HFILL
}},
373 { &hf_pagp_partner_device_id
,
374 { "Partner Device ID", "pagp.partnerdevid",
375 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
376 "Remote Device ID (MAC)", HFILL
}},
378 { &hf_pagp_partner_learn_cap
,
379 { "Partner Learn Capability", "pagp.partnerlearncap",
380 FT_UINT8
, BASE_HEX
, VALS(learn_cap
), 0x0,
381 "Remote learn capability", HFILL
}},
383 { &hf_pagp_partner_port_priority
,
384 { "Partner Port Hot Standby Priority", "pagp.partnerportpri",
385 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
386 "Remote port priority", HFILL
}},
388 { &hf_pagp_partner_sent_port_ifindex
,
389 { "Partner Sent Port ifindex", "pagp.partnersentportifindex",
390 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
391 "Remote port interface index sent", HFILL
}},
393 { &hf_pagp_partner_group_capability
,
394 { "Partner Group Capability", "pagp.partnergroupcap",
395 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
396 "Remote group capability", HFILL
}},
398 { &hf_pagp_partner_group_ifindex
,
399 { "Partner Group ifindex", "pagp.partnergroupifindex",
400 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
401 "Remote group interface index", HFILL
}},
403 { &hf_pagp_partner_count
,
404 { "Partner Count", "pagp.partnercount",
405 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
409 { "Number of TLVs", "pagp.numtlvs",
410 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
411 "Number of TLVs following", HFILL
}},
414 { "Type", "pagp.tlv",
415 FT_UINT16
, BASE_DEC
, VALS(tlv_types
), 0x0,
416 "Type/Length/Value", HFILL
}},
418 { &hf_pagp_tlv_length
,
419 { "Length", "pagp.tlv_length",
420 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
423 { &hf_pagp_tlv_device_name
,
424 { "Device Name", "pagp.tlvdevname",
425 FT_STRING
, BASE_NONE
, NULL
, 0x0,
426 "sysName of device", HFILL
}},
428 { &hf_pagp_tlv_port_name
,
429 { "Physical Port Name", "pagp.tlvportname",
430 FT_STRING
, BASE_NONE
, NULL
, 0x0,
431 "Name of port used to send PDU", HFILL
}},
433 { &hf_pagp_tlv_agport_mac
,
434 { "Agport MAC Address", "pagp.tlvagportmac",
435 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
436 "Source MAC on frames for this aggregate", HFILL
}},
438 { &hf_pagp_flush_local_device_id
,
439 { "Flush Local Device ID", "pagp.flushlocaldevid",
440 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
443 { &hf_pagp_flush_partner_device_id
,
444 { "Flush Partner Device ID", "pagp.flushpartnerdevid",
445 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
446 "Flush remote device ID", HFILL
}},
448 { &hf_pagp_flush_transaction_id
,
449 { "Transaction ID", "pagp.transid",
450 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
451 "Flush transaction ID", HFILL
}},
455 /* Setup protocol subtree array */
457 static int *ett
[] = {
463 static ei_register_info ei
[] = {
464 { &ei_pagp_tlv_length
, { "pagp.tlv_length.invalid", PI_PROTOCOL
, PI_WARN
, "Invalid TLV length", EXPFILL
}},
466 expert_module_t
* expert_pagp
;
468 /* Register the protocol name and description */
470 proto_pagp
= proto_register_protocol("Port Aggregation Protocol", "PAGP", "pagp");
472 /* Required function calls to register the header fields and subtrees used */
474 proto_register_field_array(proto_pagp
, hf
, array_length(hf
));
475 proto_register_subtree_array(ett
, array_length(ett
));
476 expert_pagp
= expert_register_protocol(proto_pagp
);
477 expert_register_field_array(expert_pagp
, ei
, array_length(ei
));
478 pagp_handle
= register_dissector("pagp", dissect_pagp
, proto_pagp
);
483 proto_reg_handoff_pagp(void)
485 dissector_add_uint("llc.cisco_pid", CISCO_PID_PAGP
, pagp_handle
);
489 * Editor modelines - https://www.wireshark.org/tools/modelines.html
494 * indent-tabs-mode: nil
497 * vi: set shiftwidth=4 tabstop=8 expandtab:
498 * :indentSize=4:tabSize=8:noTabs=true: