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