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