1*e6c7c102Sjsg /* $OpenBSD: print-slow.c,v 1.5 2024/04/23 13:34:51 jsg Exp $ */
23b63b2bcSmpf
33b63b2bcSmpf /*
43b63b2bcSmpf * Copyright (c) 1998-2005 The TCPDUMP project
53b63b2bcSmpf *
63b63b2bcSmpf * Redistribution and use in source and binary forms, with or without
73b63b2bcSmpf * modification, are permitted provided that: (1) source code
83b63b2bcSmpf * distributions retain the above copyright notice and this paragraph
93b63b2bcSmpf * in its entirety, and (2) distributions including binary code include
103b63b2bcSmpf * the above copyright notice and this paragraph in its entirety in
113b63b2bcSmpf * the documentation or other materials provided with the distribution.
123b63b2bcSmpf * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
133b63b2bcSmpf * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
143b63b2bcSmpf * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
153b63b2bcSmpf * FOR A PARTICULAR PURPOSE.
163b63b2bcSmpf *
173b63b2bcSmpf * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad
183b63b2bcSmpf *
193b63b2bcSmpf * Original code by Hannes Gredler (hannes@juniper.net)
203b63b2bcSmpf */
213b63b2bcSmpf
223b63b2bcSmpf #include <sys/time.h>
233b63b2bcSmpf #include <sys/socket.h>
243b63b2bcSmpf #include <sys/file.h>
253b63b2bcSmpf #include <sys/ioctl.h>
263b63b2bcSmpf
273b63b2bcSmpf #include <net/if.h>
283b63b2bcSmpf
293b63b2bcSmpf #include <netinet/in.h>
303b63b2bcSmpf #include <netinet/ip.h>
313b63b2bcSmpf #include <netinet/if_ether.h>
323b63b2bcSmpf #include <stdio.h>
333b63b2bcSmpf #include <stdlib.h>
343b63b2bcSmpf #include <string.h>
353b63b2bcSmpf
363b63b2bcSmpf #include "interface.h"
373b63b2bcSmpf #include "extract.h"
383b63b2bcSmpf #include "addrtoname.h"
393b63b2bcSmpf
403b63b2bcSmpf
413b63b2bcSmpf struct slow_common_header {
423b63b2bcSmpf u_int8_t proto_subtype;
433b63b2bcSmpf u_int8_t version;
443b63b2bcSmpf };
453b63b2bcSmpf
463b63b2bcSmpf #define SLOW_PROTO_LACP 1
473b63b2bcSmpf #define SLOW_PROTO_MARKER 2
483b63b2bcSmpf
493b63b2bcSmpf #define LACP_VERSION 1
503b63b2bcSmpf #define MARKER_VERSION 1
513b63b2bcSmpf
523b63b2bcSmpf static const struct tok slow_proto_values[] = {
533b63b2bcSmpf { SLOW_PROTO_LACP, "LACP" },
543b63b2bcSmpf { SLOW_PROTO_MARKER, "MARKER" },
553b63b2bcSmpf { 0, NULL}
563b63b2bcSmpf };
573b63b2bcSmpf
583b63b2bcSmpf struct tlv_header_t {
593b63b2bcSmpf u_int8_t type;
603b63b2bcSmpf u_int8_t length;
613b63b2bcSmpf };
623b63b2bcSmpf
633b63b2bcSmpf #define LACP_TLV_TERMINATOR 0x00
643b63b2bcSmpf #define LACP_TLV_ACTOR_INFO 0x01
653b63b2bcSmpf #define LACP_TLV_PARTNER_INFO 0x02
663b63b2bcSmpf #define LACP_TLV_COLLECTOR_INFO 0x03
673b63b2bcSmpf
683b63b2bcSmpf #define MARKER_TLV_TERMINATOR 0x00
693b63b2bcSmpf #define MARKER_TLV_MARKER_INFO 0x01
703b63b2bcSmpf #define MARKER_TLV_MARKER_RESP 0x02
713b63b2bcSmpf
723b63b2bcSmpf static const struct tok slow_tlv_values[] = {
733b63b2bcSmpf { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
743b63b2bcSmpf { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
753b63b2bcSmpf { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO,
763b63b2bcSmpf "Partner Information"},
773b63b2bcSmpf { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO,
783b63b2bcSmpf "Collector Information"},
793b63b2bcSmpf
803b63b2bcSmpf { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
813b63b2bcSmpf { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO,
823b63b2bcSmpf "Marker Information"},
833b63b2bcSmpf { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP,
843b63b2bcSmpf "Marker Response Information"},
853b63b2bcSmpf { 0, NULL}
863b63b2bcSmpf };
873b63b2bcSmpf
883b63b2bcSmpf struct lacp_tlv_actor_partner_info_t {
893b63b2bcSmpf u_int8_t sys_pri[2];
903b63b2bcSmpf u_int8_t sys[ETHER_ADDR_LEN];
913b63b2bcSmpf u_int8_t key[2];
923b63b2bcSmpf u_int8_t port_pri[2];
933b63b2bcSmpf u_int8_t port[2];
943b63b2bcSmpf u_int8_t state;
953b63b2bcSmpf u_int8_t pad[3];
963b63b2bcSmpf };
973b63b2bcSmpf
983b63b2bcSmpf #define ACTOR_PARTNER_BITS \
993b63b2bcSmpf "\020\1Activity\2Timeout\3Aggregation\4Synchronization\5Collecting\
1003b63b2bcSmpf \6Distributing\7Default\10Expired"
1013b63b2bcSmpf
1023b63b2bcSmpf struct lacp_tlv_collector_info_t {
1033b63b2bcSmpf u_int8_t max_delay[2];
1043b63b2bcSmpf u_int8_t pad[12];
1053b63b2bcSmpf };
1063b63b2bcSmpf
1073b63b2bcSmpf struct marker_tlv_marker_info_t {
1083b63b2bcSmpf u_int8_t req_port[2];
1093b63b2bcSmpf u_int8_t req_sys[ETHER_ADDR_LEN];
1103b63b2bcSmpf u_int8_t req_trans_id[4];
1113b63b2bcSmpf u_int8_t pad[2];
1123b63b2bcSmpf };
1133b63b2bcSmpf
1143b63b2bcSmpf struct lacp_marker_tlv_terminator_t {
1153b63b2bcSmpf u_int8_t pad[50];
1163b63b2bcSmpf };
1173b63b2bcSmpf
1183b63b2bcSmpf void
slow_print(const u_char * pptr,u_int len)1196ad041cbSmmcc slow_print(const u_char *pptr, u_int len)
1203b63b2bcSmpf {
1213b63b2bcSmpf
1223b63b2bcSmpf const struct slow_common_header *slow_com_header;
1233b63b2bcSmpf const struct tlv_header_t *tlv_header;
1243b63b2bcSmpf const u_char *tptr, *tlv_tptr;
1253b63b2bcSmpf u_int tlv_len, tlen, tlv_tlen;
1263b63b2bcSmpf
1273b63b2bcSmpf union {
1283b63b2bcSmpf struct lacp_marker_tlv_terminator_t *marker_terminator;
1293b63b2bcSmpf struct lacp_tlv_actor_partner_info_t *actor_partner_info;
1303b63b2bcSmpf struct lacp_tlv_collector_info_t *collector_info;
1313b63b2bcSmpf struct marker_tlv_marker_info_t *marker_tlv_marker_info;
1323b63b2bcSmpf } tlv_ptr;
1333b63b2bcSmpf
1343b63b2bcSmpf tptr = pptr;
1353b63b2bcSmpf slow_com_header = (const struct slow_common_header *)pptr;
1363b63b2bcSmpf TCHECK(*slow_com_header);
1373b63b2bcSmpf
1383b63b2bcSmpf /*
1393b63b2bcSmpf * Sanity checking of the header.
1403b63b2bcSmpf */
1413b63b2bcSmpf if (slow_com_header->proto_subtype == SLOW_PROTO_LACP &&
1423b63b2bcSmpf slow_com_header->version != LACP_VERSION) {
1433b63b2bcSmpf printf("LACP version %u packet not supported",
1443b63b2bcSmpf slow_com_header->version);
1453b63b2bcSmpf return;
1463b63b2bcSmpf }
1473b63b2bcSmpf if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER &&
1483b63b2bcSmpf slow_com_header->version != MARKER_VERSION) {
1493b63b2bcSmpf printf("MARKER version %u packet not supported",
1503b63b2bcSmpf slow_com_header->version);
1513b63b2bcSmpf return;
1523b63b2bcSmpf }
1533b63b2bcSmpf
1543b63b2bcSmpf printf("%sv%u, length: %u",
1553b63b2bcSmpf tok2str(slow_proto_values, "unknown (%u)",
1563b63b2bcSmpf slow_com_header->proto_subtype), slow_com_header->version, len);
1573b63b2bcSmpf
1583b63b2bcSmpf if (!vflag)
1593b63b2bcSmpf return;
1603b63b2bcSmpf
1613b63b2bcSmpf /* ok they seem to want to know everything - lets fully decode it */
1623b63b2bcSmpf tlen = len - sizeof(struct slow_common_header);
1633b63b2bcSmpf tptr += sizeof(const struct slow_common_header);
1643b63b2bcSmpf
1653b63b2bcSmpf while (tlen > 0) {
1663b63b2bcSmpf /* did we capture enough for fully decoding the tlv header ? */
1673b63b2bcSmpf TCHECK2(*tptr, sizeof(struct tlv_header_t));
1683b63b2bcSmpf tlv_header = (const struct tlv_header_t *)tptr;
1693b63b2bcSmpf tlv_len = tlv_header->length;
1703b63b2bcSmpf
1713b63b2bcSmpf /* End of message */
1723b63b2bcSmpf if (tlv_header->type == LACP_TLV_TERMINATOR ||
1733b63b2bcSmpf tlv_header->type == MARKER_TLV_TERMINATOR)
1743b63b2bcSmpf return;
1753b63b2bcSmpf
1763b63b2bcSmpf printf("\n\t%s TLV (0x%02x), length: %u",
1773b63b2bcSmpf tok2str(slow_tlv_values, "Unknown",
1783b63b2bcSmpf (slow_com_header->proto_subtype << 8) + tlv_header->type),
1793b63b2bcSmpf tlv_header->type, tlv_len);
1803b63b2bcSmpf
1813b63b2bcSmpf if (tlv_len < sizeof(struct tlv_header_t) || tlv_len > tlen) {
1823b63b2bcSmpf printf("\n\tInvalid TLV length: %u", tlv_len);
1833b63b2bcSmpf return;
1843b63b2bcSmpf }
1853b63b2bcSmpf
1863b63b2bcSmpf tlv_tptr = tptr + sizeof(struct tlv_header_t);
1873b63b2bcSmpf tlv_tlen = tlv_len - sizeof(struct tlv_header_t);
1883b63b2bcSmpf
1893b63b2bcSmpf /* did we capture enough for fully decoding the tlv ? */
1903b63b2bcSmpf TCHECK2(*tptr, tlv_len);
1913b63b2bcSmpf
1923b63b2bcSmpf switch((slow_com_header->proto_subtype << 8) +
1933b63b2bcSmpf tlv_header->type) {
1943b63b2bcSmpf
1953b63b2bcSmpf /* those two TLVs have the same structure -> fall through */
1963b63b2bcSmpf case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
1973b63b2bcSmpf case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
1983b63b2bcSmpf tlv_ptr.actor_partner_info =
1993b63b2bcSmpf (struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
2003b63b2bcSmpf if (tlv_tlen != sizeof(*tlv_ptr.actor_partner_info)) {
2013b63b2bcSmpf printf("\n\tInvalid partner/actor info length %u",
2023b63b2bcSmpf tlv_tlen);
2033b63b2bcSmpf break;
2043b63b2bcSmpf }
2053b63b2bcSmpf
2063b63b2bcSmpf printf("\n\t System %s, System Priority %u, Key %u"
2073b63b2bcSmpf ", Port %u, Port Priority %u\n\t ",
2083b63b2bcSmpf etheraddr_string(tlv_ptr.actor_partner_info->sys),
2093b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.actor_partner_info->sys_pri),
2103b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.actor_partner_info->key),
2113b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.actor_partner_info->port),
2123b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.actor_partner_info->
2133b63b2bcSmpf port_pri));
2143b63b2bcSmpf printb("State", tlv_ptr.actor_partner_info->state,
2153b63b2bcSmpf ACTOR_PARTNER_BITS);
2163b63b2bcSmpf break;
2173b63b2bcSmpf
2183b63b2bcSmpf case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
2193b63b2bcSmpf tlv_ptr.collector_info =
2203b63b2bcSmpf (struct lacp_tlv_collector_info_t *)tlv_tptr;
2213b63b2bcSmpf if (tlv_tlen != sizeof(*tlv_ptr.collector_info)) {
2223b63b2bcSmpf printf("\n\tInvalid collector info length %u",
2233b63b2bcSmpf tlv_tlen);
2243b63b2bcSmpf break;
2253b63b2bcSmpf }
2263b63b2bcSmpf
2273b63b2bcSmpf printf("\n\t Max Delay %u",
2283b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.collector_info->max_delay));
2293b63b2bcSmpf break;
2303b63b2bcSmpf
2313b63b2bcSmpf case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
2323b63b2bcSmpf case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP):
2333b63b2bcSmpf tlv_ptr.marker_tlv_marker_info =
2343b63b2bcSmpf (struct marker_tlv_marker_info_t *)tlv_tptr;
2353b63b2bcSmpf if (tlv_tlen !=
2363b63b2bcSmpf sizeof(*tlv_ptr.marker_tlv_marker_info)) {
2373b63b2bcSmpf printf("\n\tInvalid marker info/resp length %u",
2383b63b2bcSmpf tlv_tlen);
2393b63b2bcSmpf break;
2403b63b2bcSmpf }
2413b63b2bcSmpf
2423b63b2bcSmpf printf("\n\t Request System %s, Request Port %u,"
2433b63b2bcSmpf " Request Transaction ID 0x%08x",
2443b63b2bcSmpf etheraddr_string(tlv_ptr.marker_tlv_marker_info->
2453b63b2bcSmpf req_sys),
2463b63b2bcSmpf EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->
2473b63b2bcSmpf req_port),
2483b63b2bcSmpf EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->
2493b63b2bcSmpf req_trans_id));
2503b63b2bcSmpf break;
2513b63b2bcSmpf
2523b63b2bcSmpf default:
2533b63b2bcSmpf if (vflag > 1)
2543b63b2bcSmpf printf("\n\t Unknown TLV type: 0x%x \n",
2553b63b2bcSmpf (slow_com_header->proto_subtype << 8) +
2563b63b2bcSmpf tlv_header->type);
2573b63b2bcSmpf break;
2583b63b2bcSmpf }
2593b63b2bcSmpf
2603b63b2bcSmpf tptr += tlv_len;
2613b63b2bcSmpf tlen -= tlv_len;
2623b63b2bcSmpf }
2633b63b2bcSmpf
2643b63b2bcSmpf return;
2653b63b2bcSmpf trunc:
2663b63b2bcSmpf printf("\n\t[|slow]");
2673b63b2bcSmpf }
268