Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-amp.c
Line
Count
Source
1
/* packet-amp.c
2
 * Routines for Asynchronous management Protocol dissection
3
 * Copyright 2018, Krishnamurthy Mayya (krishnamurthymayya@gmail.com)
4
 * Updated to CBOR encoding: Keith Scott, 2019 (kscott@mitre.org)
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
#include "config.h"
13
14
#include <epan/exceptions.h>
15
#include <epan/expert.h>
16
#include <epan/packet.h>
17
#include <epan/tfs.h>
18
#include "packet-amp.h"
19
20
/* The AMP standard can be found here:
21
 * https://tools.ietf.org/html/draft-birrane-dtn-amp-04
22
 * https://tools.ietf.org/html/draft-birrane-dtn-amp-03
23
 */
24
25
16
#define AMP_APID 0x000 /* TODO - To be decided. Currently, the function 'dissect_amp_as_subtree' is
26
                          being called from dtn.c file when required to decode the bundle protocol's
27
                          data-payload as AMP. Later in the future, when a dedicated field is given to
28
                          this, this should be filled. */
29
30
/*
31
 */
32
static void
33
add_value_time_to_tree(uint64_t value, int len, proto_tree *tree, tvbuff_t *tvb, unsigned offset, int hf_time_format)
34
1
{
35
1
    nstime_t dtn_time;
36
37
    // If it's a relative time, just make it zero.
38
1
    if ( value < 558230400 ) {
39
0
        value = 0;
40
0
    }
41
1
    dtn_time.secs = (time_t)(value);
42
1
    dtn_time.nsecs = 0;
43
1
    proto_tree_add_time(tree, hf_time_format, tvb, offset, len, &dtn_time);
44
45
1
    return;
46
1
}
47
48
16
#define AMP_HDR_RESERVED         0xC0
49
16
#define AMP_HDR_ACL              0x20
50
16
#define AMP_HDR_NACK             0x10
51
16
#define AMP_HDR_ACK              0x08
52
16
#define AMP_HDR_OPCODE           0x07
53
54
16
#define AMP_ARI_NICKNAME         0x80
55
16
#define AMP_ARI_PARAMETERS       0x40
56
16
#define AMP_ARI_ISSUER           0x20
57
16
#define AMP_ARI_TAG              0x10
58
16
#define AMP_ARI_STRUCT           0x0F
59
16
#define AMP_ARI_VALUE            0xF0
60
61
16
#define AMP_CBOR_UINT_SMALL      0x1F
62
63
16
#define AMP_TNVC_RESERVED        0xF0
64
16
#define AMP_TNVC_MIXED           0x08
65
16
#define AMP_TNVC_TYPE            0x04
66
16
#define AMP_TNVC_NAME            0x02
67
16
#define AMP_TNVC_VALUE           0x01
68
69
#define AMP_MSG_REGISTER_AGENT   0x01
70
#define AMP_MSG_DATA_REPORT      0x00
71
#define AMP_MSG_PERFORM_CONTROL  0x02
72
73
static dissector_handle_t amp_handle;
74
75
void proto_register_amp(void);
76
void proto_reg_handoff_amp(void);
77
78
static int hf_amp_message_header;
79
static int hf_amp_report_bytestring;
80
static int hf_amp_report_data;
81
static int hf_amp_report_integer8_small;
82
static int hf_amp_report_integer;
83
static int hf_amp_cbor_header;
84
static int hf_amp_primary_timestamp;
85
static int hf_amp_agent_name;
86
static int hf_amp_text_string;
87
static int hf_amp_ari_flags;
88
static int hf_ari_value;
89
static int hf_ari_struct;
90
static int hf_ari_nickname;
91
static int hf_ari_parameters;
92
static int hf_ari_issuer;
93
static int hf_ari_tag;
94
static int hf_amp_tnvc_flags;
95
static int hf_amp_tnvc_reserved;
96
static int hf_amp_tnvc_mixed;
97
static int hf_amp_tnvc_typed;
98
static int hf_amp_tnvc_name;
99
static int hf_amp_tnvc_values;
100
101
/* Initialize the protocol and registered fields */
102
static int proto_amp;
103
104
static int ett_amp_message_header;
105
static int ett_amp_proto;
106
static int ett_amp;
107
static int ett_amp_cbor_header;
108
static int ett_amp_message;
109
static int ett_amp_register;
110
static int ett_amp_report_set;
111
static int ett_amp_report;
112
static int ett_amp_tnvc_flags;
113
static int ett_amp_ari_flags;
114
115
static int hf_amp_reserved;
116
static int hf_amp_acl;
117
static int hf_amp_nack;
118
static int hf_amp_ack;
119
static int hf_amp_opcode;
120
static int hf_amp_rx_name;
121
122
static expert_field ei_amp_cbor_malformed;
123
124
static const value_string opcode[] = {
125
    { 0, "Register Agent" },
126
    { 1, "Report Set" },
127
    { 2, "Perform Control" },
128
    { 3, "Table Set" },
129
    { 0, NULL }
130
};
131
132
static const value_string amp_ari_struct_type[] = {
133
    { 0, "Const" },
134
    { 1, "Control" },
135
    { 2, "Externally Defined Data" },
136
    { 3, "Macro" },
137
    { 4, "Operation" },
138
    { 5, "Report Template" },
139
    { 6, "State-Based Rule" },
140
    { 7, "Table Templates" },
141
    { 8, "Time-Based Rule" },
142
    { 9, "Variables" },
143
    { 10, "Metadata" },
144
    { 11, "Reserved" },
145
    { 12, "Reserved" },
146
    { 13, "Reserved" },
147
    { 14, "Reserved" },
148
    { 15, "Reserved" },
149
    { 0, NULL }
150
};
151
152
153
/* AMP Message Header */
154
static int * const amp_message_header[] = {
155
    &hf_amp_reserved,
156
    &hf_amp_acl,
157
    &hf_amp_nack,
158
    &hf_amp_ack,
159
    &hf_amp_opcode,
160
    0
161
};
162
163
/* TNVC Flags */
164
static int * const amp_tnvc_flags[] = {
165
    &hf_amp_tnvc_reserved,
166
    &hf_amp_tnvc_mixed,
167
    &hf_amp_tnvc_typed,
168
    &hf_amp_tnvc_name,
169
    &hf_amp_tnvc_values,
170
    0
171
};
172
173
/* ARI Flags */
174
static int * const amp_ari_flags[] = {
175
    &hf_ari_nickname,
176
    &hf_ari_parameters,
177
    &hf_ari_issuer,
178
    &hf_ari_tag,
179
    &hf_ari_struct,
180
    0
181
};
182
183
/* CBOR Types */
184
typedef enum {
185
    CBOR_UNKNOWN = -1,
186
    CBOR_UINT = 0, // Positive, unsigned integer
187
    CBOR_INT = 1, // Negative integer
188
    CBOR_BYTESTRING = 2,
189
    CBOR_TEXTSTRING = 3,
190
    CBOR_ARRAY = 4,
191
    CBOR_MAP = 5,
192
    CBOR_SEMANTIC_TAG = 6,
193
    CBOR_PRIMITIVE = 7
194
} CBOR_TYPE;
195
196
typedef struct {
197
    int type;
198
    int size; // for integers, the value
199
              // for bytestrings and textstrings, the size of the string
200
              // for arrays, the number of elements in the array
201
    uint64_t totalSize; // total size (including size above and any bytestring
202
                       // size).
203
    uint64_t uint;
204
} cborObj;
205
206
207
// Decode the CBOR object at the given offset in the tvb.
208
// The returned cborObj contains the object (with type) and the size
209
// (including the CBOR identifier).
210
static cborObj cbor_info(tvbuff_t *tvb, unsigned offset)
211
41
{
212
41
    int tmp = 0;
213
41
    cborObj ret;
214
41
    ret.size = 0;
215
41
    ret.totalSize = 0;
216
41
    ret.uint = -1;
217
41
    int theSize;
218
219
41
    tmp = tvb_get_uint8(tvb, offset);
220
221
41
    offset += 1;
222
41
    ret.size += 1;
223
224
41
    ret.type = (tmp & 0xE0)>>5; // Top 3 bits
225
41
    theSize = (tmp & 0x1F);
226
227
41
    switch ( ret.type )
228
41
    {
229
9
    case 0x00: // Positive / Unsigned integer
230
9
        if ( theSize<24 ) {
231
9
            ret.uint = (tmp & 0x1F); // May be actual size or indication of follow-on size
232
9
        } else if (theSize==24) { // next byte is uint8_t data
233
0
            ret.uint = tvb_get_uint8(tvb, offset);
234
0
            ret.size += 1;
235
0
        } else if (theSize==25) { // next 2 bytes are uint16_t data
236
0
            ret.uint = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
237
0
            ret.size += 2;
238
0
        } else if (theSize==26) { // next 4 bytes are uint32_t data
239
0
            ret.uint = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
240
0
            ret.size += 4;
241
0
        } else if (theSize==27) { // next 8 bytes are uint64_t data
242
0
            ret.uint = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
243
0
            ret.size += 8;
244
0
        }
245
9
        ret.totalSize = ret.size;
246
9
        break;
247
248
21
    case 0x02: // Byte string
249
21
        if ( theSize<24 ) { // Array size is contained in the identifier byte
250
0
            ret.uint = (tmp & 0x1F);
251
21
        } else if (theSize==24) { // next byte is uint8_t data (length)
252
21
            ret.uint = tvb_get_uint8(tvb, offset);
253
21
            ret.size += 1;
254
21
        } else if (theSize==25) { // next 2bytes are uint16_t data (length)
255
0
            ret.uint = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
256
0
            ret.size += 2;
257
0
        } else if (theSize==26) { // next 4bytes are uint32_t data
258
0
            ret.uint = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
259
0
            ret.size += 4;
260
0
        } else if (theSize==27) { // next byte is uint64_t data
261
0
            ret.uint = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
262
0
            ret.size += 8;
263
0
        }
264
21
        ret.totalSize = ret.size+ret.uint;
265
21
        break;
266
267
1
    case 0x03: // Text string
268
1
        if ( theSize<24 ) // Array size is contained in the identifier byte
269
1
        {
270
1
            ret.uint = (tmp & 0x1F);
271
1
        } else if (theSize==24) // next byte is uint8_t data
272
0
        {
273
0
            ret.uint = tvb_get_uint8(tvb, offset);
274
0
            ret.size += 1;
275
0
        } else if (theSize==25) // next 2bytes are uint16_t data
276
0
        {
277
0
            ret.uint = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
278
0
            ret.size += 2;
279
0
        } else if (theSize==26) // next 4bytes are uint32_t data
280
0
        {
281
0
            ret.uint = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
282
0
            ret.size += 4;
283
0
        } else if (theSize==27) // next byte is uint64_t data
284
0
        {
285
0
            ret.uint = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
286
0
            ret.size += 8;
287
0
        }
288
1
        ret.totalSize = ret.size+ret.uint;
289
1
        break;
290
291
5
    case 0x04: // Array
292
5
        if ( theSize<24 ) // Array size is contained in the identifier byte
293
0
        {
294
0
            ret.uint = (tmp & 0x1F);
295
5
        } else if (theSize==24) // next byte is uint8_t data
296
0
        {
297
0
            ret.uint = tvb_get_uint8(tvb, offset);
298
0
            ret.size += 1;
299
5
        } else if (theSize==25) // next 2bytes are uint16_t data
300
0
        {
301
0
            ret.uint = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
302
0
            ret.size += 2;
303
5
        } else if (theSize==26) // next 4bytes are uint32_t data
304
0
        {
305
0
            ret.uint = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
306
0
            ret.size += 4;
307
5
        } else if (theSize==27) // next byte is uint64_t data
308
0
        {
309
0
            ret.uint = tvb_get_uint64(tvb, offset, ENC_BIG_ENDIAN);
310
0
            ret.size += 8;
311
0
        }
312
        // I know how many elements are in the array, but NOT the total
313
        // size of the array data.
314
5
        ret.totalSize = -1;
315
5
        break;
316
317
1
    case 0x06: // Semantic tag
318
1
        if ( theSize<24 )
319
0
        {
320
0
            ret.uint = (tmp & 0x1F);
321
0
        }
322
1
        ret.totalSize += ret.uint;
323
1
        break;
324
325
1
    case 0x01: // Negative integer
326
4
    case 0x07: // Primitives e.g. break, float, simple values
327
4
    default:
328
        // TODO -- not supported yet.
329
4
        break;
330
41
    }
331
41
    return ret;
332
41
}
333
334
void
335
dissect_amp_as_subtree(tvbuff_t *tvb,  packet_info *pinfo, proto_tree *tree, unsigned offset)
336
1
{
337
1
    uint64_t messages = 0;
338
1
    unsigned int i=0;
339
1
    unsigned int j=0;
340
1
    unsigned int k=0;
341
1
    unsigned int numTNVCEntries = 0;
342
343
1
    proto_tree *amp_tree = NULL;
344
1
    proto_tree *amp_register_tree = NULL;
345
1
    proto_tree *amp_report_set_tree = NULL;
346
1
    proto_tree *amp_report_tree = NULL;
347
1
    proto_tree *amp_report_TNVC_tree = NULL;
348
1
    proto_tree *amp_control_tree = NULL;
349
1
    proto_tree *amp_table_tree = NULL;
350
1
    proto_item *payload_item = NULL;
351
1
    proto_tree *amp_message_tree = NULL;
352
1
    proto_tree *amp_report_TNVC_sub_tree = NULL;
353
1
    proto_item  *amp_message = NULL;
354
1
    proto_item  *amp_register  = NULL;
355
1
    proto_item  *amp_report_set = NULL;
356
1
    proto_item  *amp_report = NULL;
357
358
1
    cborObj myObj;
359
1
    cborObj tmpObj;
360
1
    cborObj tmpObj2;
361
1
    cborObj tmpObj3;
362
1
    cborObj tmpObj4;
363
1
    int reportHasTimestamp = 0;
364
1
    unsigned report_types_offset = 0;
365
366
1
    amp_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_amp_proto,
367
1
                                       &payload_item, "Payload Data: AMP Protocol");
