Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1998-2005 The TCPDUMP project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that: (1) source code
      6  * distributions retain the above copyright notice and this paragraph
      7  * in its entirety, and (2) distributions including binary code include
      8  * the above copyright notice and this paragraph in its entirety in
      9  * the documentation or other materials provided with the distribution.
     10  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     11  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     12  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     13  * FOR A PARTICULAR PURPOSE.
     14  *
     15  * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad
     16  *
     17  * Original code by Hannes Gredler (hannes (at) juniper.net)
     18  */
     19 
     20 #ifndef lint
     21 static const char rcsid[] _U_ =
     22     "@(#) $Header: /tcpdump/master/tcpdump/print-slow.c,v 1.1.2.1 2005/07/10 14:47:56 hannes Exp $";
     23 #endif
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include "config.h"
     27 #endif
     28 
     29 #include <tcpdump-stdinc.h>
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 
     35 #include "interface.h"
     36 #include "extract.h"
     37 #include "addrtoname.h"
     38 #include "ether.h"
     39 
     40 struct slow_common_header {
     41     u_int8_t proto_subtype;
     42     u_int8_t version;
     43 };
     44 
     45 #define	SLOW_PROTO_LACP                     1
     46 #define	SLOW_PROTO_MARKER                   2
     47 
     48 #define	LACP_VERSION                        1
     49 #define	MARKER_VERSION                      1
     50 
     51 static const struct tok slow_proto_values[] = {
     52     { SLOW_PROTO_LACP, "LACP" },
     53     { SLOW_PROTO_MARKER, "MARKER" },
     54     { 0, NULL}
     55 };
     56 
     57 struct tlv_header_t {
     58     u_int8_t type;
     59     u_int8_t length;
     60 };
     61 
     62 #define LACP_TLV_TERMINATOR     0x00
     63 #define LACP_TLV_ACTOR_INFO     0x01
     64 #define LACP_TLV_PARTNER_INFO   0x02
     65 #define LACP_TLV_COLLECTOR_INFO 0x03
     66 
     67 #define MARKER_TLV_TERMINATOR   0x00
     68 #define MARKER_TLV_MARKER_INFO  0x01
     69 
     70 static const struct tok slow_tlv_values[] = {
     71     { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
     72     { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
     73     { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, "Partner Information"},
     74     { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, "Collector Information"},
     75 
     76     { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
     77     { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, "Marker Information"},
     78     { 0, NULL}
     79 };
     80 
     81 struct lacp_tlv_actor_partner_info_t {
     82     u_int8_t sys_pri[2];
     83     u_int8_t sys[ETHER_ADDR_LEN];
     84     u_int8_t key[2];
     85     u_int8_t port_pri[2];
     86     u_int8_t port[2];
     87     u_int8_t state;
     88     u_int8_t pad[3];
     89 };
     90 
     91 static const struct tok lacp_tlv_actor_partner_info_state_values[] = {
     92     { 0x01, "Activity"},
     93     { 0x02, "Timeout"},
     94     { 0x04, "Aggregation"},
     95     { 0x08, "Synchronization"},
     96     { 0x10, "Collecting"},
     97     { 0x20, "Distributing"},
     98     { 0x40, "Default"},
     99     { 0x80, "Expired"},
    100     { 0, NULL}
    101 };
    102 
    103 struct lacp_tlv_collector_info_t {
    104     u_int8_t max_delay[2];
    105     u_int8_t pad[12];
    106 };
    107 
    108 struct marker_tlv_marker_info_t {
    109     u_int8_t req_port[2];
    110     u_int8_t req_sys[ETHER_ADDR_LEN];
    111     u_int8_t req_trans_id[4];
    112     u_int8_t pad[2];
    113 };
    114 
    115 struct lacp_marker_tlv_terminator_t {
    116     u_int8_t pad[50];
    117 };
    118 
    119 void
    120 slow_print(register const u_char *pptr, register u_int len) {
    121 
    122     const struct slow_common_header *slow_com_header;
    123     const struct tlv_header_t *tlv_header;
    124     const u_char *tptr,*tlv_tptr;
    125     u_int tlv_len,tlen,tlv_tlen;
    126 
    127     union {
    128         const struct lacp_marker_tlv_terminator_t *lacp_marker_tlv_terminator;
    129         const struct lacp_tlv_actor_partner_info_t *lacp_tlv_actor_partner_info;
    130         const struct lacp_tlv_collector_info_t *lacp_tlv_collector_info;
    131         const struct marker_tlv_marker_info_t *marker_tlv_marker_info;
    132     } tlv_ptr;
    133 
    134     tptr=pptr;
    135     slow_com_header = (const struct slow_common_header *)pptr;
    136     TCHECK(*slow_com_header);
    137 
    138     /*
    139      * Sanity checking of the header.
    140      */
    141     if (slow_com_header->proto_subtype == SLOW_PROTO_LACP &&
    142         slow_com_header->version != LACP_VERSION) {
    143 	printf("LACP version %u packet not supported",slow_com_header->version);
    144 	return;
    145     }
    146     if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER &&
    147         slow_com_header->version != MARKER_VERSION) {
    148 	printf("MARKER version %u packet not supported",slow_com_header->version);
    149 	return;
    150     }
    151 
    152     printf("%sv%u, length: %u",
    153            tok2str(slow_proto_values, "unknown (%u)",slow_com_header->proto_subtype),
    154            slow_com_header->version,
    155            len);
    156 
    157     if (!vflag)
    158         return;
    159 
    160     /* ok they seem to want to know everything - lets fully decode it */
    161     tlen=len-sizeof(struct slow_common_header);
    162     tptr+=sizeof(const struct slow_common_header);
    163 
    164     while(tlen>0) {
    165         /* did we capture enough for fully decoding the tlv header ? */
    166         TCHECK2(*tptr, sizeof(struct tlv_header_t));
    167         tlv_header = (const struct tlv_header_t *)tptr;
    168         tlv_len = tlv_header->length;
    169 
    170         printf("\n\t%s TLV (0x%02x), length: %u",
    171                tok2str(slow_tlv_values,
    172                        "Unknown",
    173                        (slow_com_header->proto_subtype << 8) + tlv_header->type),
    174                tlv_header->type,
    175                tlv_len);
    176 
    177         if ((tlv_len < sizeof(struct tlv_header_t) ||
    178             tlv_len > tlen) &&
    179             tlv_header->type != LACP_TLV_TERMINATOR &&
    180             tlv_header->type != MARKER_TLV_TERMINATOR) {
    181             printf("\n\t-----trailing data-----");
    182             print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t  ",tlen);
    183             return;
    184         }
    185 
    186         tlv_tptr=tptr+sizeof(struct tlv_header_t);
    187         tlv_tlen=tlv_len-sizeof(struct tlv_header_t);
    188 
    189         /* did we capture enough for fully decoding the tlv ? */
    190         TCHECK2(*tptr, tlv_len);
    191 
    192         switch((slow_com_header->proto_subtype << 8) + tlv_header->type) {
    193 
    194             /* those two TLVs have the same structure -> fall through */
    195         case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
    196         case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
    197             tlv_ptr.lacp_tlv_actor_partner_info = (const struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
    198 
    199             printf("\n\t  System %s, System Priority %u, Key %u" \
    200                    ", Port %u, Port Priority %u\n\t  State Flags [%s]",
    201                    etheraddr_string(tlv_ptr.lacp_tlv_actor_partner_info->sys),
    202                    EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->sys_pri),
    203                    EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->key),
    204                    EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port),
    205                    EXTRACT_16BITS(tlv_ptr.lacp_tlv_actor_partner_info->port_pri),
    206                    bittok2str(lacp_tlv_actor_partner_info_state_values,
    207                               "none",
    208                               tlv_ptr.lacp_tlv_actor_partner_info->state));
    209 
    210             break;
    211 
    212         case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
    213             tlv_ptr.lacp_tlv_collector_info = (const struct lacp_tlv_collector_info_t *)tlv_tptr;
    214 
    215             printf("\n\t  Max Delay %u",
    216                    EXTRACT_16BITS(tlv_ptr.lacp_tlv_collector_info->max_delay));
    217 
    218             break;
    219 
    220         case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
    221             tlv_ptr.marker_tlv_marker_info = (const struct marker_tlv_marker_info_t *)tlv_tptr;
    222 
    223             printf("\n\t  Request System %s, Request Port %u, Request Transaction ID 0x%08x",
    224                    etheraddr_string(tlv_ptr.marker_tlv_marker_info->req_sys),
    225                    EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->req_port),
    226                    EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->req_trans_id));
    227 
    228             break;
    229 
    230             /* those two TLVs have the same structure -> fall through */
    231         case ((SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR):
    232         case ((SLOW_PROTO_MARKER << 8) + LACP_TLV_TERMINATOR):
    233             tlv_ptr.lacp_marker_tlv_terminator = (const struct lacp_marker_tlv_terminator_t *)tlv_tptr;
    234             if (tlv_len == 0) {
    235                 tlv_len = sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad) +
    236                     sizeof(struct tlv_header_t);
    237                 /* tell the user that we modified the length field  */
    238                 if (vflag>1)
    239                     printf(" (=%u)",tlv_len);
    240                 /* we have messed around with the length field - now we need to check
    241                  * again if there are enough bytes on the wire for the hexdump */
    242                 TCHECK2(tlv_ptr.lacp_marker_tlv_terminator->pad[0],
    243                         sizeof(tlv_ptr.lacp_marker_tlv_terminator->pad));
    244             }
    245 
    246             break;
    247 
    248         default:
    249             if (vflag <= 1)
    250                 print_unknown_data(tlv_tptr,"\n\t  ",tlv_tlen);
    251             break;
    252         }
    253         /* do we want to see an additionally hexdump ? */
    254         if (vflag > 1)
    255             print_unknown_data(tptr+sizeof(sizeof(struct tlv_header_t)),"\n\t  ",
    256                                tlv_len-sizeof(struct tlv_header_t));
    257 
    258         tptr+=tlv_len;
    259         tlen-=tlv_len;
    260     }
    261     return;
    262 trunc:
    263     printf("\n\t\t packet exceeded snapshot");
    264 }
    265