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