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