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 #include <sys/cdefs.h> 21 #ifndef lint 22 __RCSID("$NetBSD: print-mpcp.c,v 1.10 2024/09/02 16:15:32 christos Exp $"); 23 #endif 24 25 #include <config.h> 26 27 #include "netdissect-stdinc.h" 28 29 #include "netdissect.h" 30 #include "extract.h" 31 32 struct mpcp_common_header_t { 33 nd_uint16_t opcode; 34 nd_uint32_t timestamp; 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 nd_uint32_t starttime; 67 nd_uint16_t duration; 68 }; 69 70 struct mpcp_reg_req_t { 71 nd_uint8_t flags; 72 nd_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 nd_uint16_t assigned_port; 84 nd_uint8_t flags; 85 nd_uint16_t sync_time; 86 nd_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 nd_uint8_t flags; 113 nd_uint16_t echoed_assigned_port; 114 nd_uint16_t echoed_sync_time; 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, const u_char *pptr, u_int length) 125 { 126 const struct mpcp_common_header_t *mpcp_common_header; 127 const struct mpcp_reg_req_t *mpcp_reg_req; 128 const struct mpcp_reg_t *mpcp_reg; 129 const struct mpcp_reg_ack_t *mpcp_reg_ack; 130 131 132 const u_char *tptr; 133 uint16_t opcode; 134 uint32_t timestamp; 135 uint8_t grant_numbers, grant; 136 uint8_t queue_sets, queue_set, report_bitmap, report; 137 138 ndo->ndo_protocol = "mpcp"; 139 tptr=pptr; 140 mpcp_common_header = (const struct mpcp_common_header_t *)pptr; 141 142 opcode = GET_BE_U_2(mpcp_common_header->opcode); 143 timestamp = GET_BE_U_4(mpcp_common_header->timestamp); 144 ND_PRINT("MPCP, Opcode %s", tok2str(mpcp_opcode_values, "Unknown (%u)", opcode)); 145 if (opcode != MPCP_OPCODE_PAUSE) { 146 ND_PRINT(", Timestamp %u ticks", timestamp); 147 } 148 ND_PRINT(", length %u", length); 149 150 if (!ndo->ndo_vflag) 151 return; 152 153 tptr += sizeof(struct mpcp_common_header_t); 154 155 switch (opcode) { 156 case MPCP_OPCODE_PAUSE: 157 break; 158 159 case MPCP_OPCODE_GATE: 160 grant_numbers = GET_U_1(tptr) & MPCP_GRANT_NUMBER_MASK; 161 ND_PRINT("\n\tGrant Numbers %u, Flags [ %s ]", 162 grant_numbers, 163 bittok2str(mpcp_grant_flag_values, 164 "?", 165 GET_U_1(tptr) & ~MPCP_GRANT_NUMBER_MASK)); 166 tptr++; 167 168 for (grant = 1; grant <= grant_numbers; grant++) { 169 const struct mpcp_grant_t *mpcp_grant = (const struct mpcp_grant_t *)tptr; 170 ND_PRINT("\n\tGrant #%u, Start-Time %u ticks, duration %u ticks", 171 grant, 172 GET_BE_U_4(mpcp_grant->starttime), 173 GET_BE_U_2(mpcp_grant->duration)); 174 tptr += sizeof(struct mpcp_grant_t); 175 } 176 177 ND_PRINT("\n\tSync-Time %u ticks", GET_BE_U_2(tptr)); 178 break; 179 180 181 case MPCP_OPCODE_REPORT: 182 queue_sets = GET_U_1(tptr); 183 tptr+=MPCP_REPORT_QUEUESETS_LEN; 184 ND_PRINT("\n\tTotal Queue-Sets %u", queue_sets); 185 186 for (queue_set = 1; queue_set < queue_sets; queue_set++) { 187 report_bitmap = GET_U_1(tptr); 188 ND_PRINT("\n\t Queue-Set #%u, Report-Bitmap [ %s ]", 189 queue_sets, 190 bittok2str(mpcp_report_bitmap_values, "Unknown", report_bitmap)); 191 tptr++; 192 193 report=1; 194 while (report_bitmap != 0) { 195 if (report_bitmap & 1) { 196 ND_PRINT("\n\t Q%u Report, Duration %u ticks", 197 report, 198 GET_BE_U_2(tptr)); 199 tptr += 2; 200 } 201 report++; 202 report_bitmap = report_bitmap >> 1; 203 } 204 } 205 break; 206 207 case MPCP_OPCODE_REG_REQ: 208 mpcp_reg_req = (const struct mpcp_reg_req_t *)tptr; 209 ND_PRINT("\n\tFlags [ %s ], Pending-Grants %u", 210 bittok2str(mpcp_reg_req_flag_values, "Reserved", GET_U_1(mpcp_reg_req->flags)), 211 GET_U_1(mpcp_reg_req->pending_grants)); 212 break; 213 214 case MPCP_OPCODE_REG: 215 mpcp_reg = (const struct mpcp_reg_t *)tptr; 216 ND_PRINT("\n\tAssigned-Port %u, Flags [ %s ]" 217 "\n\tSync-Time %u ticks, Echoed-Pending-Grants %u", 218 GET_BE_U_2(mpcp_reg->assigned_port), 219 bittok2str(mpcp_reg_flag_values, "Reserved", GET_U_1(mpcp_reg->flags)), 220 GET_BE_U_2(mpcp_reg->sync_time), 221 GET_U_1(mpcp_reg->echoed_pending_grants)); 222 break; 223 224 case MPCP_OPCODE_REG_ACK: 225 mpcp_reg_ack = (const struct mpcp_reg_ack_t *)tptr; 226 ND_PRINT("\n\tEchoed-Assigned-Port %u, Flags [ %s ]" 227 "\n\tEchoed-Sync-Time %u ticks", 228 GET_BE_U_2(mpcp_reg_ack->echoed_assigned_port), 229 bittok2str(mpcp_reg_ack_flag_values, "Reserved", GET_U_1(mpcp_reg_ack->flags)), 230 GET_BE_U_2(mpcp_reg_ack->echoed_sync_time)); 231 break; 232 233 default: 234 /* unknown opcode - hexdump for now */ 235 print_unknown_data(ndo,pptr, "\n\t", length); 236 break; 237 } 238 } 239