1 1.1 christos /* 2 1.1 christos * Copyright (c) 1998-2006 The TCPDUMP project 3 1.1 christos * 4 1.1 christos * Redistribution and use in source and binary forms, with or without 5 1.1 christos * modification, are permitted provided that: (1) source code 6 1.1 christos * distributions retain the above copyright notice and this paragraph 7 1.1 christos * in its entirety, and (2) distributions including binary code include 8 1.1 christos * the above copyright notice and this paragraph in its entirety in 9 1.1 christos * the documentation or other materials provided with the distribution. 10 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 11 1.1 christos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 12 1.1 christos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 1.1 christos * FOR A PARTICULAR PURPOSE. 14 1.1 christos * 15 1.8 christos * Original code by Hannes Gredler (hannes (at) gredler.at) 16 1.1 christos */ 17 1.1 christos 18 1.7 spz /* \summary: IEEE 802.3ah Multi-Point Control Protocol (MPCP) printer */ 19 1.7 spz 20 1.2 christos #include <sys/cdefs.h> 21 1.1 christos #ifndef lint 22 1.10 christos __RCSID("$NetBSD: print-mpcp.c,v 1.10 2024/09/02 16:15:32 christos Exp $"); 23 1.1 christos #endif 24 1.1 christos 25 1.9 christos #include <config.h> 26 1.1 christos 27 1.9 christos #include "netdissect-stdinc.h" 28 1.1 christos 29 1.6 christos #include "netdissect.h" 30 1.1 christos #include "extract.h" 31 1.1 christos 32 1.1 christos struct mpcp_common_header_t { 33 1.9 christos nd_uint16_t opcode; 34 1.9 christos nd_uint32_t timestamp; 35 1.1 christos }; 36 1.1 christos 37 1.1 christos #define MPCP_OPCODE_PAUSE 0x0001 38 1.1 christos #define MPCP_OPCODE_GATE 0x0002 39 1.1 christos #define MPCP_OPCODE_REPORT 0x0003 40 1.1 christos #define MPCP_OPCODE_REG_REQ 0x0004 41 1.1 christos #define MPCP_OPCODE_REG 0x0005 42 1.1 christos #define MPCP_OPCODE_REG_ACK 0x0006 43 1.1 christos 44 1.1 christos static const struct tok mpcp_opcode_values[] = { 45 1.1 christos { MPCP_OPCODE_PAUSE, "Pause" }, 46 1.1 christos { MPCP_OPCODE_GATE, "Gate" }, 47 1.1 christos { MPCP_OPCODE_REPORT, "Report" }, 48 1.1 christos { MPCP_OPCODE_REG_REQ, "Register Request" }, 49 1.1 christos { MPCP_OPCODE_REG, "Register" }, 50 1.1 christos { MPCP_OPCODE_REG_ACK, "Register ACK" }, 51 1.1 christos { 0, NULL} 52 1.1 christos }; 53 1.1 christos 54 1.1 christos #define MPCP_GRANT_NUMBER_LEN 1 55 1.4 christos #define MPCP_GRANT_NUMBER_MASK 0x7 56 1.1 christos static const struct tok mpcp_grant_flag_values[] = { 57 1.1 christos { 0x08, "Discovery" }, 58 1.1 christos { 0x10, "Force Grant #1" }, 59 1.1 christos { 0x20, "Force Grant #2" }, 60 1.1 christos { 0x40, "Force Grant #3" }, 61 1.1 christos { 0x80, "Force Grant #4" }, 62 1.1 christos { 0, NULL} 63 1.1 christos }; 64 1.1 christos 65 1.1 christos struct mpcp_grant_t { 66 1.9 christos nd_uint32_t starttime; 67 1.9 christos nd_uint16_t duration; 68 1.1 christos }; 69 1.1 christos 70 1.1 christos struct mpcp_reg_req_t { 71 1.9 christos nd_uint8_t flags; 72 1.9 christos nd_uint8_t pending_grants; 73 1.1 christos }; 74 1.1 christos 75 1.1 christos 76 1.1 christos static const struct tok mpcp_reg_req_flag_values[] = { 77 1.1 christos { 1, "Register" }, 78 1.1 christos { 3, "De-Register" }, 79 1.1 christos { 0, NULL} 80 1.1 christos }; 81 1.1 christos 82 1.1 christos struct mpcp_reg_t { 83 1.9 christos nd_uint16_t assigned_port; 84 1.9 christos nd_uint8_t flags; 85 1.9 christos nd_uint16_t sync_time; 86 1.9 christos nd_uint8_t echoed_pending_grants; 87 1.1 christos }; 88 1.1 christos 89 1.1 christos static const struct tok mpcp_reg_flag_values[] = { 90 1.1 christos { 1, "Re-Register" }, 91 1.1 christos { 2, "De-Register" }, 92 1.1 christos { 3, "ACK" }, 93 1.1 christos { 4, "NACK" }, 94 1.1 christos { 0, NULL} 95 1.1 christos }; 96 1.1 christos 97 1.1 christos #define MPCP_REPORT_QUEUESETS_LEN 1 98 1.1 christos #define MPCP_REPORT_REPORTBITMAP_LEN 1 99 1.1 christos static const struct tok mpcp_report_bitmap_values[] = { 100 1.1 christos { 0x01, "Q0" }, 101 1.1 christos { 0x02, "Q1" }, 102 1.1 christos { 0x04, "Q2" }, 103 1.1 christos { 0x08, "Q3" }, 104 1.1 christos { 0x10, "Q4" }, 105 1.1 christos { 0x20, "Q5" }, 106 1.1 christos { 0x40, "Q6" }, 107 1.1 christos { 0x80, "Q7" }, 108 1.1 christos { 0, NULL} 109 1.1 christos }; 110 1.1 christos 111 1.1 christos struct mpcp_reg_ack_t { 112 1.9 christos nd_uint8_t flags; 113 1.9 christos nd_uint16_t echoed_assigned_port; 114 1.9 christos nd_uint16_t echoed_sync_time; 115 1.1 christos }; 116 1.1 christos 117 1.1 christos static const struct tok mpcp_reg_ack_flag_values[] = { 118 1.1 christos { 0, "NACK" }, 119 1.1 christos { 1, "ACK" }, 120 1.1 christos { 0, NULL} 121 1.1 christos }; 122 1.1 christos 123 1.1 christos void 124 1.9 christos mpcp_print(netdissect_options *ndo, const u_char *pptr, u_int length) 125 1.5 christos { 126 1.9 christos const struct mpcp_common_header_t *mpcp_common_header; 127 1.9 christos const struct mpcp_reg_req_t *mpcp_reg_req; 128 1.9 christos const struct mpcp_reg_t *mpcp_reg; 129 1.9 christos const struct mpcp_reg_ack_t *mpcp_reg_ack; 130 1.1 christos 131 1.1 christos 132 1.1 christos const u_char *tptr; 133 1.4 christos uint16_t opcode; 134 1.9 christos uint32_t timestamp; 135 1.4 christos uint8_t grant_numbers, grant; 136 1.4 christos uint8_t queue_sets, queue_set, report_bitmap, report; 137 1.1 christos 138 1.9 christos ndo->ndo_protocol = "mpcp"; 139 1.1 christos tptr=pptr; 140 1.9 christos mpcp_common_header = (const struct mpcp_common_header_t *)pptr; 141 1.1 christos 142 1.9 christos opcode = GET_BE_U_2(mpcp_common_header->opcode); 143 1.9 christos timestamp = GET_BE_U_4(mpcp_common_header->timestamp); 144 1.9 christos ND_PRINT("MPCP, Opcode %s", tok2str(mpcp_opcode_values, "Unknown (%u)", opcode)); 145 1.1 christos if (opcode != MPCP_OPCODE_PAUSE) { 146 1.9 christos ND_PRINT(", Timestamp %u ticks", timestamp); 147 1.1 christos } 148 1.9 christos ND_PRINT(", length %u", length); 149 1.1 christos 150 1.4 christos if (!ndo->ndo_vflag) 151 1.1 christos return; 152 1.1 christos 153 1.9 christos tptr += sizeof(struct mpcp_common_header_t); 154 1.1 christos 155 1.1 christos switch (opcode) { 156 1.1 christos case MPCP_OPCODE_PAUSE: 157 1.1 christos break; 158 1.1 christos 159 1.1 christos case MPCP_OPCODE_GATE: 160 1.9 christos grant_numbers = GET_U_1(tptr) & MPCP_GRANT_NUMBER_MASK; 161 1.9 christos ND_PRINT("\n\tGrant Numbers %u, Flags [ %s ]", 162 1.1 christos grant_numbers, 163 1.1 christos bittok2str(mpcp_grant_flag_values, 164 1.1 christos "?", 165 1.9 christos GET_U_1(tptr) & ~MPCP_GRANT_NUMBER_MASK)); 166 1.1 christos tptr++; 167 1.1 christos 168 1.1 christos for (grant = 1; grant <= grant_numbers; grant++) { 169 1.9 christos const struct mpcp_grant_t *mpcp_grant = (const struct mpcp_grant_t *)tptr; 170 1.9 christos ND_PRINT("\n\tGrant #%u, Start-Time %u ticks, duration %u ticks", 171 1.1 christos grant, 172 1.9 christos GET_BE_U_4(mpcp_grant->starttime), 173 1.9 christos GET_BE_U_2(mpcp_grant->duration)); 174 1.9 christos tptr += sizeof(struct mpcp_grant_t); 175 1.1 christos } 176 1.1 christos 177 1.9 christos ND_PRINT("\n\tSync-Time %u ticks", GET_BE_U_2(tptr)); 178 1.1 christos break; 179 1.1 christos 180 1.1 christos 181 1.1 christos case MPCP_OPCODE_REPORT: 182 1.9 christos queue_sets = GET_U_1(tptr); 183 1.1 christos tptr+=MPCP_REPORT_QUEUESETS_LEN; 184 1.9 christos ND_PRINT("\n\tTotal Queue-Sets %u", queue_sets); 185 1.1 christos 186 1.1 christos for (queue_set = 1; queue_set < queue_sets; queue_set++) { 187 1.9 christos report_bitmap = GET_U_1(tptr); 188 1.9 christos ND_PRINT("\n\t Queue-Set #%u, Report-Bitmap [ %s ]", 189 1.1 christos queue_sets, 190 1.9 christos bittok2str(mpcp_report_bitmap_values, "Unknown", report_bitmap)); 191 1.1 christos tptr++; 192 1.1 christos 193 1.1 christos report=1; 194 1.4 christos while (report_bitmap != 0) { 195 1.1 christos if (report_bitmap & 1) { 196 1.9 christos ND_PRINT("\n\t Q%u Report, Duration %u ticks", 197 1.1 christos report, 198 1.9 christos GET_BE_U_2(tptr)); 199 1.9 christos tptr += 2; 200 1.1 christos } 201 1.1 christos report++; 202 1.1 christos report_bitmap = report_bitmap >> 1; 203 1.1 christos } 204 1.1 christos } 205 1.1 christos break; 206 1.1 christos 207 1.1 christos case MPCP_OPCODE_REG_REQ: 208 1.9 christos mpcp_reg_req = (const struct mpcp_reg_req_t *)tptr; 209 1.9 christos ND_PRINT("\n\tFlags [ %s ], Pending-Grants %u", 210 1.9 christos bittok2str(mpcp_reg_req_flag_values, "Reserved", GET_U_1(mpcp_reg_req->flags)), 211 1.9 christos GET_U_1(mpcp_reg_req->pending_grants)); 212 1.1 christos break; 213 1.1 christos 214 1.1 christos case MPCP_OPCODE_REG: 215 1.9 christos mpcp_reg = (const struct mpcp_reg_t *)tptr; 216 1.9 christos ND_PRINT("\n\tAssigned-Port %u, Flags [ %s ]" 217 1.1 christos "\n\tSync-Time %u ticks, Echoed-Pending-Grants %u", 218 1.9 christos GET_BE_U_2(mpcp_reg->assigned_port), 219 1.9 christos bittok2str(mpcp_reg_flag_values, "Reserved", GET_U_1(mpcp_reg->flags)), 220 1.9 christos GET_BE_U_2(mpcp_reg->sync_time), 221 1.9 christos GET_U_1(mpcp_reg->echoed_pending_grants)); 222 1.1 christos break; 223 1.1 christos 224 1.1 christos case MPCP_OPCODE_REG_ACK: 225 1.9 christos mpcp_reg_ack = (const struct mpcp_reg_ack_t *)tptr; 226 1.9 christos ND_PRINT("\n\tEchoed-Assigned-Port %u, Flags [ %s ]" 227 1.1 christos "\n\tEchoed-Sync-Time %u ticks", 228 1.9 christos GET_BE_U_2(mpcp_reg_ack->echoed_assigned_port), 229 1.9 christos bittok2str(mpcp_reg_ack_flag_values, "Reserved", GET_U_1(mpcp_reg_ack->flags)), 230 1.9 christos GET_BE_U_2(mpcp_reg_ack->echoed_sync_time)); 231 1.1 christos break; 232 1.1 christos 233 1.1 christos default: 234 1.1 christos /* unknown opcode - hexdump for now */ 235 1.4 christos print_unknown_data(ndo,pptr, "\n\t", length); 236 1.1 christos break; 237 1.1 christos } 238 1.1 christos } 239