368
369
    // First byte is the main CBOR type (probably an array of things)
370
    // e.g. 0x82 (byte array of 2 things)
371
1
    myObj = cbor_info(tvb, offset);
372
1
    offset += myObj.size;
373
1
    messages = myObj.uint;
374
375
    // Item 0 is the timestamp
376
1
    myObj = cbor_info(tvb, offset);
377
1
    add_value_time_to_tree((int) myObj.uint, MIN(myObj.size-1, 1), amp_tree, tvb, offset, hf_amp_primary_timestamp);
378
1
    offset += myObj.size;
379
380
27
    for ( i=1; i<messages; i++ ) {
381
        // Get the bytestring object that gives the total length of the AMP chunk
382
27
        myObj = cbor_info(tvb, offset);
383
27
        offset += myObj.size; // Note: myObj.uint is the length of the amp chunk; used later
384
                              // to advance offset past this message.
385
386
        // The first byte of this byte string (the AMP message) is going to be the message header
387
        // This is just a byte, not a CBOR uint8
388
27
        int ampHeader;
389
27
        ampHeader = tvb_get_uint8(tvb, offset);
390
27
        amp_message_tree = proto_tree_add_subtree(amp_tree, tvb, offset, -1,
391
27
                                                  ett_amp_message, &amp_message, "AMP Message");
392
393
27
        proto_tree_add_bitmask(amp_message_tree, tvb, offset, hf_amp_message_header, ett_amp_message_header,
394
27
                               amp_message_header, ENC_BIG_ENDIAN);
395
27
        offset += 1;
396
27
        unsigned old_offset;
397
398
27
        switch ( ampHeader & 0x07)
399
27
        {
400
12
        case 0x00: // Register agent
401
            //amp_register_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp);
402
12
            amp_register_tree = proto_tree_add_subtree(amp_message_tree, tvb, offset-1, 1,
403
12
                                            ett_amp_register, &amp_register, "Register-Agent");
404
12
            tmpObj = cbor_info(tvb, offset); // Should come back a CBOR text string if some length.
405
12
            offset += tmpObj.size;
406
12
            proto_tree_add_item(amp_register_tree, hf_amp_agent_name, tvb, offset,
407
12
                                (int) tmpObj.uint, ENC_ASCII|ENC_NA);
408
12
            old_offset = offset;
409
12
            offset += (int) tmpObj.uint;
410
12
            if (offset < old_offset) {
411
0
                proto_tree_add_expert_remaining(amp_tree, pinfo, &ei_amp_cbor_malformed, tvb, offset);
412
0
                return;
413
0
            }
414
12
            break;
415
416
12
        case 0x01: // Report set
417
0
            amp_report_set_tree = proto_tree_add_subtree(amp_message_tree, tvb, offset-2, -1,
418
0
                                            ett_amp_report_set, &amp_report_set, "Report-Set");
419
420
            // Rx Names
421
0
            tmpObj = cbor_info(tvb, offset); // Should come back a CBOR array of some size (Rx Names)
422
0
            if ( tmpObj.type != 0x04 ) {
423
0
                return;
424
0
            }
425
0
            offset += tmpObj.size;
426
            // read rx names
427
0
            for ( j=0; j<tmpObj.uint; j++ ) {
428
0
                tmpObj2 = cbor_info(tvb, offset); // Should be text string of some size
429
0
                offset += tmpObj2.size;
430
0
                proto_tree_add_item(amp_report_set_tree, hf_amp_rx_name, tvb, offset,
431
0
                                    (int) tmpObj2.uint, ENC_ASCII|ENC_NA);
432
0
                old_offset = offset;
433
0
                offset +=  (unsigned)tmpObj2.uint;
434
0
                if (offset < old_offset) {
435
0
                    proto_tree_add_expert_remaining(amp_tree, pinfo, &ei_amp_cbor_malformed, tvb, offset);
436
0
                    return;
437
0
                }
438
0
            }
439
440
            // How many reports?
441
0
            tmpObj2 = cbor_info(tvb, offset); // Should come back a CBOR array of some size
442
0
            offset += tmpObj2.size;
443
444
0
            for ( j=0; j<tmpObj2.uint; j++ ) {
445
                // Internals of each report per section 8.4.7 of https://tools.ietf.org/pdf/draft-birrane-dtn-amp-07.pdf
446
                // amp_report_sub_tree = proto_item_add_subtree(amp_report_set_tree, ett_amp);
447
0
                amp_report_tree = proto_tree_add_subtree(amp_report_set_tree, tvb, offset, -1,
448
0
                                                             ett_amp_report, &amp_report, "Report");
449
450
                // Each Report is a:
451
                //     Template [ARI]
452
                //     Timestamp [TS] (opt)
453
                //     Entries [TNVC] (bytestring containing a TNVC)
454
0
                tmpObj3 = cbor_info(tvb, offset); // Should come back a CBOR array of size 2 or 3
455
0
                offset += tmpObj3.size;
456
0
                if ( tmpObj3.uint==3 )
457
0
                {
458
0
                    reportHasTimestamp = 1;
459
0
                } else
460
0
                {
461
0
                    reportHasTimestamp = 0;
462
0
                }
463
464
                // Template (bytestring); starts with ARI
465
0
                tmpObj3 = cbor_info(tvb, offset);
466
0
                offset += tmpObj3.size;
467
0
                uint8_t ariFlags;
468
0
                ariFlags = tvb_get_uint8(tvb, offset);
469
470
0
                if ( (ariFlags&0x0F)==0x03 ) {
471
                    // Literal
472
0
                    proto_tree_add_uint(amp_report_tree, hf_ari_value, tvb, offset, 1, ariFlags);
473
0
                } else {
474
                    // NOT literal
475
0
                    proto_tree_add_bitmask(amp_report_tree, tvb, offset, hf_amp_ari_flags, ett_amp_ari_flags,
476
0
                                           amp_ari_flags, ENC_BIG_ENDIAN);
477
478
0
                }
479
                //proto_tree_add_uint(amp_ari_tree, hf_ari_struct, tvb, offset, 1, ariFlags);
480
481
0
                if ( (ariFlags & 0x0F) != 0x03 && tmpObj3.uint > 0 )
482
0
                {
483
                    // ARI is NOT Literal
484
0
                    proto_tree_add_item(amp_report_tree, hf_amp_report_bytestring, tvb, offset+1, (int) tmpObj3.uint-1, ENC_NA);
485
0
                }
486
0
                old_offset = offset;
487
0
                offset += (int) tmpObj3.uint;
488
0
                if (offset < old_offset) {
489
0
                    proto_tree_add_expert_remaining(amp_tree, pinfo, &ei_amp_cbor_malformed, tvb, offset);
490
0
                    return;
491
0
                }
492
493
0
                if ( reportHasTimestamp )
494
0
                {
495
0
                    tmpObj3 = cbor_info(tvb, offset);
496
0
                    offset += 1;
497
0
                    add_value_time_to_tree((int) tmpObj3.uint, 4, amp_report_tree, tvb, offset, hf_amp_primary_timestamp);
498
0
                    offset += (tmpObj3.size-1);
499
0
                }
500
501
                // Entries [TNVC] -- This is th collection of data values that comprise the report
502
                // contents in accordance with the associated Report Template.
503
                // Contained in a CBOR bytestring
504
0
                tmpObj3 = cbor_info(tvb, offset);
505
0
                offset += tmpObj3.size;
506
507
                // Now read array length for TNVC
508
0
                tmpObj3 = cbor_info(tvb, offset);
509
0
                offset += tmpObj3.size;
510
0
                numTNVCEntries = (int) tmpObj3.uint;
511
512
                // TNVC Flags
513
0
                proto_tree_add_bitmask(amp_report_tree, tvb, offset, hf_amp_tnvc_flags, ett_amp_tnvc_flags,
514
0
                                       amp_tnvc_flags, ENC_BIG_ENDIAN);
515
0
                offset += 1;
516
517
                // TNVC entries
518
0
                amp_report_TNVC_sub_tree = proto_item_add_subtree(amp_report_tree, ett_amp);
519
0
                amp_report_TNVC_tree = proto_tree_add_subtree(amp_report_TNVC_sub_tree, tvb, offset, -1,
520
0
                        ett_amp_message, &amp_message, "TNVC Entries");
521
522
                // Byte string containing data types
523
0
                tmpObj3 = cbor_info(tvb, offset);
524
0
                offset += tmpObj3.size;
525
0
                report_types_offset = offset;
526
0
                offset += (int) tmpObj3.uint;
527
0
                if (offset < report_types_offset) {
528
0
                    proto_tree_add_expert_remaining(amp_tree, pinfo, &ei_amp_cbor_malformed, tvb, offset);
529
0
                    return;
530
0
                }
531
532
                // TNVC data items
533
0
                for ( k=0; k+2<numTNVCEntries; k++ ) {
534
0
                    tmpObj3 = cbor_info(tvb, offset);
535
0
                    switch ( tmpObj3.type ) {
536
0
                    case 0x02: // bytestring
537
                        // Get the type from the type dictionary
538
0
                        switch ( tvb_get_uint8(tvb, report_types_offset+k) ) {
539
0
                        case 0x12: // string
540
                            // It's a text string of some size INSIDE a byte string
541
0
                            tmpObj4 = cbor_info(tvb, offset+tmpObj3.size);
542
                            // printf("tmpObj4.type of (%02x) is (%d)\n", tvb_get_uint8(tvb, offset+tmpObj3.size), tmpObj4.type);
543
0
                            proto_tree_add_item(amp_report_TNVC_tree, hf_amp_text_string, tvb,
544
0
                                        offset+tmpObj3.size+tmpObj4.size,
545
0
                                        (int) tmpObj3.uint-tmpObj4.size, 0x00);
546
0
                            break;
547
0
                        case 0x16: // uvast
548
0
                            tmpObj4 = cbor_info(tvb, offset+tmpObj3.size);
549
0
                            if ( tmpObj4.type != CBOR_UINT ) {
550
0
                                break;
551
0
                            }
552
0
                            switch ( tmpObj4.size ) {
553
0
                            case 1:
554
0
                                proto_tree_add_item(amp_report_TNVC_tree, hf_amp_report_integer8_small,
555
0
                                                tvb, offset+tmpObj3.size, 1, 0x00);
556
0
                                break;
557
0
                            default: // Note: CBOR will only let these sizes be 1, 2, 4, or 8 bytes.
558
0
                                proto_tree_add_item(amp_report_TNVC_tree, hf_amp_report_integer,
559
0
                                                tvb, offset+tmpObj3.size+1, tmpObj4.size-1, 0x00);
560
0
                                break;
561
0
                            }
562
0
                            break;
563
0
                        default:
564
0
                            break;
565
0
                        }
566
0
                        break;
567
0
                    default:
568
0
                        proto_tree_add_item(amp_report_TNVC_tree, hf_amp_report_data, tvb, offset+tmpObj3.size, (int) tmpObj3.uint, 0x00);
569
0
                        break;
570
0
                    }
571
0
                    if ( tmpObj3.totalSize == 0 ) {
572
0
                        break;
573
0
                    }
574
                    /* Arrays have no known size, and a string length can exceed the packet */
575
0
                    if ( tmpObj3.totalSize > tvb_reported_length_remaining(tvb, offset) ) {
576
0
                        proto_tree_add_expert_remaining(amp_tree, pinfo, &ei_amp_cbor_malformed, tvb, offset);
577
0
                        return;
578
0
                    }
579
0
                    offset += (unsigned)tmpObj3.totalSize;
580
0
                }
581
582
0
            }
583
0
            break;
584
585
0
        case 0x02: // Perform Control
586
            // TODO
587
            //amp_control_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp);
588
0
            amp_control_tree = proto_tree_add_subtree(amp_message_tree, tvb, offset-1, -1,
589
0
                                            ett_amp_message, &amp_message, "Perform-Control");
590
0
            proto_tree_add_item(amp_control_tree, hf_amp_cbor_header, tvb, offset, 1, ENC_BIG_ENDIAN);
591
0
            break;
592
593
0
        case 0x03: // Table Set
594
            // TODO
595
            //amp_table_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp);
596
0
            amp_table_tree = proto_tree_add_subtree(amp_message_tree, tvb, offset-1, -1,
597
0
                                            ett_amp_message, &amp_message, "AMP Message: Table-Set");
598
0
            proto_tree_add_item(amp_table_tree, hf_amp_cbor_header, tvb, offset, 1, ENC_BIG_ENDIAN);
599
0
            break;
600
15
        default:
601
15
            break;
602
27
        }
603
27
    }
