1 /* $OpenBSD: print-slow.c,v 1.4 2015/11/16 00:16:39 mmcc 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/time.h> 23 #include <sys/socket.h> 24 #include <sys/file.h> 25 #include <sys/ioctl.h> 26 27 #include <net/if.h> 28 29 #include <netinet/in.h> 30 #include <netinet/ip.h> 31 #include <netinet/if_ether.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "interface.h" 37 #include "extract.h" 38 #include "addrtoname.h" 39 40 41 struct slow_common_header { 42 u_int8_t proto_subtype; 43 u_int8_t version; 44 }; 45 46 #define SLOW_PROTO_LACP 1 47 #define SLOW_PROTO_MARKER 2 48 49 #define LACP_VERSION 1 50 #define MARKER_VERSION 1 51 52 static const struct tok slow_proto_values[] = { 53 { SLOW_PROTO_LACP, "LACP" }, 54 { SLOW_PROTO_MARKER, "MARKER" }, 55 { 0, NULL} 56 }; 57 58 struct tlv_header_t { 59 u_int8_t type; 60 u_int8_t length; 61 }; 62 63 #define LACP_TLV_TERMINATOR 0x00 64 #define LACP_TLV_ACTOR_INFO 0x01 65 #define LACP_TLV_PARTNER_INFO 0x02 66 #define LACP_TLV_COLLECTOR_INFO 0x03 67 68 #define MARKER_TLV_TERMINATOR 0x00 69 #define MARKER_TLV_MARKER_INFO 0x01 70 #define MARKER_TLV_MARKER_RESP 0x02 71 72 static const struct tok slow_tlv_values[] = { 73 { (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"}, 74 { (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"}, 75 { (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO, 76 "Partner Information"}, 77 { (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO, 78 "Collector Information"}, 79 80 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"}, 81 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO, 82 "Marker Information"}, 83 { (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP, 84 "Marker Response Information"}, 85 { 0, NULL} 86 }; 87 88 struct lacp_tlv_actor_partner_info_t { 89 u_int8_t sys_pri[2]; 90 u_int8_t sys[ETHER_ADDR_LEN]; 91 u_int8_t key[2]; 92 u_int8_t port_pri[2]; 93 u_int8_t port[2]; 94 u_int8_t state; 95 u_int8_t pad[3]; 96 }; 97 98 #define ACTOR_PARTNER_BITS \ 99 "\020\1Activity\2Timeout\3Aggregation\4Synchronization\5Collecting\ 100 \6Distributing\7Default\10Expired" 101 102 struct lacp_tlv_collector_info_t { 103 u_int8_t max_delay[2]; 104 u_int8_t pad[12]; 105 }; 106 107 struct marker_tlv_marker_info_t { 108 u_int8_t req_port[2]; 109 u_int8_t req_sys[ETHER_ADDR_LEN]; 110 u_int8_t req_trans_id[4]; 111 u_int8_t pad[2]; 112 }; 113 114 struct lacp_marker_tlv_terminator_t { 115 u_int8_t pad[50]; 116 }; 117 118 void 119 slow_print(const u_char *pptr, u_int len) 120 { 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 struct lacp_marker_tlv_terminator_t *marker_terminator; 129 struct lacp_tlv_actor_partner_info_t *actor_partner_info; 130 struct lacp_tlv_collector_info_t *collector_info; 131 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", 144 slow_com_header->version); 145 return; 146 } 147 if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER && 148 slow_com_header->version != MARKER_VERSION) { 149 printf("MARKER version %u packet not supported", 150 slow_com_header->version); 151 return; 152 } 153 154 printf("%sv%u, length: %u", 155 tok2str(slow_proto_values, "unknown (%u)", 156 slow_com_header->proto_subtype), slow_com_header->version, len); 157 158 if (!vflag) 159 return; 160 161 /* ok they seem to want to know everything - lets fully decode it */ 162 tlen = len - sizeof(struct slow_common_header); 163 tptr += sizeof(const struct slow_common_header); 164 165 while (tlen > 0) { 166 /* did we capture enough for fully decoding the tlv header ? */ 167 TCHECK2(*tptr, sizeof(struct tlv_header_t)); 168 tlv_header = (const struct tlv_header_t *)tptr; 169 tlv_len = tlv_header->length; 170 171 /* End of message */ 172 if (tlv_header->type == LACP_TLV_TERMINATOR || 173 tlv_header->type == MARKER_TLV_TERMINATOR) 174 return; 175 176 printf("\n\t%s TLV (0x%02x), length: %u", 177 tok2str(slow_tlv_values, "Unknown", 178 (slow_com_header->proto_subtype << 8) + tlv_header->type), 179 tlv_header->type, tlv_len); 180 181 if (tlv_len < sizeof(struct tlv_header_t) || tlv_len > tlen) { 182 printf("\n\tInvalid TLV length: %u", tlv_len); 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) + 193 tlv_header->type) { 194 195 /* those two TLVs have the same structure -> fall through */ 196 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO): 197 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO): 198 tlv_ptr.actor_partner_info = 199 (struct lacp_tlv_actor_partner_info_t *)tlv_tptr; 200 if (tlv_tlen != sizeof(*tlv_ptr.actor_partner_info)) { 201 printf("\n\tInvalid partner/actor info length %u", 202 tlv_tlen); 203 break; 204 } 205 206 printf("\n\t System %s, System Priority %u, Key %u" 207 ", Port %u, Port Priority %u\n\t ", 208 etheraddr_string(tlv_ptr.actor_partner_info->sys), 209 EXTRACT_16BITS(tlv_ptr.actor_partner_info->sys_pri), 210 EXTRACT_16BITS(tlv_ptr.actor_partner_info->key), 211 EXTRACT_16BITS(tlv_ptr.actor_partner_info->port), 212 EXTRACT_16BITS(tlv_ptr.actor_partner_info-> 213 port_pri)); 214 printb("State", tlv_ptr.actor_partner_info->state, 215 ACTOR_PARTNER_BITS); 216 break; 217 218 case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO): 219 tlv_ptr.collector_info = 220 (struct lacp_tlv_collector_info_t *)tlv_tptr; 221 if (tlv_tlen != sizeof(*tlv_ptr.collector_info)) { 222 printf("\n\tInvalid collector info length %u", 223 tlv_tlen); 224 break; 225 } 226 227 printf("\n\t Max Delay %u", 228 EXTRACT_16BITS(tlv_ptr.collector_info->max_delay)); 229 break; 230 231 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO): 232 case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP): 233 tlv_ptr.marker_tlv_marker_info = 234 (struct marker_tlv_marker_info_t *)tlv_tptr; 235 if (tlv_tlen != 236 sizeof(*tlv_ptr.marker_tlv_marker_info)) { 237 printf("\n\tInvalid marker info/resp length %u", 238 tlv_tlen); 239 break; 240 } 241 242 printf("\n\t Request System %s, Request Port %u," 243 " Request Transaction ID 0x%08x", 244 etheraddr_string(tlv_ptr.marker_tlv_marker_info-> 245 req_sys), 246 EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info-> 247 req_port), 248 EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info-> 249 req_trans_id)); 250 break; 251 252 default: 253 if (vflag > 1) 254 printf("\n\t Unknown TLV type: 0x%x \n", 255 (slow_com_header->proto_subtype << 8) + 256 tlv_header->type); 257 break; 258 } 259 260 tptr += tlv_len; 261 tlen -= tlv_len; 262 } 263 264 return; 265 trunc: 266 printf("\n\t[|slow]"); 267 } 268