Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-linx.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-linx.c
2
 * Routines for LINX packet dissection
3
 *
4
 * Copyright 2006, Martin Peylo <martin.peylo@siemens.com>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/* The used document is:
14
 * ENEA Link Protocol Specification available at
15
 * http://linx.sourceforge.net
16
 *
17
 * Fits currently to
18
 * Enea LINX for Linux
19
 * Version: 2.5.0, May 16, 2011
20
 *
21
 * Added support for LINX ETHCM version 3 and LINX RLNH version 2.
22
 * Mattias Wallin, linx@enea.com, September 23, 2007
23
 *
24
 * Added support for LINX TCP CM.
25
 * Dejan Bucar, linx@enea.com, June 21, 2011
26
 *
27
 * Added support for LINX ETHCM Multicore header.
28
 * Dejan Bucar, linx@enea.com, June 21, 2011
29
*/
30
31
#include "config.h"
32
33
#include <epan/packet.h>
34
#include <epan/expert.h>
35
#include <epan/etypes.h>
36
#include <epan/tfs.h>
37
#include <wsutil/array.h>
38
39
void proto_register_linx(void);
40
void proto_reg_handoff_linx(void);
41
void proto_register_linx_tcp(void);
42
void proto_reg_handoff_linx_tcp(void);
43
44
static dissector_handle_t linx_handle;
45
46
static int proto_linx;
47
static int proto_linx_tcp;
48
49
/* ALL */
50
static int hf_linx_nexthdr;
51
52
/* MULTICORE */
53
static int hf_linx_multicore_scoreid;
54
static int hf_linx_multicore_dcoreid;
55
static int hf_linx_multicore_reserved;
56
static int hf_linx_multicore_reserved1;
57
58
59
/* MAIN */
60
static int hf_linx_main_version;
61
static int hf_linx_main_reserved;
62
static int hf_linx_main_connection;
63
static int hf_linx_main_bundle;
64
static int hf_linx_main_pkg_size;
65
66
/* UDATA */
67
static int hf_linx_udata_reserved;
68
static int hf_linx_udata_morefrags;
69
static int hf_linx_udata_fragno;
70
static int hf_linx_udata_signo;
71
static int hf_linx_udata_dstaddr16;
72
static int hf_linx_udata_dstaddr32;
73
static int hf_linx_udata_srcaddr16;
74
static int hf_linx_udata_srcaddr32;
75
static int hf_linx_udata_payload;
76
77
/* ACK */
78
static int hf_linx_ack_reserved;
79
static int hf_linx_ack_request;
80
static int hf_linx_ack_ackno;
81
static int hf_linx_ack_seqno;
82
83
/* CONN */
84
static int hf_linx_conn_cmd;
85
static int hf_linx_conn_size;
86
static int hf_linx_conn_reserved;
87
static int hf_linx_conn_srcmac;
88
static int hf_linx_conn_dstmac;
89
static int hf_linx_conn_winsize;
90
static int hf_linx_conn_publcid;
91
static int hf_linx_conn_feat_neg_str;
92
/* FRAG */
93
static int hf_linx_frag_reserved;
94
static int hf_linx_frag_morefrags;
95
static int hf_linx_frag_fragno;
96
97
/* NACK */
98
static int hf_linx_nack_reserv1;
99
static int hf_linx_nack_reserv2;
100
static int hf_linx_nack_count;
101
static int hf_linx_nack_seqno;
102
103
/* RLNH */
104
static int hf_linx_rlnh_msg_type32;
105
static int hf_linx_rlnh_msg_type8;
106
/* static int hf_linx_rlnh_linkaddr; */
107
static int hf_linx_rlnh_src_linkaddr;
108
static int hf_linx_rlnh_version;
109
static int hf_linx_rlnh_status;
110
static int hf_linx_rlnh_name;
111
static int hf_linx_rlnh_peer_linkaddr;
112
static int hf_linx_rlnh_feat_neg_str;
113
static int hf_linx_rlnh_msg_reserved;
114
115
/* TCP CM */
116
/* static int hf_linx_tcp_reserved; */
117
static int hf_linx_tcp_oob;
118
static int hf_linx_tcp_version;
119
static int hf_linx_tcp_type;
120
static int hf_linx_tcp_src;
121
static int hf_linx_tcp_dst;
122
static int hf_linx_tcp_size;
123
static int hf_linx_tcp_rlnh_msg_type32;
124
static int hf_linx_tcp_rlnh_msg_type8;
125
/* static int hf_linx_tcp_rlnh_linkaddr; */
126
static int hf_linx_tcp_rlnh_src_linkaddr;
127
static int hf_linx_tcp_rlnh_version;
128
static int hf_linx_tcp_rlnh_status;
129
static int hf_linx_tcp_rlnh_name;
130
static int hf_linx_tcp_rlnh_peer_linkaddr;
131
static int hf_linx_tcp_rlnh_feat_neg_str;
132
static int hf_linx_tcp_rlnh_msg_reserved;
133
static int hf_linx_tcp_payload;
134
135
136
static int rlnh_version;
137
138
static int ett_linx;
139
static int ett_linx_multicore;
140
static int ett_linx_main;
141
static int ett_linx_error;
142
static int ett_linx_udata;
143
static int ett_linx_ack;
144
static int ett_linx_tcp;
145
146
static expert_field ei_linx_version;
147
static expert_field ei_linx_rlnh_msg;
148
static expert_field ei_linx_header;
149
150
static expert_field ei_linx_tcp_version;
151
static expert_field ei_linx_tcp_rlnh_msg;
152
153
154
155
/* Definition and Names */
156
157
392
#define ETHCM_MAIN  0x0
158
380
#define ETHCM_CONN  0x1
159
17
#define ETHCM_UDATA 0x2
160
12
#define ETHCM_FRAG  0x3
161
3
#define ETHCM_ACK   0x4
162
251
#define ETHCM_NACK  0x5
163
740
#define ETHCM_NONE  0xf
164
165
static const value_string linx_short_header_names[]={
166
  { ETHCM_MAIN,  "MAIN"},
167
  { ETHCM_CONN,  "CONN"},
168
  { ETHCM_UDATA, "UDATA"},
169
  { ETHCM_FRAG,  "FRAG"},
170
  { ETHCM_ACK,   "ACK"},
171
  { ETHCM_NACK,  "NACK"},
172
  { ETHCM_NONE,  "NONE"},
173
  { 0,  NULL}
174
};
175
176
static const value_string linx_long_header_names[] = {
177
  { ETHCM_MAIN,  "Main"},
178
  { ETHCM_CONN,  "Connection"},
179
  { ETHCM_UDATA, "Udata"},
180
  { ETHCM_FRAG,  "Fragmentation"},
181
  { ETHCM_ACK,   "Ack"},
182
  { ETHCM_NACK,  "Nack"},
183
  { ETHCM_NONE,  "None"},
184
  { 0,  NULL}
185
};
186
187
#define TCP_CM_CONN  0x43
188
#define TCP_CM_UDATA 0x55
189
#define TCP_CM_PING  0x50
190
#define TCP_CM_PONG  0x51
191
192
static const value_string linx_short_tcp_names[] = {
193
  {TCP_CM_CONN,  "conn"},
194
  {TCP_CM_UDATA, "udata"},
195
  {TCP_CM_PING,  "ping"},
196
  {TCP_CM_PONG,  "pong"},
197
  {0,     NULL}
198
};
199
200
static const value_string linx_long_tcp_names[] = {
201
  {TCP_CM_CONN,  "Connection msg"},
202
  {TCP_CM_UDATA, "User data"},
203
  {TCP_CM_PING,  "Ping msg"},
204
  {TCP_CM_PONG,  "Pong msg"},
205
  {0,     NULL}
206
};
207
208
/* RLNH version 1 */
209
1
#define RLNH_LINK_ADDR     0
210
0
#define RLNH_QUERY_NAME    1
211
0
#define RLNH_PUBLISH       2
212
0
#define RLNH_UNPUBLISH     3
213
0
#define RLNH_UNPUBLISH_ACK 4
214
0
#define RLNH_INIT          5
215
0
#define RLNH_INIT_REPLY    6
216
0
#define RLNH_PUBLISH_PEER  7
217
218
static const value_string linx_short_rlnh_names[]={
219
  { RLNH_LINK_ADDR,     "link_addr"},
220
  { RLNH_QUERY_NAME,    "query_name"},
221
  { RLNH_PUBLISH,       "publish"},
222
  { RLNH_UNPUBLISH,     "unpublish"},
223
  { RLNH_UNPUBLISH_ACK, "unpublish_ack"},
224
  { RLNH_INIT,          "init"},
225
  { RLNH_INIT_REPLY,    "init_reply"},
226
  { RLNH_PUBLISH_PEER,  "publish_peer"},
227
  { 0,  NULL}
228
};
229
230
static const value_string linx_long_rlnh_names[]={
231
  { RLNH_LINK_ADDR,     "Link Address"},
232
  { RLNH_QUERY_NAME,    "Query Name"},
233
  { RLNH_PUBLISH,       "Publish"},
234
  { RLNH_UNPUBLISH,     "Unpublish"},
235
  { RLNH_UNPUBLISH_ACK, "Unpublish Ack"},
236
  { RLNH_INIT,          "Init"},
237
  { RLNH_INIT_REPLY,    "Init Reply"},
238
  { RLNH_PUBLISH_PEER,  "Publish Peer"},
239
  { 0,  NULL}
240
};
241
242
static const value_string linx_rlnh_reply[] = {
243
  { 0, "Version supported"},
244
  { 1, "Version NOT supported"},
245
  { 0, NULL}
246
};
247
248
static const value_string linx_nofragment[] = {
249
  { 0x7fff, "No Fragment"},
250
  { 0,  NULL}
251
};
252
253
static const value_string linx_coreid[]= {
254
  {0xff, "None"},
255
  {0,     NULL}
256
};
257
258
#define CONN_RESET       1
259
#define CONN_CONNECT     2
260
#define CONN_CONNECT_ACK 3
261
#define CONN_ACK         4
262
263
static const value_string linx_conn_cmd[] = {
264
  { CONN_RESET,       "Reset"},
265
  { CONN_CONNECT,     "Connect"},
266
  { CONN_CONNECT_ACK, "Connect_Ack"},
267
  { CONN_ACK,         "Ack"},
268
  { 0,  NULL}
269
};
270
271
static int
272
dissect_linx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
273
48
{
274
48
  uint32_t dword;
275
48
  int offset = 0;
276
48
  int nexthdr;
277
48
  int thishdr;
278
48
  int size;
279
48
  int pkgsize;
280
48
  int payloadsize;
281
48
  int version;
282
48
  int     conntype;
283
48
  proto_tree *multicore_header_tree;
284
48
  proto_tree *main_header_tree;
285
48
  proto_tree *conn_header_tree;
286
48
  proto_tree *ack_header_tree;
287
48
  proto_tree *udata_header_tree;
288
48
  proto_tree *nack_header_tree;
289
48
  proto_tree *frag_header_tree;
290
48
  proto_tree *rlnh_header_tree;
291
292
  /* Show name in protocol column */
293
48
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "LINX");
294
  /* Clear out stuff in the info column */
