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