1 /* 2 * Copyright (c) 1998-2006 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 MPCP protocol as per 802.3ah 16 * 17 * Original code by Hannes Gredler (hannes@juniper.net) 18 */ 19 20 #include <sys/cdefs.h> 21 #ifndef lint 22 #if 0 23 static const char rcsid[] _U_ = 24 "@(#) Header: /tcpdump/master/tcpdump/print-mpcp.c,v 1.2 2006-02-10 17:24:55 hannes Exp"; 25 #else 26 __RCSID("$NetBSD: print-mpcp.c,v 1.2 2010/12/05 05:11:30 christos Exp $"); 27 #endif 28 #endif 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include <tcpdump-stdinc.h> 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 #include "interface.h" 41 #include "extract.h" 42 #include "addrtoname.h" 43 #include "ether.h" 44 45 #define MPCP_TIMESTAMP_LEN 4 46 #define MPCP_TIMESTAMP_DURATION_LEN 2 47 48 struct mpcp_common_header_t { 49 u_int8_t opcode[2]; 50 u_int8_t timestamp[MPCP_TIMESTAMP_LEN]; 51 }; 52 53 #define MPCP_OPCODE_PAUSE 0x0001 54 #define MPCP_OPCODE_GATE 0x0002 55 #define MPCP_OPCODE_REPORT 0x0003 56 #define MPCP_OPCODE_REG_REQ 0x0004 57 #define MPCP_OPCODE_REG 0x0005 58 #define MPCP_OPCODE_REG_ACK 0x0006 59 60 static const struct tok mpcp_opcode_values[] = { 61 { MPCP_OPCODE_PAUSE, "Pause" }, 62 { MPCP_OPCODE_GATE, "Gate" }, 63 { MPCP_OPCODE_REPORT, "Report" }, 64 { MPCP_OPCODE_REG_REQ, "Register Request" }, 65 { MPCP_OPCODE_REG, "Register" }, 66 { MPCP_OPCODE_REG_ACK, "Register ACK" }, 67 { 0, NULL} 68 }; 69 70 #define MPCP_GRANT_NUMBER_LEN 1 71 #define MPCP_GRANT_NUMBER_MASK 0x7 72 static const struct tok mpcp_grant_flag_values[] = { 73 { 0x08, "Discovery" }, 74 { 0x10, "Force Grant #1" }, 75 { 0x20, "Force Grant #2" }, 76 { 0x40, "Force Grant #3" }, 77 { 0x80, "Force Grant #4" }, 78 { 0, NULL} 79 }; 80 81 struct mpcp_grant_t { 82 u_int8_t starttime[MPCP_TIMESTAMP_LEN]; 83 u_int8_t duration[MPCP_TIMESTAMP_DURATION_LEN]; 84 }; 85 86 struct mpcp_reg_req_t { 87 u_int8_t flags; 88 u_int8_t pending_grants; 89 }; 90 91 92 static const struct tok mpcp_reg_req_flag_values[] = { 93 { 1, "Register" }, 94 { 3, "De-Register" }, 95 { 0, NULL} 96 }; 97 98 struct mpcp_reg_t { 99 u_int8_t assigned_port[2]; 100 u_int8_t flags; 101 u_int8_t sync_time[MPCP_TIMESTAMP_DURATION_LEN]; 102 u_int8_t echoed_pending_grants; 103 }; 104 105 static const struct tok mpcp_reg_flag_values[] = { 106 { 1, "Re-Register" }, 107 { 2, "De-Register" }, 108 { 3, "ACK" }, 109 { 4, "NACK" }, 110 { 0, NULL} 111 }; 112 113 #define MPCP_REPORT_QUEUESETS_LEN 1 114 #define MPCP_REPORT_REPORTBITMAP_LEN 1 115 static const struct tok mpcp_report_bitmap_values[] = { 116 { 0x01, "Q0" }, 117 { 0x02, "Q1" }, 118 { 0x04, "Q2" }, 119 { 0x08, "Q3" }, 120 { 0x10, "Q4" }, 121 { 0x20, "Q5" }, 122 { 0x40, "Q6" }, 123 { 0x80, "Q7" }, 124 { 0, NULL} 125 }; 126 127 struct mpcp_reg_ack_t { 128 u_int8_t flags; 129 u_int8_t echoed_assigned_port[2]; 130 u_int8_t echoed_sync_time[MPCP_TIMESTAMP_DURATION_LEN]; 131 }; 132 133 static const struct tok mpcp_reg_ack_flag_values[] = { 134 { 0, "NACK" }, 135 { 1, "ACK" }, 136 { 0, NULL} 137 }; 138 139 void 140 mpcp_print(register const u_char *pptr, register u_int length) { 141 142 union { 143 const struct mpcp_common_header_t *common_header; 144 const struct mpcp_grant_t *grant; 145 const struct mpcp_reg_req_t *reg_req; 146 const struct mpcp_reg_t *reg; 147 const struct mpcp_reg_ack_t *reg_ack; 148 } mpcp; 149 150 151 const u_char *tptr; 152 u_int16_t opcode; 153 u_int8_t grant_numbers, grant; 154 u_int8_t queue_sets, queue_set, report_bitmap, report; 155 156 tptr=pptr; 157 mpcp.common_header = (const struct mpcp_common_header_t *)pptr; 158 159 if (!TTEST2(*tptr, sizeof(const struct mpcp_common_header_t))) 160 goto trunc; 161 opcode = EXTRACT_16BITS(mpcp.common_header->opcode); 162 printf("MPCP, Opcode %s", tok2str(mpcp_opcode_values, "Unknown (%u)", opcode)); 163 if (opcode != MPCP_OPCODE_PAUSE) { 164 printf(", Timestamp %u ticks", EXTRACT_32BITS(mpcp.common_header->timestamp)); 165 } 166 printf(", length %u", length); 167 168 if (!vflag) 169 return; 170 171 tptr += sizeof(const struct mpcp_common_header_t); 172 173 switch (opcode) { 174 case MPCP_OPCODE_PAUSE: 175 break; 176 177 case MPCP_OPCODE_GATE: 178 if (!TTEST2(*tptr, MPCP_GRANT_NUMBER_LEN)) 179 goto trunc; 180 grant_numbers = *tptr & MPCP_GRANT_NUMBER_MASK; 181 printf("\n\tGrant Numbers %u, Flags [ %s ]", 182 grant_numbers, 183 bittok2str(mpcp_grant_flag_values, 184 "?", 185 *tptr &~ MPCP_GRANT_NUMBER_MASK)); 186 tptr++; 187 188 for (grant = 1; grant <= grant_numbers; grant++) { 189 if (!TTEST2(*tptr, sizeof(const struct mpcp_grant_t))) 190 goto trunc; 191 mpcp.grant = (const struct mpcp_grant_t *)tptr; 192 printf("\n\tGrant #%u, Start-Time %u ticks, duration %u ticks", 193 grant, 194 EXTRACT_32BITS(mpcp.grant->starttime), 195 EXTRACT_16BITS(mpcp.grant->duration)); 196 tptr += sizeof(const struct mpcp_grant_t); 197 } 198 199 if (!TTEST2(*tptr, MPCP_TIMESTAMP_DURATION_LEN)) 200 goto trunc; 201 printf("\n\tSync-Time %u ticks", EXTRACT_16BITS(tptr)); 202 break; 203 204 205 case MPCP_OPCODE_REPORT: 206 if (!TTEST2(*tptr, MPCP_REPORT_QUEUESETS_LEN)) 207 goto trunc; 208 queue_sets = *tptr; 209 tptr+=MPCP_REPORT_QUEUESETS_LEN; 210 printf("\n\tTotal Queue-Sets %u", queue_sets); 211 212 for (queue_set = 1; queue_set < queue_sets; queue_set++) { 213 if (!TTEST2(*tptr, MPCP_REPORT_REPORTBITMAP_LEN)) 214 goto trunc; 215 report_bitmap = *(tptr); 216 printf("\n\t Queue-Set #%u, Report-Bitmap [ %s ]", 217 queue_sets, 218 bittok2str(mpcp_report_bitmap_values, "Unknown", report_bitmap)); 219 tptr++; 220 221 report=1; 222 while (report_bitmap != 0) { 223 if (report_bitmap & 1) { 224 if (!TTEST2(*tptr, MPCP_TIMESTAMP_DURATION_LEN)) 225 goto trunc; 226 printf("\n\t Q%u Report, Duration %u ticks", 227 report, 228 EXTRACT_16BITS(tptr)); 229 tptr+=MPCP_TIMESTAMP_DURATION_LEN; 230 } 231 report++; 232 report_bitmap = report_bitmap >> 1; 233 } 234 } 235 break; 236 237 case MPCP_OPCODE_REG_REQ: 238 if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_req_t))) 239 goto trunc; 240 mpcp.reg_req = (const struct mpcp_reg_req_t *)tptr; 241 printf("\n\tFlags [ %s ], Pending-Grants %u", 242 bittok2str(mpcp_reg_req_flag_values, "Reserved", mpcp.reg_req->flags), 243 mpcp.reg_req->pending_grants); 244 break; 245 246 case MPCP_OPCODE_REG: 247 if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_t))) 248 goto trunc; 249 mpcp.reg = (const struct mpcp_reg_t *)tptr; 250 printf("\n\tAssigned-Port %u, Flags [ %s ]" \ 251 "\n\tSync-Time %u ticks, Echoed-Pending-Grants %u", 252 EXTRACT_16BITS(mpcp.reg->assigned_port), 253 bittok2str(mpcp_reg_flag_values, "Reserved", mpcp.reg->flags), 254 EXTRACT_16BITS(mpcp.reg->sync_time), 255 mpcp.reg->echoed_pending_grants); 256 break; 257 258 case MPCP_OPCODE_REG_ACK: 259 if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_ack_t))) 260 goto trunc; 261 mpcp.reg_ack = (const struct mpcp_reg_ack_t *)tptr; 262 printf("\n\tEchoed-Assigned-Port %u, Flags [ %s ]" \ 263 "\n\tEchoed-Sync-Time %u ticks", 264 EXTRACT_16BITS(mpcp.reg_ack->echoed_assigned_port), 265 bittok2str(mpcp_reg_ack_flag_values, "Reserved", mpcp.reg_ack->flags), 266 EXTRACT_16BITS(mpcp.reg_ack->echoed_sync_time)); 267 break; 268 269 default: 270 /* unknown opcode - hexdump for now */ 271 print_unknown_data(pptr, "\n\t", length); 272 break; 273 } 274 275 return; 276 277 trunc: 278 printf("\n\t[|MPCP]"); 279 } 280