295
48
  col_clear(pinfo->cinfo, COL_INFO);
296
297
48
  { /* Work out the details */
298
48
    proto_item *ti        = NULL;
299
48
    proto_tree *linx_tree = NULL;
300
48
    proto_item *ver_item, *msg_item;
301
302
48
    ti = proto_tree_add_item(tree, proto_linx, tvb, 0, -1, ENC_NA);
303
48
    linx_tree = proto_item_add_subtree(ti, ett_linx);
304
305
48
    dword   = tvb_get_ntohl(tvb, offset);
306
48
    nexthdr = (dword >> 28) & 0xf;
307
308
    /* check if we have multicore header*/
309
48
    if (nexthdr == ETHCM_MAIN)
310
29
    {
311
29
      multicore_header_tree = proto_tree_add_subtree(linx_tree, tvb, 0, 4, ett_linx_multicore, NULL, "Multicore Header");
312
313
      /* Multicore header */
314
      /*
315
         0                   1                   2                   3
316
         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
317
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318
         | Next  |   R   |  Dest Coreid  | Source Coreid |      R        |
319
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320
       */
321
29
      proto_tree_add_item(multicore_header_tree, hf_linx_nexthdr,             tvb, 0, 4, ENC_BIG_ENDIAN);
322
29
      proto_tree_add_item(multicore_header_tree, hf_linx_multicore_reserved,  tvb, 0, 4, ENC_BIG_ENDIAN);
323
29
      proto_tree_add_item(multicore_header_tree, hf_linx_multicore_dcoreid,   tvb, 0, 4, ENC_BIG_ENDIAN);
324
29
      proto_tree_add_item(multicore_header_tree, hf_linx_multicore_scoreid,   tvb, 0, 4, ENC_BIG_ENDIAN);
325
29
      proto_tree_add_item(multicore_header_tree, hf_linx_multicore_reserved1, tvb, 0, 4, ENC_BIG_ENDIAN);
326
327
29
      offset += 4;
328
      /* read main header*/
329
29
      dword = tvb_get_ntohl(tvb, offset);
330
29
    }
331
332
48
    version = (dword >> 25) & 0x7;
333
48
    nexthdr = (dword >> 28) & 0xf;
334
48
    pkgsize = dword & 0x3fff;
335
336
    /* Main header */
337
48
    main_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Main Header");
338
339
    /*
340
    0                   1                   2                   3
341
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
342
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
343
    | Next  | Ver | R |   Connection  |R|        Packet size        |
344
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
345
    */
346
347
48
    proto_tree_add_item(main_header_tree, hf_linx_nexthdr        , tvb, offset, 4, ENC_BIG_ENDIAN);
348
48
    ver_item = proto_tree_add_item(main_header_tree, hf_linx_main_version   , tvb, offset, 4, ENC_BIG_ENDIAN);
349
48
    proto_tree_add_item(main_header_tree, hf_linx_main_reserved  , tvb, offset, 4, ENC_BIG_ENDIAN);
350
48
    proto_tree_add_item(main_header_tree, hf_linx_main_connection, tvb, offset, 4, ENC_BIG_ENDIAN);
351
48
    proto_tree_add_item(main_header_tree, hf_linx_main_bundle    , tvb, offset, 4, ENC_BIG_ENDIAN);
352
48
    proto_tree_add_item(main_header_tree, hf_linx_main_pkg_size  , tvb, offset, 4, ENC_BIG_ENDIAN);
353
48
    offset += 4;
354
355
    /* Supports version 2 and 3 so far */
356
48
    if (version < 2 || version > 3) {
357
45
      expert_add_info(pinfo, ver_item, &ei_linx_version);
358
45
    }
359
360
371
    while (nexthdr != ETHCM_NONE) {
361
362
352
      dword    = tvb_get_ntohl(tvb, offset);
363
352
      thishdr  = nexthdr;
364
352
      nexthdr  = (dword >>28) & 0xf;
365
352
      conntype = (dword >>24) & 0xf;
366
      /* Write non trivial header name to info column */
367
352
      if ((thishdr != ETHCM_NONE) && (thishdr != ETHCM_MAIN)) {
368
336
              col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(thishdr, linx_short_header_names, "unknown"));
369
336
        if(thishdr == ETHCM_CONN)
370
44
                col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(conntype, linx_conn_cmd, "unknown"));
371
336
      }
372
373
352
      switch (thishdr) {
374
375
44
        case ETHCM_CONN:
376
          /* Connect header */
377
          /*
378
             0                   1                   2                   3
379
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
380
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381
            | Next  | Type  |Size |Winsize|    Reserved     |Publish conn id|
382
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383
            :                                                               :
384
            :              dst hw addr followed by src hw addr              :
385
            :                                                               :
386
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
387
            :                                                               :
388
            :         Feature negotiation string (null terminated)          :
389
            :                                                               :
390
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391
          */
392
393
44
          size = (dword >>21) & 0x7;
394
44
          conn_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, (4+2*size), ett_linx_main, NULL, "Connection Header");
395
44
          proto_tree_add_item(conn_header_tree, hf_linx_nexthdr      , tvb, offset, 4, ENC_BIG_ENDIAN);
396
44
          proto_tree_add_item(conn_header_tree, hf_linx_conn_cmd     , tvb, offset, 4, ENC_BIG_ENDIAN);
397
44
          proto_tree_add_item(conn_header_tree, hf_linx_conn_size    , tvb, offset, 4, ENC_BIG_ENDIAN);
398
44
          proto_tree_add_item(conn_header_tree, hf_linx_conn_winsize , tvb, offset, 4, ENC_BIG_ENDIAN);
399
44
          proto_tree_add_item(conn_header_tree, hf_linx_conn_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
400
44
          proto_tree_add_item(conn_header_tree, hf_linx_conn_publcid , tvb, offset, 4, ENC_BIG_ENDIAN);
401
44
          offset += 4;
402
          /* MEDIA ADDRESS */
403
44
          if (size == 6) {
404
            /* Most likely ETHERNET */
405
1
            proto_tree_add_item(conn_header_tree, hf_linx_conn_dstmac, tvb, offset, 6, ENC_NA);
406
1
            proto_tree_add_item(conn_header_tree, hf_linx_conn_srcmac, tvb, offset + 6, 6, ENC_NA);
407
1
          }
408
409
44
          offset += (2*size);
410
          /* Feature Negotiation String */
411
44
          if(version > 2) {
412
20
                  proto_tree_add_item(conn_header_tree, hf_linx_conn_feat_neg_str, tvb, offset, -1, ENC_ASCII);
413
20
            offset += tvb_strnlen(tvb, offset, -1);
414
20
          }
415
44
          break;
416
417
251
        case ETHCM_NACK:
418
          /* Nack header */
419
          /*
420
             0                   1                   2                   3
421
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
422
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
423
            | Next  |  Res  |     Count     |  Res  |         Seqno         |
424
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
425
          */
426
427
          /* how many sequence numbers will be there? */
428
          /* this is not implemented due to a lack of documentation with */
429
          /* longer sequence numbers. */
430
          /* guess there will be padding if the Seqno doesn't reach */
431
          /* a 32bit boundary */
432
433
251
          nack_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "NACK Header");
434
251
          proto_tree_add_item(nack_header_tree, hf_linx_nexthdr     , tvb, offset, 4, ENC_BIG_ENDIAN);
435
251
          proto_tree_add_item(nack_header_tree, hf_linx_nack_reserv1, tvb, offset, 4, ENC_BIG_ENDIAN);
436
251
          proto_tree_add_item(nack_header_tree, hf_linx_nack_count  , tvb, offset, 4, ENC_BIG_ENDIAN);
437
251
          proto_tree_add_item(nack_header_tree, hf_linx_nack_reserv2, tvb, offset, 4, ENC_BIG_ENDIAN);
438
251
          proto_tree_add_item(nack_header_tree, hf_linx_nack_seqno  , tvb, offset, 4, ENC_BIG_ENDIAN);
439
251
          offset += 4;
440
251
          break;
441
442
17
        case ETHCM_UDATA:
443
          /* User data / fragment header => Version 3 */
444
          /*
445
            0         1       2         3
446
            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
447
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
448
            | Next  |  Reserved   |M|        Frag no      |
449
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
450
            |                          Destination                          |
451
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452
            |                             Source                            |
453
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454
455
            * User data / fragment header => Version 2
456
457
            0         1       2         3
458
            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
459
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460
            | Next  |  Reserved   |M|        Frag no      |
461
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462
            |                           Reserved                            |
463
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464
            |     Dst     |     Src     |
465
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466
467
            - fragments (not first fragment)
468
469
            0         1       2         3
470
            0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
471
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
472
            | Next  |  Reserved   |M|        Frag no      |
473
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
474
          */
475
476
477
17
          udata_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 12, ett_linx_main, NULL, "Udata Header");
478
17
          proto_tree_add_item(udata_header_tree, hf_linx_nexthdr, tvb, offset, 4, ENC_BIG_ENDIAN);
479
17
          proto_tree_add_item(udata_header_tree, hf_linx_udata_reserved , tvb, offset, 4, ENC_BIG_ENDIAN);
480
17
          proto_tree_add_item(udata_header_tree, hf_linx_udata_morefrags, tvb, offset, 4, ENC_BIG_ENDIAN);
481
17
          proto_tree_add_item(udata_header_tree, hf_linx_udata_fragno   , tvb, offset, 4, ENC_BIG_ENDIAN);
482
17
          offset += 4;
483
          /* signo removed in version 3 and linkaddresses extended to 32 bits */
484
17
          if(version == 2) {
485
1
               proto_tree_add_item(udata_header_tree, hf_linx_udata_signo    , tvb, offset, 4, ENC_BIG_ENDIAN);
486
1
               offset += 4;
487
1
               proto_tree_add_item(udata_header_tree, hf_linx_udata_dstaddr16, tvb, offset, 4, ENC_BIG_ENDIAN);
488
1
               proto_tree_add_item(udata_header_tree, hf_linx_udata_srcaddr16, tvb, offset, 4, ENC_BIG_ENDIAN);
489
1
               dword = tvb_get_ntohl(tvb, offset);
490
16
          } else {
491
16
               proto_tree_add_item(udata_header_tree, hf_linx_udata_dstaddr32, tvb, offset, 4, ENC_BIG_ENDIAN);
492
16
               dword = tvb_get_ntohl(tvb, offset);
493
16
               offset += 4;
494
16
               proto_tree_add_item(udata_header_tree, hf_linx_udata_srcaddr32, tvb, offset, 4, ENC_BIG_ENDIAN);
495
16
               if(dword == 0 && tvb_get_ntohl(tvb, offset) == 0) {
496
1
                 dword = 0;
497
15
               } else {
498
15
                 dword = 1;
499
15
               }
500
16
          }
501
17
          offset += 4;
502
17
          if (dword == 0) {
503
            /* (dstaddr == srcaddr == 0) -> RLNH Protocol Message */
504
505
1
                  dword = tvb_get_ntohl(tvb, offset);
506
507
            /* Write to info column */
508
1
            col_append_fstr(pinfo->cinfo, COL_INFO, "rlnh:%s ", val_to_str_const(dword, linx_short_rlnh_names, "unknown"));
509
510
            /* create new paragraph for RLNH */
511
1
            rlnh_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "RLNH");
512
513
1
            if(version == 1) {
514
0
              msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_type32, tvb, offset, 4, ENC_BIG_ENDIAN);
515
0
              offset += 4;
516
1
            } else {
517
              /* in version 2 of the rlnh protocol the length of the message type is restricted to 8 bits */
518
1
              proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
519
1
              msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_msg_type8, tvb, offset, 4, ENC_BIG_ENDIAN);
520
1
              offset += 4;
521
1
            }
522
523
1
            switch (dword) {
524
1
              case RLNH_LINK_ADDR:
525
                /* XXX what is this? */
526
1
                break;
527
0
              case RLNH_QUERY_NAME:
528
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
529
0
                  offset += 4;
530
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_name, tvb, offset, -1, ENC_ASCII);
531
0
                  offset += tvb_strnlen(tvb, offset, -1);
532
0
                break;
533
0
              case RLNH_PUBLISH:
534
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
535
0
                  offset += 4;
536
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_name, tvb, offset, -1, ENC_ASCII);
537
0
                  offset += tvb_strnlen(tvb, offset, -1);
538
0
                break;
539
0
              case RLNH_UNPUBLISH:
540
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
541
0
                  offset += 4;
542
0
                break;
543
0
              case RLNH_UNPUBLISH_ACK:
544
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
545
0
                  offset += 4;
546
0
                break;
547
0
              case RLNH_INIT:
548
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_version, tvb, offset, 4, ENC_BIG_ENDIAN);
549
                  /* This is not working if nodes are at different versions. Only the latest value will be saved in rlnh_version */
550
0
                  rlnh_version = tvb_get_ntohl(tvb, offset);
551
0
                  offset += 4;
552
0
                break;
553
0
              case RLNH_INIT_REPLY:
554
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_status, tvb, offset, 4, ENC_BIG_ENDIAN);
555
0
                  offset += 4;
556
0
                  if(rlnh_version > 1) {
557
0
                          proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_feat_neg_str, tvb, offset, -1, ENC_ASCII);
558
0
                    offset += tvb_strnlen(tvb, offset, -1);
559
0
                  }
560
0
                break;
561
0
              case RLNH_PUBLISH_PEER:
562
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
563
0
                  offset += 4;
564
0
                  proto_tree_add_item(rlnh_header_tree, hf_linx_rlnh_peer_linkaddr, tvb, offset, -1, ENC_BIG_ENDIAN);
565
0
                  offset += tvb_strnlen(tvb, offset, -1);
566
0
                break;
567
0
              default:
568
                  /* no known Message type... */
569
0
                  expert_add_info(pinfo, msg_item, &ei_linx_rlnh_msg);
570
0
                break;
571
1
            }
572
16
          } else {
573
            /* Is there payload? */
574
            /* anything better to do with that? */
575
16
            payloadsize = pkgsize-offset;
576
16
            if (payloadsize) {
577
16
              proto_tree_add_item(linx_tree, hf_linx_udata_payload, tvb, offset, payloadsize, ENC_NA);
578
16
            }
579
16
          }
580
17
          break;
581
582
17
        case ETHCM_ACK:
583
          /* Reliable header */
584
          /*
585
             0                   1                   2                   3
586
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
587
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588
            | Next  |R| Res.|         Ackno         |         Seqno         |
589
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590
          */
591
3
          ack_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Ack Header");
592
3
          proto_tree_add_item(ack_header_tree, hf_linx_nexthdr     , tvb, offset, 4, ENC_BIG_ENDIAN);
593
3
          proto_tree_add_item(ack_header_tree, hf_linx_ack_request , tvb, offset, 4, ENC_BIG_ENDIAN);
594
3
          proto_tree_add_item(ack_header_tree, hf_linx_ack_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
595
3
          proto_tree_add_item(ack_header_tree, hf_linx_ack_ackno   , tvb, offset, 4, ENC_BIG_ENDIAN);
596
3
          proto_tree_add_item(ack_header_tree, hf_linx_ack_seqno   , tvb, offset, 4, ENC_BIG_ENDIAN);
597
3
          offset += 4;
598
3
          break;
599
600
12
        case ETHCM_FRAG:
601
          /*
602
            - fragments (not first fragment)
603
604
             0                   1                   2                   3
605
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
606
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
607
            | Next  |      Reserved         |M|          Frag no            |
608
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609
           */
610
611
12
          frag_header_tree = proto_tree_add_subtree(linx_tree, tvb, offset, 4, ett_linx_main, NULL, "Fragmentation Header");
612
12
          proto_tree_add_item(frag_header_tree, hf_linx_nexthdr       , tvb, offset, 4, ENC_BIG_ENDIAN);
613
12
          proto_tree_add_item(frag_header_tree, hf_linx_frag_reserved , tvb, offset, 4, ENC_BIG_ENDIAN);
614
12
          proto_tree_add_item(frag_header_tree, hf_linx_frag_morefrags, tvb, offset, 4, ENC_BIG_ENDIAN);
615
12
          proto_tree_add_item(frag_header_tree, hf_linx_frag_fragno   , tvb, offset, 4, ENC_BIG_ENDIAN);
616
12
          offset += 4;
617
12
          break;
618
619
17
        default:
620
17
          proto_tree_add_expert_format(linx_tree, pinfo, &ei_linx_header, tvb, offset, 4, "ERROR: Header \"%u\" not recognized", thishdr);
621
17
          nexthdr = ETHCM_NONE; /* avoid endless loop with faulty packages */
622
17
          break;
623
352
      }
624
352
    }
625
626
48
  }
627
19
  return tvb_captured_length(tvb);
628
48
}
629
630
631
/* Protocol Initialisation */
632
void
633
proto_register_linx(void)
634
14
{
635
636
  /* Registering Data Structures */
637
638
14
  static hf_register_info hf[] = {
639
14
    { &hf_linx_nexthdr,
640
14
      { "Next Header", "linx.nexthdr", FT_UINT32, BASE_DEC, VALS(linx_long_header_names), 0xf0000000, NULL, HFILL },
641
14
    },
642
14
    { &hf_linx_multicore_scoreid, /* in ETHCM_MULTICORE */
643
14
      { "Source coreid", "linx.scoreid", FT_UINT32, BASE_DEC, VALS(linx_coreid), 0x0000ff00, "Multicore source core id", HFILL },
644
14
    },
645
14
    { &hf_linx_multicore_dcoreid, /* in ETHCM_MULTICORE */
646
14
      { "Destination coreid", "linx.dcoreid", FT_UINT32, BASE_DEC, VALS(linx_coreid), 0x00ff0000, "Multicore destination core id", HFILL},
647
14
    },
648
14
    { &hf_linx_multicore_reserved, /* in ETHCM_MULTICORE */
649
14
      { "Reserved", "linx.reserved8", FT_UINT32, BASE_DEC, NULL, 0x0f000000, "Multicore Hdr Reserved", HFILL},
650
14
    },
651
14
    { &hf_linx_multicore_reserved1, /* in ETHCM_MULTICORE */
652
14
      { "Reserved", "linx.reserved9", FT_UINT32, BASE_DEC, NULL, 0x000000ff, "Multicore Hdr Reserved", HFILL},
653
14
    },
654
14
    { &hf_linx_main_version, /* in ETHCM_MAIN */
655
14
      { "Version", "linx.version", FT_UINT32, BASE_DEC, NULL, 0x0e000000, "LINX Version", HFILL },
656
14
    },
657
14
    { &hf_linx_main_reserved, /* in ETHCM_MAIN */
658
14
      { "Reserved", "linx.reserved1", FT_UINT32, BASE_DEC, NULL, 0x01800000, "Main Hdr Reserved", HFILL },
659
14
    },
660
14
    { &hf_linx_main_connection, /* in ETHCM_MAIN */
661
14
      { "Connection", "linx.connection", FT_UINT32, BASE_DEC, NULL, 0x007f8000, NULL, HFILL },
662
14
    },
663
14
    { &hf_linx_main_bundle, /* in ETHCM_MAIN */
664
14
      { "Bundle", "linx.bundle", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00004000, NULL, HFILL },
665
14
    },
666
14
    { &hf_linx_main_pkg_size, /* in ETHCM_MAIN */
667
14
      { "Package Size", "linx.pcksize", FT_UINT32, BASE_DEC, NULL, 0x00003fff, NULL, HFILL },
668
14
    },
669
14
    { &hf_linx_udata_reserved, /* in ETHCM_UDATA */
670
14
      { "Reserved", "linx.reserved5", FT_UINT32, BASE_DEC, NULL, 0x0fff0000, "Udata Hdr Reserved", HFILL },
671
14
    },
672
14
    { &hf_linx_udata_morefrags, /* in ETHCM_UDATA */
673
14
      { "More Fragments", "linx.morefra", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00008000, "More fragments follow", HFILL },
674
14
    },
675
14
    { &hf_linx_udata_fragno, /* in ETHCM_UDATA */
676
14
      { "Fragment Number", "linx.fragno", FT_UINT32, BASE_DEC, VALS(linx_nofragment), 0x00007fff, NULL, HFILL },
677
14
    },
678
14
    { &hf_linx_udata_signo, /* in ETHCM_UDATA */
679
14
      { "Signal Number", "linx.signo", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
680
14
    },
681
14
    { &hf_linx_udata_dstaddr16, /* in ETHCM_UDATA - protocol version 2 */
682
14
      { "Receiver Address", "linx.dstaddr", FT_UINT32, BASE_DEC, NULL, 0xffff0000, NULL, HFILL },
683
14
    },
684
14
    { &hf_linx_udata_dstaddr32, /* in ETHCM_UDATA - protocol version 3 */
685
14
      { "Receiver Address", "linx.dstaddr32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
686
14
    },
687
14
    { &hf_linx_udata_srcaddr16, /* in ETHCM_UDATA - protocol version 2 */
688
14
      { "Sender Address", "linx.srcaddr", FT_UINT32, BASE_DEC, NULL, 0x0000ffff, NULL, HFILL },
689
14
    },
690
14
    { &hf_linx_udata_srcaddr32, /* in ETHCM_UDATA - protocol version 3 */
691
14
      { "Sender Address", "linx.srcaddr32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
692
14
    },
693
14
    { &hf_linx_udata_payload, /* in ETHCM_UDATA */
694
14
      { "Payload", "linx.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
695
14
    },
696
14
    { &hf_linx_ack_request, /* in ETHCM_ACK */
697
14
      { "ACK-request", "linx.ackreq", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x08000000, NULL, HFILL },
698
14
    },
699
14
    { &hf_linx_ack_reserved, /* in ETHCM_ACK */
700
14
      { "Reserved", "linx.reserved7", FT_UINT32, BASE_DEC, NULL, 0x07000000, "ACK Hdr Reserved", HFILL },
701
14
    },
702
14
    { &hf_linx_ack_ackno, /* in ETHCM_ACK */
703
14
      { "ACK Number", "linx.ackno", FT_UINT32, BASE_DEC, NULL, 0x00fff000, NULL, HFILL },
704
14
    },
705
14
    { &hf_linx_ack_seqno, /* in ETHCM_ACK */
706
14
      { "Sequence Number", "linx.seqno", FT_UINT32, BASE_DEC, NULL, 0x00000fff, NULL, HFILL },
707
14
    },
708
14
    { &hf_linx_conn_cmd, /* in ETHCM_CONN */
709
14
      { "Command", "linx.cmd", FT_UINT32, BASE_DEC, VALS(linx_conn_cmd), 0x0f000000, NULL, HFILL },
710
14
    },
711
14
    { &hf_linx_conn_size, /* in ETHCM_CONN */
712
14
      { "Size", "linx.size", FT_UINT32, BASE_DEC, NULL, 0x00e00000, NULL, HFILL },
713
14
    },
714
14
    { &hf_linx_conn_winsize, /* in ETHCM_CONN */
715
14
      { "WinSize", "linx.winsize", FT_UINT32, BASE_DEC, NULL, 0x001e0000, "Window Size", HFILL },
716
14
    },
717
14
    { &hf_linx_conn_reserved, /* in ETHCM_CONN */
718
14
      { "Reserved", "linx.reserved3", FT_UINT32, BASE_DEC, NULL, 0x0001ff00, "Conn Hdr Reserved", HFILL },
719
14
    },
720
14
    { &hf_linx_conn_publcid, /* in ETHCM_CONN */
721
14
      { "Publish Conn ID", "linx.publcid", FT_UINT32, BASE_DEC, NULL, 0x000000ff, NULL, HFILL },
722
14
    },
723
14
    { &hf_linx_conn_srcmac, /* in ETHCM_CONN */
724
14
      { "Source", "linx.srcmaddr_ether", FT_ETHER, BASE_NONE, NULL, 0x0, "Source Media Address (ethernet)", HFILL },
725
14
    },
726
14
    { &hf_linx_conn_dstmac, /* in ETHCM_CONN */
727
14
      { "Destination", "linx.destmaddr_ether", FT_ETHER, BASE_NONE, NULL, 0x0, "Destination Media Address (ethernet)", HFILL },
728
14
    },
729
14
    { &hf_linx_conn_feat_neg_str, /* in ETHCM_CONN */
730
14
            { "Feature Negotiation String", "linx.feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
731
14
    },
732
14
    { &hf_linx_frag_reserved, /* in ETHCM_FRAG */
733
14
      { "Reserved", "linx.reserved6", FT_UINT32, BASE_DEC, NULL, 0x0fff0000, "Frag Hdr Reserved", HFILL },
734
14
    },
735
14
    { &hf_linx_frag_morefrags, /* in ETHCM_FRAG */
736
14
      { "More Fragments", "linx.morefr2", FT_BOOLEAN, 32, TFS(&tfs_yes_no), 0x00008000, NULL, HFILL },
737
14
    },
738
14
    { &hf_linx_frag_fragno, /* in ETHCM_FRAG */
739
14
      { "Fragment Number", "linx.fragno2", FT_UINT32, BASE_DEC, NULL, 0x00007fff, NULL, HFILL },
740
14
    },
741
14
    { &hf_linx_nack_reserv1, /* in ETHCM_NACK */
742
14
      { "Reserved", "linx.nack_reserv", FT_UINT32, BASE_DEC, NULL, 0x0f000000, "Nack Hdr Reserved", HFILL },
743
14
    },
744
14
    { &hf_linx_nack_count, /* in ETHCM_NACK */
745
14
      { "Count", "linx.nack_count", FT_UINT32, BASE_DEC, NULL, 0x00ff0000, NULL, HFILL },
746
14
    },
747
14
    { &hf_linx_nack_reserv2, /* in ETHCM_NACK */
748
14
      { "Reserved", "linx.nack_reserv", FT_UINT32, BASE_DEC, NULL, 0x0000f000, "Nack Hdr Reserved", HFILL },
749
14
    },
750
14
    { &hf_linx_nack_seqno, /* in ETHCM_NACK */
751
14
      { "Sequence Number", "linx.nack_seqno", FT_UINT32, BASE_DEC, NULL, 0x00000fff, NULL, HFILL },
752
14
    },
753
754
    /* RLNH */
755
14
    { &hf_linx_rlnh_msg_type32, /* in RLNH */
756
14
      { "RLNH msg type", "linx.rlnh_msg_type", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x0, "RLNH message type", HFILL },
757
14
    },
758
14
    { &hf_linx_rlnh_msg_type8, /* in RLNH */
759
14
      { "RLNH msg type", "linx.rlnh_msg_type8", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x000000ff, "RLNH message type", HFILL },
760
14
    },
761
14
    { &hf_linx_rlnh_msg_reserved, /* in RLNH */
762
14
            { "RLNH msg reserved", "linx.rlnh_msg_reserved", FT_UINT32, BASE_DEC, NULL, 0xffffff00, "RLNH message reserved", HFILL },
763
14
    },
764
#if 0
765
    { &hf_linx_rlnh_linkaddr, /* in RLNH */
766
      { "RLNH linkaddr", "linx.rlnh_linkaddr", FT_UINT32, BASE_DEC, NULL, 0xffffffff, "RLNH linkaddress", HFILL },
767
    },
768
#endif
769
14
    { &hf_linx_rlnh_src_linkaddr, /* in RLNH */
770
14
      { "RLNH src linkaddr", "linx.rlnh_src_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH source linkaddress", HFILL },
771
14
    },
772
14
    { &hf_linx_rlnh_peer_linkaddr, /* in RLNH */
773
14
      { "RLNH peer linkaddr", "linx.rlnh_peer_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH peer linkaddress", HFILL },
774
14
    },
775
14
    { &hf_linx_rlnh_version, /* in RLNH */
776
14
      { "RLNH version", "linx.rlnh_version", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
777
14
    },
778
14
    { &hf_linx_rlnh_status, /* in RLNH */
779
14
      { "RLNH reply", "linx.rlnh_status", FT_UINT32, BASE_DEC, VALS(linx_rlnh_reply), 0x0, NULL, HFILL },
780
14
    },
781
14
    { &hf_linx_rlnh_name, /* in RLNH */
782
14
      { "RLNH name", "linx.rlnh_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
783
14
    },
784
14
    { &hf_linx_rlnh_feat_neg_str, /* in RLNH */
785
14
            { "RLNH Feature Negotiation String", "linx.rlnh_feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
786
14
    }
787
14
  };
788
789
  /* Setup protocol subtree array */
790
14
  static int *ett[] = {
791
14
    &ett_linx,
792
14
    &ett_linx_multicore,
793
14
    &ett_linx_main,
794
14
    &ett_linx_error,
795
14
    &ett_linx_udata,
796
14
    &ett_linx_ack
797
14
  };
798
799
14
  static ei_register_info ei[] = {
800
14
    { &ei_linx_version, { "linx.version.unknown", PI_PROTOCOL, PI_WARN, "Version not yet supported and might be dissected incorrectly!", EXPFILL }},
801
14
    { &ei_linx_rlnh_msg, { "linx.rlnh_msg.unknown", PI_PROTOCOL, PI_WARN, "Message type not recognized", EXPFILL }},
802
14
    { &ei_linx_header, { "linx.header_not_recognized", PI_PROTOCOL, PI_WARN, "Header not recognized", EXPFILL }},
803
14
  };
804
805
14
  expert_module_t* expert_linx;
806
807
14
  proto_linx = proto_register_protocol (
808
14
    "ENEA LINX",  /* name */
809
14
    "LINX",   /* short name */
810
14
    "linx"    /* abbrev */
811
14
    );
812
813
  /* Protocol Registering data structures. */
814
14
  proto_register_field_array(proto_linx, hf, array_length(hf));
815
14
  proto_register_subtree_array(ett, array_length(ett));
816
14
  expert_linx = expert_register_protocol(proto_linx);
817
14
  expert_register_field_array(expert_linx, ei, array_length(ei));
818
819
  /* Register the dissector */
820
14
  linx_handle = register_dissector("linx", dissect_linx, proto_linx);
821
14
}
822
823
824
/* Protocol Handoff */
825
void
826
proto_reg_handoff_linx(void)
827
14
{
828
14
  dissector_add_uint("ethertype", ETHERTYPE_LINX, linx_handle);
829
14
}
830
831
/************ TCP CM **************/
832
833
static int
834
dissect_linx_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
835
0
{
836
0
  uint32_t dword;
837
0
  int offset = 0;
838
0
  proto_item *ti, *ver_item, *msg_item;
839
0
  proto_tree *linx_tcp_tree;
840
0
  proto_tree *tcp_header_tree;
841
0
  proto_tree *rlnh_header_tree;
842
0
  int payloadsize;
843
0
  int version;
844
0
  int size;
845
0
  int type;
846
847
  /* Show name in protocol column */
848
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "LINX/TCP");
849
850
  /* Clear out stuff in the info column */
851
0
  col_clear(pinfo->cinfo, COL_INFO);
852
853
0
  dword   = tvb_get_ntohl(tvb, 0);
854
0
  version = (dword >> 16) & 0xFF;
855
0
  type    = (dword >> 24) & 0xFF;
856
857
  /* size of linx tcp cm header */
858
0
  size    = 16;
859
860
0
  if (type == 0x55) {
861
0
    dword  = tvb_get_ntohl(tvb, 12);
862
0
    size  += (dword & 0xFFFFFFFF);
863
0
  }
864
865
0
  col_append_fstr(pinfo->cinfo, COL_INFO, "tcpcm:%s ", val_to_str_const(type, linx_short_tcp_names, "unknown"));
866
867
0
  ti = proto_tree_add_item(tree, proto_linx_tcp, tvb, 0, -1, ENC_NA);
868
0
  linx_tcp_tree = proto_item_add_subtree(ti, ett_linx_tcp);
869
870
0
  tcp_header_tree = proto_tree_add_subtree(linx_tcp_tree, tvb, 0, 16, ett_linx_tcp, NULL, "TCP CM Header");
871
872
0
  proto_tree_add_item(tcp_header_tree, hf_linx_tcp_type, tvb, 0, 4, ENC_BIG_ENDIAN);
873
0
  ver_item = proto_tree_add_item(tcp_header_tree, hf_linx_tcp_version, tvb, 0, 4, ENC_BIG_ENDIAN);
874
0
  proto_tree_add_item(tcp_header_tree, hf_linx_tcp_oob, tvb, 0, 4, ENC_BIG_ENDIAN);
875
0
  proto_tree_add_item(tcp_header_tree, hf_linx_tcp_src, tvb, 4, 4, ENC_BIG_ENDIAN);
876
0
  proto_tree_add_item(tcp_header_tree, hf_linx_tcp_dst, tvb, 8, 4, ENC_BIG_ENDIAN);
877
0
  proto_tree_add_item(tcp_header_tree, hf_linx_tcp_size, tvb, 12, 4,  ENC_BIG_ENDIAN);
878
879
0
  if (version != 3) {
880
0
    expert_add_info(pinfo, ver_item, &ei_linx_tcp_version);
881
0
  }
882
883
0
  offset += 16;
884
885
0
  if (type == 0x55) { /* UDATA */
886
0
    dword = tvb_get_ntohl(tvb, 8);
887
0
    if (dword == 0) { /* RLNH Message*/
888
889
0
      dword = tvb_get_ntohl(tvb, offset);
890
891
      /* Write to info column */
892
0
      col_append_fstr(pinfo->cinfo, COL_INFO, "rlnh:%s ", val_to_str_const(dword, linx_short_rlnh_names, "unknown"));
893
894
      /* create new paragraph for RLNH */
895
0
      rlnh_header_tree = proto_tree_add_subtree(linx_tcp_tree, tvb, offset, 4, ett_linx_tcp, NULL, "RLNH");
896
897
0
      if(version == 1) {
898
0
        msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_type32, tvb, offset, 4, ENC_BIG_ENDIAN);
899
0
        offset += 4;
900
0
      } else {
901
        /*
902
         * In version 2 of the rlnh protocol the length of the message type is
903
         * restricted to 8 bits.
904
         */
905
0
        proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
906
0
        msg_item = proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_msg_type8, tvb, offset, 4, ENC_BIG_ENDIAN);
907
0
        offset += 4;
908
0
      }
909
910
0
      switch (dword) {
911
0
        case RLNH_LINK_ADDR:
912
0
          break;
913
0
        case RLNH_QUERY_NAME:
914
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
915
0
          offset += 4;
916
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_name, tvb, offset, -1, ENC_ASCII);
917
          /*offset += tvb_strnlen(tvb, offset, -1);*/
918
0
          break;
919
0
        case RLNH_PUBLISH:
920
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
921
0
          offset += 4;
922
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_name, tvb, offset, -1, ENC_ASCII);
923
          /*offset += tvb_strnlen(tvb, offset, -1);*/
924
0
          break;
925
0
        case RLNH_UNPUBLISH:
926
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
927
          /*offset += 4;*/
928
0
          break;
929
0
        case RLNH_UNPUBLISH_ACK:
930
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
931
          /*offset += 4;*/
932
0
          break;
933
0
        case RLNH_INIT:
934
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_version, tvb, offset, 4, ENC_BIG_ENDIAN);
935
0
          rlnh_version = tvb_get_ntohl(tvb, offset);
936
          /*offset += 4;*/
937
0
          break;
938
0
        case RLNH_INIT_REPLY:
939
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_status, tvb, offset, 4, ENC_BIG_ENDIAN);
940
0
          offset += 4;
941
0
          if(rlnh_version > 1) {
942
0
            proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_feat_neg_str, tvb, offset, -1, ENC_ASCII);
943
            /*offset += tvb_strnlen(tvb, offset, -1);*/
944
0
          }
945
0
          break;
946
0
        case RLNH_PUBLISH_PEER:
947
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_src_linkaddr, tvb, offset, 4, ENC_BIG_ENDIAN);
948
0
          offset += 4;
949
0
          proto_tree_add_item(rlnh_header_tree, hf_linx_tcp_rlnh_peer_linkaddr, tvb, offset, -1, ENC_BIG_ENDIAN);
950
          /*offset += tvb_strnlen(tvb, offset, -1);*/
951
0
          break;
952
0
        default:
953
          /* No known Message type */
954
0
          expert_add_info(pinfo, msg_item, &ei_linx_tcp_rlnh_msg);
955
0
          break;
956
0
      }
957
0
    } else {
958
      /* User payload */
959
0
      payloadsize = size-offset;
960
0
      if (payloadsize) {
961
0
        proto_tree_add_item(linx_tcp_tree, hf_linx_tcp_payload, tvb, offset, payloadsize, ENC_NA);
962
0
      }
963
0
    }
964
0
  }
965
0
  return tvb_captured_length(tvb);
966
0
}
967
968
void
969
proto_register_linx_tcp(void)
970
14
{
971
14
  static hf_register_info hf[] = {
972
#if 0
973
    { &hf_linx_tcp_reserved,
974
      { "Reserved", "linxtcp.reserved", FT_UINT32, BASE_DEC, NULL, 0x00007FFF, "TCP CM reserved", HFILL },
975
    },
976
#endif
977
14
    { &hf_linx_tcp_oob,
978
14
      { "Out-of-band", "linxtcp.oob", FT_UINT32, BASE_DEC, NULL, 0x00008000, "TCP CM oob", HFILL },
979
14
    },
980
14
    { &hf_linx_tcp_version,
981
14
      { "Version", "linxtcp.version", FT_UINT32, BASE_DEC, NULL, 0x00FF0000, "TCP CM version", HFILL },
982
14
    },
983
14
    { &hf_linx_tcp_type,
984
14
      { "Type", "linxtcp.type", FT_UINT32, BASE_HEX, VALS(linx_long_tcp_names), 0xFF000000, "TCP CM type", HFILL },
985
14
    },
986
14
    { &hf_linx_tcp_src,
987
14
      { "Source", "linxtcp.src", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM source", HFILL },
988
14
    },
989
14
    { &hf_linx_tcp_dst,
990
14
      { "Destination", "linxtcp.dst", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM destination", HFILL },
991
14
    },
992
14
    { &hf_linx_tcp_size,
993
14
      { "Size", "linxtcp.size", FT_UINT32, BASE_DEC, NULL, 0x0, "TCP CM size", HFILL },
994
14
    },
995
996
    /* RLNH */
997
14
    { &hf_linx_tcp_rlnh_msg_type32,
998
14
      { "RLNH msg type", "linxtcp.rlnh_msg_type", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x0, "RLNH message type", HFILL },
999
14
    },
1000
14
    { &hf_linx_tcp_rlnh_msg_type8,
1001
14
      { "RLNH msg type", "linxtcp.rlnh_msg_type8", FT_UINT32, BASE_DEC, VALS(linx_long_rlnh_names), 0x000000ff, "RLNH message type", HFILL },
1002
14
    },
1003
14
    { &hf_linx_tcp_rlnh_msg_reserved,
1004
14
      { "RLNH msg reserved", "linxtcp.rlnh_msg_reserved", FT_UINT32, BASE_DEC, NULL, 0xffffff00, "RLNH message reserved", HFILL },
1005
14
    },
1006
#if 0
1007
    { &hf_linx_tcp_rlnh_linkaddr,
1008
      { "RLNH linkaddr", "linxtcp.rlnh_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH linkaddress", HFILL },
1009
    },
1010
#endif
1011
14
    { &hf_linx_tcp_rlnh_src_linkaddr,
1012
14
        { "RLNH src linkaddr", "linxtcp.rlnh_src_linkaddr", FT_UINT32, BASE_DEC, NULL, 0x0, "RLNH source linkaddress", HFILL },
1013
14
    },
1014
14
    { &hf_linx_tcp_rlnh_peer_linkaddr,
1015
14
      { "RLNH peer linkaddr", "linxtcp.rlnh_peer_linkaddr", FT_UINT32,
1016
14
        BASE_DEC, NULL, 0x0, "RLNH peer linkaddress", HFILL },
1017
14
    },
1018
14
    { &hf_linx_tcp_rlnh_version,
1019
14
      { "RLNH version", "linxtcp.rlnh_version", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL },
1020
14
    },
1021
14
    { &hf_linx_tcp_rlnh_status,
1022
14
      { "RLNH reply", "linxtcp.rlnh_status", FT_UINT32, BASE_DEC, VALS(linx_rlnh_reply), 0x0, NULL, HFILL },
1023
14
    },
1024
14
    { &hf_linx_tcp_rlnh_name,
1025
14
      { "RLNH name", "linxtcp.rlnh_name", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
1026
14
    },
1027
14
    { &hf_linx_tcp_rlnh_feat_neg_str,
1028
14
      { "RLNH Feature Negotiation String", "linxtcp.rlnh_feat_neg_str", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL },
1029
14
    },
1030
14
    { &hf_linx_tcp_payload,
1031
14
      { "Payload", "linxtcp.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
1032
14
    }
1033
14
  };
1034
1035
14
  static int *ett[] = {
1036
14
    &ett_linx_tcp,
1037
14
  };
1038
1039
14
  static ei_register_info ei[] = {
1040
14
    { &ei_linx_tcp_version, { "linxtcp.version.unknown", PI_PROTOCOL, PI_WARN, "Version not yet supported and might be dissected incorrectly!", EXPFILL }},
1041
14
    { &ei_linx_tcp_rlnh_msg, { "linxtcp.rlnh_msg.unknown", PI_PROTOCOL, PI_WARN, "Message type not recognized", EXPFILL }},
1042
14
  };
1043
1044
14
  expert_module_t* expert_linx_tcp;
1045
1046
14
  proto_linx_tcp = proto_register_protocol("ENEA LINX over TCP", "LINX/TCP", "linxtcp");
1047
14
  proto_register_field_array(proto_linx_tcp, hf, array_length(hf));
1048
14
  proto_register_subtree_array(ett, array_length(ett));
1049
14
  expert_linx_tcp = expert_register_protocol(proto_linx_tcp);
1050
14
  expert_register_field_array(expert_linx_tcp, ei, array_length(ei));
1051
14
}
1052
1053
void
1054
proto_reg_handoff_linx_tcp(void)
1055
14
{
1056
14
  dissector_handle_t linx_tcp_handle;
1057
1058
14
  linx_tcp_handle = create_dissector_handle(dissect_linx_tcp, proto_linx_tcp);
1059
1060
14
  dissector_add_for_decode_as_with_preference("tcp.port", linx_tcp_handle);
1061
14
}
1062
1063
/*
1064
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1065
 *
1066
 * Local variables:
1067
 * c-basic-offset: 8
1068
 * tab-width: 8
1069
 * indent-tabs-mode: t
1070
 * End:
1071
 *
1072
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1073
 * :indentSize=8:tabSize=8:noTabs=false:
1074
 */