summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-trill.c
blob: 755b272e59a8124e7b844a6db4b6b152b35b5b70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* packet-trill.c
 * Routines for TRILL (TRansparent Interconnection of Lots of Links) dissection
 * Copyright 2010, David Bond <mokon@mokon.net>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

/*
 * See: RFC6325
 */

#include "config.h"

#include <epan/packet.h>
#include <epan/etypes.h>

void proto_register_trill(void);
void proto_reg_handoff_trill(void);

static dissector_handle_t trill_handle;

static int proto_trill = -1 ;
static gint ett_trill = -1 ;

static int hf_trill_version = -1 ;
static int hf_trill_reserved = -1 ;
static int hf_trill_multi_dst = -1 ;
static int hf_trill_op_len = -1 ;
static int hf_trill_hop_cnt = -1 ;
static int hf_trill_egress_nick = -1 ;
static int hf_trill_ingress_nick = -1 ;
/* TODO For now we will just add all the options into a byte field.
   Later this should be parsed out into a sub-tree with all the option
   details. */
static int hf_trill_options= -1 ;

static dissector_handle_t eth_dissector ;

#define TRILL_VERSION_MASK   0xC000
#define TRILL_RESERVED_MASK  0x3000
#define TRILL_MULTI_DST_MASK 0x0800
#define TRILL_OP_LEN_MASK    0x07C0
#define TRILL_HOP_CNT_MASK   0x003F

#define TRILL_PROTO_COL_NAME "TRILL"
#define TRILL_PROTO_COL_INFO "TRILL Encapsulated Frame"

#define TRILL_MIN_FRAME_LENGTH     6
#define TRILL_BIT_FIELDS_LEN       2
#define TRILL_NICKNAME_LEN         2
#define TRILL_OP_LENGTH_BYTE_UNITS 0x4

static const true_false_string multi_dst_strings = {
  "Multi-Destination TRILL Frame",
  "Known Unicast TRILL Frame"
} ;

static const range_string version_strings[] = {
  { 0, 0, "RFC6325 Version" },
  { 1, 3, "Unallocated Version" },
  { 0, 0, NULL }
} ;

static const range_string reserved_strings[] = {
  { 0, 0, "Legal Value" },
  { 1, 3, "Illegal Value" },
  { 0, 0, NULL }
} ;

static const range_string nickname_strings[] = {
  { 0x0000, 0x0000, "Nickname Not Specified" },
  { 0x0001, 0xFFBF, "Valid Nickname" },
  { 0xFFC0, 0xFFC0, "Any RBridge" },
  { 0xFFC1, 0xFFC1, "OOMF" },
  { 0xFFC2, 0xFFFE, "Reserved for Future Specification" },
  { 0xFFFF, 0xFFFF, "Permanently Reserved" },
  { 0, 0, NULL }
} ;

