1190203Srpaulo/*
2190203Srpaulo * Copyright (c) 1998-2006 The TCPDUMP project
3190203Srpaulo *
4190203Srpaulo * Redistribution and use in source and binary forms, with or without
5190203Srpaulo * modification, are permitted provided that: (1) source code
6190203Srpaulo * distributions retain the above copyright notice and this paragraph
7190203Srpaulo * in its entirety, and (2) distributions including binary code include
8190203Srpaulo * the above copyright notice and this paragraph in its entirety in
9190203Srpaulo * the documentation or other materials provided with the distribution.
10190203Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11190203Srpaulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12190203Srpaulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13190203Srpaulo * FOR A PARTICULAR PURPOSE.
14190203Srpaulo *
15190203Srpaulo * support for the IEEE MPCP protocol as per 802.3ah
16190203Srpaulo *
17190203Srpaulo * Original code by Hannes Gredler (hannes@juniper.net)
18190203Srpaulo */
19190203Srpaulo
20190203Srpaulo#ifndef lint
21190203Srpaulostatic const char rcsid[] _U_ =
22190203Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-mpcp.c,v 1.2 2006-02-10 17:24:55 hannes Exp $";
23190203Srpaulo#endif
24190203Srpaulo
25190203Srpaulo#ifdef HAVE_CONFIG_H
26190203Srpaulo#include "config.h"
27190203Srpaulo#endif
28190203Srpaulo
29190203Srpaulo#include <tcpdump-stdinc.h>
30190203Srpaulo
31190203Srpaulo#include <stdio.h>
32190203Srpaulo#include <stdlib.h>
33190203Srpaulo#include <string.h>
34190203Srpaulo
35190203Srpaulo#include "interface.h"
36190203Srpaulo#include "extract.h"
37190203Srpaulo#include "addrtoname.h"
38190203Srpaulo#include "ether.h"
39190203Srpaulo
40190203Srpaulo#define MPCP_TIMESTAMP_LEN        4
41190203Srpaulo#define MPCP_TIMESTAMP_DURATION_LEN 2
42190203Srpaulo
43190203Srpaulostruct mpcp_common_header_t {
44190203Srpaulo    u_int8_t opcode[2];
45190203Srpaulo    u_int8_t timestamp[MPCP_TIMESTAMP_LEN];
46190203Srpaulo};
47190203Srpaulo
48190203Srpaulo#define	MPCP_OPCODE_PAUSE   0x0001
49190203Srpaulo#define	MPCP_OPCODE_GATE    0x0002
50190203Srpaulo#define	MPCP_OPCODE_REPORT  0x0003
51190203Srpaulo#define	MPCP_OPCODE_REG_REQ 0x0004
52190203Srpaulo#define	MPCP_OPCODE_REG     0x0005
53190203Srpaulo#define	MPCP_OPCODE_REG_ACK 0x0006
54190203Srpaulo
55190203Srpaulostatic const struct tok mpcp_opcode_values[] = {
56190203Srpaulo    { MPCP_OPCODE_PAUSE, "Pause" },
57190203Srpaulo    { MPCP_OPCODE_GATE, "Gate" },
58190203Srpaulo    { MPCP_OPCODE_REPORT, "Report" },
59190203Srpaulo    { MPCP_OPCODE_REG_REQ, "Register Request" },
60190203Srpaulo    { MPCP_OPCODE_REG, "Register" },
61190203Srpaulo    { MPCP_OPCODE_REG_ACK, "Register ACK" },
62190203Srpaulo    { 0, NULL}
63190203Srpaulo};
64190203Srpaulo
65190203Srpaulo#define MPCP_GRANT_NUMBER_LEN 1
66190203Srpaulo#define	MPCP_GRANT_NUMBER_MASK 0x7
67190203Srpaulostatic const struct tok mpcp_grant_flag_values[] = {
68190203Srpaulo    { 0x08, "Discovery" },
69190203Srpaulo    { 0x10, "Force Grant #1" },
70190203Srpaulo    { 0x20, "Force Grant #2" },
71190203Srpaulo    { 0x40, "Force Grant #3" },
72190203Srpaulo    { 0x80, "Force Grant #4" },
73190203Srpaulo    { 0, NULL}
74190203Srpaulo};
75190203Srpaulo
76190203Srpaulostruct mpcp_grant_t {
77190203Srpaulo    u_int8_t starttime[MPCP_TIMESTAMP_LEN];
78190203Srpaulo    u_int8_t duration[MPCP_TIMESTAMP_DURATION_LEN];
79190203Srpaulo};
80190203Srpaulo
81190203Srpaulostruct mpcp_reg_req_t {
82190203Srpaulo    u_int8_t flags;
83190203Srpaulo    u_int8_t pending_grants;
84190203Srpaulo};
85190203Srpaulo
86190203Srpaulo
87190203Srpaulostatic const struct tok mpcp_reg_req_flag_values[] = {
88190203Srpaulo    { 1, "Register" },
89190203Srpaulo    { 3, "De-Register" },
90190203Srpaulo    { 0, NULL}
91190203Srpaulo};
92190203Srpaulo
93190203Srpaulostruct mpcp_reg_t {
94190203Srpaulo    u_int8_t assigned_port[2];
95190203Srpaulo    u_int8_t flags;
96190203Srpaulo    u_int8_t sync_time[MPCP_TIMESTAMP_DURATION_LEN];
97190203Srpaulo    u_int8_t echoed_pending_grants;
98190203Srpaulo};
99190203Srpaulo
100190203Srpaulostatic const struct tok mpcp_reg_flag_values[] = {
101190203Srpaulo    { 1, "Re-Register" },
102190203Srpaulo    { 2, "De-Register" },
103190203Srpaulo    { 3, "ACK" },
104190203Srpaulo    { 4, "NACK" },
105190203Srpaulo    { 0, NULL}
106190203Srpaulo};
107190203Srpaulo
108190203Srpaulo#define MPCP_REPORT_QUEUESETS_LEN    1
109190203Srpaulo#define MPCP_REPORT_REPORTBITMAP_LEN 1
110190203Srpaulostatic const struct tok mpcp_report_bitmap_values[] = {
111190203Srpaulo    { 0x01, "Q0" },
112190203Srpaulo    { 0x02, "Q1" },
113190203Srpaulo    { 0x04, "Q2" },
114190203Srpaulo    { 0x08, "Q3" },
115190203Srpaulo    { 0x10, "Q4" },
116190203Srpaulo    { 0x20, "Q5" },
117190203Srpaulo    { 0x40, "Q6" },
118190203Srpaulo    { 0x80, "Q7" },
119190203Srpaulo    { 0, NULL}
120190203Srpaulo};
121190203Srpaulo
122190203Srpaulostruct mpcp_reg_ack_t {
123190203Srpaulo    u_int8_t flags;
124190203Srpaulo    u_int8_t echoed_assigned_port[2];
125190203Srpaulo    u_int8_t echoed_sync_time[MPCP_TIMESTAMP_DURATION_LEN];
126190203Srpaulo};
127190203Srpaulo
128190203Srpaulostatic const struct tok mpcp_reg_ack_flag_values[] = {
129190203Srpaulo    { 0, "NACK" },
130190203Srpaulo    { 1, "ACK" },
131190203Srpaulo    { 0, NULL}
132190203Srpaulo};
133190203Srpaulo
134190203Srpaulovoid
135190203Srpaulompcp_print(register const u_char *pptr, register u_int length) {
136190203Srpaulo
137190203Srpaulo    union {
138190203Srpaulo        const struct mpcp_common_header_t *common_header;
139190203Srpaulo        const struct mpcp_grant_t *grant;
140190203Srpaulo        const struct mpcp_reg_req_t *reg_req;
141190203Srpaulo        const struct mpcp_reg_t *reg;
142190203Srpaulo        const struct mpcp_reg_ack_t *reg_ack;
143190203Srpaulo    } mpcp;
144190203Srpaulo
145190203Srpaulo
146190203Srpaulo    const u_char *tptr;
147190203Srpaulo    u_int16_t opcode;
148190203Srpaulo    u_int8_t grant_numbers, grant;
149190203Srpaulo    u_int8_t queue_sets, queue_set, report_bitmap, report;
150190203Srpaulo
151190203Srpaulo    tptr=pptr;
152190203Srpaulo    mpcp.common_header = (const struct mpcp_common_header_t *)pptr;
153190203Srpaulo
154190203Srpaulo    if (!TTEST2(*tptr, sizeof(const struct mpcp_common_header_t)))
155190203Srpaulo        goto trunc;
156190203Srpaulo    opcode = EXTRACT_16BITS(mpcp.common_header->opcode);
157190203Srpaulo    printf("MPCP, Opcode %s", tok2str(mpcp_opcode_values, "Unknown (%u)", opcode));
158190203Srpaulo    if (opcode != MPCP_OPCODE_PAUSE) {
159190203Srpaulo        printf(", Timestamp %u ticks", EXTRACT_32BITS(mpcp.common_header->timestamp));
160190203Srpaulo    }
161190203Srpaulo    printf(", length %u", length);
162190203Srpaulo
163190203Srpaulo    if (!vflag)
164190203Srpaulo        return;
165190203Srpaulo
166190203Srpaulo    tptr += sizeof(const struct mpcp_common_header_t);
167190203Srpaulo
168190203Srpaulo    switch (opcode) {
169190203Srpaulo    case MPCP_OPCODE_PAUSE:
170190203Srpaulo        break;
171190203Srpaulo
172190203Srpaulo    case MPCP_OPCODE_GATE:
173190203Srpaulo	if (!TTEST2(*tptr, MPCP_GRANT_NUMBER_LEN))
174190203Srpaulo	    goto trunc;
175190203Srpaulo        grant_numbers = *tptr & MPCP_GRANT_NUMBER_MASK;
176190203Srpaulo        printf("\n\tGrant Numbers %u, Flags [ %s ]",
177190203Srpaulo               grant_numbers,
178190203Srpaulo               bittok2str(mpcp_grant_flag_values,
179190203Srpaulo                          "?",
180190203Srpaulo                          *tptr &~ MPCP_GRANT_NUMBER_MASK));
181190203Srpaulo        tptr++;
182190203Srpaulo
183190203Srpaulo        for (grant = 1; grant <= grant_numbers; grant++) {
184190203Srpaulo            if (!TTEST2(*tptr, sizeof(const struct mpcp_grant_t)))
185190203Srpaulo                goto trunc;
186190203Srpaulo            mpcp.grant = (const struct mpcp_grant_t *)tptr;
187190203Srpaulo            printf("\n\tGrant #%u, Start-Time %u ticks, duration %u ticks",
188190203Srpaulo                   grant,
189190203Srpaulo                   EXTRACT_32BITS(mpcp.grant->starttime),
190190203Srpaulo                   EXTRACT_16BITS(mpcp.grant->duration));
191190203Srpaulo            tptr += sizeof(const struct mpcp_grant_t);
192190203Srpaulo        }
193190203Srpaulo
194190203Srpaulo	if (!TTEST2(*tptr, MPCP_TIMESTAMP_DURATION_LEN))
195190203Srpaulo	    goto trunc;
196190203Srpaulo        printf("\n\tSync-Time %u ticks", EXTRACT_16BITS(tptr));
197190203Srpaulo        break;
198190203Srpaulo
199190203Srpaulo
200190203Srpaulo    case MPCP_OPCODE_REPORT:
201190203Srpaulo	if (!TTEST2(*tptr, MPCP_REPORT_QUEUESETS_LEN))
202190203Srpaulo	    goto trunc;
203190203Srpaulo        queue_sets = *tptr;
204190203Srpaulo        tptr+=MPCP_REPORT_QUEUESETS_LEN;
205190203Srpaulo        printf("\n\tTotal Queue-Sets %u", queue_sets);
206190203Srpaulo
207190203Srpaulo        for (queue_set = 1; queue_set < queue_sets; queue_set++) {
208190203Srpaulo            if (!TTEST2(*tptr, MPCP_REPORT_REPORTBITMAP_LEN))
209190203Srpaulo                goto trunc;
210190203Srpaulo            report_bitmap = *(tptr);
211190203Srpaulo            printf("\n\t  Queue-Set #%u, Report-Bitmap [ %s ]",
212190203Srpaulo                   queue_sets,
213190203Srpaulo                   bittok2str(mpcp_report_bitmap_values, "Unknown", report_bitmap));
214190203Srpaulo            tptr++;
215190203Srpaulo
216190203Srpaulo            report=1;
217190203Srpaulo            while (report_bitmap != 0) {
218190203Srpaulo                if (report_bitmap & 1) {
219190203Srpaulo                    if (!TTEST2(*tptr, MPCP_TIMESTAMP_DURATION_LEN))
220190203Srpaulo                        goto trunc;
221190203Srpaulo                    printf("\n\t    Q%u Report, Duration %u ticks",
222190203Srpaulo                           report,
223190203Srpaulo                           EXTRACT_16BITS(tptr));
224190203Srpaulo                    tptr+=MPCP_TIMESTAMP_DURATION_LEN;
225190203Srpaulo                }
226190203Srpaulo                report++;
227190203Srpaulo                report_bitmap = report_bitmap >> 1;
228190203Srpaulo            }
229190203Srpaulo        }
230190203Srpaulo        break;
231190203Srpaulo
232190203Srpaulo    case MPCP_OPCODE_REG_REQ:
233190203Srpaulo        if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_req_t)))
234190203Srpaulo            goto trunc;
235190203Srpaulo        mpcp.reg_req = (const struct mpcp_reg_req_t *)tptr;
236190203Srpaulo        printf("\n\tFlags [ %s ], Pending-Grants %u",
237190203Srpaulo               bittok2str(mpcp_reg_req_flag_values, "Reserved", mpcp.reg_req->flags),
238190203Srpaulo               mpcp.reg_req->pending_grants);
239190203Srpaulo        break;
240190203Srpaulo
241190203Srpaulo    case MPCP_OPCODE_REG:
242190203Srpaulo        if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_t)))
243190203Srpaulo            goto trunc;
244190203Srpaulo        mpcp.reg = (const struct mpcp_reg_t *)tptr;
245190203Srpaulo        printf("\n\tAssigned-Port %u, Flags [ %s ]" \
246190203Srpaulo               "\n\tSync-Time %u ticks, Echoed-Pending-Grants %u",
247190203Srpaulo               EXTRACT_16BITS(mpcp.reg->assigned_port),
248190203Srpaulo               bittok2str(mpcp_reg_flag_values, "Reserved", mpcp.reg->flags),
249190203Srpaulo               EXTRACT_16BITS(mpcp.reg->sync_time),
250190203Srpaulo               mpcp.reg->echoed_pending_grants);
251190203Srpaulo        break;
252190203Srpaulo
253190203Srpaulo    case MPCP_OPCODE_REG_ACK:
254190203Srpaulo        if (!TTEST2(*tptr, sizeof(const struct mpcp_reg_ack_t)))
255190203Srpaulo            goto trunc;
256190203Srpaulo        mpcp.reg_ack = (const struct mpcp_reg_ack_t *)tptr;
257190203Srpaulo        printf("\n\tEchoed-Assigned-Port %u, Flags [ %s ]" \
258190203Srpaulo               "\n\tEchoed-Sync-Time %u ticks",
259190203Srpaulo               EXTRACT_16BITS(mpcp.reg_ack->echoed_assigned_port),
260190203Srpaulo               bittok2str(mpcp_reg_ack_flag_values, "Reserved", mpcp.reg_ack->flags),
261190203Srpaulo               EXTRACT_16BITS(mpcp.reg_ack->echoed_sync_time));
262190203Srpaulo        break;
263190203Srpaulo
264190203Srpaulo    default:
265190203Srpaulo        /* unknown opcode - hexdump for now */
266190203Srpaulo        print_unknown_data(pptr, "\n\t", length);
267190203Srpaulo        break;
268190203Srpaulo    }
269190203Srpaulo
270190203Srpaulo    return;
271190203Srpaulo
272190203Srpaulotrunc:
273190203Srpaulo    printf("\n\t[|MPCP]");
274190203Srpaulo}
275