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)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/exceptions.h>
15 #include <epan/expert.h>
16 #include <epan/packet.h>
18 #include "packet-amp.h"
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
25 #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. */
33 add_value_time_to_tree(uint64_t value
, int len
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int hf_time_format
)
37 // If it's a relative time, just make it zero.
38 if ( value
< 558230400 ) {
41 dtn_time
.secs
= (time_t)(value
);
43 proto_tree_add_time(tree
, hf_time_format
, tvb
, offset
, len
, &dtn_time
);
48 #define AMP_HDR_RESERVED 0xC0
49 #define AMP_HDR_ACL 0x20
50 #define AMP_HDR_NACK 0x10
51 #define AMP_HDR_ACK 0x08
52 #define AMP_HDR_OPCODE 0x07
54 #define AMP_ARI_NICKNAME 0x80
55 #define AMP_ARI_PARAMETERS 0x40
56 #define AMP_ARI_ISSUER 0x20
57 #define AMP_ARI_TAG 0x10
58 #define AMP_ARI_STRUCT 0x0F
59 #define AMP_ARI_VALUE 0xF0
61 #define AMP_CBOR_UINT_SMALL 0x1F
63 #define AMP_TNVC_RESERVED 0xF0
64 #define AMP_TNVC_MIXED 0x08
65 #define AMP_TNVC_TYPE 0x04
66 #define AMP_TNVC_NAME 0x02
67 #define AMP_TNVC_VALUE 0x01
69 #define AMP_MSG_REGISTER_AGENT 0x01
70 #define AMP_MSG_DATA_REPORT 0x00
71 #define AMP_MSG_PERFORM_CONTROL 0x02
73 static dissector_handle_t amp_handle
;
75 void proto_register_amp(void);
76 void proto_reg_handoff_amp(void);
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
;
101 /* Initialize the protocol and registered fields */
102 static int proto_amp
;
104 static int ett_amp_message_header
;
105 static int ett_amp_proto
;
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
;
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
;
122 static expert_field ei_amp_cbor_malformed
;
124 static const value_string opcode
[] = {
125 { 0, "Register Agent" },
127 { 2, "Perform Control" },
131 static const value_string amp_ari_struct_type
[] = {
134 { 2, "Externally Defined Data" },
137 { 5, "Report Template" },
138 { 6, "State-Based Rule" },
139 { 7, "Table Templates" },
140 { 8, "Time-Based Rule" },
152 /* AMP Message Header */
153 static int * const amp_message_header
[] = {
163 static int * const amp_tnvc_flags
[] = {
164 &hf_amp_tnvc_reserved
,
173 static int * const amp_ari_flags
[] = {
185 CBOR_UINT
= 0, // Positive, unsigned integer
186 CBOR_INT
= 1, // Negative integer
191 CBOR_SEMANTIC_TAG
= 6,
197 int size
; // for integers, the value
198 // for bytestrings and textstrings, the size of the string
199 // for arrays, the number of elements in the array
200 uint64_t totalSize
; // total size (including size above and any bytestring
206 // Decode the CBOR object at the given offset in the tvb.
207 // The returned cborObj contains the object (with type) and the size
208 // (including the CBOR identifier).
209 static cborObj
cbor_info(tvbuff_t
*tvb
, int offset
)
213 ret
.type
= CBOR_UNKNOWN
;
219 tmp
= tvb_get_uint8(tvb
, offset
);
224 ret
.type
= (tmp
& 0xE0)>>5; // Top 3 bits
225 theSize
= (tmp
& 0x1F);
229 case 0x00: // Positive / Unsigned integer
231 ret
.uint
= (tmp
& 0x1F); // May be actual size or indication of follow-on size
232 } else if (theSize
==24) { // next byte is uint8_t data
233 ret
.uint
= tvb_get_uint8(tvb
, offset
);
235 } else if (theSize
==25) { // next 2 bytes are uint16_t data
236 ret
.uint
= tvb_get_uint16(tvb
, offset
, 0);
238 } else if (theSize
==26) { // next 4 bytes are uint32_t data
239 ret
.uint
= tvb_get_uint32(tvb
, offset
, 0);
241 } else if (theSize
==27) { // next 8 bytes are uint64_t data
242 ret
.uint
= tvb_get_uint64(tvb
, offset
, 0);
245 ret
.totalSize
= ret
.size
;
248 case 0x02: // Byte string
249 if ( theSize
<24 ) { // Array size is contained in the identifier byte
250 ret
.uint
= (tmp
& 0x1F);
251 } else if (theSize
==24) { // next byte is uint8_t data (length)
252 ret
.uint
= tvb_get_uint8(tvb
, offset
);
254 } else if (theSize
==25) { // next 2bytes are uint16_t data (length)
255 ret
.uint
= tvb_get_uint16(tvb
, offset
, 0);
257 } else if (theSize
==26) { // next 4bytes are uint32_t data
258 ret
.uint
= tvb_get_uint32(tvb
, offset
, 0);
260 } else if (theSize
==27) { // next byte is uint64_t data
261 ret
.uint
= tvb_get_uint64(tvb
, offset
, 0);
264 ret
.totalSize
= ret
.size
+ret
.uint
;
267 case 0x03: // Text string
268 if ( theSize
<24 ) // Array size is contained in the identifier byte
270 ret
.uint
= (tmp
& 0x1F);
271 } else if (theSize
==24) // next byte is uint8_t data
273 ret
.uint
= tvb_get_uint8(tvb
, offset
);
275 } else if (theSize
==25) // next 2bytes are uint16_t data
277 ret
.uint
= tvb_get_uint16(tvb
, offset
, 0);
279 } else if (theSize
==26) // next 4bytes are uint32_t data
281 ret
.uint
= tvb_get_uint32(tvb
, offset
, 0);
283 } else if (theSize
==27) // next byte is uint64_t data
285 ret
.uint
= tvb_get_uint64(tvb
, offset
, 0);
288 ret
.totalSize
= ret
.size
+ret
.uint
;
292 if ( theSize
<24 ) // Array size is contained in the identifier byte
294 ret
.uint
= (tmp
& 0x1F);
295 } else if (theSize
==24) // next byte is uint8_t data
297 ret
.uint
= tvb_get_uint8(tvb
, offset
);
299 } else if (theSize
==25) // next 2bytes are uint16_t data
301 ret
.uint
= tvb_get_uint16(tvb
, offset
, 0);
303 } else if (theSize
==26) // next 4bytes are uint32_t data
305 ret
.uint
= tvb_get_uint32(tvb
, offset
, 0);
307 } else if (theSize
==27) // next byte is uint64_t data
309 ret
.uint
= tvb_get_uint64(tvb
, offset
, 0);
312 // I know how many elements are in the array, but NOT the total
313 // size of the array data.
317 case 0x06: // Semantic tag
320 ret
.uint
= (tmp
& 0x1F);
322 ret
.totalSize
+= ret
.uint
;
325 case 0x01: // Negative integer
326 case 0x07: // Primitives e.g. break, float, simple values
328 // TODO -- not supported yet.
335 dissect_amp_as_subtree(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
)
337 uint64_t messages
= 0;
341 unsigned int numTNVCEntries
= 0;
343 proto_tree
*amp_tree
= NULL
;
344 proto_tree
*amp_items_tree
= NULL
;
345 proto_tree
*amp_register_tree
= NULL
;
346 proto_tree
*amp_report_set_tree
= NULL
;
347 proto_tree
*amp_report_tree
= NULL
;
348 proto_tree
*amp_report_TNVC_tree
= NULL
;
349 proto_tree
*amp_control_tree
= NULL
;
350 proto_tree
*amp_table_tree
= NULL
;
351 proto_item
*payload_item
= NULL
;
352 proto_tree
*amp_message_tree
= NULL
;
353 proto_tree
*amp_report_TNVC_sub_tree
= NULL
;
354 proto_item
*amp_message
= NULL
;
355 proto_item
*amp_register
= NULL
;
356 proto_item
*amp_report_set
= NULL
;
357 proto_item
*amp_report
= NULL
;
364 int reportHasTimestamp
= 0;
365 int report_types_offset
= 0;
367 amp_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_amp_proto
,
368 &payload_item
, "Payload Data: AMP Protocol");
370 // First byte is the main CBOR type (probably an array of things)
371 // e.g. 0x82 (byte array of 2 things)
372 myObj
= cbor_info(tvb
, offset
);
373 offset
+= myObj
.size
;
374 messages
= myObj
.uint
;
376 // Item 0 is the timestamp
377 myObj
= cbor_info(tvb
, offset
);
378 add_value_time_to_tree((int) myObj
.uint
, MIN(myObj
.size
-1, 1), amp_tree
, tvb
, offset
, hf_amp_primary_timestamp
);
379 offset
+= myObj
.size
;
381 for ( i
=1; i
<messages
; i
++ ) {
382 // Get the bytestring object that gives the total length of the AMP chunk
383 myObj
= cbor_info(tvb
, offset
);
384 offset
+= myObj
.size
; // Note: myObj.uint is the length of the amp chunk; used later
385 // to advance offset past this message.
387 // The first byte of this byte string (the AMP message) is going to be the message header
388 // This is just a byte, not a CBOR uint8
390 ampHeader
= tvb_get_uint8(tvb
, offset
);
391 amp_message_tree
= proto_tree_add_subtree(amp_tree
, tvb
, offset
, -1,
392 ett_amp_message
, &_message
, "AMP Message");
394 proto_tree_add_bitmask(amp_message_tree
, tvb
, offset
, hf_amp_message_header
, ett_amp_message_header
,
395 amp_message_header
, ENC_BIG_ENDIAN
);
399 switch ( ampHeader
& 0x07)
401 case 0x00: // Register agent
402 //amp_register_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp);
403 amp_register_tree
= proto_tree_add_subtree(amp_message_tree
, tvb
, offset
-1, 1,
404 ett_amp_register
, &_register
, "Register-Agent");
405 tmpObj
= cbor_info(tvb
, offset
); // Should come back a CBOR text string if some length.
406 offset
+= tmpObj
.size
;
407 proto_tree_add_item(amp_register_tree
, hf_amp_agent_name
, tvb
, offset
,
408 (int) tmpObj
.uint
, ENC_ASCII
|ENC_NA
);
410 offset
+= (int) tmpObj
.uint
;
411 if (offset
< old_offset
) {
412 proto_tree_add_expert(amp_tree
, pinfo
, &ei_amp_cbor_malformed
, tvb
, offset
, -1);
417 case 0x01: // Report set
418 amp_report_set_tree
= proto_tree_add_subtree(amp_message_tree
, tvb
, offset
-2, -1,
419 ett_amp_report_set
, &_report_set
, "Report-Set");
422 tmpObj
= cbor_info(tvb
, offset
); // Should come back a CBOR array of some size (Rx Names)
423 if ( tmpObj
.type
!= 0x04 ) {
426 offset
+= tmpObj
.size
;
428 for ( j
=0; j
<tmpObj
.uint
; j
++ ) {
429 tmpObj2
= cbor_info(tvb
, offset
); // Should be text string of some size
430 offset
+= tmpObj2
.size
;
431 proto_tree_add_item(amp_report_set_tree
, hf_amp_rx_name
, tvb
, offset
,
432 (int) tmpObj2
.uint
, ENC_ASCII
|ENC_NA
);
434 offset
+= (int) tmpObj2
.uint
;
435 if (offset
< old_offset
) {
436 proto_tree_add_expert(amp_tree
, pinfo
, &ei_amp_cbor_malformed
, tvb
, offset
, -1);
442 tmpObj2
= cbor_info(tvb
, offset
); // Should come back a CBOR array of some size
443 offset
+= tmpObj
.size
;
445 for ( j
=0; j
<tmpObj2
.uint
; j
++ ) {
446 // Internals of each report per section 8.4.7 of https://tools.ietf.org/pdf/draft-birrane-dtn-amp-07.pdf
447 // amp_report_sub_tree = proto_item_add_subtree(amp_report_set_tree, ett_amp);
448 amp_report_tree
= proto_tree_add_subtree(amp_report_set_tree
, tvb
, offset
, -1,
449 ett_amp_report
, &_report
, "Report");
453 // Timestamp [TS] (opt)
454 // Entries [TNVC] (bytestring containing a TNVC)
455 tmpObj3
= cbor_info(tvb
, offset
); // Should come back a CBOR array of size 2 or 3
456 offset
+= tmpObj3
.size
;
457 if ( tmpObj3
.uint
==3 )
459 reportHasTimestamp
= 1;
462 reportHasTimestamp
= 0;
465 // Tempate (bytestring); starts with ARI
466 tmpObj3
= cbor_info(tvb
, offset
);
467 offset
+= tmpObj3
.size
;
469 ariFlags
= tvb_get_uint8(tvb
, offset
);
471 if ( (ariFlags
&0x0F)==0x03 ) {
473 proto_tree_add_uint(amp_report_tree
, hf_ari_value
, tvb
, offset
, 1, ariFlags
);
476 proto_tree_add_bitmask(amp_report_tree
, tvb
, offset
, hf_amp_ari_flags
, ett_amp_ari_flags
,
477 amp_ari_flags
, ENC_BIG_ENDIAN
);
480 //proto_tree_add_uint(amp_ari_tree, hf_ari_struct, tvb, offset, 1, ariFlags);
482 if ( (ariFlags
& 0x0F) != 0x03 )
484 // ARI is NOT Literal
485 proto_tree_add_item(amp_report_tree
, hf_amp_report_bytestring
, tvb
, offset
+1, (int) tmpObj3
.uint
-1, ENC_NA
);
488 offset
+= (int) tmpObj3
.uint
;
489 if (offset
< old_offset
) {
490 proto_tree_add_expert(amp_tree
, pinfo
, &ei_amp_cbor_malformed
, tvb
, offset
, -1);
494 if ( reportHasTimestamp
)
496 tmpObj3
= cbor_info(tvb
, offset
);
498 add_value_time_to_tree((int) tmpObj3
.uint
, 4, amp_report_tree
, tvb
, offset
, hf_amp_primary_timestamp
);
499 offset
+= (tmpObj3
.size
-1);
502 // Entries [TNVC] -- This is th collection of data values that comprise the report
503 // contents in accordance with the associated Report Template.
504 // Contained in a CBOR bytestring
505 tmpObj3
= cbor_info(tvb
, offset
);
506 offset
+= tmpObj3
.size
;
508 // Now read array length for TNVC
509 tmpObj3
= cbor_info(tvb
, offset
);
510 offset
+= tmpObj3
.size
;
511 numTNVCEntries
= (int) tmpObj3
.uint
;
514 proto_tree_add_bitmask(amp_report_tree
, tvb
, offset
, hf_amp_tnvc_flags
, ett_amp_tnvc_flags
,
515 amp_tnvc_flags
, ENC_BIG_ENDIAN
);
519 amp_report_TNVC_sub_tree
= proto_item_add_subtree(amp_report_tree
, ett_amp
);
520 amp_report_TNVC_tree
= proto_tree_add_subtree(amp_report_TNVC_sub_tree
, tvb
, offset
, -1,
521 ett_amp_message
, &_message
, "TNVC Entries");
523 // Byte string containing data types
524 tmpObj3
= cbor_info(tvb
, offset
);
525 offset
+= tmpObj3
.size
;
526 report_types_offset
= offset
;
527 offset
+= (int) tmpObj3
.uint
;
528 if (offset
< report_types_offset
) {
529 proto_tree_add_expert(amp_tree
, pinfo
, &ei_amp_cbor_malformed
, tvb
, offset
, -1);
534 for ( k
=0; k
<numTNVCEntries
-2; k
++ ) {
535 tmpObj3
= cbor_info(tvb
, offset
);
536 switch ( tmpObj3
.type
) {
537 case 0x02: // bytestring
538 // Get the type from the type dictionary
539 switch ( tvb_get_uint8(tvb
, report_types_offset
+k
) ) {
541 // It's a text string of some size INSIDE a byte string
542 tmpObj4
= cbor_info(tvb
, offset
+tmpObj3
.size
);
543 // printf("tmpObj4.type of (%02x) is (%d)\n", tvb_get_uint8(tvb, offset+tmpObj3.size), tmpObj4.type);
544 proto_tree_add_item(amp_report_TNVC_tree
, hf_amp_text_string
, tvb
,
545 offset
+tmpObj3
.size
+tmpObj4
.size
,
546 (int) tmpObj3
.uint
-tmpObj4
.size
, 0x00);
549 tmpObj4
= cbor_info(tvb
, offset
+tmpObj3
.size
);
550 if ( tmpObj4
.type
!= CBOR_UINT
) {
553 switch ( tmpObj4
.size
) {
555 proto_tree_add_item(amp_report_TNVC_tree
, hf_amp_report_integer8_small
,
556 tvb
, offset
+tmpObj3
.size
, 1, 0x00);
558 default: // Note: CBOR will only let these sizes be 1, 2, 4, or 8 bytes.
559 proto_tree_add_item(amp_report_TNVC_tree
, hf_amp_report_integer
,
560 tvb
, offset
+tmpObj3
.size
+1, tmpObj4
.size
-1, 0x00);
569 proto_tree_add_item(amp_report_TNVC_tree
, hf_amp_report_data
, tvb
, offset
+tmpObj3
.size
, (int) tmpObj3
.uint
, 0x00);
572 if ( tmpObj3
.totalSize
> 0 ) {
573 DISSECTOR_ASSERT(tmpObj3
.totalSize
<= INT32_MAX
);
574 offset
+= (int)tmpObj3
.totalSize
;
583 case 0x02: // Perform Control
585 //amp_control_sub_tree = proto_item_add_subtree(amp_message_tree, ett_amp);
586 amp_control_tree
= proto_tree_add_subtree(amp_message_tree
, tvb
, offset
-1, -1,
587 ett_amp_message
, &_message
, "Perform-Control");
588 proto_tree_add_item(amp_control_tree
, hf_amp_cbor_header
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
591 case 0x03: // Table Set
593 //amp_table_sub_tree = proto_item_add_subtree(amp_items_tree, ett_amp);
594 amp_table_tree
= proto_tree_add_subtree(amp_items_tree
, tvb
, offset
, -1,
595 ett_amp_message
, &_message
, "AMP Message: Table-Set");
596 proto_tree_add_item(amp_table_tree
, hf_amp_cbor_header
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
606 /* Code to actually dissect the packets */
608 dissect_amp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
611 proto_item
*amp_packet
;
612 proto_item
*amp_tree
;
613 int amp_packet_reported_length
;
615 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "AMP");
616 col_clear(pinfo
->cinfo
, COL_INFO
);
618 amp_packet_reported_length
= tvb_reported_length_remaining(tvb
, 0);
620 amp_packet
= proto_tree_add_item(tree
, proto_amp
, tvb
, 0, amp_packet_reported_length
, ENC_NA
);
621 amp_tree
= proto_item_add_subtree(amp_packet
, ett_amp
);
623 dissect_amp_as_subtree (tvb
, pinfo
, amp_tree
, offset
);
625 return tvb_captured_length(tvb
);
629 proto_register_amp(void)
631 static hf_register_info hf
[] = {
633 { &hf_amp_message_header
,
634 { "AMP Message Header", "amp.message.header",
635 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
638 { &hf_amp_report_data
,
639 { "Report-Data", "amp.report.data",
640 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
643 { &hf_amp_report_bytestring
,
644 { "Report-Bytestring", "amp.report.bytestring",
645 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
648 { &hf_amp_report_integer8_small
,
649 { "Report-Integer8_small", "amp.report.integer8_small",
650 FT_UINT8
, BASE_DEC
, NULL
, AMP_CBOR_UINT_SMALL
,
653 { &hf_amp_report_integer
,
654 { "Report-Integer", "amp.report.integer",
655 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
658 { &hf_amp_cbor_header
,
659 { "CBOR-Header", "amp.cbor_header",
660 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
663 { &hf_amp_primary_timestamp
,
664 { "Timestamp", "amp.primary_timestamp",
665 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}
667 { &hf_amp_tnvc_flags
,
668 { "TNVC Flags", "amp.tnvc.flags",
669 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
672 { &hf_amp_tnvc_reserved
,
673 { "Reserved", "amp.tnvc.reserved",
674 FT_UINT8
, BASE_DEC
, NULL
, AMP_TNVC_RESERVED
,
677 { &hf_amp_tnvc_mixed
,
678 { "Mixed", "amp.tnvc.mixed",
679 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), AMP_TNVC_MIXED
,
682 { &hf_amp_tnvc_typed
,
683 { "TNVC Values are Typed", "amp.tnvc.typed",
684 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), AMP_TNVC_TYPE
,
688 { "Name", "amp.tnvc.name",
689 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), AMP_TNVC_NAME
,
692 { &hf_amp_tnvc_values
,
693 { "Values", "amp.tnvc.value",
694 FT_BOOLEAN
, 8, TFS(&tfs_yes_no
), AMP_TNVC_VALUE
,
698 { "Nickname", "amp.nickname",
699 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_ARI_NICKNAME
,
703 { "ARI Flags", "amp.ari.flags",
704 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
707 { &hf_ari_parameters
,
708 { "Parameters", "amp.parameters",
709 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_ARI_PARAMETERS
,
713 { "Issuer", "amp.issuer",
714 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_ARI_ISSUER
,
719 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_ARI_TAG
,
723 { "Value", "amp.value",
724 FT_UINT8
, BASE_DEC
, NULL
, AMP_ARI_VALUE
,
728 { "Struct Type", "amp.struct",
729 FT_UINT8
, BASE_DEC
, VALS(amp_ari_struct_type
), AMP_ARI_STRUCT
,
733 { "Reserved", "amp.reserved",
734 FT_UINT8
, BASE_DEC
, NULL
, AMP_HDR_RESERVED
,
739 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_HDR_ACL
,
743 { "NACK", "amp.nack",
744 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_HDR_NACK
,
749 FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), AMP_HDR_ACK
,
753 { "Opcode", "amp.opcode",
754 FT_UINT8
, BASE_DEC
, VALS(opcode
), AMP_HDR_OPCODE
,
758 {"Agent-Name", "amp.agent_name",
759 FT_STRINGZPAD
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
761 {&hf_amp_text_string
,
762 {"String", "amp.string",
763 FT_STRINGZPAD
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
766 {"Rx-Name", "amp.rx_name",
767 FT_STRINGZPAD
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
772 /* Setup protocol subtree array */
773 static int *ett
[] = {
775 &ett_amp_message_header
,
776 &ett_amp_cbor_header
,
786 static ei_register_info ei
[] = {
787 { &ei_amp_cbor_malformed
, { "amp.cbor.malformed", PI_MALFORMED
, PI_ERROR
, "Malformed CBOR object", EXPFILL
}},
790 /* Register the protocol name and description */
791 proto_amp
= proto_register_protocol("AMP", "AMP", "amp");
793 /* Required function calls to register the header fields and subtrees used */
794 proto_register_field_array(proto_amp
, hf
, array_length(hf
));
795 proto_register_subtree_array(ett
, array_length(ett
));
796 expert_module_t
* expert_amp
= expert_register_protocol(proto_amp
);
797 expert_register_field_array(expert_amp
, ei
, array_length(ei
));
799 amp_handle
= register_dissector("amp", dissect_amp
, proto_amp
);
803 proto_reg_handoff_amp(void)
805 dissector_add_uint("ccsds.apid", AMP_APID
, amp_handle
);
806 dissector_add_for_decode_as_with_preference("udp.port", amp_handle
);
810 * Editor modelines - http://www.wireshark.org/tools/modelines.html
815 * indent-tabs-mode: nil
818 * vi: set shiftwidth=4 tabstop=8 expandtab:
819 * :indentSize=4:tabSize=8:noTabs=true: