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