/* Trill Dissector */
static int
dissect_trill( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
{
  proto_item *ti ;
  proto_tree *trill_tree ;
  guint32     op_len ;
  tvbuff_t   *next_tvb ;
  int         offset = 0 ;

  col_set_str( pinfo->cinfo, COL_PROTOCOL, TRILL_PROTO_COL_NAME ) ;
  col_set_str( pinfo->cinfo, COL_INFO, TRILL_PROTO_COL_INFO ) ;

  op_len = tvb_get_bits( tvb, 5, 5, ENC_BIG_ENDIAN ) * TRILL_OP_LENGTH_BYTE_UNITS ;
  if (tree) {
    ti = proto_tree_add_item( tree, proto_trill, tvb, 0,
      TRILL_MIN_FRAME_LENGTH + op_len, ENC_NA ) ;
    trill_tree = proto_item_add_subtree( ti, ett_trill ) ;

    /* Parse the bit fields, i.e. V, R, M, Op-Length, Hop Count. */
    proto_tree_add_item( trill_tree, hf_trill_version, tvb, offset,
      TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
    proto_tree_add_item( trill_tree, hf_trill_reserved, tvb, offset,
      TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
    proto_tree_add_item( trill_tree, hf_trill_multi_dst, tvb, offset,
      TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
    proto_tree_add_item( trill_tree, hf_trill_op_len, tvb, offset,
      TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;
    proto_tree_add_item( trill_tree, hf_trill_hop_cnt, tvb, offset,
      TRILL_BIT_FIELDS_LEN, ENC_BIG_ENDIAN ) ;

    /* Parse the egress nickname. */
    offset += TRILL_BIT_FIELDS_LEN ;
    proto_tree_add_item( trill_tree, hf_trill_egress_nick, tvb, offset,
      TRILL_NICKNAME_LEN, ENC_BIG_ENDIAN ) ;

    /* Parse the ingress nickname. */
    offset += TRILL_NICKNAME_LEN  ;
    proto_tree_add_item( trill_tree, hf_trill_ingress_nick, tvb, offset,
      TRILL_NICKNAME_LEN , ENC_BIG_ENDIAN ) ;

    /* Parse the options field. */
    offset += TRILL_NICKNAME_LEN  ;
    if( op_len != 0 ) {
      proto_tree_add_item( trill_tree, hf_trill_options, tvb,
        offset, op_len, ENC_NA ) ;
    }
  }

  /* call the eth dissector */
  next_tvb = tvb_new_subset_remaining( tvb, TRILL_MIN_FRAME_LENGTH + op_len ) ;
  call_dissector( eth_dissector, next_tvb, pinfo, tree ) ;

  return tvb_reported_length( tvb ) ;
}

/* Register the protocol with Wireshark */
void
proto_register_trill(void)
{
  static hf_register_info hf[] = {
    { &hf_trill_version,
      { "Version", "trill.version",
        FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(version_strings),
        TRILL_VERSION_MASK, "The TRILL version number.", HFILL }},
    { &hf_trill_reserved,
      { "Reserved", "trill.reserved",
        FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(reserved_strings),
        TRILL_RESERVED_MASK, "Bits reserved for future specification.", HFILL }},
    { &hf_trill_multi_dst,
      { "Multi Destination", "trill.multi_dst",
        FT_BOOLEAN, 16, TFS(&multi_dst_strings), TRILL_MULTI_DST_MASK,
        "A boolean specifying if this is a multi-destination frame.", HFILL }},
    { &hf_trill_op_len,
      { "Option Length", "trill.op_len",
        FT_UINT16, BASE_DEC_HEX, NULL, TRILL_OP_LEN_MASK,
        "The length of the options field of this frame.", HFILL }},
    { &hf_trill_hop_cnt,
      { "Hop Count", "trill.hop_cnt",
        FT_UINT16, BASE_DEC_HEX, NULL, TRILL_HOP_CNT_MASK,
        "The remaining hop count for this frame.", HFILL }},
    { &hf_trill_egress_nick,
      { "Egress/Root RBridge Nickname", "trill.egress_nick",
        FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(nickname_strings), 0x0,
        "The Egress or Distribution Tree Root RBridge Nickname.", HFILL }},
    { &hf_trill_ingress_nick,
      { "Ingress RBridge Nickname", "trill.ingress_nick",
        FT_UINT16, BASE_DEC_HEX|BASE_RANGE_STRING, RVALS(nickname_strings), 0x0,
        "The Ingress RBridge Nickname.", HFILL }},
    { &hf_trill_options,
      { "Options", "trill.options",
        FT_BYTES, BASE_NONE, NULL, 0x0,
        "The TRILL Options field.", HFILL }}
  };

  static gint *ett[] = {
    &ett_trill
  };

  proto_trill = proto_register_protocol("TRILL", "TRILL", "trill");
  proto_register_field_array(proto_trill, hf, array_length(hf));
  proto_register_subtree_array(ett, array_length(ett));
  trill_handle = register_dissector("trill", dissect_trill, proto_trill);
}

void
proto_reg_handoff_trill(void)
{
  dissector_add_uint("ethertype", ETHERTYPE_TRILL, trill_handle);

  /*
   * RFC 6325, section 4.1.4 "Frame Check Sequence (FCS)", says
   *
   * "Thus, when a frame is encapsulated, the original FCS is not
   * included but is discarded."
   *
   * meaning that the inner Ethernet frame does *not* include an
   * FCS.
   */
  eth_dissector = find_dissector_add_dependency( "eth_withoutfcs", proto_trill );
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local Variables:
 * c-basic-offset: 2
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * ex: set shiftwidth=2 tabstop=8 expandtab:
 * :indentSize=2:tabSize=8:noTabs=true:
 */