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