604
605
0
    return;
606
1
}
607
608
/* Code to actually dissect the packets */
609
static int
610
dissect_amp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
611
0
{
612
0
  int offset = 0;
613
0
  proto_item  *amp_packet;
614
0
  proto_item  *amp_tree;
615
0
  int amp_packet_reported_length;
616
617
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "AMP");
618
0
  col_clear(pinfo->cinfo, COL_INFO);
619
620
0
  amp_packet_reported_length = tvb_reported_length_remaining(tvb, 0);
621
622
0
  amp_packet = proto_tree_add_item(tree, proto_amp, tvb, 0, amp_packet_reported_length, ENC_NA);
623
0
  amp_tree   = proto_item_add_subtree(amp_packet, ett_amp);
624
625
0
  dissect_amp_as_subtree (tvb, pinfo, amp_tree, offset);
626
627
0
  return tvb_captured_length(tvb);
628
0
}
629
630
void
631
proto_register_amp(void)
632
16
{
633
16
    static hf_register_info hf[] = {
634
635
16
        { &hf_amp_message_header,
636
16
        { "AMP Message Header", "amp.message.header",
637
16
          FT_UINT8, BASE_DEC, NULL, 0x0,
638
16
          NULL, HFILL }
639
16
        },
640
16
        { &hf_amp_report_data,
641
16
        { "Report-Data", "amp.report.data",
642
16
            FT_BYTES, BASE_NONE, NULL, 0x0,
643
16
            NULL, HFILL }
644
16
        },
645
16
        { &hf_amp_report_bytestring,
646
16
        { "Report-Bytestring", "amp.report.bytestring",
647
16
            FT_BYTES, BASE_NONE, NULL, 0x0,
648
16
            NULL, HFILL }
649
16
        },
650
16
        { &hf_amp_report_integer8_small,
651
16
        { "Report-Integer8_small", "amp.report.integer8_small",
652
16
            FT_UINT8, BASE_DEC, NULL, AMP_CBOR_UINT_SMALL,
653
16
            NULL, HFILL }
654
16
        },
655
16
        { &hf_amp_report_integer,
656
16
        { "Report-Integer", "amp.report.integer",
657
16
            FT_UINT64, BASE_DEC, NULL, 0x0,
658
16
            NULL, HFILL }
659
16
        },
660
16
        { &hf_amp_cbor_header,
661
16
        { "CBOR-Header", "amp.cbor_header",
662
16
            FT_UINT8, BASE_HEX, NULL, 0x0,
663
16
            NULL, HFILL }
664
16
        },
665
16
        { &hf_amp_primary_timestamp,
666
16
        { "Timestamp", "amp.primary_timestamp",
667
16
          FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}
668
16
        },
669
16
        { &hf_amp_tnvc_flags,
670
16
        { "TNVC Flags", "amp.tnvc.flags",
671
16
          FT_UINT8, BASE_DEC, NULL, 0x0,
672
16
          NULL, HFILL }
673
16
        },
674
16
        { &hf_amp_tnvc_reserved,
675
16
        { "Reserved", "amp.tnvc.reserved",
676
16
          FT_UINT8, BASE_DEC, NULL, AMP_TNVC_RESERVED,
677
16
          NULL, HFILL }
678
16
        },
679
16
        { &hf_amp_tnvc_mixed,
680
16
        { "Mixed", "amp.tnvc.mixed",
681
16
          FT_BOOLEAN, 8, TFS(&tfs_yes_no), AMP_TNVC_MIXED,
682
16
          NULL, HFILL }
683
16
        },
684
16
        { &hf_amp_tnvc_typed,
685
16
        { "TNVC Values are Typed", "amp.tnvc.typed",
686
16
          FT_BOOLEAN, 8, TFS(&tfs_yes_no), AMP_TNVC_TYPE,
687
16
          NULL, HFILL }
688
16
        },
689
16
        { &hf_amp_tnvc_name,
690
16
        { "Name", "amp.tnvc.name",
691
16
          FT_BOOLEAN, 8, TFS(&tfs_yes_no), AMP_TNVC_NAME,
692
16
          NULL, HFILL }
693
16
        },
694
16
        { &hf_amp_tnvc_values,
695
16
        { "Values", "amp.tnvc.value",
696
16
          FT_BOOLEAN, 8, TFS(&tfs_yes_no), AMP_TNVC_VALUE,
697
16
          NULL, HFILL }
698
16
        },
699
16
        { &hf_ari_nickname,
700
16
        { "Nickname", "amp.nickname",
701
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_ARI_NICKNAME,
702
16
          NULL, HFILL }
703
16
        },
704
16
        { &hf_amp_ari_flags,
705
16
        { "ARI Flags", "amp.ari.flags",
706
16
          FT_UINT8, BASE_DEC, NULL, 0x0,
707
16
          NULL, HFILL }
708
16
        },
709
16
        { &hf_ari_parameters,
710
16
        { "Parameters", "amp.parameters",
711
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_ARI_PARAMETERS,
712
16
          NULL, HFILL }
713
16
        },
714
16
        { &hf_ari_issuer,
715
16
        { "Issuer", "amp.issuer",
716
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_ARI_ISSUER,
717
16
          NULL, HFILL }
718
16
        },
719
16
        { &hf_ari_tag,
720
16
        { "Tag", "amp.tag",
721
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_ARI_TAG,
722
16
          NULL, HFILL }
723
16
        },
724
16
        { &hf_ari_value,
725
16
        { "Value", "amp.value",
726
16
          FT_UINT8, BASE_DEC, NULL, AMP_ARI_VALUE,
727
16
          NULL, HFILL }
728
16
        },
729
16
        { &hf_ari_struct,
730
16
        { "Struct Type", "amp.struct",
731
16
          FT_UINT8, BASE_DEC, VALS(amp_ari_struct_type), AMP_ARI_STRUCT,
732
16
          NULL, HFILL }
733
16
        },
734
16
        { &hf_amp_reserved,
735
16
        { "Reserved", "amp.reserved",
736
16
          FT_UINT8, BASE_DEC, NULL, AMP_HDR_RESERVED,
737
16
          NULL, HFILL }
738
16
        },
739
16
        { &hf_amp_acl,
740
16
          { "ACL", "amp.acl",
741
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_HDR_ACL,
742
16
          NULL, HFILL }
743
16
        },
744
16
        { &hf_amp_nack,
745
16
          { "NACK", "amp.nack",
746
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_HDR_NACK,
747
16
          NULL, HFILL }
748
16
        },
749
16
        { &hf_amp_ack,
750
16
          { "ACK", "amp.ack",
751
16
          FT_BOOLEAN, 8, TFS(&tfs_present_not_present), AMP_HDR_ACK,
752
16
          NULL, HFILL }
753
16
        },
754
16
        { &hf_amp_opcode,
755
16
          { "Opcode", "amp.opcode",
756
16
          FT_UINT8, BASE_DEC, VALS(opcode), AMP_HDR_OPCODE,
757
16
          NULL, HFILL }
758
16
        },
759
16
        {&hf_amp_agent_name,
760
16
         {"Agent-Name", "amp.agent_name",
761
16
          FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL}
762
16
        },
763
16
        {&hf_amp_text_string,
764
16
         {"String", "amp.string",
765
16
          FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL}
766
16
        },
767
16
        {&hf_amp_rx_name,
768
16
         {"Rx-Name", "amp.rx_name",
769
16
          FT_STRINGZPAD, BASE_NONE, NULL, 0x0, NULL, HFILL}
770
16
        },
771
772
16
    };
773
774
    /* Setup protocol subtree array */
775
16
    static int *ett[] = {
776
16
        &ett_amp,
777
16
        &ett_amp_message_header,
778
16
        &ett_amp_cbor_header,
779
16
        &ett_amp_message,
780
16
        &ett_amp_register,
781
16
        &ett_amp_report_set,
782
16
        &ett_amp_report,
783
16
        &ett_amp_tnvc_flags,
784
16
        &ett_amp_ari_flags,
785
16
        &ett_amp_proto
786
16
    };
787
788
16
    static ei_register_info ei[] = {
789
16
        { &ei_amp_cbor_malformed, { "amp.cbor.malformed", PI_MALFORMED, PI_ERROR, "Malformed CBOR object", EXPFILL }},
790
16
    };
791
792
    /* Register the protocol name and description */
793
16
    proto_amp = proto_register_protocol("AMP", "AMP", "amp");
794
795
    /* Required function calls to register the header fields and subtrees used */
796
16
    proto_register_field_array(proto_amp, hf, array_length(hf));
797
16
    proto_register_subtree_array(ett, array_length(ett));
798
16
    expert_module_t* expert_amp = expert_register_protocol(proto_amp);
799
16
    expert_register_field_array(expert_amp, ei, array_length(ei));
800
801
16
    amp_handle = register_dissector("amp", dissect_amp, proto_amp);
802
16
}
803
804
void
805
proto_reg_handoff_amp(void)
806
16
{
807
16
    dissector_add_uint("ccsds.apid", AMP_APID, amp_handle);
808
16
    dissector_add_for_decode_as_with_preference("udp.port", amp_handle);
809
16
}
810
811
/*
812
 * Editor modelines - http://www.wireshark.org/tools/modelines.html
813
 *
814
 * Local variables:
815
 * c-basic-offset: 4
816
 * tab-width: 8
817
 * indent-tabs-mode: nil
818
 * End:
819
 *
820
 * vi: set shiftwidth=4 tabstop=8 expandtab:
821
 * :indentSize=4:tabSize=8:noTabs=true:
822
 */