mirror of
https://github.com/the-tcpdump-group/tcpdump.git
synced 2024-12-18 06:14:06 +08:00
265 lines
9.0 KiB
C
265 lines
9.0 KiB
C
/*
|
|
* Copyright (c) 1998-2005 The TCPDUMP project
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that: (1) source code
|
|
* distributions retain the above copyright notice and this paragraph
|
|
* in its entirety, and (2) distributions including binary code include
|
|
* the above copyright notice and this paragraph in its entirety in
|
|
* the documentation or other materials provided with the distribution.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND
|
|
* WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
|
|
* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad
|
|
*
|
|
* Original code by Hannes Gredler (hannes@juniper.net)
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char rcsid[] _U_ =
|
|
"@(#) $Header: /tcpdump/master/tcpdump/print-slow.c,v 1.1 2005-07-10 14:41:34 hannes Exp $";
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <tcpdump-stdinc.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "interface.h"
|
|
#include "extract.h"
|
|
#include "addrtoname.h"
|
|
#include "ether.h"
|
|
|
|
struct slow_common_header {
|
|
u_int8_t proto_subtype;
|
|
u_int8_t version;
|
|
};
|
|
|
|
#define SLOW_PROTO_LACP 1
|
|
#define SLOW_PROTO_MARKER 2
|
|
|
|
#define LACP_VERSION 1
|
|
#define MARKER_VERSION 1
|
|
|
|
static const struct tok slow_proto_values[] = {
|
|
{ SLOW_PROTO_LACP, "LACP" },
|
|
{ SLOW_PROTO_MARKER, "MARKER" },
|
|
{ 0, NULL}
|
|
};
|
|
|
|
struct tlv_header_t {
|
|
u_int8_t type;
|
|
u_int8_t length;
|
|
};
|
|
|
|
#define LACP_TLV_TERMINATOR 0x00
|
|
#define LACP_TLV_ACTOR_INFO 0x01
|
|
#define LACP_TLV_PARTNER_INFO 0x02
|
|
#define LACP_TLV_COLLECTOR_INFO 0x03
|
|
|
|
#define MARKER_TLV_TERMINATOR 0x00
|
|
#define MARKER_TLV_MARKER_INFO 0x01
|
|
|
|
static const struct tok slow_tlv_values[] = {
|
|
{ (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
|
|
{ (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
|
|
{ (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"},
|
|
{ (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"},
|
|
|
|
{ (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
|
|
{ (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"},
|
|
{ 0, NULL}
|
|
};
|
|
|
|
struct lacp_tlv_actor_partner_info_t {
|
|
u_int8_t sys_pri[2];
|
|
u_int8_t sys[ETHER_ADDR_LEN];
|
|
u_int8_t key[2];
|
|
u_int8_t port_pri[2];
|
|
u_int8_t port[2];
|
|
u_int8_t state;
|
|
u_int8_t pad[3];
|
|
};
|
|
|
|
static const struct tok lacp_tlv_actor_partner_info_state_values[] = {
|
|
{ 0x01, "Activity"},
|
|
{ 0x02, "Timeout"},
|
|
{ 0x04, "Aggregation"},
|
|
{ 0x08, "Synchronization"},
|
|
{ 0x10, "Collecting"},
|
|
{ 0x20, "Distributing"},
|
|
{ 0x40, "Default"},
|
|
{ 0x80, "Expired"},
|
|
{ 0, NULL}
|
|
};
|
|
|
|
struct lacp_tlv_collector_info_t {
|
|
u_int8_t max_delay[2];
|
|
u_int8_t pad[12];
|
|
};
|
|
|
|
struct marker_tlv_marker_info_t {
|
|
u_int8_t req_port[2];
|
|
u_int8_t req_sys[ETHER_ADDR_LEN];
|
|
u_int8_t req_trans_id[4];
|
|
u_int8_t pad[2];
|
|
};
|
|
|
|
struct lacp_marker_tlv_terminator_t {
|
|
u_int8_t pad[50];
|
|
};
|
|
|
|
void
|
|
slow_print(register const u_char *pptr, register u_int len) {
|
|
|
|
const struct slow_common_header *slow_com_header;
|
|
const struct tlv_header_t *tlv_header;
|
|
const u_char *tptr,*tlv_tptr;
|
|
u_int tlv_len,tlen,tlv_tlen;
|
|
|
|
union {
|
|
const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator;
|
|
const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info;
|
|
const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info;
|
|
const struct marker_tlv_marker_info_t *marker_tlv_marker_info;
|
|
} tlv_ptr;
|
|
|
|
tptr=pptr;
|
|
slow_com_header = (const struct slow_common_header *)pptr;
|
|
TCHECK(*slow_com_header);
|
|
|
|
/*
|
|
* Sanity checking of the header.
|
|
*/
|
|
if (slow_com_header->proto_subtype == SLOW_PROTO_LACP &&
|
|
slow_com_header->version != LACP_VERSION) {
|
|
printf("LACP version %u packet not supported",slow_com_header->version);
|
|
return;
|
|
}
|
|
if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER &&
|
|
slow_com_header->version != MARKER_VERSION) {
|
|
printf("MARKER version %u packet not supported",slow_com_header->version);
|
|
return;
|
|
}
|
|
|
|
printf("%sv%u, length: %u",
|
|
tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
|
|
slow_com_header->version,
|
|
len);
|
|
|
|
if (!vflag)
|
|
return;
|
|
|
|
/* ok they seem to want to know everything - lets fully decode it */
|
|
tlen=len-sizeof(struct slow_common_header);
|
|
tptr+=sizeof(const struct slow_common_header);
|
|
|
|
while(tlen>0) {
|
|
/* did we capture enough for fully decoding the tlv header ? */
|
|
TCHECK2(*tptr, sizeof(struct tlv_header_t));
|
|
tlv_header = (const struct tlv_header_t *)tptr;
|
|
tlv_len = tlv_header->length;
|
|
|
|
printf("\n\t%s TLV (0x%02x), length: %u",
|
|
tok2str(slow_tlv_values,
|
|
"Unknown",
|
|
(slow_com_header->proto_subtype << 8) + tlv_header->type),
|
|
tlv_header->type,
|
|
tlv_len);
|
|
|
|
if ((tlv_len < sizeof(struct tlv_header_t) ||
|
|
tlv_len > tlen) &&
|
|
tlv_header->type != LACP_TLV_TERMINATOR &&
|
|
tlv_header->type != MARKER_TLV_TERMINATOR) {
|
|
printf("\n\t-----trailing data-----");
|
|
print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",tlen);
|
|
return;
|
|
}
|
|
|
|
tlv_tptr=tptr+sizeof(struct tlv_header_t);
|
|
tlv_tlen=tlv_len-sizeof(struct tlv_header_t);
|
|
|
|
/* did we capture enough for fully decoding the tlv ? */
|
|
TCHECK2(*tptr, tlv_len);
|
|
|
|
switch((slow_com_header->proto_subtype << 8) + tlv_header->type) {
|
|
|
|
/* those two TLVs have the same structure -> fall through */
|
|
case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
|
|
case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
|
|
tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
|
|
|
|
printf("\n\t System %s, System Priority %u, Key %u" \
|
|
", Port %u, Port Priority %u\n\t State Flags [%s]",
|
|
etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys),
|
|
EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri),
|
|
EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key),
|
|
EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port),
|
|
EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri),
|
|
bittok2str(lacp_tlv_actor_partner_info_state_values,
|
|
"none",
|
|
tlv_ptr.lacp_tlv_actor_partner_info->state));
|
|
|
|
break;
|
|
|
|
case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
|
|
tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr;
|
|
|
|
printf("\n\t Max Delay %u",
|
|
EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay));
|
|
|
|
break;
|
|
|
|
case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
|
|
tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr;
|
|
|
|
printf("\n\t Request System %s, Request Port %u, Request Transaction ID 0x%08x",
|
|
etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys),
|
|
EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port),
|
|
EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id));
|
|
|
|
break;
|
|
|
|
/* those two TLVs have the same structure -> fall through */
|
|
case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR):
|
|
case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR):
|
|
tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr;
|
|
if (tlv_len == 0) {
|
|
tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) +
|
|
sizeof(struct tlv_header_t);
|
|
/* tell the user that we modified the length field */
|
|
if (vflag>1)
|
|
printf(" (=%u)",tlv_len);
|
|
/* we have messed around with the length field - now we need to check
|
|
* again if there are enough bytes on the wire for the hexdump */
|
|
TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0],
|
|
sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad));
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
if (vflag <= 1)
|
|
print_unknown_data(tlv_tptr,"\n\t ",tlv_tlen);
|
|
break;
|
|
}
|
|
/* do we want to see an additionally hexdump ? */
|
|
if (vflag > 1)
|
|
print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t ",
|
|
tlv_len-sizeof(struct tlv_header_t));
|
|
|
|
tptr+=tlv_len;
|
|
tlen-=tlv_len;
|
|
}
|
|
return;
|
|
trunc:
|
|
printf("\n\t\t packet exceeded snapshot");
|
|
}
|