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