2 * Routines for Distributed Object Framework (DOF) Wireshark Support
3 * Copyright 2015 Bryant Eastham <bryant.eastham[AT]us.panasonic.com>
4 * See https://opendof.org for more information.
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 * This very large dissector implements packet decoding for the entire
15 * protocol suite of the OpenDOF Project. The OpenDOF Project
16 * (https://opendof.org) is an open-source IoT platform with
17 * implementations in Java, C#, and C. The protocols are documented
18 * on the web site, and the IP ports referenced are registered with IANA.
20 * "DOF" stands for Distributed Object Framework. The protocols define
21 * a complete protocol stack that can sit on top of a variety of transports.
22 * The stack itself is called the DPS, or "DOF Protocol Stack". It
23 * is a layered stack including a Network, Presentation, and Application
24 * layer. The underlying transport can be anything, these dissectors
25 * hook in to UDP and TCP. To the Wireshark user, however, this is
26 * referred to as "dof" and not "dps".
28 * The following protocols are defined in the stack and implemented
30 * DNP - DOF Network Protocol (versions: 0, 1)
31 * DPP - DOF Presentation Protocol (version: 0, 2) [1 is reserved and not supported]
32 * DAP - DOF Application Protocols:
33 * DSP - DOF Session Protocol (versions: 0)
34 * OAP - Object Access Protocol (versions: 1)
35 * TEP - Ticket Exchange Protocol (versions: 128)
36 * TRP - Ticket Request Protocol (versions: 129)
37 * SGMP - Secure Group Management Protocol (versions: 130)
38 * DOFSEC - DOF Security Protocols:
40 * TUN - A tunneling protocol for embedding DOF in other protocols.
43 /* VERSIONS AND NAMING
44 * There are several different ways in which "versions" are used
45 * throughout the dissector. First, each of the DNP and DPP layers
46 * has a defined 'version'. The DOF Application Protocols are also
47 * distinguished by versioning, but it is actually the registered
48 * application ID that is the version. This is complicated by
49 * the fact that many of the application IDs represent the same
50 * version of a protocol from a capability perspective (and
51 * a user perspective) with the difference being some attribute
52 * of the protocol - for example the security primitives used.
54 * Another means of versioning is by specification document.
55 * In this case the document is identified by a year and sequence,
56 * with specifications and PDUs using a name and sequence.
57 * Naming of fields and variables will use these identifiers
58 * as they are the easiest way to tie the code to the specifications.
60 * The specification documents are also the easiest way (although
61 * maybe not the clearest) to expose fields to the Wireshar user.
62 * A consistent naming is used, which is:
64 * (spec)-pdu-(seq)-(field)
65 * For example: dof-2009-1-pdu-1-value
67 * Variable naming includes a protocol name to provide clarity.
69 * This is not the clearest from a user perspective, but it
70 * has the benefit of tying directly to the specifications
71 * themselves and uniquely identifies each field.
73 * Routines that dissect are uniformly named by the PDU
74 * that they dissect using the PDU specification document
75 * and PDU name from that document as follows:
77 * dissect_(spec)_(name)
81 * The original work on these dissectors began over ten years ago, but
82 * shared only within Panasonic. During the opening of the protocols in
83 * March of 2015 the decision was made to contribute the code to the Wireshark
84 * community. During this process the plugin approach was rejected and the
85 * entire set made into standard dissectors, and further to that all of the
86 * dissectors were merged into a single file.
88 * There are several types of supported dissectors that are part of the DPS family.
89 * At the lowest level are the transport dissectors. The responsibility
90 * of these dissectors is to determine the transport session information, pass
91 * DPS packets to the DPS dissector, and properly maintain the dof_api_data
94 * The DPS dissector API comprises:
95 * 1. The structure (dof_api_data) that is passed in the data field to the DPS
96 * dissector. Transport plugins must understand this.
97 * 2. The dof_transport_session structure, which contains all transport
98 * information that is passed to the DPS dissector.
99 * 3. The name of the DPS dissector.
101 * The DPS dissector API extends to dissectors that are called by the DPS dissectors.
103 * Finally, there is the DPS Security Mode dissectors. These dissectors are passed
104 * additional security context information and it is their job to decrypt packets
105 * and pass them to higher-level dissectors.
107 * The DOF Protocol Stack is strictly layered with minimal (and defined) state
108 * exchanged between layers. This allows a fairly structured design, using
109 * dissector tables at each layer. The main DPS dissector receives packets
110 * from the transport hooks, and then dissects the packet layer by layer using
111 * the different dissector tables. Dissectors and the DNP, DPP, and DAP layers.
113 * In addition to the main protocol stack with its associated protocols there are
114 * additional common data elements that include extensibility. If an extension
115 * is found then it will be used to dissect, otherwise the base dissector will be
120 * DOF defines sessions at many different levels, and state is always associated
121 * with a session. Much of the power (and complexity) of these dissectors relates
122 * to accurately tracking and maintaining context for each session, and displaying
123 * context-related decode information based on the session. This includes, for
124 * example, decoding encrypted data (including multicast group traffic) and
125 * showing full packet information even when the packet data uses aliases or
126 * other context specific data.
128 * Sessions are an extremely complex part of the dissectors because they occur at
129 * so many different levels, and that they are temporal in nature while wireshark
130 * is not. This means that all data structures that deal with sessions must deal
131 * with both the level and the time of the packet.
134 * 1. Transport. These sessions are defined by the transport, and transport
135 * addresses. As in the transports, there is no transport information allowed
136 * at the dps level, but transport information is allowed to influence other
137 * decisions. Every dps packet must be part of a transport session. Transport
138 * sessions are usually managed as conversations in Wireshark. Each transport
139 * session is has an identifier that is defined by the DPS plugin the first
140 * time a packet in the transport session is passed to the plugin.
141 * 2. DPS. These sessions are defined by DPS, and are part of the DNP definition.
142 * These sessions are also assigned a unique DPS session identifier.
144 * 3. Security (Optional). Security sessions always exist inside of
145 * an DPS session. Security sessions are further divided into epochs, keys, etc.
147 * Temporal information is always associated with packet numbers, which always increase.
148 * This temporal information is used during the first pass to create sessions by
149 * determining that a new packet doesn't belong to a previous session.
151 * During the first pass the data structures are referenced from the transport
152 * session information up. The goal of the first pass is to create the most specific
153 * session information and associate each packet with the appropriate session. These
154 * sessions refer to more general session information.
156 * In order to make lookups easier, the most fine-grainded sessions are assigned
157 * unique identifiers. Secure sessions are always born unsecure (during security
158 * negotiation). These use the same session identifiers, but the state for the
159 * secure and unsecured times are separated. Once a session is secured it never
160 * transitions back to unsecured.
163 * Each packet is sent by a member of the session. Session members have state related
164 * to the session. Packets are received by either a member of the session or the
165 * session itself (implying all members). This means that packet state can come
168 * 2. The receiver (if directed to a receiver).
170 * The identity of a member is always a combination of transport and dps information.
171 * However, the state of the membership is in the context of the session, keyed by
174 * In order to make lookups easier, each unique sender in the system is
175 * assigned a unique identifier.
182 #include <wsutil/wsgcrypt.h>
184 #include <epan/packet.h>
185 #include <epan/proto.h>
186 #include <epan/proto_data.h>
187 #include <epan/prefs.h>
188 #include <epan/conversation.h>
189 #include <epan/expert.h>
190 #include <epan/uat.h>
191 #include <wsutil/str_util.h>
192 #include <epan/tfs.h>
193 #include "packet-tcp.h"
195 /* DEFINES, STRUCTURES, AND SUPPORT METHOD DECLARATIONS
196 * The following sections includes preprocessor definitions, structure definitions,
197 * and method declarations for all dissectors.
198 * The ordering is by DPS stack order, general first and then by protocols.
202 * GENERAL SUPPORT STRUCTURES
203 * The following structures represent state that must be maintained for
204 * the dissectors to operate. They are not directly related to protocol
209 * This structure represents a SID, or Sender ID, in the system.
210 * This is allocated as global memory, and must be freed. SIDs
211 * are Object IDs, and can be displayed in hex but preferably
212 * using the OID output format. Even though the OID contains
213 * a length, we prefix this buffer with a length (which must
214 * be less than 255 by the definition of a SID.
215 * SIDs are not versioned, so they can be used universally in
216 * any protocol version.
218 typedef uint8_t *dof_2009_1_pdu_19_sid
;
221 * This structure encapsulates an OPID, which is the combination of
222 * a source identifier (SID, and OID) and a packet number. This is a separate
223 * structure because some operations actually contain multiple opids, but need
224 * to be placed in the appropriate data structures based on SID lookup. This
225 * structure can be used as a key in different hash tables.
227 typedef struct _dpp_opid
230 dof_2009_1_pdu_19_sid op_sid
;
232 } dof_2009_1_pdu_20_opid
;
235 * This structure contains all of the transport session information
236 * related to a particular session, but not related to the packet
237 * within that session. That information is separated to allow
238 * reuse of the structure.
240 typedef struct _dof_transport_session
243 * TRANSPORT ID: This is a unique identifier for each transport,
244 * used to prevent aliasing of the SENDER ID value in the
245 * transport packet structure. It contains the protocol id
246 * assigned by Wireshark (unique per protocol).
251 * For new sessions, this is left zero. The DPS dissector will
254 uint32_t transport_session_id
;
257 * Timestamp of start of session.
259 nstime_t session_start_ts
;
262 * Whether negotiation is required on this session.
264 bool negotiation_required
;
267 * The frame number where negotiation was complete, or zero if not complete.
269 uint32_t negotiation_complete_at
;
272 * The time when negotiation was complete, or zero if not complete.
274 nstime_t negotiation_complete_at_ts
;
277 * Type of transport session.
279 bool is_streaming
; /* Inverse is 'is_datagram'. */
282 * Cardinality of transport session.
284 bool is_2_node
; /* Inverse is 'is_n_node'. */
285 } dof_transport_session
;
287 typedef struct _dof_transport_packet
290 * Source of packet (if known, default is server).
292 bool is_sent_by_client
; /* Inverse is 'is_sent_by_server'. */
295 * SENDER ID/RECEIVER ID: A unique value that identifies the unique
296 * transport sender/receiver address. This number is based on only
297 * the transport, and not session, information.
300 unsigned receiver_id
;
301 } dof_transport_packet
;
304 * This structure maintains security state throughout an DPS session.
305 * It is managed by the key exchange protocol, and becomes effective
306 * at different dps packets in each communication direction. Decrypting
307 * a packet requires that this structure exists.
309 typedef struct _dof_session_key_exchange_data
312 * The frame at which this becomes valid for initiator packets.
317 * The frame at which this becomes valid for responder packets.
322 * SECURITY MODE: The security mode for a secure session. Set
323 * by the key exchange dissector.
325 uint32_t security_mode
;
328 * SECURITY MODE INITIALIZATION DATA: Determined by the key exchange
329 * protocol and passed here for the reference of the security mode.
331 uint32_t security_mode_data_length
;
332 uint8_t *security_mode_data
;
335 * SECURITY MODE DATA: Created and managed by the security mode
338 void *security_mode_key_data
;
341 * SESSION KEY: Pointer to seasonal data that holds the encryption key.
343 uint8_t *session_key
;
346 * The next security data in this session.
348 struct _dof_session_key_exchange_data
*next
;
349 } dof_session_key_exchange_data
;
352 * This structure contains security keys that should be tried with
353 * sessions that otherwise are not known.
355 typedef struct _dof_session_key_data
357 uint8_t *session_key
;
358 } dof_session_key_data
;
361 * This structure contains security keys for groups.
363 typedef struct _dof_group_data
366 uint8_t domain_length
;
368 uint8_t identity_length
;
373 * This structure contains security keys for non-group identities.
375 typedef struct _dof_identity_data
378 uint8_t domain_length
;
380 uint8_t identity_length
;
385 * This structure exists for global security state. It exposes the
386 * configuration data associated with DPS, and also is a common location
387 * that learned security information is stored. Each dof_packet_data will
388 * contain a pointer to this structure - there is only one for the entire
391 typedef struct _dof_security_data
393 /* Array of session_keys. */
394 dof_session_key_data
*session_key
;
395 uint16_t session_key_count
;
397 /* Array of group data. */
398 dof_group_data
*group_data
;
399 uint16_t group_data_count
;
401 /* Array of identity data. */
402 dof_identity_data
*identity_data
;
403 uint16_t identity_data_count
;
405 /* Global sessions. */
406 /*TODO: Figure this out */
407 /* dof_session_list* sessions; */
411 * This structure represents a key that is learned for a group and epoch.
413 struct _dof_learned_group_data
;
414 typedef struct _dof_learned_group_auth_data
418 unsigned mode_length
;
420 uint16_t security_mode
;
421 struct _dof_learned_group_data
*parent
;
422 struct _dof_learned_group_auth_data
*next
;
423 } dof_learned_group_auth_data
;
426 * This structure represents a group that is learned about.
428 typedef struct _dof_learned_group_data
430 uint8_t domain_length
;
432 uint8_t group_length
;
436 dof_learned_group_auth_data
*keys
;
437 struct _dof_learned_group_data
*next
;
438 } dof_learned_group_data
;
441 * This structure exists for each secure DPS session. This is kept in
442 * addition to the normal session
443 * Each packet that has state will contain a reference to one of these.
445 * Information in this structure is invariant for the duration of the
446 * session *or* is only used during the initial pass through the packets.
447 * Information that changes (for example, security parameters, keys, etc.)
448 * needs to be maintained separately, although this structure is the
449 * starting place for this information.
451 * This structure is initialized to zero.
453 struct _dof_session_data
;
454 typedef struct _dof_secure_session_data
457 * SSID: Zero is typically used for streaming sessions.
462 * DOMAIN LENGTH: The length of the security domain, greater than
463 * zero for secure sessions. Set by the key exchange dissector.
465 uint8_t domain_length
;
468 * DOMAIN: The security domain itself, seasonal storage, non-null
469 * for secure sessions. Set by the key exchange dissector.
474 * SESSION SECURITY: This is a list of security data for this
475 * session, created by the key exchange protocol.
477 dof_session_key_exchange_data
*session_security_data
;
478 dof_session_key_exchange_data
*session_security_data_last
;
481 * NEXT: This is the next secure session related to the parent
482 * unsecure session. Protocols can define new secure sessions and
483 * add them to this list. DPP then finds the correct secure session
484 * for a secure packet and caches it.
486 struct _dof_secure_session_data
*next
;
487 struct _dof_session_data
*parent
;
488 uint32_t original_session_id
;
490 } dof_secure_session_data
;
493 * This structure exists for each DPS session. Secure sessions have an
494 * additional data structure that includes the secure session information.
495 * Each packet that has state will contain a reference to one of these.
497 * Information in this structure is invariant for the duration of the
498 * session *or* is only used during the initial pass through the packets.
499 * Information that changes (for example, security parameters, keys, etc.)
500 * needs to be maintained separately, although this structure is the
501 * starting place for this information.
503 * This structure is initialized to zero.
505 typedef struct _dof_session_data
508 * SESSION ID: Set when the session is created, required.
513 * DPS ID: The type of DPS SENDER ID (in the packet data) to prevent
514 * aliasing. Since DPS senders identifiers relate to DNP, this is the
515 * DNP version number.
520 * SECURE SESSIONS: When secure sessions are created from this
521 * unsecure session then they are added to this list. Each member
522 * of the list must be distinguished.
524 dof_secure_session_data
*secure_sessions
;
527 * Protocol-specific data.
532 /* DOF Security Structures. */
533 /* Return structures for different packets. */
535 typedef struct _dof_2008_16_security_3_1
538 } dof_2008_16_security_3_1
;
540 typedef struct _dof_2008_16_security_4
544 } dof_2008_16_security_4
;
546 typedef struct _dof_2008_16_security_6_1
548 tvbuff_t
*i_identity
;
550 uint16_t security_mode
;
551 uint32_t security_mode_data_length
;
552 uint8_t *security_mode_data
;
553 } dof_2008_16_security_6_1
;
555 typedef struct _dof_2008_16_security_6_2
557 tvbuff_t
*r_identity
;
559 } dof_2008_16_security_6_2
;
563 * This structure defines the address for Wireshark transports. There is no
564 * DPS information associated here.
566 typedef struct _ws_node
572 typedef struct _dof_session_list
574 dof_session_data
*session
;
575 struct _dof_session_list
*next
;
580 * This structure exists for each DOF packet. There is ABSOLUTELY NO
581 * transport-specific information here, although there is a session
582 * number which may relate to transport information indirectly through
583 * a transport session.
584 * There will be one of these for each DOF packet, even if the corresponding
585 * Wireshark frame has multiple DOF packets encapsulated in it. The key
586 * to this structure is the operation identifier, and there is a hash
587 * lookup to go from an operation identifier to this structure.
589 typedef struct _dof_packet_data
592 * NON-DPS FIELDS, USED FOR WIRESHARK COMMUNICATION/PROCESSING
593 * Protocol-specific data.
595 wmem_list_t
*data_list
;
598 * The Wireshark frame. Note that a single frame can have multiple DPS packets.
603 * The DPS frame/packet. This number is unique in the entire trace.
608 * Packet linked list for all dps packets.
610 struct _dof_packet_data
*next
;
614 * Indicator that the packet has already been processed. Processed packets
615 * have all their fields set that can be determined. Further attempts to
616 * determine NULL fields are worthless.
621 * SUMMARY: An operation summary, displayed in the Operation History. This is seasonal
622 * data, managed by the DPP dissector.
627 * SENDER ID/RECEIVER ID: An identifier for each unique sender/receiver according to DPS.
628 * This augments the transport SENDER ID/RECEIVER ID in determining each
635 * DPP INFORMATION - CACHED INFORMATION
637 bool is_command
; /* Inverse is 'is_response'. */
638 bool is_sent_by_initiator
;
641 * SENDER SID ID/RECEIVER SID ID: An identifier for the sid associated with this packet's sender.
642 * Zero indicates that it has not been assigned. Assigned by the DPP
645 unsigned sender_sid_id
;
646 unsigned receiver_sid_id
;
649 * SENDER SID/RECEIVER SID: The SID of the sender/receiver, or NULL if not known.
651 dof_2009_1_pdu_19_sid sender_sid
;
652 dof_2009_1_pdu_19_sid receiver_sid
;
655 * Operation references.
658 dof_2009_1_pdu_20_opid op
;
659 bool has_referenced_opid
;
660 dof_2009_1_pdu_20_opid ref_op
;
662 struct _dof_packet_data
*opid_first
;
663 struct _dof_packet_data
*opid_next
;
664 struct _dof_packet_data
*opid_last
;
665 struct _dof_packet_data
*opid_first_response
;
666 struct _dof_packet_data
*opid_next_response
;
667 struct _dof_packet_data
*opid_last_response
;
670 * SECURITY INFORMATION - CACHED
672 const char *security_session_error
;
673 dof_session_key_exchange_data
*security_session
;
674 void *security_packet
;
675 uint8_t *decrypted_buffer
;
676 tvbuff_t
*decrypted_tvb
;
677 uint16_t decrypted_offset
;
678 char *decrypted_buffer_error
;
682 * OPERATION DATA: Generic data, seasonal, owned by the application protocol dissector
690 * This structure represents globals that are passed to all dissectors.
692 typedef struct _dof_globals
694 uint32_t next_transport_session
;
695 uint32_t next_session
;
696 dof_packet_data
*dof_packet_head
;
697 dof_packet_data
*dof_packet_tail
;
698 dof_security_data
*global_security
;
699 dof_learned_group_data
*learned_group_data
;
700 bool decrypt_all_packets
;
701 bool track_operations
;
702 unsigned track_operations_window
;
706 * This structure contains all information that is passed between
707 * transport dissectors/plugins and the DPS dissector. It is allocated
708 * by the transport plugin, and its fields are set as described here.
710 typedef struct _dof_api_data
713 * TRANSPORT SESSION: Set by the transport dissector, required.
715 dof_transport_session
*transport_session
;
718 * TRANSPORT PACKET: Set by the transport dissector, required.
720 dof_transport_packet
*transport_packet
;
723 * DPS SESSION: Set by the DPS dissector.
725 dof_session_data
*session
;
728 * DPS DATA: Set by the DPS dissector.
730 dof_packet_data
*packet
;
733 * DPS SECURE SESSION: Set by the DPP dissector.
735 dof_secure_session_data
*secure_session
;
739 * This set of types defines the Security Mode dissector API.
740 * This structure identifies the context of the dissection,
741 * allowing a single structure to know what part of the packet
742 * of sequence of packets it is working with.
744 * Structure for Security Mode of Operation dissectors.
746 typedef enum _dof_secmode_context
751 } dof_secmode_context
;
753 /* Seasonal, initialized to zero. */
754 typedef struct _dof_secmode_api_data
757 * API VERSION: Set by the DPS dissector, required.
758 * MUST BE THE FIRST FIELD.
763 * CONTEXT: Set the DPS dissector, required.
765 dof_secmode_context context
;
768 * SECURITY MODE OFFSET: The packet offset from the DPP header of the security mode.
770 unsigned security_mode_offset
;
773 * API DATA: Set by the DPS dissector, required.
775 dof_api_data
*dof_api
;
778 * SECURE SESSION DATA: Controlled by the caller, either associated
779 * with the current packet (HEADER mode) or not (other modes).
780 * Used to access session information.
782 dof_secure_session_data
*secure_session
;
785 * KEY EXCHANGE: Controlled by the caller, represents the key exchange
786 * for INITIALIZE mode.
788 dof_session_key_exchange_data
*session_key_data
;
789 } dof_secmode_api_data
;
791 /* These should be the only non-static declarations in the file. */
792 void proto_register_dof(void);
793 void proto_reg_handoff_dof(void);
795 /* Dissector routines. */
796 static int dissect_2008_1_dsp_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
);
797 static int dissect_2008_16_security_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
798 static int dissect_2008_16_security_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
799 static int dissect_2008_16_security_3_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
800 static int dissect_2008_16_security_3_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
801 static int dissect_2008_16_security_4(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
802 static int dissect_2008_16_security_5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
803 static int dissect_2008_16_security_6_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
804 static int dissect_2008_16_security_6_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
805 static int dissect_2008_16_security_6_3(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
806 static int dissect_2008_16_security_7(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
807 static int dissect_2008_16_security_8(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
808 static int dissect_2008_16_security_9(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
809 static int dissect_2008_16_security_10(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
810 static int dissect_2008_16_security_11(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
811 static int dissect_2008_16_security_12(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
812 static int dissect_2008_16_security_13(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
813 static int dissect_2009_11_type_4(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
);
814 static int dissect_2009_11_type_5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
);
816 static const char* dof_oid_create_standard_string(uint32_t bufferSize
, const uint8_t *pOIDBuffer
, packet_info
*pinfo
);
817 static const char* dof_iid_create_standard_string(uint32_t bufferSize
, const uint8_t *pIIDBuffer
);
818 static uint8_t dof_oid_create_internal(const char *oid
, uint32_t *size
, uint8_t *buffer
);
819 static void dof_oid_new_standard_string(const char *data
, uint32_t *rsize
, uint8_t **oid
);
820 static int read_c4(tvbuff_t
*tvb
, int offset
, uint32_t *v
, int *len
);
821 static void validate_c4(packet_info
*pinfo
, proto_item
*pi
, uint32_t, int len
);
822 static int read_c3(tvbuff_t
*tvb
, int offset
, uint32_t *v
, int *len
);
823 static void validate_c3(packet_info
*pinfo
, proto_item
*pi
, uint32_t, int len
);
824 static int read_c2(tvbuff_t
*tvb
, int offset
, uint16_t *v
, int *len
);
825 static void validate_c2(packet_info
*pinfo
, proto_item
*pi
, uint16_t, int len
);
827 static int dof_dissect_pdu(dissector_t dissector
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *result
);
828 static int dof_dissect_pdu_as_field(dissector_t dissector
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int item
, int ett
, void *result
);
830 #if 0 /* TODO not used yet */
831 static void dof_session_add_proto_data(dof_session_data
*session
, int proto
, void *proto_data
);
832 static void* dof_session_get_proto_data(dof_session_data
*session
, int proto
);
833 static void dof_session_delete_proto_data(dof_session_data
*session
, int proto
);
836 static void dof_packet_add_proto_data(dof_packet_data
*packet
, int proto
, void *proto_data
);
837 static void* dof_packet_get_proto_data(dof_packet_data
*packet
, int proto
);
839 /* DOF PROTOCOL STACK */
840 #define DOF_PROTOCOL_STACK "DOF Protocol Stack"
844 * The following ports are registered with IANA and used to hook transport
845 * dissectors into the lower-level Wireshark transport dissectors.
847 * Related to these ports is the usage of conversations for DOF. The goal of
848 * using Wireshark conversations is to guarantee that DPS data is available for
849 * any DPS packet. However, there is no assumption that Wireshark conversations
850 * map in any way to DOF sessions.
852 * One exception to this use is in discovery of DOF servers. The DOF_MCAST_NEG_SEC_UDP_PORT
853 * is watched for all traffic. A "wildcard" conversation is then created for the
854 * source address, and the DPS dissector is associated with that port. In this
855 * way, servers on non-standard ports will automatically be decoded using DPS.
857 #define DOF_NEG_SEC_UDP_PORT_RANGE "3567,5567" /* P2P + Multicast */
858 #define DOF_P2P_NEG_SEC_TCP_PORT 3567
859 /* Reserved UDP port 3568*/
860 #define DOF_TUN_SEC_TCP_PORT 3568
861 #define DOF_P2P_SEC_TCP_PORT 5567
862 /* Reserved UDP port 8567*/
863 #define DOF_TUN_NON_SEC_TCP_PORT 8567
865 /* This is needed to register multicast sessions with the UDP handler. */
866 static dissector_handle_t dof_udp_handle
;
868 static int proto_2008_1_dof
;
869 static int proto_2008_1_dof_tcp
;
870 static int proto_2008_1_dof_udp
;
872 static int hf_2008_1_dof_session
;
873 static int hf_2008_1_dof_is_2_node
;
874 static int hf_2008_1_dof_is_streaming
;
875 static int hf_2008_1_dof_is_from_client
;
876 static int hf_2008_1_dof_frame
;
877 static int hf_2008_1_dof_session_transport
;
879 static int ett_2008_1_dof
;
881 /* DOF Tunnel Protocol */
883 /* UDP Registrations */
884 #define TUNNEL_PROTOCOL_STACK "DOF Tunnel Protocol Stack"
885 #define TUNNEL_APPLICATION_PROTOCOL "DOF Tunnel Protocol"
887 static dissector_table_t dof_tun_app_dissectors
;
890 static int proto_2012_1_tunnel
;
892 static int ett_2012_1_tunnel
;
894 static int hf_2012_1_tunnel_1_version
;
895 static int hf_2012_1_tunnel_1_length
;
897 /* DOF NETWORK PROTOCOL */
898 #define DNP_MAX_VERSION 1
899 #define DOF_NETWORK_PROTOCOL "DOF Network Protocol"
901 static dissector_table_t dnp_dissectors
;
902 static dissector_table_t dnp_framing_dissectors
;
904 static int proto_2008_1_dnp
;
906 static int hf_2008_1_dnp_1_version
;
907 static int hf_2008_1_dnp_1_flag
;
909 static int ett_2008_1_dnp
;
910 static int ett_2008_1_dnp_header
;
913 static int proto_2008_1_dnp_0
;
915 static int hf_2008_1_dnp_0_1_1_padding
;
916 static int hf_2008_1_dnp_0_1_1_version
;
919 #define DNP_V1_DEFAULT_FLAGS (0)
920 static int proto_2009_9_dnp_1
;
922 static int hf_2009_9_dnp_1_flags
;
923 static int hf_2009_9_dnp_1_flag_length
;
924 static int hf_2009_9_dnp_1_length
;
925 static int hf_2009_9_dnp_1_flag_srcport
;
926 static int hf_2009_9_dnp_1_srcport
;
927 static int hf_2009_9_dnp_1_flag_dstport
;
928 static int hf_2009_9_dnp_1_dstport
;
930 static int ett_2009_9_dnp_1_flags
;
932 static int * const bitmask_2009_9_dnp_1_flags
[] = {
933 &hf_2009_9_dnp_1_flag_length
,
934 &hf_2009_9_dnp_1_flag_srcport
,
935 &hf_2009_9_dnp_1_flag_dstport
,
939 /* DOF PRESENTATION PROTOCOL */
940 #define DOF_PRESENTATION_PROTOCOL "DOF Presentation Protocol"
942 static dissector_table_t dof_dpp_dissectors
;
944 static int proto_2008_1_dpp
;
946 static int hf_2008_1_dpp_sid_num
;
947 static int hf_2008_1_dpp_rid_num
;
948 static int hf_2008_1_dpp_sid_str
;
949 static int hf_2008_1_dpp_rid_str
;
950 static int hf_2008_1_dpp_first_command
;
951 static int hf_2008_1_dpp_last_command
;
952 static int hf_2008_1_dpp_first_response
;
953 static int hf_2008_1_dpp_last_response
;
954 static int hf_2008_1_dpp_related_frame
;
955 static int hf_2008_1_dpp_1_version
;
956 static int hf_2008_1_dpp_1_flag
;
958 static int ett_2008_1_dpp
;
959 static int ett_2008_1_dpp_1_header
;
962 static int proto_2008_1_dpp_0
;
964 static int hf_2008_1_dpp_0_1_1_version
;
966 /* DPP V1 - RESERVED, NOT SUPPORTED */
969 #define DPP_V2_DEFAULT_FLAGS (0)
970 #define DPP_V2_SEC_FLAG_E (0x80)
971 #define DPP_V2_SEC_FLAG_D (0x08)
972 #define DPP_V2_SEC_FLAG_P (0x04)
973 #define DPP_V2_SEC_FLAG_A (0x02)
974 #define DPP_V2_SEC_FLAG_S (0x01)
976 static int proto_2009_12_dpp
;
977 static int proto_2009_12_dpp_common
;
979 /* TODO: The complete on final and final flags are not covered. */
980 static int hf_2009_12_dpp_2_1_flags
;
981 static int hf_2009_12_dpp_2_1_flag_security
;
982 static int hf_2009_12_dpp_2_1_flag_opid
;
983 static int hf_2009_12_dpp_2_1_flag_seq
;
984 static int hf_2009_12_dpp_2_1_flag_retry
;
985 static int hf_2009_12_dpp_2_1_flag_cmdrsp
;
986 static int hf_2009_12_dpp_2_3_sec_flags
;
987 static int hf_2009_12_dpp_2_3_sec_flag_secure
;
988 static int hf_2009_12_dpp_2_3_sec_flag_rdid
;
989 static int hf_2009_12_dpp_2_3_sec_flag_partition
;
990 static int hf_2009_12_dpp_2_3_sec_flag_ssid
;
991 static int hf_2009_12_dpp_2_3_sec_flag_as
;
992 static int hf_2009_12_dpp_2_3_sec_ssid
;
993 static int hf_2009_12_dpp_2_3_sec_rdid
;
994 static int hf_2009_12_dpp_2_3_sec_remote_partition
;
995 static int hf_2009_12_dpp_2_3_sec_partition
;
996 static int hf_2009_12_dpp_2_1_opcnt
;
997 static int hf_2009_12_dpp_2_1_seq
;
998 static int hf_2009_12_dpp_2_1_retry
;
999 static int hf_2009_12_dpp_2_1_delay
;
1000 static int hf_2009_12_dpp_2_14_opcode
;
1002 static int ett_2009_12_dpp_2_1_flags
;
1003 static int ett_2009_12_dpp_2_3_security
;
1004 static int ett_2009_12_dpp_2_3_sec_flags
;
1005 static int ett_2009_12_dpp_2_3_sec_remote_partition
;
1006 static int ett_2009_12_dpp_2_3_sec_partition
;
1007 static int ett_2009_12_dpp_2_opid
;
1008 static int ett_2009_12_dpp_2_opid_history
;
1010 static int ett_2009_12_dpp_common
;
1012 static const value_string strings_2009_12_dpp_opid_types
[] = {
1013 { 0, "Not Present" },
1014 { 1, "SID [Sender]" },
1015 { 2, "SID [Receiver]" },
1016 { 3, "SID [Explicit]" },
1020 #define OP_2009_12_RESPONSE_FLAG (0x80)
1021 #define OP_2009_12_NODE_DOWN_CMD (0)
1022 #define OP_2009_12_NODE_DOWN_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_NODE_DOWN_CMD)
1023 #define OP_2009_12_SOURCE_LOST_CMD (1)
1024 #define OP_2009_12_SOURCE_LOST_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_SOURCE_LOST_CMD)
1025 #define OP_2009_12_RENAME_CMD (2)
1026 #define OP_2009_12_RENAME_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_RENAME_CMD)
1027 #define OP_2009_12_PING_CMD (3)
1028 #define OP_2009_12_PING_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_PING_CMD)
1029 #define OP_2009_12_CANCEL_ALL_CMD (4)
1030 #define OP_2009_12_CANCEL_ALL_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_CANCEL_ALL_CMD)
1031 #define OP_2009_12_HEARTBEAT_CMD (5)
1032 #define OP_2009_12_HEARTBEAT_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_HEARTBEAT_CMD)
1033 #define OP_2009_12_QUERY_CMD (6)
1034 #define OP_2009_12_QUERY_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_QUERY_CMD)
1035 #define OP_2009_12_SOURCE_FOUND_CMD (8)
1036 #define OP_2009_12_SOURCE_FOUND_RSP (OP_2009_12_RESPONSE_FLAG|OP_2009_12_SOURCE_FOUND_CMD)
1038 static const value_string strings_2009_12_dpp_common_opcodes
[] = {
1039 { OP_2009_12_NODE_DOWN_CMD
, "DPP Node Down" },
1040 { OP_2009_12_NODE_DOWN_RSP
, "DPP Node Down Response (Illegal)" },
1041 { OP_2009_12_SOURCE_LOST_CMD
, "DPP Source Lost" },
1042 { OP_2009_12_SOURCE_LOST_RSP
, "DPP Source Lost Response (Illegal)" },
1043 { OP_2009_12_SOURCE_FOUND_CMD
, "DPP Source Found" },
1044 { OP_2009_12_SOURCE_FOUND_RSP
, "DPP Source Found Response (Illegal)" },
1045 { OP_2009_12_RENAME_CMD
, "DPP Rename" },
1046 { OP_2009_12_RENAME_RSP
, "DPP Rename Response (Illegal)" },
1047 { OP_2009_12_PING_CMD
, "DPP Ping" },
1048 { OP_2009_12_PING_RSP
, "DPP Ping Response" },
1049 { OP_2009_12_HEARTBEAT_CMD
, "DPP Heartbeat" },
1050 { OP_2009_12_HEARTBEAT_RSP
, "DPP Heartbeat Response (Illegal)" },
1051 { OP_2009_12_QUERY_CMD
, "DPP Query" },
1052 { OP_2009_12_QUERY_RSP
, "DPP Query Response" },
1053 { OP_2009_12_CANCEL_ALL_CMD
, "DPP Cancel All" },
1054 { OP_2009_12_CANCEL_ALL_RSP
, "DPP Cancel All Response (Illegal)" },
1058 /* DOF APPLICATION PROTOCOL */
1059 #define DOF_APPLICATION_PROTOCOL "DOF Application Protocol"
1061 static dissector_table_t app_dissectors
;
1063 static int proto_2008_1_app
;
1065 static int hf_2008_1_app_version
;
1067 /* DAP V0 (DSP - DOF SESSION PROTOCOL) */
1068 /* Note that DSP is *always* appid 0 and so it violates the standard naming rule. */
1069 static dissector_table_t dsp_option_dissectors
;
1071 static int hf_2008_1_dsp_12_opcode
;
1072 static int hf_2008_1_dsp_attribute_code
;
1073 static int hf_2008_1_dsp_attribute_data
;
1074 static int hf_2008_1_dsp_value_length
;
1075 static int hf_2008_1_dsp_value_data
;
1077 static const value_string strings_2008_1_dsp_attribute_codes
[] = {
1078 { 0, "TEP Family" },
1079 { 1, "OAP Family" },
1080 { 2, "CCM Family" },
1081 { 3, "TRP Family" },
1086 #define DOF_PROTOCOL_DSP 0
1087 #define DSP_OAP_FAMILY 0x010000
1089 static int proto_2008_1_dsp
;
1091 #define OP_2008_1_RSP (0x80)
1092 #define OP_2008_1_QUERY_CMD 0
1093 #define OP_2008_1_QUERY_RSP (OP_2008_1_RSP|OP_2008_1_QUERY_CMD)
1094 #define OP_2008_1_CONFIG_REQ 1
1095 #define OP_2008_1_CONFIG_ACK (OP_2008_1_RSP|2)
1096 #define OP_2008_1_CONFIG_NAK (OP_2008_1_RSP|3)
1097 #define OP_2008_1_CONFIG_REJ (OP_2008_1_RSP|4)
1098 #define OP_2008_1_TERMINATE_CMD 5
1099 #define OP_2008_1_TERMINATE_RSP (OP_2008_1_RSP|OP_2008_1_TERMINATE_CMD)
1100 #define OP_2008_1_OPEN_CMD 6
1101 #define OP_2008_1_OPEN_RSP (OP_2008_1_RSP|OP_2008_1_OPEN_CMD)
1102 #define OP_2008_1_OPEN_SECURE_RSP (OP_2008_1_RSP|7)
1104 static const value_string strings_2008_1_dsp_opcodes
[] = {
1105 { OP_2008_1_QUERY_CMD
, "DSP Query" },
1106 { OP_2008_1_QUERY_RSP
, "DSP Query Response" },
1107 { OP_2008_1_CONFIG_REQ
, "DSP Request" },
1108 { OP_2008_1_CONFIG_ACK
, "DSP ACK Response" },
1109 { OP_2008_1_CONFIG_NAK
, "DSP NAK Response" },
1110 { OP_2008_1_CONFIG_REJ
, "DSP REJ Response" },
1111 { OP_2008_1_TERMINATE_CMD
, "DSP Terminate/Close Request" },
1112 { OP_2008_1_TERMINATE_RSP
, "DSP Terminate/Close Response" },
1113 { OP_2008_1_OPEN_CMD
, "DSP Open" },
1114 { OP_2008_1_OPEN_RSP
, "DSP Open Response" },
1115 { OP_2008_1_OPEN_SECURE_RSP
, "DSP Open Secure Response" },
1119 #define DSP_AVP_AUTHENTICATION 0
1120 #define DSP_AVP_APPLICATION 1
1122 #if 0 /* not used yet */
1123 static const value_string strings_2008_1_dsp_attributes
[] = {
1124 { DSP_AVP_AUTHENTICATION
, "Authentication Protocol" },
1125 { DSP_AVP_APPLICATION
, "Application Protocol" },
1129 static const value_string strings_2008_1_dsp_values
[] = {
1130 { 1, "DOF Object Access Protocol (version 1)" },
1131 { 3, "DOF Ticket Exchange Protocol (version 1)" },
1136 static int ett_2008_1_dsp_12
;
1137 static int ett_2008_1_dsp_12_options
;
1138 static int ett_2008_1_dsp_12_option
;
1140 /* DAP V1 (OAP - OBJECT ACCESS PROTOCOL V1) */
1141 /* This is the defined protocol id for OAP. */
1142 #define DOF_PROTOCOL_OAP_1 1
1143 /* There are two "protocols", one hooks into DSP and the other to DOF. */
1144 static int proto_oap_1
;
1145 static int proto_oap_1_dsp
;
1147 /* OAP DSP protocol items. */
1148 static int hf_oap_1_dsp_option
;
1150 /* OAP protocol items. */
1151 static int hf_oap_1_opcode
;
1153 static int hf_oap_1_alias_size
;
1154 static int hf_oap_1_flags
;
1155 static int hf_oap_1_exception_internal_flag
;
1156 static int hf_oap_1_exception_final_flag
;
1157 static int hf_oap_1_exception_provider_flag
;
1158 static int hf_oap_1_cmdcontrol
;
1159 static int hf_oap_1_cmdcontrol_cache_flag
;
1160 static int hf_oap_1_cmdcontrol_verbosity_flag
;
1161 static int hf_oap_1_cmdcontrol_noexecute_flag
;
1162 static int hf_oap_1_cmdcontrol_ack_flag
;
1163 static int hf_oap_1_cmdcontrol_delay_flag
;
1164 static int hf_oap_1_cmdcontrol_heuristic_flag
;
1165 static int hf_oap_1_cmdcontrol_heuristic
;
1166 static int hf_oap_1_cmdcontrol_cache
;
1167 static int hf_oap_1_cmdcontrol_ackcnt
;
1168 static int hf_oap_1_cmdcontrol_ack
;
1170 #if 0 /* not used yet */
1171 static int hf_oap_1_opinfo_start_frame
;
1172 static int hf_oap_1_opinfo_end_frame
;
1173 static int hf_oap_1_opinfo_timeout
;
1176 static int hf_oap_1_providerid
;
1177 static int ett_oap_1_1_providerid
;
1179 static int hf_oap_1_objectid
;
1180 static int ett_oap_1_objectid
;
1182 static int hf_oap_1_interfaceid
;
1183 static int hf_oap_1_itemid
;
1185 #if 0 /* not used yet */
1186 static int hf_oap_1_distance
;
1189 static int hf_oap_1_alias
;
1190 static int hf_oap_1_alias_frame
;
1192 static int hf_oap_1_subscription_delta
;
1193 static int hf_oap_1_update_sequence
;
1194 static int hf_oap_1_value_list
;
1196 static int ett_oap_1_dsp
;
1197 static int ett_oap_1_dsp_options
;
1199 static int ett_oap_1
;
1200 static int ett_oap_1_opinfo
;
1201 static int ett_oap_1_cmdcontrol
;
1202 static int ett_oap_1_cmdcontrol_flags
;
1203 static int ett_oap_1_cmdcontrol_ack
;
1204 static int ett_oap_1_alias
;
1206 static int * const bitmask_oap_1_cmdcontrol_flags
[] = {
1207 &hf_oap_1_cmdcontrol_cache_flag
,
1208 &hf_oap_1_cmdcontrol_verbosity_flag
,
1209 &hf_oap_1_cmdcontrol_noexecute_flag
,
1210 &hf_oap_1_cmdcontrol_ack_flag
,
1211 &hf_oap_1_cmdcontrol_delay_flag
,
1212 &hf_oap_1_cmdcontrol_heuristic_flag
,
1216 static expert_field ei_oap_no_session
;
1218 static GHashTable
*oap_1_alias_to_binding
;
1220 #define OAP_1_RESPONSE (0x80)
1221 #define OAP_1_CMD_ACTIVATE 28
1222 #define OAP_1_RSP_ACTIVATE (OAP_1_CMD_ACTIVATE|OAP_1_RESPONSE)
1223 #define OAP_1_CMD_ADVERTISE 5
1224 #define OAP_1_RSP_ADVERTISE (OAP_1_CMD_ADVERTISE|OAP_1_RESPONSE)
1225 #define OAP_1_CMD_CHANGE 2
1226 #define OAP_1_RSP_CHANGE (OAP_1_CMD_CHANGE|OAP_1_RESPONSE)
1227 #define OAP_1_CMD_CONNECT 4
1228 #define OAP_1_RSP_CONNECT (OAP_1_CMD_CONNECT|OAP_1_RESPONSE)
1229 #define OAP_1_CMD_DEFINE 6
1230 #define OAP_1_RSP_DEFINE (OAP_1_CMD_DEFINE|OAP_1_RESPONSE)
1231 #define OAP_1_CMD_EXCEPTION 9
1232 #define OAP_1_RSP_EXCEPTION (OAP_1_CMD_EXCEPTION|OAP_1_RESPONSE)
1233 #define OAP_1_CMD_FULL_CONNECT 3
1234 #define OAP_1_RSP_FULL_CONNECT (OAP_1_CMD_FULL_CONNECT|OAP_1_RESPONSE)
1235 #define OAP_1_CMD_GET 10
1236 #define OAP_1_RSP_GET (OAP_1_CMD_GET|OAP_1_RESPONSE)
1237 #define OAP_1_CMD_INVOKE 12
1238 #define OAP_1_RSP_INVOKE (OAP_1_CMD_INVOKE|OAP_1_RESPONSE)
1239 #define OAP_1_CMD_OPEN 14
1240 #define OAP_1_RSP_OPEN (OAP_1_CMD_OPEN|OAP_1_RESPONSE)
1241 #define OAP_1_CMD_PROVIDE 16
1242 #define OAP_1_RSP_PROVIDE (OAP_1_CMD_PROVIDE|OAP_1_RESPONSE)
1243 #define OAP_1_CMD_REGISTER 25
1244 #define OAP_1_RSP_REGISTER (OAP_1_CMD_REGISTER|OAP_1_RESPONSE)
1245 #define OAP_1_CMD_SET 20
1246 #define OAP_1_RSP_SET (OAP_1_CMD_SET|OAP_1_RESPONSE)
1247 #define OAP_1_CMD_SIGNAL 22
1248 #define OAP_1_RSP_SIGNAL (OAP_1_CMD_SIGNAL|OAP_1_RESPONSE)
1249 #define OAP_1_CMD_SUBSCRIBE 24
1250 #define OAP_1_RSP_SUBSCRIBE (OAP_1_CMD_SUBSCRIBE|OAP_1_RESPONSE)
1251 #define OAP_1_CMD_WATCH 30
1252 #define OAP_1_RSP_WATCH (OAP_1_CMD_WATCH|OAP_1_RESPONSE)
1254 static const value_string oap_opcode_strings
[] = {
1255 { OAP_1_CMD_ACTIVATE
, "OAP Activate" },
1256 { OAP_1_RSP_ACTIVATE
, "OAP Activate Response (Illegal)" },
1257 { OAP_1_CMD_ADVERTISE
, "OAP Advertise" },
1258 { OAP_1_RSP_ADVERTISE
, "OAP Advertise Response (Illegal)" },
1259 { OAP_1_CMD_CHANGE
, "OAP Change" },
1260 { OAP_1_RSP_CHANGE
, "OAP Change Response (Illegal)" },
1261 { OAP_1_CMD_CONNECT
, "OAP Connect" },
1262 { OAP_1_RSP_CONNECT
, "OAP Connect Response (Illegal)" },
1263 { OAP_1_CMD_DEFINE
, "OAP Define" },
1264 { OAP_1_RSP_DEFINE
, "OAP Define Response" },
1265 { OAP_1_CMD_EXCEPTION
, "OAP Exception (Illegal)" },
1266 { OAP_1_RSP_EXCEPTION
, "OAP Exception Response" },
1267 { OAP_1_CMD_FULL_CONNECT
, "OAP Full Connect" },
1268 { OAP_1_RSP_FULL_CONNECT
, "OAP Full Connect Response (Illegal)" },
1269 { OAP_1_CMD_GET
, "OAP Get" },
1270 { OAP_1_RSP_GET
, "OAP Get Response" },
1271 { OAP_1_CMD_INVOKE
, "OAP Invoke" },
1272 { OAP_1_RSP_INVOKE
, "OAP Invoke Response" },
1273 { OAP_1_CMD_OPEN
, "OAP Open" },
1274 { OAP_1_RSP_OPEN
, "OAP Open Response" },
1275 { OAP_1_CMD_PROVIDE
, "OAP Provide" },
1276 { OAP_1_RSP_PROVIDE
, "OAP Provide Response (Illegal)" },
1277 { OAP_1_CMD_REGISTER
, "OAP Register" },
1278 { OAP_1_RSP_REGISTER
, "OAP Register Response" },
1279 { OAP_1_CMD_SET
, "OAP Set" },
1280 { OAP_1_RSP_SET
, "OAP Set Response" },
1281 { OAP_1_CMD_SIGNAL
, "OAP Signal" },
1282 { OAP_1_RSP_SIGNAL
, "OAP Signal Response (Illegal)" },
1283 { OAP_1_CMD_SUBSCRIBE
, "OAP Subscribe" },
1284 { OAP_1_RSP_SUBSCRIBE
, "OAP Subscribe Response" },
1285 { OAP_1_CMD_WATCH
, "OAP Watch" },
1286 { OAP_1_RSP_WATCH
, "OAP Watch Response (Illegal)" },
1291 typedef struct _alias_key
1298 static unsigned oap_1_alias_hash_func(const void *ptr
)
1300 const oap_1_alias_key
*key
= (const oap_1_alias_key
*)ptr
;
1301 return g_int_hash(&key
->session
) + g_int_hash(&key
->sender
) + g_int_hash(&key
->alias
);
1304 static int oap_1_alias_equal_func(const void *ptr1
, const void *ptr2
)
1306 const oap_1_alias_key
*key1
= (const oap_1_alias_key
*)ptr1
;
1307 const oap_1_alias_key
*key2
= (const oap_1_alias_key
*)ptr2
;
1309 if (key1
->session
!= key2
->session
)
1312 if (key1
->sender
!= key2
->sender
)
1315 if (key1
->alias
!= key2
->alias
)
1324 uint16_t oid_length
;
1326 uint16_t iid_length
;
1330 typedef struct oap_1_binding_list
1332 oap_1_binding
*binding
;
1333 struct oap_1_binding_list
*next
;
1334 } oap_1_binding_list
;
1338 oap_1_binding
*resolved_alias
;
1339 } oap_1_packet_data
;
1341 static oap_1_binding
* oap_1_resolve_alias(oap_1_alias_key
*key
);
1343 static int oap_1_tree_add_alias(dof_api_data
*api_data
, oap_1_packet_data
*oap_packet _U_
, dof_packet_data
*packet
, proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, uint8_t alias_length
, uint8_t resolve
)
1345 dof_session_data
*session
= api_data
->session
;
1347 proto_tree
*options_tree
;
1349 if (alias_length
== 0)
1350 /* TODO: Output error. */
1353 if (session
== NULL
)
1354 /* TODO: Output error. */
1357 ti
= proto_tree_add_item(tree
, hf_oap_1_alias
, tvb
, offset
, alias_length
, ENC_BIG_ENDIAN
);
1361 oap_1_binding
*binding
= NULL
;
1362 oap_1_alias_key key
;
1367 for (i
= 0; i
< alias_length
; i
++)
1368 alias
= (alias
<< 8) | tvb_get_uint8(tvb
, offset
+ i
);
1370 key
.session
= session
->session_id
;
1371 key
.sender
= packet
->sender_id
;
1373 binding
= oap_1_resolve_alias(&key
);
1377 options_tree
= proto_item_add_subtree(ti
, ett_oap_1_alias
);
1379 /* Decode the Interface */
1380 ti
= proto_tree_add_bytes_format_value(tree
, hf_oap_1_interfaceid
, tvb
, 0, 0, binding
->iid
, "%s", dof_iid_create_standard_string(binding
->iid_length
, binding
->iid
));
1381 proto_item_set_generated(ti
);
1383 /* Decode the Object ID */
1384 ti
= proto_tree_add_bytes_format_value(tree
, hf_oap_1_objectid
, tvb
, 0, 0, binding
->oid
, "%s", dof_oid_create_standard_string(binding
->oid_length
, binding
->oid
, pinfo
));
1385 proto_item_set_generated(ti
);
1387 proto_tree_add_uint_format(options_tree
, hf_oap_1_alias_frame
,
1388 tvb
, 0, 0, binding
->frame
,
1389 "This alias is defined in frame %u",
1394 return offset
+ alias_length
;
1397 static int oap_1_tree_add_interface(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
1402 registry
= tvb_get_uint8(tvb
, offset
);
1403 len
= registry
& 0x03;
1407 len
= 1 << (len
- 1);
1409 proto_tree_add_item(tree
, hf_oap_1_interfaceid
, tvb
, offset
, 1 + len
, ENC_NA
);
1410 return offset
+ 1 + len
;
1413 static int oap_1_tree_add_binding(proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
)
1418 len
= tvb_get_uint8(tvb
, offset
);
1423 len
= 1 << (len
- 1);
1425 proto_tree_add_item(tree
, hf_oap_1_interfaceid
, tvb
, offset
, 1 + len
, ENC_NA
);
1428 #if 0 /* this seems to be dead code - check! */
1429 cl
= tvb_get_uint8(tvb
, offset
);
1431 len
= tvb_get_uint8(tvb
, offset
+ 2);
1433 len
= tvb_get_uint8(tvb
, offset
+ 1);
1436 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, tree
,
1437 offset
, hf_oap_1_objectid
, ett_oap_1_objectid
, NULL
);
1441 static int oap_1_tree_add_cmdcontrol(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
1444 proto_tree
*opinfo_tree
;
1447 flags
= tvb_get_uint8(tvb
, offset
);
1449 ti
= proto_tree_add_bitmask(tree
, tvb
, offset
, hf_oap_1_cmdcontrol
, ett_oap_1_cmdcontrol_flags
, bitmask_oap_1_cmdcontrol_flags
, ENC_NA
);
1450 opinfo_tree
= proto_item_add_subtree(ti
, ett_oap_1_cmdcontrol
);
1452 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_cache_flag
, tvb
, offset
, 1, ENC_NA
);
1453 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_verbosity_flag
, tvb
, offset
, 1, ENC_NA
);
1454 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_noexecute_flag
, tvb
, offset
, 1, ENC_NA
);
1455 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_ack_flag
, tvb
, offset
, 1, ENC_NA
);
1456 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_delay_flag
, tvb
, offset
, 1, ENC_NA
);
1457 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_heuristic_flag
, tvb
, offset
, 1, ENC_NA
);
1468 read_c2(tvb
, offset
, &heur
, &heur_len
);
1469 pi
= proto_tree_add_uint_format(opinfo_tree
, hf_oap_1_cmdcontrol_heuristic
, tvb
, offset
, heur_len
, heur
, "Heuristic Value: %hu", heur
);
1470 validate_c2(pinfo
, pi
, heur
, heur_len
);
1480 ackcnt
= tvb_get_uint8(tvb
, offset
);
1481 proto_tree_add_item(opinfo_tree
, hf_oap_1_cmdcontrol_ackcnt
, tvb
, offset
, 1, ENC_NA
);
1484 for (i
= 0; i
< ackcnt
; i
++)
1486 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, opinfo_tree
,
1487 offset
, hf_oap_1_cmdcontrol_ack
, ett_oap_1_cmdcontrol_ack
, NULL
);
1498 read_c2(tvb
, offset
, &cache
, &cache_len
);
1499 pi
= proto_tree_add_uint_format(opinfo_tree
, hf_oap_1_cmdcontrol_cache
, tvb
, offset
, cache_len
, cache
, "Cache Delay: %hu", cache
);
1500 validate_c2(pinfo
, pi
, cache
, cache_len
);
1501 offset
+= cache_len
;
1508 * Define an alias. This routine is called for each Provide operation that includes an alias assignment.
1509 * It is also called for retries of Provide operations.
1510 * The alias is defined for the duration of the Provide. This means that if the operation is cancelled
1511 * then the alias should no longer be valid.
1512 * The alias is associated with an oap_session, an dof_node, and the alias itself. Aliases
1513 * may be reused as long as the previous use has expired, and so the list is stored in reverse
1516 * NOTE: The alias is passed as a structure pointer, and must be reallocated if it is stored in
1519 static void oap_1_define_alias(dof_api_data
*api_data
, uint32_t alias
, oap_1_binding
*binding
)
1521 /* The definer of an alias is the sender, in the session. */
1522 dof_session_data
*session
= api_data
->session
;
1523 dof_packet_data
*packet
= (dof_packet_data
*)api_data
->packet
;
1524 uint32_t session_id
;
1526 oap_1_alias_key key
;
1531 session_id
= session
->session_id
;
1532 sender_id
= packet
->sender_id
;
1537 key
.session
= session_id
;
1538 key
.sender
= sender_id
;
1541 /* If there isn't an entry for the alias, then we need to create one.
1542 * The first entry will be the binding we are defining.
1544 if (!g_hash_table_lookup(oap_1_alias_to_binding
, &key
))
1546 oap_1_alias_key
*alias_ptr
= wmem_new0(wmem_file_scope(), oap_1_alias_key
);
1547 memcpy(alias_ptr
, &key
, sizeof(oap_1_alias_key
));
1548 g_hash_table_insert(oap_1_alias_to_binding
, alias_ptr
, binding
);
1553 * Given an oap_alias, resolve it to an oap_1_binding. This assumes that the destination of the
1554 * packet is the one that defined the alias.
1556 static oap_1_binding
* oap_1_resolve_alias(oap_1_alias_key
*key
)
1558 /* The first lookup is inside the session based on defining node. */
1559 return (oap_1_binding
*)g_hash_table_lookup(oap_1_alias_to_binding
, key
);
1562 /* DAP V128 (TEP - TICKET EXCHANGE PROTOCOL V1) */
1563 #define DOF_PROTOCOL_TEP 128
1564 #define DSP_TEP_FAMILY 0x000000
1565 static int proto_tep
;
1566 static int proto_tep_dsp
;
1568 static int hf_dsp_option
;
1570 static int ett_tep_operation
;
1571 static int hf_tep_operation
;
1572 static int hf_tep_operation_type
;
1573 static int hf_tep_opcode
;
1574 static int hf_tep_k
;
1575 static int hf_tep_c
;
1576 static int hf_tep_reject_code
;
1577 static int hf_tep_reject_data
;
1579 static const true_false_string tep_optype_vals
= { "DPP Response", "DPP Command" };
1582 static int ett_tep_2_1_domain
;
1583 static int hf_tep_2_1_domain
;
1584 static int ett_tep_2_1_initiator_block
;
1585 static int hf_tep_2_1_initiator_block
;
1586 static int hf_tep_2_1_ticket_confirmation
;
1589 static int ett_tep_2_2_initiator_ticket
;
1590 static int hf_tep_2_2_initiator_ticket
;
1591 static int hf_tep_2_2_ticket_confirmation
;
1592 static int ett_tep_2_2_responder_initialization
;
1593 static int hf_tep_2_2_responder_initialization
;
1594 static int ett_tep_2_2_responder_block
;
1595 static int hf_tep_2_2_responder_block
;
1596 static int ett_tep_2_2_authenticator_initialization
;
1597 static int hf_tep_2_2_authenticator_initialization
;
1600 static int hf_tep_2_2_1_state_identifier
;
1601 static int ett_tep_2_2_1_initial_state
;
1602 static int hf_tep_2_2_1_initial_state
;
1604 static int hf_tep_session_key
;
1606 static int ett_tep_dsp
;
1607 static int ett_tep_dsp_options
;
1610 #if 0 /* not used yet */
1611 static const value_string tep_filter_existing
[] = {
1612 { 1, "Include Existing Matches" },
1613 { 0, "Exclude Existing Matches" },
1618 #define TEP_OPCODE_RSP (0x80)
1619 #define TEP_OPCODE_C (0x20)
1620 #define TEP_OPCODE_K (0x10)
1621 #define TEP_PDU_REJECT (TEP_OPCODE_RSP|0)
1622 #define TEP_PDU_REQUEST (1)
1623 #define TEP_PDU_END_SESSION (5)
1624 #define TEP_PDU_SESSION_ENDING (6)
1626 #define TEP_PDU_REQUEST_KEY (TEP_OPCODE_K|TEP_PDU_REQUEST)
1627 #define TEP_PDU_CONFIRM (TEP_OPCODE_C|TEP_PDU_REQUEST)
1628 #define TEP_PDU_ACCEPT (TEP_OPCODE_RSP|TEP_PDU_REQUEST)
1629 #define TEP_PDU_CONFIRM_ACK (TEP_OPCODE_RSP|TEP_OPCODE_C|TEP_PDU_REQUEST)
1631 static const value_string tep_opcode_strings
[] = {
1632 { TEP_PDU_REJECT
, "TEP Reject" },
1633 { TEP_PDU_REQUEST
, "TEP Request" },
1634 { TEP_PDU_END_SESSION
, "TEP End Session" },
1635 { TEP_PDU_SESSION_ENDING
, "TEP Session Ending" },
1637 { TEP_PDU_REQUEST_KEY
, "TEP Rekey" },
1638 { TEP_PDU_CONFIRM
, "TEP Confirm" },
1639 { TEP_PDU_ACCEPT
, "TEP Accept" },
1640 { TEP_PDU_CONFIRM_ACK
, "TEP Confirm Ack" },
1645 #if 0 /* not use yet */
1646 static const value_string tep_error_strings
[] = {
1647 { 1, "Parse Error" },
1648 { 2, "Access Denied" },
1649 { 3, "Duration Not Supported" },
1650 { 4, "Authentication Failed" },
1655 /* Initialized to zero. */
1656 typedef struct tep_rekey_data
1658 /* Stored from the K bit of the Request PDU. */
1661 /* Stored from the key request for non-secure rekeys. Otherwise 0 and NULL. */
1662 uint8_t domain_length
;
1665 /* Stored from the identity of the Request PDU. Seasonal. */
1666 uint8_t *i_identity
;
1667 uint8_t i_identity_length
;
1669 /* Stored from the nonce of the Request PDU. Seasonal. */
1671 uint8_t i_nonce_length
;
1673 /* Stored from the identity of the Request response PDU. Seasonal. */
1674 uint8_t *r_identity
;
1675 uint8_t r_identity_length
;
1677 /* Stored from the nonce of the Request response PDU. Seasonal. */
1679 uint8_t r_nonce_length
;
1681 uint16_t security_mode
;
1682 uint32_t security_mode_data_length
;
1683 uint8_t *security_mode_data
;
1685 /* Security session data for this rekey, if is_rekey is true. */
1686 dof_session_key_exchange_data
*key_data
;
1689 /* DAP V129 (TRP - TICKET REQUEST PROTOCOL V2) */
1690 #define DOF_PROTOCOL_TRP 129
1691 #define DSP_TRP_FAMILY 0x030000
1692 typedef struct _trp_packet_data
1695 uint8_t domain_length
;
1697 uint8_t identity_length
;
1699 uint8_t group_length
;
1701 uint16_t block_I_length
;
1707 static int proto_trp
;
1708 static int proto_trp_dsp
;
1710 static int hf_trp_dsp_option
;
1712 static int hf_trp_opcode
;
1713 static int hf_domain
;
1714 static int hf_identity_resolution
;
1715 static int hf_initiator_request
;
1716 static int hf_responder_request
;
1717 static int hf_initiator_ticket
;
1718 static int hf_responder_ticket
;
1719 static int hf_authentication_block
;
1720 static int hf_group_identifier
;
1721 static int hf_node_identifier
;
1725 static int hf_trp_epoch
;
1727 static int hf_security_scope
;
1728 static int hf_security_mode
;
1730 #if 0 /* not used yet */
1731 static int hf_initiator_pg
;
1733 static int hf_initiator_validation
;
1734 static int hf_responder_pg
;
1735 static int hf_responder_validation
;
1737 static int hf_trp_errorcode
;
1738 static int hf_trp_duration
;
1739 #if 0 /* not used yet */
1740 static int hf_trp_rnonce
;
1741 static int hf_trp_pnonce
;
1742 static int hf_trp_reqid
;
1743 static int hf_trp_provid
;
1744 static int hf_trp_perm_count
;
1745 static int hf_trp_perm_type
;
1746 static int hf_trp_perm_rcache
;
1747 static int hf_trp_perm_rsrp
;
1748 static int hf_trp_perm_rsrp_a
;
1749 static int hf_trp_perm_rsrp_u
;
1750 static int hf_trp_perm_rflags
;
1751 static int hf_trp_perm_pcache
;
1752 static int hf_trp_perm_psrp
;
1753 static int hf_trp_perm_psrp_a
;
1754 static int hf_trp_perm_psrp_u
;
1755 static int hf_trp_perm_psrp_b
;
1756 static int hf_trp_perm_psrp_s
;
1757 static int hf_trp_perm_pflags
;
1758 static int hf_trp_confirmation
;
1759 static int hf_trp_perm_pke
;
1760 static int hf_trp_perm_pka
;
1763 static int ett_trp_dsp
;
1765 static int ett_domain
;
1766 static int ett_identity_resolution
;
1767 static int ett_initiator_request
;
1768 static int ett_initiator_ticket
;
1769 static int ett_responder_request
;
1770 static int ett_responder_ticket
;
1771 static int ett_authentication_block
;
1772 static int ett_group_identifier
;
1773 static int ett_node_identifier
;
1774 static int ett_sidg
;
1775 static int ett_security_scope
;
1776 static int ett_security_mode
;
1777 static int ett_initiator_pg
;
1778 static int ett_initiator_validation
;
1779 static int ett_responder_pg
;
1780 static int ett_responder_validation
;
1783 static int ett_trp_permset
;
1784 static int ett_srp_flags
;
1785 static int ett_trp_ticket
;
1787 static expert_field ei_trp_initiator_id_known
;
1788 static expert_field ei_trp_kek_discovered
;
1790 #define TRP_RESPONSE (0x80)
1792 #define TRP_RSP_REJECT (TRP_RESPONSE|0)
1793 #define TRP_CMD_REQUEST_KEK (1)
1794 #define TRP_RSP_REQUEST_KEK (TRP_RESPONSE|TRP_CMD_REQUEST_KEK)
1795 #define TRP_CMD_REQUEST_RANDOM (2)
1796 #define TRP_RSP_REQUEST_RANDOM (TRP_RESPONSE|TRP_CMD_REQUEST_RANDOM)
1797 #define TRP_CMD_REQUEST_SESSION (3)
1798 #define TRP_RSP_REQUEST_SESSION (TRP_RESPONSE|TRP_CMD_REQUEST_SESSION)
1799 #define TRP_CMD_REQUEST_SECURITY_SCOPES (4)
1800 #define TRP_RSP_REQUEST_SECURITY_SCOPES (TRP_RESPONSE|TRP_CMD_REQUEST_SECURITY_SCOPES)
1801 #define TRP_CMD_RESOLVE_CREDENTIAL (6)
1802 #define TRP_RSP_RESOLVE_CREDENTIAL (TRP_RESPONSE|TRP_CMD_RESOLVE_CREDENTIAL)
1803 #define TRP_CMD_REQUEST_LOCAL_DOMAIN (7)
1804 #define TRP_RSP_REQUEST_LOCAL_DOMAIN (TRP_RESPONSE|TRP_CMD_REQUEST_LOCAL_DOMAIN)
1805 #define TRP_CMD_REQUEST_REMOTE_DOMAIN (8)
1806 #define TRP_RSP_REQUEST_REMOTE_DOMAIN (TRP_RESPONSE|TRP_CMD_REQUEST_REMOTE_DOMAIN)
1807 #define TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN (TRP_RESPONSE|0x0A)
1808 #define TRP_CMD_VALIDATE_CREDENTIAL (9)
1809 #define TRP_RSP_VALIDATE_CREDENTIAL (TRP_RESPONSE|TRP_CMD_VALIDATE_CREDENTIAL)
1811 static const value_string trp_opcode_strings
[] = {
1812 { TRP_RSP_REJECT
, "Reject" },
1814 { TRP_CMD_REQUEST_KEK
, "TRP Request KEK" },
1815 { TRP_RSP_REQUEST_KEK
, "TRP Request KEK Response" },
1817 { TRP_CMD_REQUEST_RANDOM
, "TRP Request Random" },
1818 { TRP_RSP_REQUEST_RANDOM
, "TRP Request Random Response" },
1820 { TRP_CMD_REQUEST_SESSION
, "TRP Request Session" },
1821 { TRP_RSP_REQUEST_SESSION
, "TRP Request Session Response" },
1823 { TRP_CMD_REQUEST_SECURITY_SCOPES
, "TRP Request Security Scopes" },
1824 { TRP_RSP_REQUEST_SECURITY_SCOPES
, "TRP Request Security Scopes Response" },
1826 { TRP_CMD_RESOLVE_CREDENTIAL
, "TRP Resolve Credential" },
1827 { TRP_RSP_RESOLVE_CREDENTIAL
, "TRP Resolve Credential Response" },
1829 { TRP_CMD_REQUEST_LOCAL_DOMAIN
, "TRP Request Local Domain" },
1830 { TRP_RSP_REQUEST_LOCAL_DOMAIN
, "TRP Request Local Domain Response" },
1832 { TRP_CMD_REQUEST_REMOTE_DOMAIN
, "TRP Request Remote Domain" },
1833 { TRP_RSP_REQUEST_REMOTE_DOMAIN
, "TRP Request Remote Domain Response" },
1834 { TRP_RSP_REQUEST_DISCOVERED_REMOTE_DOMAIN
, "TRP Request Discovered Remote Domain Response" },
1836 { TRP_CMD_VALIDATE_CREDENTIAL
, "TRP Validate Credential" },
1837 { TRP_RSP_VALIDATE_CREDENTIAL
, "TRP Validate Credential Response" },
1842 static const value_string trp_error_strings
[] = {
1843 { 1, "Parse Error" },
1844 { 2, "Access Denied" },
1845 { 3, "Unknown Initiator" },
1846 { 4, "Unknown Responder" },
1847 { 5, "Unknown Domain" },
1850 { 8, "Incompatible Security Identifiers" },
1851 { 127, "Internal Error" },
1856 /* DAP V130 (SGMP - SECURE GROUP MANAGEMENT PROTOCOL V1) */
1857 #define DOF_PROTOCOL_SGMP 130
1858 typedef struct _sgmp_packet_data
1860 uint8_t domain_length
;
1863 uint8_t group_length
;
1874 dof_session_data
*request_session
;
1877 static int proto_sgmp
;
1879 static int hf_opcode
;
1880 static int hf_sgmp_domain
;
1881 static int hf_sgmp_epoch
;
1882 static int hf_initiator_block
;
1883 static int hf_sgmp_security_scope
;
1884 static int hf_initial_state
;
1885 static int hf_latest_version
;
1886 static int hf_desire
;
1887 static int hf_ticket
;
1888 static int hf_sgmp_tmin
;
1889 static int hf_tie_breaker
;
1890 static int hf_delay
;
1893 static int ett_sgmp
;
1894 static int ett_sgmp_domain
;
1895 static int ett_initiator_block
;
1896 static int ett_sgmp_security_scope
;
1897 static int ett_initial_state
;
1898 static int ett_ticket
;
1900 #define SGMP_RESPONSE (0x80)
1901 #define SGMP_CMD_HEARTBEAT (0)
1902 #define SGMP_RSP_HEARTBEAT (SGMP_CMD_HEARTBEAT|SGMP_RESPONSE)
1903 #define SGMP_CMD_EPOCH_CHANGED (1)
1904 #define SGMP_RSP_EPOCH_CHANGED (SGMP_CMD_EPOCH_CHANGED|SGMP_RESPONSE)
1905 #define SGMP_CMD_REKEY (2)
1906 #define SGMP_RSP_REKEY (SGMP_CMD_REKEY|SGMP_RESPONSE)
1907 #define SGMP_CMD_REQUEST_GROUP (3)
1908 #define SGMP_RSP_REQUEST_GROUP (SGMP_CMD_REQUEST_GROUP|SGMP_RESPONSE)
1909 #define SGMP_CMD_REKEY_EPOCH (5)
1910 #define SGMP_RSP_REKEY_EPOCH (SGMP_CMD_REKEY_EPOCH|SGMP_RESPONSE)
1911 #define SGMP_CMD_REKEY_MERGE (7)
1912 #define SGMP_RSP_REKEY_MERGE (SGMP_CMD_REKEY_MERGE|SGMP_RESPONSE)
1914 static const value_string sgmp_opcode_strings
[] = {
1915 { SGMP_CMD_HEARTBEAT
, "SGMP Heartbeat" },
1916 { SGMP_RSP_HEARTBEAT
, "SGMP Heartbeat Response (Illegal)" },
1917 { SGMP_CMD_EPOCH_CHANGED
, "SGMP Epoch Changed" },
1918 { SGMP_RSP_EPOCH_CHANGED
, "SGMP Epoch Changed Response (Illegal)" },
1919 { SGMP_CMD_REKEY
, "SGMP Rekey" },
1920 { SGMP_RSP_REKEY
, "SGMP Rekey Response (Illegal)" },
1921 { SGMP_CMD_REQUEST_GROUP
, "SGMP Request Group" },
1922 { SGMP_RSP_REQUEST_GROUP
, "SGMP Request Group Response" },
1923 { SGMP_CMD_REKEY_EPOCH
, "SGMP Rekey Epoch" },
1924 { SGMP_RSP_REKEY_EPOCH
, "SGMP Rekey Epoch Response (Illegal)" },
1925 { SGMP_CMD_REKEY_MERGE
, "SGMP Rekey Merge" },
1926 { SGMP_RSP_REKEY_MERGE
, "SGMP Rekey Merge Response (Illegal)" },
1932 #if 0 /* TODO not used yet */
1933 static bool sgmp_validate_session_key(sgmp_packet_data
*cmd_data
, uint8_t *confirmation
, uint8_t *kek
, uint8_t *key
)
1936 gcry_error_t result
;
1938 result
= gcry_mac_open(&hmac
, GCRY_MAC_HMAC_SHA256
, 0, NULL
);
1942 gcry_mac_setkey(hmac
, kek
, 32);
1943 gcry_mac_write(hmac
, cmd_data
->I
, cmd_data
->I_length
);
1944 gcry_mac_write(hmac
, cmd_data
->A
, cmd_data
->A_length
);
1945 gcry_mac_write(hmac
, key
, 32);
1946 result
= gcry_mac_verify(hmac
, confirmation
, sizeof(confirmation
));
1951 /* DOF SECURITY PROTOCOL */
1952 #define DOF_SECURITY_PROTOCOL "DOF Security Protocol"
1953 static dissector_table_t dof_sec_dissectors
;
1954 #define AS_ASSIGNED_SSID 0x40000000
1956 /* DOFSEC Vxxxx (CCM - COUNTER WITH CBC-MAC PROTOCOL V1) */
1957 #define DOF_PROTOCOL_CCM 24577
1958 #define DSP_CCM_FAMILY 0x020000
1960 static int proto_ccm_app
;
1961 static int proto_ccm
;
1962 static int proto_ccm_dsp
;
1964 static int hf_ccm_dsp_option
;
1965 static int hf_ccm_dsp_strength_count
;
1966 static int hf_ccm_dsp_strength
;
1967 static int hf_ccm_dsp_e_flag
;
1968 static int hf_ccm_dsp_m_flag
;
1969 static int hf_ccm_dsp_tmax
;
1970 static int hf_ccm_dsp_tmin
;
1972 static const value_string ccm_strengths
[] = {
1978 static int hf_ccm_opcode
;
1980 static int hf_epp_v1_ccm_flags
;
1981 static int hf_epp_v1_ccm_flags_manager
;
1982 static int hf_epp_v1_ccm_flags_period
;
1983 static int hf_epp_v1_ccm_flags_target
;
1984 static int hf_epp_v1_ccm_flags_next_nid
;
1985 static int hf_epp_v1_ccm_flags_packet
;
1986 static int hf_epp_v1_ccm_tnid
;
1987 static int hf_epp_v1_ccm_nnid
;
1988 static int hf_epp_v1_ccm_nid
;
1989 static int hf_epp_v1_ccm_slot
;
1990 static int hf_epp_v1_ccm_pn
;
1992 static int ett_header
;
1993 static int ett_epp_v1_ccm_flags
;
1995 static int ett_ccm_dsp_option
;
1996 static int ett_ccm_dsp
;
1999 static expert_field ei_decode_failure
;
2001 typedef struct _ccm_session_data
2003 unsigned protocol_id
;
2004 gcry_cipher_hd_t cipher_data
;
2005 GHashTable
*cipher_data_table
;
2006 /* Starts at 1, incrementing for each new key. */
2008 /* Mapping from wire period to absolute periods. */
2013 uint32_t client_datagram_number
;
2014 uint32_t server_datagram_number
;
2017 typedef struct _ccm_packet_data
2024 #define CCM_PDU_PROBE (0)
2026 static const value_string ccm_opcode_strings
[] = {
2027 { CCM_PDU_PROBE
, "Probe" },
2031 /* DOF OBJECT IDENTIFIER (OID) */
2032 #define DOF_OBJECT_IDENTIFIER "DOF Object Identifier"
2034 static dissector_handle_t dof_oid_handle
;
2036 static int oid_proto
= -1;
2038 static int hf_oid_class
;
2039 static int hf_oid_header
;
2040 static int hf_oid_attribute
;
2041 static int hf_oid_length
;
2042 static int hf_oid_data
;
2043 static int hf_oid_all_attribute_data
;
2044 static int hf_oid_attribute_header
;
2045 static int hf_oid_attribute_attribute
;
2046 static int hf_oid_attribute_id
;
2047 static int hf_oid_attribute_length
;
2048 static int hf_oid_attribute_data
;
2049 static int hf_oid_attribute_oid
;
2052 static int ett_oid_header
;
2053 static int ett_oid_attribute
;
2054 static int ett_oid_attribute_header
;
2055 static int ett_oid_attribute_oid
;
2059 * Expert infos are related to either a PDU type or a specification, and so
2060 * they are listed separately.
2063 static expert_field ei_undecoded
;
2065 static expert_field ei_malformed
;
2066 static expert_field ei_implicit_no_op
;
2067 static expert_field ei_c2_c3_c4_format
;
2068 static expert_field ei_type_4_header_zero
;
2069 static expert_field ei_dof_10_flags_zero
;
2071 static expert_field ei_dof_13_length_specified
;
2074 static expert_field ei_dpp2_dof_10_flags_zero
;
2075 static expert_field ei_dpp_default_flags
;
2076 static expert_field ei_dpp_explicit_sender_sid_included
;
2077 static expert_field ei_dpp_explicit_receiver_sid_included
;
2078 static expert_field ei_dpp_no_security_context
;
2079 static expert_field ei_dof_6_timeout
;
2081 static expert_field ei_security_3_1_invalid_stage
;
2082 static expert_field ei_security_4_invalid_bit
;
2083 static expert_field ei_security_13_out_of_range
;
2086 * SOURCE IDENTIFIER (SID) SUPPORT
2087 * Source identifiers are used as part of operation tracking in the
2088 * DOF Protocol Stack. They are version independent, and associated with
2089 * a node in the DOF mesh network. Each session is associated with a SID.
2091 * DPP Manages the SID information, since it is DPP that learns about SIDs.
2092 * SIDs are complicated because the can be 'unknown' for periods, and then
2093 * learned later. The requirement here is that all SIDs that can be known
2094 * are known by the second pass of the dissector (pinfo->visited != 0).
2096 * There are two hash tables to map to an actual SID. The first goes
2097 * from sender information to SID ID. During the first pass multiple SID ID
2098 * may actually refer to the same SID, and so the system must be able to "patch"
2099 * these values as actual SIDs are learned. The second hash table goes from SID ID
2100 * to actual SID. This lookup is only known after a real SID has been learned.
2102 * The hash tables are used in order to look up full SID information when only
2103 * partial information is known, and must support looking up in both directions
2104 * based on what is known from a particular PDU.
2106 static GHashTable
*node_key_to_sid_id
;
2107 static GHashTable
*sid_buffer_to_sid_id
;
2108 static GHashTable
*sid_id_to_sid_buffer
;
2110 typedef struct _node_key_to_sid_id_key
2113 int transport_node_id
;
2117 } node_key_to_sid_id_key
;
2119 static unsigned sender_key_hash_fn(const void *key
)
2121 const node_key_to_sid_id_key
*sid_key_ptr
= (const node_key_to_sid_id_key
*)key
;
2122 unsigned result
= 0;
2124 result
+= g_int_hash(&(sid_key_ptr
->transport_id
));
2125 result
+= g_int_hash(&(sid_key_ptr
->transport_node_id
));
2126 result
+= g_int_hash(&(sid_key_ptr
->dof_id
));
2127 result
+= g_int_hash(&(sid_key_ptr
->dof_node_id
));
2128 result
+= g_int_hash(&(sid_key_ptr
->dof_session_id
));
2133 static unsigned sid_buffer_hash_fn(const void *key
)
2135 /* The sid buffer is a length byte followed by data. */
2136 unsigned hash
= 5381;
2137 const uint8_t *str
= (const uint8_t *)key
;
2140 for (i
= 0; i
<= str
[0]; i
++)
2141 hash
= ((hash
<< 5) + hash
) + str
[i
]; /* hash * 33 + c */
2146 static gboolean
sender_key_equal_fn(const void *key1
, const void *key2
)
2148 const node_key_to_sid_id_key
*sid_key_ptr1
= (const node_key_to_sid_id_key
*)key1
;
2149 const node_key_to_sid_id_key
*sid_key_ptr2
= (const node_key_to_sid_id_key
*)key2
;
2151 if (sid_key_ptr1
->transport_id
!= sid_key_ptr2
->transport_id
)
2154 if (sid_key_ptr1
->transport_node_id
!= sid_key_ptr2
->transport_node_id
)
2157 if (sid_key_ptr1
->dof_id
!= sid_key_ptr2
->dof_id
)
2160 if (sid_key_ptr1
->dof_node_id
!= sid_key_ptr2
->dof_node_id
)
2163 if (sid_key_ptr1
->dof_session_id
!= sid_key_ptr2
->dof_session_id
)
2169 static gboolean
sid_buffer_equal_fn(const void *key1
, const void *key2
)
2171 const uint8_t *sb1
= (const uint8_t *)key1
;
2172 const uint8_t *sb2
= (const uint8_t *)key2
;
2174 if (sb1
[0] != sb2
[0])
2177 return memcmp(sb1
+ 1, sb2
+ 1, sb1
[0]) == 0;
2180 static unsigned dpp_next_sid_id
= 1;
2183 * This routine is called for each reset (file load, capture) and is responsible
2184 * for allocating the SID support hash tables. Previous information is freed
2187 static void dpp_reset_sid_support(void)
2189 dpp_next_sid_id
= 1;
2191 if (node_key_to_sid_id
!= NULL
)
2193 g_hash_table_destroy(node_key_to_sid_id
);
2194 node_key_to_sid_id
= NULL
;
2197 if (sid_buffer_to_sid_id
!= NULL
)
2199 g_hash_table_destroy(sid_buffer_to_sid_id
);
2200 sid_buffer_to_sid_id
= NULL
;
2203 if (sid_id_to_sid_buffer
!= NULL
)
2205 g_hash_table_destroy(sid_id_to_sid_buffer
);
2206 sid_id_to_sid_buffer
= NULL
;
2209 /* The value is not allocated, so does not need to be freed. */
2210 node_key_to_sid_id
= g_hash_table_new_full(sender_key_hash_fn
, sender_key_equal_fn
, g_free
, NULL
);
2211 sid_buffer_to_sid_id
= g_hash_table_new_full(sid_buffer_hash_fn
, sid_buffer_equal_fn
, g_free
, NULL
);
2212 sid_id_to_sid_buffer
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, NULL
);
2216 * OPERATION IDENTIFIER SUPPORT
2217 * Operation identifiers are an extension of a SID, and represent each separate
2218 * operation in the DOF. They are identified by a SID and an operation count.
2219 * Like SIDs, they are indepenent of version (at least in meaning, the formatting
2222 * The hash is used to look up common operation information each time an operation
2223 * is seen in any packet.
2225 static GHashTable
*dpp_opid_to_packet_data
;
2227 static unsigned dpp_opid_hash_fn(const void *opid
)
2229 const dof_2009_1_pdu_20_opid
*ptr
= (const dof_2009_1_pdu_20_opid
*)opid
;
2230 return g_int_hash(&ptr
->op_sid_id
) + g_int_hash(&ptr
->op_cnt
);
2233 static gboolean
dpp_opid_equal_fn(const void *opid1
, const void *opid2
)
2235 const dof_2009_1_pdu_20_opid
*ptr1
= (const dof_2009_1_pdu_20_opid
*)opid1
;
2236 const dof_2009_1_pdu_20_opid
*ptr2
= (const dof_2009_1_pdu_20_opid
*)opid2
;
2237 if (ptr1
->op_cnt
!= ptr2
->op_cnt
)
2239 if (ptr1
->op_sid_id
!= ptr2
->op_sid_id
)
2245 static void dpp_reset_opid_support(void)
2247 if (dpp_opid_to_packet_data
!= NULL
)
2249 /* Clear it out. Note that this calls the destroy functions for each element. */
2250 g_hash_table_destroy(dpp_opid_to_packet_data
);
2251 dpp_opid_to_packet_data
= NULL
;
2254 dpp_opid_to_packet_data
= g_hash_table_new_full(dpp_opid_hash_fn
, dpp_opid_equal_fn
, NULL
, NULL
);
2258 * NON-SECURE SESSION LOOKUP SUPPORT
2260 static GHashTable
*dof_ns_session_lookup
;
2263 * NON-SECURE DPS SESSION
2264 * This is defined by the transport session and the DNP port information.
2266 typedef struct _dof_ns_session_key
2268 unsigned transport_session_id
;
2272 } dof_ns_session_key
;
2274 static dof_session_data
* dof_ns_session_retrieve(unsigned transport_session_id
, unsigned client
, unsigned server
)
2276 dof_ns_session_key lookup_key
;
2277 dof_session_data
*value
;
2279 /* Build a (non-allocated) key to do the lookup. */
2280 lookup_key
.transport_session_id
= transport_session_id
;
2281 lookup_key
.client
= client
;
2282 lookup_key
.server
= server
;
2284 value
= (dof_session_data
*)g_hash_table_lookup(dof_ns_session_lookup
, &lookup_key
);
2287 /* We found a match. */
2294 static void dof_ns_session_define(unsigned transport_session_id
, unsigned client
, unsigned server
, dof_session_data
*session_data
)
2296 dof_ns_session_key
*key
;
2298 /* No match, need to add a key. */
2299 key
= g_new0(dof_ns_session_key
, 1);
2300 key
->transport_session_id
= transport_session_id
;
2301 key
->client
= client
;
2302 key
->server
= server
;
2304 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
2305 g_hash_table_insert(dof_ns_session_lookup
, key
, session_data
);
2308 /* COMMON PDU DISSECTORS */
2311 static int hf_security_1_permission_type
;
2312 static int hf_security_1_length
;
2313 static int hf_security_1_data
;
2315 static const value_string dof_2008_16_permission_type
[] = {
2319 { 128, "Requestor" },
2320 { 130, "Provider" },
2322 { 133, "Tunnel Domain" },
2327 static int hf_security_2_count
;
2328 static int ett_security_2_permission
;
2329 static int hf_security_2_permission
;
2332 static int hf_security_3_1_credential_type
;
2333 static int hf_security_3_1_stage
;
2334 static int ett_security_3_1_security_node_identifier
;
2335 static int hf_security_3_1_security_node_identifier
;
2338 static int hf_security_3_2_credential_type
;
2339 static int hf_security_3_2_stage
;
2340 static int hf_security_3_2_length
;
2341 static int hf_security_3_2_public_data
;
2344 static int hf_security_4_l
;
2345 static int hf_security_4_f
;
2346 static int hf_security_4_ln
;
2347 static int ett_security_4_identity
;
2348 static int hf_security_4_identity
;
2349 static int hf_security_4_nonce
;
2350 static int ett_security_4_permission_set
;
2351 static int hf_security_4_permission_set
;
2354 static int hf_security_5_mac
;
2355 static int hf_security_5_key
;
2358 static int hf_security_6_1_desired_duration
;
2359 static int ett_security_6_1_desired_security_mode
;
2360 static int hf_security_6_1_desired_security_mode
;
2361 static int ett_security_6_1_initiator_request
;
2362 static int hf_security_6_1_initiator_request
;
2365 static int ett_security_6_2_responder_request
;
2366 static int hf_security_6_2_responder_request
;
2369 static int hf_security_6_3_granted_duration
;
2370 static int ett_security_6_3_session_security_scope
;
2371 static int hf_security_6_3_session_security_scope
;
2372 static int ett_security_6_3_initiator_validation
;
2373 static int hf_security_6_3_initiator_validation
;
2374 static int ett_security_6_3_responder_validation
;
2375 static int hf_security_6_3_responder_validation
;
2378 static int hf_security_9_length
;
2379 static int hf_security_9_initial_state
;
2382 static int hf_security_10_count
;
2383 static int hf_security_10_permission_group_identifier
;
2386 static int hf_security_11_count
;
2387 static int ett_security_11_permission_security_scope
;
2388 static int hf_security_11_permission_security_scope
;
2391 static int hf_security_12_m
;
2393 static const value_string dof_2008_16_security_12_m
[] = {
2401 static int hf_security_12_count
;
2402 static int hf_security_12_permission_group_identifier
;
2405 dof_sessions_destroy_cb(wmem_allocator_t
*allocator _U_
, wmem_cb_event_t event _U_
, void *user_data
)
2407 ccm_session_data
*ccm_data
= (ccm_session_data
*) user_data
;
2408 gcry_cipher_close(ccm_data
->cipher_data
);
2409 if (ccm_data
->cipher_data_table
) {
2410 g_hash_table_destroy(ccm_data
->cipher_data_table
);
2412 /* unregister this callback */
2416 static void dof_cipher_data_destroy (void *data
)
2418 gcry_cipher_hd_t cipher_data
= (gcry_cipher_hd_t
) data
;
2419 gcry_cipher_close(cipher_data
);
2422 static int dissect_2008_1_dsp_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
2424 proto_item
*parent
= proto_tree_get_parent(tree
);
2425 uint8_t attribute_code
= tvb_get_uint8(tvb
, 0);
2426 uint16_t attribute_data
= tvb_get_ntohs(tvb
, 1);
2427 uint8_t option_length
= tvb_get_uint8(tvb
, 3);
2429 /* Add the generic representation of the fields. */
2430 proto_tree_add_item(tree
, hf_2008_1_dsp_attribute_code
, tvb
, 0, 1, ENC_NA
);
2431 proto_tree_add_item(tree
, hf_2008_1_dsp_attribute_data
, tvb
, 1, 2, ENC_BIG_ENDIAN
);
2432 proto_tree_add_item(tree
, hf_2008_1_dsp_value_length
, tvb
, 3, 1, ENC_NA
);
2434 /* Append description to the parent. */
2435 proto_item_append_text(parent
, " (Code=%s/Data=0x%04x)", val_to_str(attribute_code
, strings_2008_1_dsp_attribute_codes
, "%u"), attribute_data
);
2439 proto_tree_add_item(tree
, hf_2008_1_dsp_value_data
, tvb
, 4, option_length
, ENC_NA
);
2441 /* call the next dissector */
2442 tvb_set_reported_length(tvb
, option_length
+ 4);
2443 dissector_try_uint(dsp_option_dissectors
, (attribute_code
<< 16) | attribute_data
, tvb
, pinfo
, tree
);
2445 return option_length
+ 4;
2449 * Security.1: Permission. This is the base type for
2450 * permissions, and supports extension.
2452 static int dissect_2008_16_security_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2458 /* Permission Type */
2464 offset
= read_c2(tvb
, offset
, &value
, &val_len
);
2465 has_length
= (bool)(value
% 2);
2466 pi
= proto_tree_add_uint(tree
, hf_security_1_permission_type
, tvb
, start
, offset
- start
, value
);
2467 validate_c2(pinfo
, pi
, value
, val_len
);
2479 offset
= read_c2(tvb
, offset
, &value
, &value_len
);
2481 pi
= proto_tree_add_uint(tree
, hf_security_1_length
, tvb
, start
, offset
- start
, value
);
2482 validate_c2(pinfo
, pi
, value
, value_len
);
2486 proto_tree_add_item(tree
, hf_security_1_data
, tvb
, offset
, length
, ENC_NA
);
2493 * Security.2: Permission Request.
2495 static int dissect_2008_16_security_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2506 offset
= read_c2(tvb
, offset
, &value
, &length
);
2508 pi
= proto_tree_add_uint(tree
, hf_security_2_count
, tvb
, start
, offset
- start
, value
);
2509 validate_c2(pinfo
, pi
, value
, length
);
2514 proto_item
*ti
= proto_tree_add_item(tree
, hf_security_2_permission
, tvb
, offset
, -1, ENC_NA
);
2515 proto_tree
*subtree
= proto_item_add_subtree(ti
, ett_security_2_permission
);
2516 tvbuff_t
*next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
2517 int len
= dissect_2008_16_security_1(next_tvb
, pinfo
, subtree
, NULL
);
2518 proto_item_set_len(ti
, len
);
2526 * Security.3.1: Base Credential Format.
2527 * Returns: dof_2008_16_security_3_1
2529 static int dissect_2008_16_security_3_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2534 dof_2008_16_security_3_1
*return_data
= (dof_2008_16_security_3_1
*)data
;
2536 /* Credential Type */
2542 offset
= read_c2(tvb
, offset
, &value
, &length
);
2543 pi
= proto_tree_add_uint(tree
, hf_security_3_1_credential_type
, tvb
, start
, offset
- start
, value
);
2544 validate_c2(pinfo
, pi
, value
, length
);
2548 stage
= tvb_get_uint8(tvb
, offset
);
2549 ti
= proto_tree_add_item(tree
, hf_security_3_1_stage
, tvb
, offset
, 1, ENC_NA
);
2553 expert_add_info(pinfo
, ti
, &ei_security_3_1_invalid_stage
);
2555 /* Security Node Identifier */
2558 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2559 proto_tree
*subtree
;
2560 ti
= proto_tree_add_item(tree
, hf_security_3_1_security_node_identifier
, tvb
, offset
, 0, ENC_NA
);
2561 subtree
= proto_item_add_subtree(ti
, ett_security_3_1_security_node_identifier
);
2562 block_length
= dissect_2008_16_security_8(start
, pinfo
, subtree
, NULL
);
2563 proto_item_set_len(ti
, block_length
);
2564 offset
+= block_length
;
2565 tvb_set_reported_length(start
, block_length
);
2567 return_data
->identity
= start
;
2574 * Security.3.2: Identity Resolution.
2576 int dissect_2008_16_security_3_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2581 /* Credential Type */
2587 offset
= read_c2(tvb
, offset
, &value
, &val_len
);
2588 pi
= proto_tree_add_uint(tree
, hf_security_3_2_credential_type
, tvb
, start
, offset
- start
, value
);
2589 validate_c2(pinfo
, pi
, value
, val_len
);
2593 proto_tree_add_item(tree
, hf_security_3_2_stage
, tvb
, offset
, 1, ENC_NA
);
2602 offset
= read_c2(tvb
, offset
, &value
, &value_len
);
2604 pi
= proto_tree_add_uint(tree
, hf_security_3_2_length
, tvb
, start
, offset
- start
, value
);
2605 validate_c2(pinfo
, pi
, value
, value_len
);
2609 proto_tree_add_item(tree
, hf_security_3_2_public_data
, tvb
, offset
, length
, ENC_NA
);
2616 * Security.4: Key Request. Returns: dof_2008_16_security_4
2618 static int dissect_2008_16_security_4(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2622 dof_2008_16_security_4
*return_data
= (dof_2008_16_security_4
*)data
;
2624 flag
= tvb_get_uint8(tvb
, offset
);
2626 expert_add_info(pinfo
, tree
, &ei_security_4_invalid_bit
);
2628 proto_tree_add_item(tree
, hf_security_4_l
, tvb
, offset
, 1, ENC_NA
);
2629 proto_tree_add_item(tree
, hf_security_4_f
, tvb
, offset
, 1, ENC_NA
);
2630 proto_tree_add_item(tree
, hf_security_4_ln
, tvb
, offset
, 1, ENC_NA
);
2635 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2637 proto_tree
*subtree
;
2638 dof_2008_16_security_3_1 return_3_1
;
2640 ti
= proto_tree_add_item(tree
, hf_security_4_identity
, tvb
, offset
, 0, ENC_NA
);
2641 subtree
= proto_item_add_subtree(ti
, ett_security_4_identity
);
2643 block_length
= dissect_2008_16_security_3_1(start
, pinfo
, subtree
, &return_3_1
);
2644 proto_item_set_len(ti
, block_length
);
2645 offset
+= block_length
;
2648 return_data
->identity
= return_3_1
.identity
;
2653 tvbuff_t
*start
= tvb_new_subset_length(tvb
, offset
, (flag
& 0x0F) + 1);
2655 return_data
->nonce
= start
;
2657 proto_tree_add_item(tree
, hf_security_4_nonce
, start
, 0, (flag
& 0x0F) + 1, ENC_NA
);
2658 offset
+= (flag
& 0x0F) + 1;
2663 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2665 proto_tree
*subtree
;
2667 ti
= proto_tree_add_item(tree
, hf_security_4_permission_set
, tvb
, offset
, 0, ENC_NA
);
2668 subtree
= proto_item_add_subtree(ti
, ett_security_4_permission_set
);
2669 block_length
= dissect_2008_16_security_2(start
, pinfo
, subtree
, NULL
);
2670 proto_item_set_len(ti
, block_length
);
2671 offset
+= block_length
;
2678 * Security.5: Key Grant.
2680 static int dissect_2008_16_security_5(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
2684 proto_tree_add_item(tree
, hf_security_5_mac
, tvb
, offset
, 32, ENC_NA
);
2687 proto_tree_add_item(tree
, hf_security_5_key
, tvb
, offset
, 32, ENC_NA
);
2694 * Security.6.1: Session Initator Block.
2695 * Returns dof_2008_16_security_6_1
2697 static int dissect_2008_16_security_6_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2701 /* Allocate the return structure. */
2702 dof_2008_16_security_6_1
*return_data
= (dof_2008_16_security_6_1
*)data
;
2704 /* Desired Duration */
2705 proto_tree_add_item(tree
, hf_security_6_1_desired_duration
, tvb
, offset
, 1, ENC_NA
);
2708 /* Desired Security Mode */
2711 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2713 proto_tree
*subtree
;
2715 ti
= proto_tree_add_item(tree
, hf_security_6_1_desired_security_mode
, tvb
, offset
, 0, ENC_NA
);
2716 subtree
= proto_item_add_subtree(ti
, ett_security_6_1_desired_security_mode
);
2718 block_length
= dissect_2008_16_security_13(start
, pinfo
, subtree
, NULL
);
2719 offset
+= block_length
;
2720 tvb_set_reported_length(start
, block_length
);
2721 proto_item_set_len(ti
, block_length
);
2725 return_data
->security_mode
= tvb_get_ntohs(start
, 1);
2726 return_data
->security_mode_data_length
= block_length
- 4;
2727 return_data
->security_mode_data
= (uint8_t *)tvb_memdup(wmem_file_scope(), start
, 4, block_length
- 4);
2731 /* Initiator Request */
2734 dof_2008_16_security_4 output
;
2735 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2737 proto_tree
*subtree
;
2739 ti
= proto_tree_add_item(tree
, hf_security_6_1_initiator_request
, tvb
, offset
, 0, ENC_NA
);
2740 subtree
= proto_item_add_subtree(ti
, ett_security_6_1_initiator_request
);
2742 block_length
= dissect_2008_16_security_4(start
, pinfo
, subtree
, &output
);
2743 proto_item_set_len(ti
, block_length
);
2744 offset
+= block_length
;
2747 return_data
->i_identity
= output
.identity
;
2748 return_data
->i_nonce
= output
.nonce
;
2756 * Security.6.2: Session Responder Block.
2757 * Returns dof_2008_16_security_6_2
2759 static int dissect_2008_16_security_6_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2762 dof_2008_16_security_6_2
*return_data
= (dof_2008_16_security_6_2
*)data
;
2764 /* Responder Request */
2767 dof_2008_16_security_4 output
;
2768 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2770 proto_tree
*subtree
;
2772 ti
= proto_tree_add_item(tree
, hf_security_6_2_responder_request
, tvb
, offset
, 0, ENC_NA
);
2773 subtree
= proto_item_add_subtree(ti
, ett_security_6_2_responder_request
);
2775 block_length
= dissect_2008_16_security_4(start
, pinfo
, subtree
, &output
);
2776 proto_item_set_len(ti
, block_length
);
2777 offset
+= block_length
;
2780 return_data
->r_identity
= output
.identity
;
2781 return_data
->r_nonce
= output
.nonce
;
2789 * Security.6.3: Authentication Response Block.
2791 static int dissect_2008_16_security_6_3(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2795 /* Granted Duration */
2796 proto_tree_add_item(tree
, hf_security_6_3_granted_duration
, tvb
, offset
, 1, ENC_NA
);
2799 /* Session Security Scope */
2802 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2804 proto_tree
*subtree
;
2806 ti
= proto_tree_add_item(tree
, hf_security_6_3_session_security_scope
, tvb
, offset
, 0, ENC_NA
);
2807 subtree
= proto_item_add_subtree(ti
, ett_security_6_3_session_security_scope
);
2808 block_length
= dissect_2008_16_security_10(start
, pinfo
, subtree
, NULL
);
2809 proto_item_set_len(ti
, block_length
);
2810 offset
+= block_length
;
2813 /* Initiator Validation */
2816 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2818 proto_tree
*subtree
;
2820 ti
= proto_tree_add_item(tree
, hf_security_6_3_initiator_validation
, tvb
, offset
, 0, ENC_NA
);
2821 subtree
= proto_item_add_subtree(ti
, ett_security_6_3_initiator_validation
);
2822 block_length
= dissect_2008_16_security_11(start
, pinfo
, subtree
, NULL
);
2823 proto_item_set_len(ti
, block_length
);
2824 offset
+= block_length
;
2827 /* Responder Validation */
2830 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
2832 proto_tree
*subtree
;
2834 ti
= proto_tree_add_item(tree
, hf_security_6_3_responder_validation
, tvb
, offset
, 0, ENC_NA
);
2835 subtree
= proto_item_add_subtree(ti
, ett_security_6_3_responder_validation
);
2836 block_length
= dissect_2008_16_security_11(start
, pinfo
, subtree
, NULL
);
2837 proto_item_set_len(ti
, block_length
);
2838 offset
+= block_length
;
2845 * Security.7: Security Domain.
2847 static int dissect_2008_16_security_7(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2849 /* Parse the base type. */
2852 block_length
= dissect_2009_11_type_4(tvb
, pinfo
, tree
, NULL
);
2854 return block_length
;
2858 * Security.8: Security Node Identifier.
2860 static int dissect_2008_16_security_8(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2862 /* Parse the base type. */
2865 block_length
= dissect_2009_11_type_4(tvb
, pinfo
, tree
, NULL
);
2867 return block_length
;
2871 * Security.9: Security Mode of Operation Initialization.
2872 * If the packet info has knowledge of the active security mode
2873 * of operation then this datagram can be further decoded.
2875 static int dissect_2008_16_security_9(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2886 offset
= read_c2(tvb
, offset
, &value
, &value_len
);
2888 pi
= proto_tree_add_uint(tree
, hf_security_9_length
, tvb
, start
, offset
- start
, value
);
2889 validate_c2(pinfo
, pi
, value
, value_len
);
2894 proto_tree_add_item(tree
, hf_security_9_initial_state
, tvb
, offset
, length
, ENC_NA
);
2902 * Security.10: Security Scope.
2904 static int dissect_2008_16_security_10(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2915 offset
= read_c2(tvb
, offset
, &value
, &length
);
2917 pi
= proto_tree_add_uint(tree
, hf_security_10_count
, tvb
, start
, offset
- start
, value
);
2918 validate_c2(pinfo
, pi
, value
, length
);
2923 const char *def
= "";
2930 offset
= read_c4(tvb
, offset
, &value
, &length
);
2935 def
= " (all scopes)";
2938 def
= " (doesn't mask)";
2941 def
= " (session scope)";
2945 pi
= proto_tree_add_uint_format_value(tree
, hf_security_10_permission_group_identifier
, tvb
, start
, offset
- start
, value
, "%u%s", value
, def
);
2946 validate_c4(pinfo
, pi
, value
, length
);
2953 * Security.11: Permission Validation.
2955 static int dissect_2008_16_security_11(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2966 offset
= read_c2(tvb
, offset
, &value
, &length
);
2968 pi
= proto_tree_add_uint(tree
, hf_security_11_count
, tvb
, start
, offset
- start
, value
);
2969 validate_c2(pinfo
, pi
, value
, length
);
2974 proto_item
*ti
= proto_tree_add_item(tree
, hf_security_11_permission_security_scope
, tvb
, offset
, -1, ENC_NA
);
2975 proto_tree
*subtree
= proto_item_add_subtree(ti
, ett_security_11_permission_security_scope
);
2976 tvbuff_t
*next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
2978 len
= dissect_2008_16_security_12(next_tvb
, pinfo
, subtree
, NULL
);
2979 proto_item_set_len(ti
, len
);
2987 * Security.12: Permission Security Scope.
2989 static int dissect_2008_16_security_12(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
2992 uint8_t m
= tvb_get_uint8(tvb
, offset
) >> 6;
2993 uint16_t count
= tvb_get_uint8(tvb
, offset
) & 0x3F;
2996 proto_tree_add_item(tree
, hf_security_12_m
, tvb
, offset
, 1, ENC_NA
);
2997 proto_tree_add_item(tree
, hf_security_12_count
, tvb
, offset
, 1, ENC_NA
);
3005 const char *def
= "";
3010 offset
= read_c4(tvb
, offset
, &value
, &length
);
3015 def
= " (all scopes)";
3018 def
= " (doesn't mask)";
3021 def
= " (session scope)";
3025 pi
= proto_tree_add_uint_format_value(tree
, hf_security_12_permission_group_identifier
, tvb
, start
, offset
- start
, value
, "%u%s", value
, def
);
3026 validate_c4(pinfo
, pi
, value
, length
);
3033 * Security.13: Security Mode of Operation Negotiation.
3035 static int dissect_2008_16_security_13(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
3037 /* Parse the base type. */
3039 uint16_t attribute_data
;
3041 /* TODO: Skipping this first byte means that no other encryption modes can be supported. */
3042 attribute_data
= tvb_get_ntohs(tvb
, 1);
3043 if (attribute_data
< 0x6000 || attribute_data
>= 0x7000)
3044 expert_add_info(pinfo
, tree
, &ei_security_13_out_of_range
);
3046 block_length
= dissect_2008_1_dsp_1(tvb
, pinfo
, tree
);
3048 return block_length
;
3052 * Dissects a buffer that is pointing at an OID.
3053 * Adds a subtree with detailed information about the fields of
3055 * returns the length of the OID,
3056 * and appends text to the tree (really a tree item) that is
3057 * passed in that gives a more accurate description of the OID.
3058 * Note that the tree already shows the bytes of the OID, so if
3059 * no additional information can be displayed then it should not
3062 * If 'tree' is NULL then just return the length.
3064 // NOLINTNEXTLINE(misc-no-recursion)
3065 static int dissect_2009_11_type_4(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
3068 int start_offset
= 0;
3072 uint8_t oid_len_byte
;
3073 proto_tree
*oid_tree
= tree
;
3074 proto_tree
*header_tree
;
3078 ti
= proto_tree_get_parent(tree
);
3079 proto_item_set_text(ti
, "Object ID: %s", dof_oid_create_standard_string(tvb_reported_length(tvb
), tvb_get_ptr(tvb
, 0, tvb_reported_length(tvb
)), pinfo
));
3082 offset
= read_c4(tvb
, offset
, &oid_class
, &oid_class_len
);
3083 ti
= proto_tree_add_uint_format(oid_tree
, hf_oid_class
, tvb
, start_offset
, offset
- start_offset
, oid_class
, "Class: %u", oid_class
);
3084 validate_c4(pinfo
, ti
, oid_class
, oid_class_len
);
3086 oid_len_byte
= tvb_get_uint8(tvb
, offset
);
3087 ti
= proto_tree_add_uint_format(oid_tree
, hf_oid_header
, tvb
,
3088 offset
, 1, oid_len_byte
, "Header: 0x%02x (%sLength=%d)", oid_len_byte
, oid_len_byte
& 0x80 ? "Attribute, " : "", oid_len_byte
& 0x3F);
3090 header_tree
= proto_item_add_subtree(ti
, ett_oid_header
);
3091 proto_tree_add_item(header_tree
, hf_oid_attribute
, tvb
, offset
, 1, ENC_NA
);
3092 proto_tree_add_item(header_tree
, hf_oid_length
, tvb
, offset
, 1, ENC_NA
);
3095 /* Validate the flag byte */
3096 if (oid_len_byte
& 0x40)
3098 /* Type.4 Malformed (bit mandated zero). */
3099 expert_add_info(pinfo
, ti
, &ei_type_4_header_zero
);
3102 if ((oid_len_byte
& 0x3F) > 0)
3104 /* Add the raw data. */
3105 proto_tree_add_item(oid_tree
, hf_oid_data
, tvb
, offset
, oid_len_byte
& 0x3F, ENC_NA
);
3106 offset
+= oid_len_byte
& 0x3F;
3109 /* Check for attributes */
3110 if (oid_len_byte
& 0x80)
3112 /* Read attributes, adding them to oid_tree. */
3117 tvbuff_t
*packet
= tvb_new_subset_remaining(tvb
, offset
);
3118 proto_tree
*attribute_tree
;
3119 int attribute_length
;
3121 ti
= proto_tree_add_item(tree
, hf_oid_all_attribute_data
, tvb
, offset
, -1, ENC_NA
);
3122 attribute_tree
= proto_item_add_subtree(ti
, ett_oid_attribute
);
3123 flag
= tvb_get_uint8(tvb
, offset
);
3124 increment_dissection_depth(pinfo
);
3125 attribute_length
= dissect_2009_11_type_5(packet
, pinfo
, attribute_tree
);
3126 decrement_dissection_depth(pinfo
);
3127 proto_item_set_len(ti
, (const int)attribute_length
);
3128 offset
+= attribute_length
;
3130 while (flag
& 0x80);
3135 ti
= proto_tree_get_parent(tree
);
3136 proto_item_set_len(ti
, offset
- start_offset
);
3139 /* TODO: Add the description. */
3140 /* proto_item_append_text( oid_tree, ": %s", "TODO" ); */
3145 * Dissects a buffer that is pointing at an attribute.
3146 * Adds a subtree with detailed information about the fields of
3148 * returns the new offset,
3149 * and appends text to the tree (really a tree item) that is
3150 * passed in that gives a more accurate description of the
3152 * Note that the tree already shows the bytes of the OID, so if
3153 * no additional information can be displayed then it should not
3156 * If 'tree' is NULL then just return the length.
3158 // NOLINTNEXTLINE(misc-no-recursion)
3159 static int dissect_2009_11_type_5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
3163 uint8_t attribute_id_byte
;
3164 uint8_t attribute_length_byte
;
3165 proto_tree
*oid_tree
= tree
;
3166 proto_tree
*header_tree
;
3168 attribute_id_byte
= tvb_get_uint8(tvb
, offset
);
3169 ti
= proto_tree_add_uint_format(oid_tree
, hf_oid_attribute_header
, tvb
,
3170 offset
, 1, attribute_id_byte
, "Header: 0x%02x (%sLength=%d)", attribute_id_byte
, attribute_id_byte
& 0x80 ? "Attribute, " : "", attribute_id_byte
& 0x3F);
3172 header_tree
= proto_item_add_subtree(ti
, ett_oid_attribute_header
);
3173 proto_tree_add_item(header_tree
, hf_oid_attribute_attribute
, tvb
, offset
, 1, ENC_NA
);
3174 proto_tree_add_item(header_tree
, hf_oid_attribute_id
, tvb
, offset
, 1, ENC_NA
);
3177 attribute_length_byte
= tvb_get_uint8(tvb
, offset
);
3178 proto_tree_add_item(oid_tree
, hf_oid_attribute_length
, tvb
, offset
, 1, ENC_NA
);
3181 switch (attribute_id_byte
& 0x7F)
3184 /* TODO: Check length */
3185 proto_tree_add_item(oid_tree
, hf_oid_attribute_data
, tvb
, offset
, attribute_length_byte
, ENC_NA
);
3186 offset
+= attribute_length_byte
;
3192 tvbuff_t
*packet
= tvb_new_subset_length(tvb
, offset
, attribute_length_byte
);
3193 proto_tree
*attribute_tree
;
3195 ti
= proto_tree_add_item(tree
, hf_oid_attribute_oid
, tvb
, offset
, -1, ENC_NA
);
3196 attribute_tree
= proto_item_add_subtree(ti
, ett_oid_attribute_oid
);
3197 increment_dissection_depth(pinfo
);
3198 offset
+= dissect_2009_11_type_4(packet
, pinfo
, attribute_tree
, NULL
);
3199 decrement_dissection_depth(pinfo
);
3204 proto_tree_add_item(oid_tree
, hf_oid_attribute_data
, tvb
, offset
, attribute_length_byte
, ENC_NA
);
3205 offset
+= attribute_length_byte
;
3212 /* Transport Session ID */
3213 static dof_globals globals
;
3215 /* Static Methods. */
3217 static dof_packet_data
* create_packet_data(packet_info
*pinfo
);
3218 static int dof_dissect_dnp_length(tvbuff_t
*tvb
, packet_info
*pinfo
, uint8_t version
, int *offset
);
3219 #define VALIDHEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
3222 /* Configuration structures. These tables allow for security
3223 * mode templates, security keys, and secrets to be configured.
3226 static bool decrypt_all_packets
;
3227 static bool track_operations
;
3228 static unsigned track_operations_window
= 5;
3229 static uint32_t next_dof_frame
= 1;
3231 /* Structure for security mode of operation templates. */
3232 typedef struct _secmode_field_t
{
3238 static secmode_field_t
*secmode_list
;
3239 static unsigned num_secmode_list
;
3241 /* Structure for security keys. */
3242 typedef struct _seckey_field_t
{
3246 /* Structure for secrets (for identities) */
3247 typedef struct _identsecret_field_t
{
3251 } identsecret_field_t
;
3253 typedef struct _tcp_ignore_data
3257 struct _tcp_ignore_data
*next
;
3260 typedef struct _tcp_dof_packet_ref
3262 /* A single TCP frame can contain multiple packets. We must
3263 * be able to keep track of them all.
3265 dof_api_data api_data
;
3267 uint16_t start_offset
;
3268 dof_transport_packet transport_packet
;
3269 struct _tcp_dof_packet_ref
*next
;
3270 } tcp_dof_packet_ref
;
3273 * This structure exists for TCP packets and allows matching Wireshark frames to
3276 typedef struct _tcp_packet_data
3278 /* Packets are ignored based on the starting TCP SEQ (sequence of first byte). */
3279 tcp_ignore_data
*from_client_ignore_list
;
3280 tcp_ignore_data
*from_server_ignore_list
;
3282 /* DPS packet structures contained within a TCP frame. */
3283 tcp_dof_packet_ref
*dof_packets
;
3287 * This structure exists for UDP sessions and allows for advanced stream handling
3288 * and matching Wireshark frames to DPS packets.
3290 typedef struct _udp_session_data
3292 /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3293 dof_transport_session common
;
3295 /* For the associated TCP conversation, this tracks the client and server
3301 /* This structure exists for TCP sessions and allows for advanced stream handling
3302 * and matching Wireshark frames to DPS packets.
3304 typedef struct _tcp_session_data
3306 /* This must be the first structure, as a pointer to this type is stored in each DPS packet. */
3307 dof_transport_session common
;
3309 /* This flag is used to determine that an entire TCP session is NOT OpenDOF.
3310 * Because of TCP/IP negotiation in the DPS it is easy to confuse arbitrary
3311 * protocols as OpenDOF. Once it is determined that it is not then this
3312 * flag can be set, which will turn off all the OpenDOF dissectors.
3316 /* For the associated TCP conversation, this tracks the client and server
3319 ws_node client
, server
;
3321 /* TCP sequence numbers, used to detect retransmissions. These are only valid
3322 * during the first pass through the packets.
3324 uint32_t from_client_seq
;
3325 uint32_t from_server_seq
;
3329 static dof_security_data global_security
;
3331 static uint8_t count_hex_bytes(char *str
);
3333 /* Global DPS data structures for security keys. */
3334 static seckey_field_t
*seckey_list
;
3335 static unsigned num_seckey_list
;
3337 /* Global DPS data structures for identity secrets. */
3338 static identsecret_field_t
*identsecret_list
;
3339 static unsigned num_identsecret_list
;
3342 /* Callbacks for Configuration security templates. */
3343 UAT_CSTRING_CB_DEF(secmode_list
, domain
, secmode_field_t
)
3344 UAT_CSTRING_CB_DEF(secmode_list
, identity
, secmode_field_t
)
3345 UAT_CSTRING_CB_DEF(secmode_list
, kek
, secmode_field_t
)
3347 static void secmode_list_post_update_cb(void)
3351 static bool secmode_list_update_cb(void *r
, char **err
)
3353 secmode_field_t
*rec
= (secmode_field_t
*)r
;
3358 size
= (uint32_t)strlen(rec
->domain
);
3359 if (!VALIDHEX(rec
->domain
[0]) && !dof_oid_create_internal(rec
->domain
, &size
, NULL
))
3361 *err
= g_strdup("Invalid domain [must be valid OID].");
3364 else if (!count_hex_bytes(rec
->domain
))
3366 *err
= g_strdup("Invalid domain [must be valid OID].");
3370 size
= (uint32_t)strlen(rec
->identity
);
3371 if (!VALIDHEX(rec
->identity
[0]) && !dof_oid_create_internal(rec
->identity
, &size
, NULL
))
3373 *err
= g_strdup("Invalid identity [must be valid OID].");
3376 else if (!count_hex_bytes(rec
->identity
))
3378 *err
= g_strdup("Invalid identity [must be valid OID].");
3382 if (count_hex_bytes(rec
->kek
) != 32)
3384 *err
= g_strdup("Invalid KEK [must be 32 byte key].");
3390 static void* secmode_list_copy_cb(void *n
, const void *o
, size_t siz _U_
)
3392 secmode_field_t
*new_rec
= (secmode_field_t
*)n
;
3393 const secmode_field_t
*old_rec
= (const secmode_field_t
*)o
;
3395 new_rec
->domain
= g_strdup(old_rec
->domain
);
3396 new_rec
->identity
= g_strdup(old_rec
->identity
);
3397 new_rec
->kek
= g_strdup(old_rec
->kek
);
3402 static void secmode_list_free_cb(void *r
)
3404 secmode_field_t
*rec
= (secmode_field_t
*)r
;
3406 g_free(rec
->domain
);
3407 g_free(rec
->identity
);
3412 /* Callbacks for security keys. */
3413 UAT_CSTRING_CB_DEF(seckey_list
, key
, seckey_field_t
)
3415 static void seckey_list_post_update_cb(void)
3419 static bool seckey_list_update_cb(void *r
, char **err
)
3421 seckey_field_t
*rec
= (seckey_field_t
*)r
;
3424 if (count_hex_bytes(rec
->key
) != 32)
3426 *err
= g_strdup("Invalid secret [must be 32 bytes].");
3432 static void* seckey_list_copy_cb(void *n
, const void *o
, size_t siz _U_
)
3434 seckey_field_t
*new_rec
= (seckey_field_t
*)n
;
3435 const seckey_field_t
*old_rec
= (const seckey_field_t
*)o
;
3437 new_rec
->key
= g_strdup(old_rec
->key
);
3442 static void seckey_list_free_cb(void *r
)
3444 seckey_field_t
*rec
= (seckey_field_t
*)r
;
3450 /* Callbacks for identity secrets. */
3451 UAT_CSTRING_CB_DEF(identsecret_list
, domain
, identsecret_field_t
)
3452 UAT_CSTRING_CB_DEF(identsecret_list
, identity
, identsecret_field_t
)
3453 UAT_CSTRING_CB_DEF(identsecret_list
, secret
, identsecret_field_t
)
3455 static void identsecret_list_post_update_cb(void)
3459 static bool identsecret_list_update_cb(void *r
, char **err
)
3461 identsecret_field_t
*rec
= (identsecret_field_t
*)r
;
3466 size
= (uint32_t)strlen(rec
->domain
);
3467 if (!VALIDHEX(rec
->domain
[0]))
3469 if (dof_oid_create_internal(rec
->domain
, &size
, NULL
))
3471 *err
= g_strdup("Invalid domain [must be valid OID].");
3475 else if (!count_hex_bytes(rec
->domain
))
3477 *err
= g_strdup("Invalid domain [must be valid OID].");
3481 size
= (uint32_t)strlen(rec
->identity
);
3482 if (!VALIDHEX(rec
->identity
[0]))
3484 if (dof_oid_create_internal(rec
->identity
, &size
, NULL
))
3486 *err
= g_strdup("Invalid identity [must be valid OID].");
3490 else if (!count_hex_bytes(rec
->identity
))
3492 *err
= g_strdup("Invalid identity [must be valid OID].");
3496 if (count_hex_bytes(rec
->secret
) != 32)
3498 *err
= g_strdup("Invalid secret [must be 32 byte key].");
3504 static void* identsecret_list_copy_cb(void *n
, const void *o
, size_t siz _U_
)
3506 identsecret_field_t
*new_rec
= (identsecret_field_t
*)n
;
3507 const identsecret_field_t
*old_rec
= (const identsecret_field_t
*)o
;
3509 new_rec
->domain
= g_strdup(old_rec
->domain
);
3510 new_rec
->identity
= g_strdup(old_rec
->identity
);
3511 new_rec
->secret
= g_strdup(old_rec
->secret
);
3516 static void identsecret_list_free_cb(void *r
)
3518 identsecret_field_t
*rec
= (identsecret_field_t
*)r
;
3520 g_free(rec
->domain
);
3521 g_free(rec
->identity
);
3522 g_free(rec
->secret
);
3525 static void init_addr_port_tables(void);
3527 /* The IP transport protocols need to assign SENDER ID based on the
3528 * transport address. This requires a hash lookup from address/port to ID.
3531 static GHashTable
*addr_port_to_id
;
3533 typedef struct _addr_port_key
3539 static unsigned addr_port_key_hash_fn(const void *key
)
3541 const addr_port_key
*addr_key
= (const addr_port_key
*)key
;
3542 unsigned result
= 0;
3543 unsigned port_as_int
= addr_key
->port
;
3544 unsigned type_as_int
= addr_key
->addr
.type
;
3546 result
+= g_int_hash(&port_as_int
);
3547 result
+= g_int_hash(&type_as_int
);
3550 unsigned hash
= 5381;
3551 const uint8_t *str
= (const uint8_t *)addr_key
->addr
.data
;
3554 for (i
= 0; i
< addr_key
->addr
.len
; i
++)
3555 hash
= ((hash
<< 5) + hash
) + str
[i
]; /* hash * 33 + c */
3563 static gboolean
addr_port_key_equal_fn(const void *key1
, const void *key2
)
3565 const addr_port_key
*addr_key_ptr1
= (const addr_port_key
*)key1
;
3566 const addr_port_key
*addr_key_ptr2
= (const addr_port_key
*)key2
;
3568 if (addr_key_ptr1
->port
!= addr_key_ptr2
->port
)
3571 return addresses_equal(&addr_key_ptr1
->addr
, &addr_key_ptr2
->addr
);
3574 static void addr_port_key_free_fn(void *key
)
3576 addr_port_key
*addr_port
= (addr_port_key
*)key
;
3577 g_free(addr_port
->addr
.priv
);
3581 static void init_addr_port_tables(void)
3583 /* This routine is called each time the system is reset (file load, capture)
3584 * and so it should take care of freeing any of our persistent stuff.
3586 if (addr_port_to_id
!= NULL
)
3588 /* Clear it out. Note that this calls the destroy functions for each element. */
3589 g_hash_table_destroy(addr_port_to_id
);
3590 addr_port_to_id
= NULL
;
3593 /* The value is not allocated, so does not need to be freed. */
3594 addr_port_to_id
= g_hash_table_new_full(addr_port_key_hash_fn
, addr_port_key_equal_fn
, addr_port_key_free_fn
, NULL
);
3597 static unsigned next_addr_port_id
= 1;
3599 #define EP_COPY_ADDRESS(to, from) { \
3600 uint8_t *EP_COPY_ADDRESS_data; \
3601 (to)->type = (from)->type; \
3602 (to)->len = (from)->len; \
3603 EP_COPY_ADDRESS_data = (uint8_t*) wmem_alloc(wmem_packet_scope(),(from)->len); \
3604 memcpy(EP_COPY_ADDRESS_data, (from)->data, (from)->len); \
3605 (to)->priv = EP_COPY_ADDRESS_data; \
3606 (to)->data = (to)->priv; \
3609 /* Return the transport ID, a unique number for each transport sender.
3611 static unsigned assign_addr_port_id(address
*addr
, uint16_t port
)
3613 addr_port_key lookup_key
;
3617 /* ensure the address contains actual data */
3618 if (addr
->type
== AT_NONE
)
3621 /* Build a (non-allocated) key to do the lookup. */
3623 EP_COPY_ADDRESS(&lookup_key
.addr
, addr
);
3624 lookup_key
.port
= port
;
3626 value
= GPOINTER_TO_UINT(g_hash_table_lookup(addr_port_to_id
, &lookup_key
));
3629 /* We found a match. */
3633 /* No match, need to add a key. */
3634 key
= g_new0(addr_port_key
, 1);
3635 copy_address(&key
->addr
, addr
);
3638 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
3639 g_hash_table_insert(addr_port_to_id
, key
, GUINT_TO_POINTER(next_addr_port_id
));
3640 return next_addr_port_id
++;
3643 /* Wireshark Configuration Dialog Routines*/
3645 static bool identsecret_chk_cb(void *r _U_
, const char *p _U_
, unsigned len _U_
, const void *u1 _U_
, const void *u2 _U_
, char **err _U_
)
3649 char* line
= ep_strndup(p
, len
);
3650 unsigned num_protos
, i
;
3653 ascii_strdown_inplace(line
);
3655 protos
= ep_strsplit(line
, ":", 0);
3657 for (num_protos
= 0; protos
[num_protos
]; num_protos
++)
3658 g_strstrip(protos
[num_protos
]);
3662 *err
= g_strdup("No protocols given");
3666 for (i
= 0; i
< num_protos
; i
++)
3668 if (!find_dissector(protos
[i
]))
3670 *err
= g_strdup("Could not find dissector for: '%s'", protos
[i
]);
3678 /* Utility Methods */
3680 static uint8_t count_hex_bytes(char *str
)
3684 while (str
!= NULL
&& *str
!= '\0' && *str
!= '#')
3686 if (!g_ascii_isxdigit(*str
))
3692 if (!g_ascii_isxdigit(str
[1]))
3702 static void parse_hex_string(char *str
, uint8_t **ptr
, uint8_t *len
)
3705 *len
= count_hex_bytes(str
);
3706 *ptr
= (uint8_t *)g_malloc0(*len
);
3712 if (!g_ascii_isxdigit(*str
))
3718 high
= ws_xton(str
[0]);
3719 low
= ws_xton(str
[1]);
3720 (*ptr
)[j
++] = (high
<< 4) | low
;
3725 /* OID and IID Parsing */
3727 static const uint8_t OALString_HexChar
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
3729 #define IS_PRINTABLE(c) ( ((uint8_t)c) >= 32U && ((uint8_t)c) < 127U )
3730 #define IS_ESCAPED(c) ( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
3731 #define DOFOBJECTID_MAX_CLASS_SIZE (4)
3732 #define MAX_OID_DATA_SIZE (63)
3733 #define OID_DATA_LEN_MASK (MAX_OID_DATA_SIZE)
3735 #define ObjectID_DataToStringLength( data, dataSize ) ObjectID_DataToString( (data), (dataSize), NULL )
3736 #define OALString_HexDigitToChar(c) (OALString_HexChar[(c)])
3737 #define DOFObjectIDAttribute_IsValid( attribute ) ((attribute).id < DOFOBJECTIDATTRIBUTE_INVALID)
3738 #define DOFObjectIDAttribute_GetValueSize( attribute ) ((attribute).dataSize)
3739 #define DOFObjectIDAttribute_GetValue( attribute ) ((attribute).data)
3740 #define DOFObjectIDAttribute_GetType( attribute ) ((DOFObjectIDAttributeType)(attribute).id)
3742 typedef enum DOFObjectIDAttributeID_t
3745 * Provider attribute. This attribute identifies an object as being
3746 * provided by a specific service provider. The associated data must
3747 * be an object identifier.
3749 DOFOBJECTIDATTRIBUTE_PROVIDER
= 0,
3752 * Session attribute. This attribute associates the object with the
3753 * specified session. The associated data must be exactly 16 bytes long.
3755 DOFOBJECTIDATTRIBUTE_SESSION
= 1,
3758 * Group attribute. This attribute is normally used in association
3759 * with the BROADCAST object identifier. It defines a target that is
3760 * a multicast group in the DOF network (as opposed to the transport).
3761 * The associated data must be an object identifier.
3763 DOFOBJECTIDATTRIBUTE_GROUP
= 2,
3766 * Invalid, used to signal that an error has occurred.
3768 DOFOBJECTIDATTRIBUTE_INVALID
= 128
3769 } DOFObjectIDAttributeType
;
3770 typedef uint32_t DOFObjectIDClass
;
3772 typedef struct DOFObjectID_t
3775 uint16_t len
; /* Actual length of oid's wire representation. Max is 32707: 4 + 1 + 63 + (127 * 257). */
3776 uint8_t oid
[]; /* Extends beyond end of this defined structure, so oid MUST be last structure member! */
3779 typedef DOFObjectID_t
*DOFObjectID
;
3781 typedef uint8_t DOFObjectIDAttributeDataSize
;
3783 typedef struct DOFObjectIDAttribute_t
3785 uint8_t id
; /**< Attribute Identifier. Intentionally defined as uint8 for size, but holds all valid values for DOFObjectIDAttributeType. **/
3786 DOFObjectIDAttributeDataSize dataSize
; /**< Size of the attribute data. **/
3787 const uint8_t *data
; /**< Attribute data. **/
3788 } DOFObjectIDAttribute
;
3791 * Read variable-length value from buffer.
3793 * @param maxSize [in] Maximum size of value to be read
3794 * @param bufLength [in,out] Input: size of buffer, output: size of value in buffer
3795 * @param buffer [in] Actual buffer
3796 * @return Uncompressed value if buffer size is valid (or 0 on error)
3798 static uint32_t OALMarshal_UncompressValue(uint8_t maxSize
, uint32_t *bufLength
, const uint8_t *buffer
)
3802 uint8_t size
= maxSize
;
3805 switch (buffer
[0] >> 6)
3817 /* Three/Four Bytes */
3832 if (size
> *bufLength
)
3835 value
= buffer
[used
++] & mask
;
3837 value
= (value
<< 8) | buffer
[used
++];
3843 static uint32_t DOFObjectID_GetClassSize(DOFObjectID self
)
3845 uint32_t size
= self
->len
;
3847 (void)OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE
, &size
, self
->oid
);
3852 static uint32_t DOFObjectID_GetDataSize(const DOFObjectID self
)
3854 return ((*((const uint8_t *)self
->oid
+ DOFObjectID_GetClassSize(self
))) & OID_DATA_LEN_MASK
);
3857 static uint32_t ObjectID_DataToString(const uint8_t *data
, uint32_t dataSize
, char *pBuf
)
3859 uint32_t len
= 0, i
, nonprintable
, escaped
;
3861 /* Determine if the data is printable... */
3862 for (i
= 0, nonprintable
= 0, escaped
= 0; i
< dataSize
; i
++)
3864 if (!IS_PRINTABLE(data
[i
]))
3866 else if (IS_ESCAPED(data
[i
]))
3869 if (nonprintable
== 0)
3871 /* Printable, so copy as a string, escaping where necessary. */
3874 for (i
= 0; i
< dataSize
; i
++)
3876 if (IS_ESCAPED(data
[i
]))
3879 pBuf
[len
++] = data
[i
];
3882 pBuf
[len
++] = data
[i
];
3887 len
= dataSize
+ escaped
; /* Count escaped characters twice. */
3892 /* Non-printable, so format as hex string. */
3896 for (i
= 0; i
< dataSize
; i
++)
3898 pBuf
[len
++] = OALString_HexDigitToChar((data
[i
] >> 4) & 0x0F);
3899 pBuf
[len
++] = OALString_HexDigitToChar((data
[i
]) & 0x0F);
3905 len
= dataSize
* 2 + 2;
3911 static const uint8_t* DOFObjectID_GetData(const DOFObjectID self
)
3913 if (DOFObjectID_GetDataSize(self
) > 0)
3914 return (const uint8_t *)self
->oid
+ DOFObjectID_GetClassSize(self
) + 1; /* 1: length of length byte. */
3919 static uint32_t DOFObjectID_GetIDClass(const DOFObjectID self
)
3923 return OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE
, &size
, self
->oid
);
3926 static bool DOFObjectID_HasAttributes(const DOFObjectID self
)
3931 /* bit 7: next attribute flag. */
3932 return (bool)(((*(const uint8_t *)((const uint8_t *)(self
->oid
) + DOFObjectID_GetClassSize(self
))) & 0x80) != 0);
3935 static uint8_t DOFObjectID_GetBaseSize(const DOFObjectID oid
)
3937 return DOFObjectID_GetClassSize(oid
) + 1 + DOFObjectID_GetDataSize(oid
);
3940 static uint8_t DOFObjectID_GetAttributeCount(const DOFObjectID self
)
3944 /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-126. So max count fits in uint8. */
3945 if (self
&& DOFObjectID_HasAttributes(self
))
3947 const uint8_t *pNextAttribute
= (const uint8_t *)self
->oid
+ DOFObjectID_GetBaseSize(self
);
3950 while (*pNextAttribute
& 0x80) /* bit 7: next attribute present flag. */
3953 pNextAttribute
+= (2 + *((const uint8_t *)pNextAttribute
+ 1)); /* 2: attribute marshalling overhead. */
3960 static DOFObjectIDAttribute
DOFObjectID_GetAttributeAtIndex(const DOFObjectID self
, uint8_t attribute_index
)
3962 DOFObjectIDAttribute retAttributeDescriptor
= { DOFOBJECTIDATTRIBUTE_INVALID
, 0, NULL
};
3964 /* Note: No OID can duplicate an attribute ID. Legal attribute IDs can be from 0-127. So max index fits in uint8. */
3965 if (self
&& attribute_index
< DOFOBJECTIDATTRIBUTE_INVALID
)
3967 if (DOFObjectID_HasAttributes(self
))
3970 const uint8_t *pNextAttribute
= (const uint8_t *)self
->oid
+ DOFObjectID_GetBaseSize(self
);
3972 while (1) /* Parse through the N Attributes. */
3974 if (attribute_index
== count
++)
3976 retAttributeDescriptor
.id
= *pNextAttribute
& 0x7F;
3977 retAttributeDescriptor
.dataSize
= (DOFObjectIDAttributeDataSize
) * ((const uint8_t *)pNextAttribute
+ 1);
3978 retAttributeDescriptor
.data
= (const uint8_t *)pNextAttribute
+ 2; /* 2: attr marshalling overhead. */
3979 break; /* Success. */
3981 if (!(*pNextAttribute
& 0x80))
3982 break; /* Fail: no more Attributes */
3983 pNextAttribute
+= (2 + *((const uint8_t *)pNextAttribute
+ 1));
3988 return retAttributeDescriptor
;
3991 static void DOFObjectID_Destroy(DOFObjectID self _U_
)
3993 /* Ephemeral memory doesn't need to be freed. */
3996 static void DOFObjectID_InitStruct(DOFObjectID newObjID
, uint32_t dataLen
)
3998 newObjID
->refCount
= 1;
3999 newObjID
->len
= dataLen
;
4002 static DOFObjectID
DOFObjectID_Create_Unmarshal(uint32_t *length
, const uint8_t *buffer
)
4004 uint32_t len
= *length
;
4006 /* Legal OID described at buffer must have at least 2 bytes. */
4007 if (buffer
&& len
>= 2)
4009 uint32_t classSize
= len
;
4010 uint32_t classv
= OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE
, &classSize
, buffer
);
4012 /* Legal OID described at buffer must have its class representation be correctly compressed. */
4015 uint32_t computedSize
;
4017 /* Above call won't return 3 because DOFOBJECTID_MAX_CLASS_SIZE (4) was passed in. */
4018 computedSize
= classSize
+ 1; /* 1: length of length byte. */
4019 /* Legal OID described at buffer must have enough bytes to describe its OID class. */
4020 if (len
>= computedSize
)
4022 uint8_t lenByte
= buffer
[classSize
];
4024 /* Legal OID described at buffer must have its length byte bit 6 be 0. */
4025 if (!(lenByte
& 0x40))
4028 uint8_t dataLen
= lenByte
& OID_DATA_LEN_MASK
;
4030 /* Legal broadcast OID described at buffer must have no base data, though it can have attribute(s)*/
4031 if ((classv
== 0) && (dataLen
> 0))
4033 computedSize
+= dataLen
;
4034 hasAttr
= lenByte
& 0x80; /* Valid OID base; check attributes. */
4037 /* Legal OID described at buffer must have enough bytes to hold each new found attribute. */
4038 if (len
>= computedSize
+ 2) /* 2: attribute marshalling overhead. */
4040 hasAttr
= buffer
[computedSize
] & 0x80; /* bit 7: next attribute present flag. */
4041 computedSize
+= (2 + buffer
[computedSize
+ 1]);
4046 /* Legal OID described at buffer must have enough buffer bytes, final check. */
4047 if (len
>= computedSize
)
4049 DOFObjectID newObjID
= (DOFObjectID
)wmem_alloc0(wmem_packet_scope(), sizeof(DOFObjectID_t
) + (sizeof(uint8_t) * (computedSize
+ 1)));
4050 /* Adds space for null-terminator, just in case. */
4052 *length
= computedSize
;
4055 DOFObjectID_InitStruct(newObjID
, computedSize
);
4056 memcpy(newObjID
->oid
, buffer
, computedSize
);
4057 newObjID
->oid
[computedSize
] = 0;
4058 return newObjID
; /* Success. */
4060 /* buffer describes valid OID, but due to alloc failure we cannot return the newly created OID*/
4068 /* buffer does not describe a valid OID, but do not log a message. The caller may have called us to find out if the
4069 buffer does or does not obey the rules of a valid OID. He learns that by our NULL return. */
4076 static DOFObjectID
DOFObjectID_Create_Bytes(uint32_t bufferSize
, const uint8_t *pOIDBuffer
)
4078 uint32_t len
= bufferSize
;
4079 DOFObjectID rval
= DOFObjectID_Create_Unmarshal(&len
, pOIDBuffer
);
4083 if (len
!= bufferSize
)
4085 DOFObjectID_Destroy(rval
);
4092 // NOLINTNEXTLINE(misc-no-recursion)
4093 static uint32_t ObjectID_ToStringLength(const DOFObjectID oid
, packet_info
*pinfo
)
4097 /* Note: All these string functions can be exercised with objectid_test.c, which outputs the string to console. */
4098 len
= 7 /* [{xx}: and trailing ] */ + ObjectID_DataToStringLength(DOFObjectID_GetData(oid
),
4099 DOFObjectID_GetDataSize(oid
));
4100 if (DOFObjectID_GetIDClass(oid
) & 0xFF000000)
4101 len
+= 6; /* Six more hex digits. */
4102 else if (DOFObjectID_GetIDClass(oid
) & 0xFF0000)
4103 len
+= 4; /* Four more hex digits. */
4104 else if (DOFObjectID_GetIDClass(oid
) & 0xFF00)
4105 len
+= 2; /* Two more hex digits. */
4106 increment_dissection_depth(pinfo
);
4107 /* Handle Attributes, if any. */
4108 if (DOFObjectID_HasAttributes(oid
))
4110 uint8_t i
; /* Max attribute count is under uint8. */
4111 uint8_t attributeCount
= DOFObjectID_GetAttributeCount(oid
);
4113 len
+= 2; /* surrounding ( ) */
4114 for (i
= 0; i
< attributeCount
; i
++)
4116 DOFObjectID embedOID
;
4117 DOFObjectIDAttribute avpDescriptor
= DOFObjectID_GetAttributeAtIndex(oid
, i
);
4119 if (!DOFObjectIDAttribute_IsValid(avpDescriptor
))
4120 break; /* Done with Attributes. If here, some error took place. */
4124 len
+= 5; /* {xx}: */
4125 /* Handle embedded Object IDs. */
4126 embedOID
= DOFObjectID_Create_Bytes(DOFObjectIDAttribute_GetValueSize(avpDescriptor
),
4127 DOFObjectIDAttribute_GetValue(avpDescriptor
));
4130 len
+= ObjectID_ToStringLength(embedOID
, pinfo
); /* Recurse to compute string rep length of found OID. */
4131 DOFObjectID_Destroy(embedOID
);
4136 len
+= ObjectID_DataToStringLength(DOFObjectIDAttribute_GetValue(avpDescriptor
),
4137 DOFObjectIDAttribute_GetValueSize(avpDescriptor
));
4141 decrement_dissection_depth(pinfo
);
4146 static uint32_t InterfaceID_ToString(const uint8_t *iid
, char *pBuf
)
4149 unsigned iid_len
= iid
[0] & 0x03;
4158 pBuf
[len
++] = OALString_HexDigitToChar((iid
[0] >> 6) & 0x0F);
4159 pBuf
[len
++] = OALString_HexDigitToChar((iid
[0] >> 2) & 0x0F);
4166 for (i
= 0; i
< iid_len
; i
++)
4168 pBuf
[len
++] = OALString_HexDigitToChar((iid
[i
+ 1] >> 4) & 0x0F);
4169 pBuf
[len
++] = OALString_HexDigitToChar(iid
[i
+ 1] & 0x0F);
4178 // NOLINTNEXTLINE(misc-no-recursion)
4179 static uint32_t ObjectID_ToString(const DOFObjectID oid
, char *pBuf
, packet_info
*pinfo
)
4181 DOFObjectIDClass oidClass
;
4187 oidClass
= DOFObjectID_GetIDClass(oid
);
4188 if (oidClass
& 0xFF000000)
4190 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 28) & 0x0F);
4191 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 24) & 0x0F);
4193 if (oidClass
& 0xFFFF0000)
4195 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 20) & 0x0F);
4196 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 16) & 0x0F);
4198 if (oidClass
& 0xFFFFFF00)
4200 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 12) & 0x0F);
4201 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 8) & 0x0F);
4203 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
>> 4) & 0x0F);
4204 pBuf
[len
++] = OALString_HexDigitToChar((oidClass
) & 0x0F);
4208 len
+= ObjectID_DataToString(DOFObjectID_GetData(oid
), DOFObjectID_GetDataSize(oid
), &pBuf
[len
]);
4209 /* Handle Attributes, if any. */
4210 if (DOFObjectID_HasAttributes(oid
))
4213 uint8_t attributeCount
= DOFObjectID_GetAttributeCount(oid
);
4216 for (i
= 0; i
< attributeCount
; i
++)
4218 DOFObjectID embedOID
;
4219 DOFObjectIDAttribute avpDescriptor
= DOFObjectID_GetAttributeAtIndex(oid
, i
);
4221 if (!DOFObjectIDAttribute_IsValid(avpDescriptor
))
4222 break; /* Done with Attributes. If here, some error took place. */
4227 pBuf
[len
++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor
) >> 4) & 0x0F);
4228 pBuf
[len
++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor
)) & 0x0F);
4232 /* Handle embedded Object IDs. */
4233 embedOID
= DOFObjectID_Create_Bytes(DOFObjectIDAttribute_GetValueSize(avpDescriptor
),
4234 DOFObjectIDAttribute_GetValue(avpDescriptor
));
4237 increment_dissection_depth(pinfo
);
4238 len
+= ObjectID_ToString(embedOID
, &pBuf
[len
], pinfo
); /* Recurse to output string rep of found OID. */
4239 decrement_dissection_depth(pinfo
);
4240 DOFObjectID_Destroy(embedOID
);
4245 len
+= ObjectID_DataToString(DOFObjectIDAttribute_GetValue(avpDescriptor
),
4246 DOFObjectIDAttribute_GetValueSize(avpDescriptor
), &pBuf
[len
]);
4256 static const char* dof_iid_create_standard_string(uint32_t bufferSize
, const uint8_t *pIIDBuffer
)
4259 unsigned len
= 9 + (bufferSize
- 1) * 2; /* Alias is always [{AA}:{01234567}] */
4261 pRetval
= (char *)wmem_alloc(wmem_packet_scope(), len
+ 1);
4264 InterfaceID_ToString(pIIDBuffer
, pRetval
);
4271 static const char* dof_oid_create_standard_string(uint32_t bufferSize
, const uint8_t *pOIDBuffer
, packet_info
*pinfo
)
4275 uint32_t len
= bufferSize
;
4277 oid
= DOFObjectID_Create_Unmarshal(&len
, pOIDBuffer
);
4279 return "Illegal OID";
4281 len
= ObjectID_ToStringLength(oid
, pinfo
);
4282 /* Use PCRMem_Alloc() and not DOFMem_Alloc() because app caller will be freeing memory with PCRMem_Destroy(). */
4283 pRetval
= (char *)wmem_alloc(wmem_packet_scope(), len
+ 1);
4286 ObjectID_ToString(oid
, pRetval
, pinfo
);
4299 uint32_t currOidPos
;
4300 uint32_t currBufferPos
;
4304 /* Operations on OID string */
4305 #define PARSECTX_PEEK_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos] )
4306 #define PARSECTX_PEEK_NEXT_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos+1] )
4307 #define PARSECTX_READ_CHAR_OID(ctx) ( (ctx)->oid[(ctx)->currOidPos++] )
4308 #define PARSECTX_GET_CURRENT_POS_OID(ctx) ( (ctx)->oid+(ctx)->currOidPos )
4309 #define PARSECTX_STEP_OID(ctx, count)((ctx)->currOidPos+=(count))
4311 /* Operations on DOFObjectID buffer */
4312 #define PARSECTX_GET_CURRENT_POS_BUF(ctx)( ((ctx)->buffer)? (ctx)->buffer+(ctx)->currBufferPos: NULL )
4313 #define PARSECTX_STEP_BUF(ctx, count)( (ctx)->currBufferPos+=(count))
4314 #define PARSECTX_WRITE_AT_POS_BUF(ctx, pos, value) do{ if((ctx)->buffer) *(pos) = (value); } while(0)
4315 #define PARSECTX_OR_AT_POS_BUF(ctx, pos, value) do{ if((ctx)->buffer) *(pos) |= (value); } while(0)
4316 #define PARSECTX_WRITE_BUF(ctx, value)( ((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (value): (ctx)->currBufferPos++ )
4317 #define PARSECTX_CHECK_LEN(ctx, len) (((ctx)->buffer)? (((ctx)->currBufferPos+len <= (ctx)->buffLen)? 0: 1): 0)
4319 /* Operation to read from OID straight to buffer */
4320 #define PARSECTX_WRITE_BUF_FROM_OID(ctx) (((ctx)->buffer)? (ctx)->buffer[(ctx)->currBufferPos++] = (ctx)->oid[(ctx)->currOidPos]: ((ctx)->currBufferPos++),((ctx)->currOidPos++))
4322 #define IS_DIGIT(c) (((c) >= '0' && (c) <= '9'))
4323 #define DIGIT2VALUE(c) (c-48)
4325 #define HEX2VALUE(c) ( (IS_DIGIT(c))? DIGIT2VALUE(c) : ((c) >= 'A' && (c) <= 'F')? (c-55): (c-87) )
4326 #define VALIDHEXSEP(c) ( (c) == ' ' || (c) == ':' || (c) == '-' )
4327 #define VALIDHEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )
4328 #define VALIDHEXBYTE(s) ( VALIDHEX((s)[0]) && VALIDHEX((s)[1]) )
4329 #define VALIDNUMBER(c) ((c) >= '0' && (c) <= '9')
4331 #define VALIDASCIICHAR(c) (((uint8_t)c) >= 32 && ((uint8_t)c) <= 126 )
4333 #define IS_ESCAPED(c) ( (c) == '(' || (c) == ')' || (c) == '[' || (c) == ']' || (c) == '{' || (c) == '}' || (c) == '\\' || (c) == '|' )
4335 static uint8_t parseFormatOID(struct parseCtx
*ctx
);
4337 static uint8_t parseHexField(struct parseCtx
*ctx
)
4339 /* Hex fields start with { and end with } can contain space, dash and colon*/
4340 if (PARSECTX_READ_CHAR_OID(ctx
) == '{' && PARSECTX_PEEK_CHAR_OID(ctx
) != '}')
4342 while (PARSECTX_PEEK_CHAR_OID(ctx
) != '}')
4344 if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx
)))
4346 if (PARSECTX_CHECK_LEN(ctx
, 1) == 0)
4348 PARSECTX_WRITE_BUF(ctx
, HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx
)) << 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx
)));
4349 PARSECTX_STEP_OID(ctx
, 2);
4351 if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx
)))
4353 if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx
) == '}')
4355 /* no separator after byte block */
4358 PARSECTX_STEP_OID(ctx
, 1);
4371 PARSECTX_STEP_OID(ctx
, 1);
4377 static uint8_t parseStringField(struct parseCtx
*ctx
)
4379 /* Copy into buffer until end or */
4380 while (ctx
->currOidPos
< (ctx
->oidLen
- 1))
4382 char curr
= PARSECTX_PEEK_CHAR_OID(ctx
);
4383 if (curr
== ']' || curr
== '(')
4385 break; /* End of string field */
4387 else if (curr
== '\\')
4389 /* Handle escaped char */
4390 PARSECTX_STEP_OID(ctx
, 1);
4391 if (!IS_ESCAPED(PARSECTX_PEEK_CHAR_OID(ctx
)) || PARSECTX_CHECK_LEN(ctx
, 1) != 0)
4393 PARSECTX_WRITE_BUF_FROM_OID(ctx
);
4397 if (VALIDASCIICHAR(curr
) && PARSECTX_CHECK_LEN(ctx
, 1) == 0)
4398 PARSECTX_WRITE_BUF_FROM_OID(ctx
);
4406 static uint8_t OALMarshal_GetCompressedValueSize(uint8_t maxSize
, uint32_t value
)
4408 uint8_t lenbytes
= (1 + (value
> 0x7F) + (value
> 0x3FFF));
4414 static uint32_t OALMarshal_CompressValue(uint8_t maxSize
, uint32_t value
, uint32_t bufLength
, uint8_t *buffer
)
4416 uint8_t lenSize
= OALMarshal_GetCompressedValueSize(maxSize
, value
);
4418 if (bufLength
< lenSize
)
4423 *(buffer
++) = (uint8_t)((value
>> 24) & 0x3F) | 0xC0;
4424 *(buffer
++) = (uint8_t)((value
>> 16) & 0xFF);
4425 *(buffer
++) = (uint8_t)((value
>> 8) & 0xFF);
4426 *(buffer
++) = (uint8_t)(value
& 0xFF);
4430 *(buffer
++) = (uint8_t)((value
>> 16) & 0x3F) | 0xC0;
4431 *(buffer
++) = (uint8_t)((value
>> 8) & 0xFF);
4432 *(buffer
++) = (uint8_t)(value
& 0xFF);
4438 *(buffer
++) = (uint8_t)((value
>> 8) & 0x7F) | 0x80;
4442 *(buffer
++) = (uint8_t)((value
>> 8) & 0x3F) | 0x80;
4444 *(buffer
++) = (uint8_t)(value
& 0xFF);
4448 *(buffer
++) = (uint8_t)(value
& 0x7F);
4452 /* Invalid computed size! */
4458 static uint8_t parseOIDClass(struct parseCtx
*ctx
)
4460 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '{' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx
) != '}')
4463 uint8_t classSize
= 0;
4464 uint32_t oidClass
= 0;
4465 PARSECTX_STEP_OID(ctx
, 1);
4466 while (PARSECTX_PEEK_CHAR_OID(ctx
) != '}')
4468 if (VALIDHEXBYTE(PARSECTX_GET_CURRENT_POS_OID(ctx
)))
4471 oidClass
+= (HEX2VALUE(PARSECTX_PEEK_CHAR_OID(ctx
)) << 4 | HEX2VALUE(PARSECTX_PEEK_NEXT_CHAR_OID(ctx
)));
4472 PARSECTX_STEP_OID(ctx
, 2);
4474 if (VALIDHEXSEP(PARSECTX_PEEK_CHAR_OID(ctx
)))
4476 if (PARSECTX_PEEK_NEXT_CHAR_OID(ctx
) == '}')
4478 /* no separator after byte block */
4481 PARSECTX_STEP_OID(ctx
, 1);
4489 PARSECTX_STEP_OID(ctx
, 1);
4491 classSize
= OALMarshal_GetCompressedValueSize(4, oidClass
);
4492 if (PARSECTX_CHECK_LEN(ctx
, classSize
) == 0)
4494 if (PARSECTX_GET_CURRENT_POS_BUF(ctx
))
4495 classSize
= OALMarshal_CompressValue(4, oidClass
, classSize
, PARSECTX_GET_CURRENT_POS_BUF(ctx
));
4497 PARSECTX_STEP_BUF(ctx
, classSize
);
4505 uint8_t classSize
= 0;
4506 uint32_t oidClass
= 0;
4507 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx
)))
4510 oidClass
+= DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx
));
4511 PARSECTX_STEP_OID(ctx
, 1);
4514 classSize
= OALMarshal_GetCompressedValueSize(4, oidClass
);
4515 if (PARSECTX_CHECK_LEN(ctx
, classSize
) == 0)
4517 if (PARSECTX_GET_CURRENT_POS_BUF(ctx
))
4518 classSize
= OALMarshal_CompressValue(4, oidClass
, classSize
, PARSECTX_GET_CURRENT_POS_BUF(ctx
));
4520 PARSECTX_STEP_BUF(ctx
, classSize
);
4527 static uint8_t parseAttributeID(struct parseCtx
*ctx
)
4529 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '{')
4531 return parseHexField(ctx
);
4536 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx
)))
4539 avpid
+= DIGIT2VALUE(PARSECTX_PEEK_CHAR_OID(ctx
));
4540 PARSECTX_STEP_OID(ctx
, 1);
4543 if (PARSECTX_CHECK_LEN(ctx
, 1) == 0)
4545 PARSECTX_WRITE_BUF(ctx
, avpid
);
4552 // NOLINTNEXTLINE(misc-no-recursion)
4553 static uint8_t parseAttributeData(struct parseCtx
*ctx
)
4557 DISSECTOR_ASSERT(ctx
->depth
< prefs
.gui_max_tree_depth
);
4558 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '[')
4560 ret
= parseFormatOID(ctx
);
4562 else if (PARSECTX_PEEK_CHAR_OID(ctx
) == '{')
4564 ret
= parseHexField(ctx
);
4568 ret
= parseStringField(ctx
);
4574 // NOLINTNEXTLINE(misc-no-recursion)
4575 static uint8_t parseAttribute(struct parseCtx
*ctx
)
4577 if (parseAttributeID(ctx
) == 0)
4579 /* separated by ':' */
4580 if (PARSECTX_READ_CHAR_OID(ctx
) == ':' && PARSECTX_CHECK_LEN(ctx
, 1) == 0)
4582 uint8_t *length
= PARSECTX_GET_CURRENT_POS_BUF(ctx
);
4586 PARSECTX_STEP_BUF(ctx
, 1);
4588 if (parseAttributeData(ctx
) == 0)
4590 PARSECTX_WRITE_AT_POS_BUF(ctx
, length
, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx
) - (length
+ 1)));
4598 // NOLINTNEXTLINE(misc-no-recursion)
4599 static uint8_t parseAttributes(struct parseCtx
*ctx
)
4601 /* AVPs surrounded by '(' ')' but needs at least an avp */
4602 if (PARSECTX_READ_CHAR_OID(ctx
) == '(' && PARSECTX_PEEK_CHAR_OID(ctx
) != ')')
4604 while (PARSECTX_PEEK_CHAR_OID(ctx
) != ')')
4606 uint8_t *avpID
= PARSECTX_GET_CURRENT_POS_BUF(ctx
);
4610 if (parseAttribute(ctx
) != 0)
4613 /* multiple separated by '|' */
4614 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '|' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx
) != ')')
4616 PARSECTX_OR_AT_POS_BUF(ctx
, avpID
, 0x80); /* set that there is a next attribute */
4617 PARSECTX_STEP_OID(ctx
, 1);
4620 PARSECTX_STEP_OID(ctx
, 1);
4626 // NOLINTNEXTLINE(misc-no-recursion)
4627 static uint8_t parseFormatOID(struct parseCtx
*ctx
)
4629 /* oid must start with '[' */
4630 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '[')
4632 PARSECTX_STEP_OID(ctx
, 1);
4634 if (parseOIDClass(ctx
) == 0)
4636 /* separated by ':' */
4637 if (PARSECTX_READ_CHAR_OID(ctx
) == ':' && PARSECTX_CHECK_LEN(ctx
, 1) == 0)
4639 uint8_t *length
= PARSECTX_GET_CURRENT_POS_BUF(ctx
);
4640 PARSECTX_STEP_BUF(ctx
, 1);
4643 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '{')
4646 if (parseHexField(ctx
) != 0)
4652 if (parseStringField(ctx
) != 0)
4659 PARSECTX_WRITE_AT_POS_BUF(ctx
, length
, (uint8_t)(PARSECTX_GET_CURRENT_POS_BUF(ctx
) - (length
+ 1)));
4661 /* Check if attributes exist */
4662 if (PARSECTX_PEEK_CHAR_OID(ctx
) == '(')
4664 PARSECTX_OR_AT_POS_BUF(ctx
, length
, 0x80); /* set that there are attributes */
4665 if (parseAttributes(ctx
) != 0)
4670 if (PARSECTX_READ_CHAR_OID(ctx
) == ']')
4680 static uint8_t dof_oid_create_internal(const char *oid
, uint32_t *size
, uint8_t *buffer
)
4682 struct parseCtx ctx
= {0};
4685 ctx
.buffer
= buffer
;
4691 ctx
.buffLen
= (*size
);
4692 ctx
.oidLen
= (uint32_t)strlen(oid
);
4693 if (PARSECTX_PEEK_CHAR_OID(&ctx
) == '[')
4696 if (parseFormatOID(&ctx
) == 0)
4698 (*size
) = ctx
.currBufferPos
;
4702 else if (PARSECTX_PEEK_CHAR_OID(&ctx
) == '{')
4705 if (parseHexField(&ctx
) == 0)
4707 (*size
) = ctx
.currBufferPos
;
4717 static void dof_oid_new_standard_string(const char *data
, uint32_t *rsize
, uint8_t **oid
)
4724 /* Call parseInternal to find out how big the buffer needs to be. */
4725 err
= dof_oid_create_internal(data
, &size
, NULL
);
4729 /* Create the DOFObjectID using the size that was just computed. */
4730 *oid
= (uint8_t *)g_malloc(size
+ 1); /* Adds space for null-terminator, just in case. */
4734 /* Now that the size is computed and the DOFObjectID is created, call parseInternal again to fill the oid buffer. */
4735 err
= dof_oid_create_internal(data
, &size
, *oid
);
4752 /* Binary Parsing Support */
4755 * Read a compressed 32-bit quantity (PDU Type.3).
4756 * Since the value is variable length, the new offset is
4757 * returned. The value can also be returned, along with the size, although
4758 * NULL is allowed for those parameters.
4760 static int read_c4(tvbuff_t
*tvb
, int offset
, uint32_t *v
, int *L
)
4764 uint8_t b
= tvb_get_uint8(tvb
, offset
++);
4767 if ((b
& 0x80) == 0)
4772 else if ((b
& 0x40) == 0)
4784 for (i
= 1; i
< len
; i
++)
4785 val
= (val
<< 8) | tvb_get_uint8(tvb
, offset
++);
4795 * Validate PDU Type.3
4796 * Validaes the encoding.
4797 * Add Expert Info if format invalid
4798 * This also validates Spec Type.3.1.
4800 static void validate_c4(packet_info
*pinfo
, proto_item
*pi
, uint32_t val
, int len
)
4802 if (len
> 1 && val
< 0x80)
4804 /* SPEC Type.3.1 Violation. */
4805 expert_add_info_format(pinfo
, pi
, &ei_c2_c3_c4_format
, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4808 if (len
> 2 && val
< 0x4000)
4810 /* SPEC Type.3.1 Violation. */
4811 expert_add_info_format(pinfo
, pi
, &ei_c2_c3_c4_format
, "DOF Violation: Type.3.1: Compressed 32-bit Compression Mandatory.");
4816 * Reads a compressed 24-bit quantity (PDU Type.2).
4817 * Since the value is variable length, the new offset is
4819 * The value can also be returned, along with the size, although
4820 * NULL is allowed for those parameters.
4822 static int read_c3(tvbuff_t
*tvb
, int offset
, uint32_t *v
, int *L
)
4826 uint8_t b
= tvb_get_uint8(tvb
, offset
++);
4829 if ((b
& 0x80) == 0)
4834 else if ((b
& 0x40) == 0)
4846 for (i
= 1; i
< len
; i
++)
4847 val
= (val
<< 8) | tvb_get_uint8(tvb
, offset
++);
4857 * Validate PDU Type.2
4858 * Validaes the encoding.
4859 * Adds Expert Info if format invalid
4860 * This also validates Spec Type.2.1.
4862 static void validate_c3(packet_info
*pinfo
, proto_item
*pi
, uint32_t val
, int len
)
4864 if (len
> 1 && val
< 0x80)
4866 /* SPEC Type.2.1 Violation. */
4867 expert_add_info_format(pinfo
, pi
, &ei_c2_c3_c4_format
, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory." );
4870 if (len
> 2 && val
< 0x4000)
4872 /* SPEC Type.2.1 Violation. */
4873 expert_add_info_format(pinfo
, pi
, &ei_c2_c3_c4_format
, "DOF Violation: Type.2.1: Compressed 24-bit Compression Mandatory.");
4878 * Reads a compressed 16-bit quantity (PDU Type.1).
4879 * Since the value is variable length, the new offset is
4880 * returned. The value can also be returned, along with the size, although
4881 * NULL is allowed for those parameters.
4883 static int read_c2(tvbuff_t
*tvb
, int offset
, uint16_t *v
, int *L
)
4886 uint8_t b
= tvb_get_uint8(tvb
, offset
++);
4890 val
= (b
<< 8) | tvb_get_uint8(tvb
, offset
++);
4907 * Validates PDU Type.1
4908 * Validaes the encoding.
4909 * Adds Expert Info if format invalid
4910 * This also validates Spec Type.1.1.
4912 static void validate_c2(packet_info
*pinfo
, proto_item
*pi
, uint16_t val
, int len
)
4914 if (len
> 1 && val
< 0x80)
4916 /* SPEC Type.1.1 Violation. */
4917 expert_add_info_format(pinfo
, pi
, &ei_c2_c3_c4_format
, "DOF Violation: Type.1.1: Compressed 16-bit Compression Mandatory." );
4922 * Given a packet data, and assuming that all of the prerequisite information is known,
4923 * assign a SID ID to the packet if not already assigned.
4924 * A SID ID is the *possibility* of a unique SID, but until the SID is learned the
4925 * association is not made. Further, multiple SID ID may end up referring to the
4926 * same SID, in which case the assignment must be repaired.
4928 static void assign_sid_id(dof_api_data
*api_data
)
4930 node_key_to_sid_id_key lookup_key
;
4931 node_key_to_sid_id_key
*key
;
4932 dof_session_data
*session
;
4933 dof_packet_data
*packet
;
4936 /* Validate input. These represent dissector misuse, not decoding problems. */
4937 /* TODO: Diagnostic/programmer message. */
4938 if (!api_data
|| !api_data
->packet
|| !api_data
->session
)
4941 session
= api_data
->session
;
4942 packet
= (dof_packet_data
*)api_data
->packet
;
4945 /* Check if the sender_sid_id is already assigned, if so we are done. */
4946 if (!packet
->sender_sid_id
)
4948 /* Build a (non-allocated) key to do the lookup. */
4949 lookup_key
.transport_id
= api_data
->transport_session
->transport_id
;
4950 lookup_key
.transport_node_id
= api_data
->transport_packet
->sender_id
;
4951 lookup_key
.dof_id
= session
->dof_id
;
4952 lookup_key
.dof_node_id
= packet
->sender_id
;
4953 lookup_key
.dof_session_id
= session
->session_id
;
4955 value
= GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id
, &lookup_key
));
4958 void *sid_id_key
= GUINT_TO_POINTER(value
);
4961 /* We found a match. */
4962 packet
->sender_sid_id
= value
;
4964 /* If we know the SID, we must get it now. */
4965 sid_buffer
= g_hash_table_lookup(sid_id_to_sid_buffer
, sid_id_key
);
4968 /* We found a match. */
4969 packet
->sender_sid
= (dof_2009_1_pdu_19_sid
)sid_buffer
;
4974 /* No match, need to add a key. */
4975 key
= g_new0(node_key_to_sid_id_key
, 1);
4976 memcpy(key
, &lookup_key
, sizeof(node_key_to_sid_id_key
));
4978 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
4979 g_hash_table_insert(node_key_to_sid_id
, key
, GUINT_TO_POINTER(dpp_next_sid_id
));
4980 packet
->sender_sid_id
= dpp_next_sid_id
++;
4984 /* Check if the receiver_sid_id is already assigned, if so we are done. */
4985 if (!packet
->receiver_sid_id
)
4987 /* Build a (non-allocated) key to do the lookup. */
4988 lookup_key
.transport_id
= api_data
->transport_session
->transport_id
;
4989 lookup_key
.transport_node_id
= api_data
->transport_packet
->receiver_id
;
4990 lookup_key
.dof_id
= session
->dof_id
;
4991 lookup_key
.dof_node_id
= packet
->receiver_id
;
4992 lookup_key
.dof_session_id
= session
->session_id
;
4994 value
= GPOINTER_TO_UINT(g_hash_table_lookup(node_key_to_sid_id
, &lookup_key
));
4997 void *sid_id_key
= GUINT_TO_POINTER(value
);
5000 /* We found a match. */
5001 packet
->receiver_sid_id
= value
;
5003 /* If we know the SID, we must get it now. */
5004 sid_buffer
= g_hash_table_lookup(sid_id_to_sid_buffer
, sid_id_key
);
5007 /* We found a match. */
5008 packet
->receiver_sid
= (dof_2009_1_pdu_19_sid
)sid_buffer
;
5013 /* No match, need to add a key. */
5014 key
= g_new0(node_key_to_sid_id_key
, 1);
5015 memcpy(key
, &lookup_key
, sizeof(node_key_to_sid_id_key
));
5017 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5018 g_hash_table_insert(node_key_to_sid_id
, key
, GUINT_TO_POINTER(dpp_next_sid_id
));
5019 packet
->receiver_sid_id
= dpp_next_sid_id
++;
5026 * Declare that the sender of the packet is known to have a SID
5027 * that is identified by the specified buffer. There are a few
5029 * 1. The sid of the sender is already assigned. This is a NOP.
5030 * 2. The sid has never been seen. This associates the SID with the sender SID ID.
5031 * 3. The sid has been seen, and matches the SID ID of the sender. This just sets the sid field.
5032 * 4. The sid has been seen, but with a different SID ID than ours. Patch up all the packets.
5034 static void learn_sender_sid(dof_api_data
*api_data
, uint8_t length
, const uint8_t *sid
)
5036 dof_packet_data
*packet
;
5037 uint8_t lookup_key
[256];
5041 /* Validate input. */
5044 /* TODO: Print error. */
5048 if (!api_data
->packet
)
5050 /* TODO: Print error. */
5054 packet
= (dof_packet_data
*)api_data
->packet
;
5055 if (!packet
->sender_sid_id
)
5058 /* Check for sender SID already known. */
5059 if (packet
->sender_sid
)
5062 /* Check for SID already known (has assigned SID ID) */
5063 /* Build a (non-allocated) key to do the lookup. */
5064 lookup_key
[0] = length
;
5065 memcpy(lookup_key
+ 1, sid
, length
);
5067 if (g_hash_table_lookup_extended(sid_buffer_to_sid_id
, &lookup_key
, (void * *)&key
, &value
))
5069 unsigned sid_id
= GPOINTER_TO_UINT(value
);
5071 /* We found a match. */
5072 if (packet
->sender_sid_id
== sid_id
)
5074 /* It matches our SID ID. Set the sid field. */
5075 packet
->sender_sid
= key
;
5080 /* There is a mis-match between SID and SID ID. We have to go through
5081 * all the packets that have SID ID (ours) and update them to SID ID (sid).
5083 unsigned sid_id_correct
= sid_id
;
5084 unsigned sid_id_incorrect
= packet
->sender_sid_id
;
5085 dof_packet_data
*ptr
= globals
.dof_packet_head
;
5089 if (ptr
->sender_sid_id
== sid_id_incorrect
)
5090 ptr
->sender_sid_id
= sid_id_correct
;
5092 if (ptr
->receiver_sid_id
== sid_id_incorrect
)
5093 ptr
->receiver_sid_id
= sid_id_correct
;
5095 if (ptr
->op
.op_sid_id
== sid_id_incorrect
)
5096 ptr
->op
.op_sid_id
= sid_id_correct
;
5098 if (ptr
->ref_op
.op_sid_id
== sid_id_incorrect
)
5099 ptr
->ref_op
.op_sid_id
= sid_id_correct
;
5108 /* The SID has never been seen. Associate with the SID ID. */
5109 key
= (dof_2009_1_pdu_19_sid
)g_malloc0(length
+ 1);
5110 memcpy(key
, lookup_key
, length
+ 1);
5112 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5113 g_hash_table_insert(sid_buffer_to_sid_id
, key
, GUINT_TO_POINTER(packet
->sender_sid_id
));
5114 g_hash_table_insert(sid_id_to_sid_buffer
, GUINT_TO_POINTER(packet
->sender_sid_id
), key
);
5116 /* NOTE: We are storing a reference to the SID in the packet data. This memory
5117 * will be freed by the dissector init routine when the SID hash table is destroyed.
5118 * Nothing else should free this SID.
5120 packet
->sender_sid
= (dof_2009_1_pdu_19_sid
)key
;
5122 /* We have learned the "correct" sid and sid_id, so we can set the sid of
5123 * any packets that have this sid_id (saves hash lookups in the future).
5126 dof_packet_data
*ptr
= globals
.dof_packet_head
;
5130 if (ptr
->sender_sid_id
== packet
->sender_sid_id
)
5131 ptr
->sender_sid
= key
;
5133 if (ptr
->receiver_sid_id
== packet
->sender_sid_id
)
5134 ptr
->receiver_sid
= key
;
5142 * Learn a SID from an explict operation. This only defines sids and sid ids.
5144 static void learn_operation_sid(dof_2009_1_pdu_20_opid
*opid
, uint8_t length
, const uint8_t *sid
)
5146 uint8_t lookup_key
[256];
5150 /* Check for sender SID already known. */
5154 /* Check for SID already known (has assigned SID ID) */
5155 /* Build a (non-allocated) key to do the lookup. */
5156 lookup_key
[0] = length
;
5157 memcpy(lookup_key
+ 1, sid
, length
);
5159 if (g_hash_table_lookup_extended(sid_buffer_to_sid_id
, &lookup_key
, (void * *)&key
, &value
))
5161 unsigned sid_id
= GPOINTER_TO_UINT(value
);
5163 opid
->op_sid_id
= sid_id
;
5168 /* The SID has never been seen. Associate with the SID ID. */
5169 key
= (dof_2009_1_pdu_19_sid
)g_malloc0(length
+ 1);
5170 memcpy(key
, lookup_key
, length
+ 1);
5172 /* Assign the op_sid_id. */
5173 opid
->op_sid_id
= dpp_next_sid_id
++;
5175 /* Note, this is not multithread safe, but Wireshark isn't multithreaded. */
5176 g_hash_table_insert(sid_buffer_to_sid_id
, key
, GUINT_TO_POINTER(opid
->op_sid_id
));
5177 g_hash_table_insert(sid_id_to_sid_buffer
, GUINT_TO_POINTER(opid
->op_sid_id
), key
);
5179 /* NOTE: We are storing a reference to the SID in the packet data. This memory
5180 * will be freed by the dissector init routine when the SID hash table is destroyed.
5181 * Nothing else should free this SID.
5183 opid
->op_sid
= (dof_2009_1_pdu_19_sid
)key
;
5186 static void generateMac(gcry_cipher_hd_t cipher_state
, uint8_t *nonce
, const uint8_t *epp
, int a_len
, uint8_t *data
, int len
, uint8_t *mac
, int mac_len
)
5191 /* a_len = 1, t = mac_len, q = 4: (t-2)/2 : (q-1) -> 4B */
5192 mac
[0] = 0x43 | (((mac_len
- 2) / 2) << 3);
5193 memcpy(mac
+ 1, nonce
, 11);
5194 memset(mac
+ 12, 0, 4);
5196 mac
[15] = len
& 0xFF;
5198 gcry_cipher_encrypt(cipher_state
, mac
, 16, NULL
, 0);
5200 mac
[0] ^= (a_len
>> 8);
5204 for (cnt
= 0; cnt
< a_len
; cnt
++, i
++)
5207 gcry_cipher_encrypt(cipher_state
, mac
, 16, NULL
, 0);
5209 mac
[i
% 16] ^= epp
[cnt
];
5213 for (cnt
= 0; cnt
< len
; cnt
++, i
++)
5216 gcry_cipher_encrypt(cipher_state
, mac
, 16, NULL
, 0);
5218 mac
[i
% 16] ^= data
[cnt
];
5221 gcry_cipher_encrypt(cipher_state
, mac
, 16, NULL
, 0);
5224 static int decrypt(ccm_session_data
*session
, ccm_packet_data
*pdata
, uint8_t *nonce
, const uint8_t *epp
, int a_len
, uint8_t *data
, int len
)
5228 unsigned char ctr
[16];
5229 unsigned char encrypted_ctr
[16];
5230 unsigned char mac
[16];
5231 unsigned char computed_mac
[16];
5235 if (data
== NULL
|| len
== 0)
5238 /* Check the mac length. */
5239 if (session
->mac_len
< 4 || session
->mac_len
> 16)
5242 if (pdata
->period
== 0)
5243 ekey
= (uint8_t *)session
->cipher_data
;
5245 ekey
= (uint8_t *)g_hash_table_lookup(session
->cipher_data_table
, GUINT_TO_POINTER(pdata
->period
));
5250 /* Determine how many blocks are skipped. */
5251 #if 0 /* seems to be dead code... check this! */
5254 if ((a_len
+ 2) % 16)
5259 /* This is hard-coded for q=4. This can only change with a protocol revision.
5260 Note the value is stored as (q-1). */
5262 memcpy(ctr
+ 1, nonce
, 11);
5266 ctr
[15] = skip
; /* Preincremented below. */
5269 for (i
= 0; i
< len
- session
->mac_len
; i
++)
5276 memcpy(encrypted_ctr
, ctr
, 16);
5277 gcry_cipher_encrypt(session
->cipher_data
, encrypted_ctr
, 16, NULL
, 0);
5280 data
[i
] ^= encrypted_ctr
[i
% 16];
5283 memcpy(mac
, data
+ i
, session
->mac_len
);
5289 memcpy(encrypted_ctr
, ctr
, 16);
5290 gcry_cipher_encrypt(session
->cipher_data
, encrypted_ctr
, 16, NULL
, 0);
5292 for (i
= 0; i
< session
->mac_len
; i
++)
5293 mac
[i
] ^= encrypted_ctr
[i
];
5295 /* Now we have to generate the MAC... */
5296 generateMac(session
->cipher_data
, nonce
, epp
, a_len
, data
, (int)(len
- session
->mac_len
), computed_mac
, session
->mac_len
);
5297 if (!memcmp(mac
, computed_mac
, session
->mac_len
))
5304 /* Master Protocol Layer Handlers */
5307 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5308 * the common header fields and then passing off to the specific DPP dissector
5310 static int dissect_app_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
5312 col_clear(pinfo
->cinfo
, COL_INFO
);
5314 /* Compute the APP control information. This is the version and the flags byte.
5315 * The flags byte is either present, or is based on the version (and can be defaulted).
5321 read_c2(tvb
, 0, &app
, &app_len
);
5323 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "APP(%u)", app
);
5325 /* call the next dissector */
5326 if (dissector_try_uint_with_data(app_dissectors
, app
, tvb
, pinfo
, tree
, true, data
))
5328 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
5329 col_set_fence(pinfo
->cinfo
, COL_INFO
);
5331 return tvb_reported_length(tvb
);
5335 proto_tree_add_protocol_format(tree
, proto_2008_1_app
, tvb
, 0, app_len
,
5336 DOF_APPLICATION_PROTOCOL
", Version: %u", app
);
5344 * This dissector is handed a DPP packet of any version. It is responsible for decoding
5345 * the common header fields and then passing off to the specific DPP dissector
5347 static int dof_dissect_dpp_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
5349 dof_api_data
*api_data
= (dof_api_data
*)data
;
5350 unsigned offset
= 0;
5352 DISSECTOR_ASSERT(api_data
!= NULL
);
5354 col_clear(pinfo
->cinfo
, COL_INFO
);
5356 /* Compute the DPP control information. This is the version and the flags byte.
5357 * The flags byte is either present, or is based on the version (and can be defaulted).
5360 uint8_t header
= tvb_get_uint8(tvb
, offset
);
5361 uint8_t dpp_version
= header
& 0x7F;
5362 uint8_t dpp_flags_included
= header
& 0x80;
5364 proto_tree
* dpp_root
,*dpp_tree
;
5366 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "DPPv%u", dpp_version
);
5369 hi
= proto_tree_add_protocol_format(tree
, proto_2008_1_dpp
, tvb
, offset
, 0,
5370 DOF_PRESENTATION_PROTOCOL
" Version %u, Flags: %s", dpp_version
, dpp_flags_included
? "Included" : "Default");
5372 dpp_root
= proto_item_add_subtree(hi
, ett_2008_1_dpp
);
5374 dpp_tree
= proto_tree_add_subtree(dpp_root
, tvb
, offset
, 1, ett_2008_1_dpp_1_header
, NULL
, "Header");
5377 /* Version and Flag bit */
5378 proto_tree_add_item(dpp_tree
, hf_2008_1_dpp_1_flag
, tvb
, offset
, 1, ENC_NA
);
5379 proto_tree_add_item(dpp_tree
, hf_2008_1_dpp_1_version
, tvb
, offset
, 1, ENC_NA
);
5382 /* This may, in some cases, be the end of the packet. This is only valid in some
5383 * situations, which are checked here.
5385 if (offset
== tvb_reported_length(tvb
))
5387 /* TODO: Complete this logic. */
5389 proto_item_set_len(hi
, offset
);
5394 if (api_data
->transport_session
->is_streaming
)
5396 col_append_str(pinfo
->cinfo
, COL_INFO
, "DNP/DPP Negotiation");
5398 if (pinfo
->fd
->visited
&&
5399 api_data
->transport_session
->negotiation_required
&&
5400 ((api_data
->transport_session
->negotiation_complete_at
== 0) || (api_data
->transport_session
->negotiation_complete_at_ts
.secs
- api_data
->transport_session
->session_start_ts
.secs
> 10)))
5402 /* This is the second pass, so we can check for timeouts. */
5403 expert_add_info(pinfo
, hi
, &ei_dof_6_timeout
);
5410 /* call the next dissector */
5411 if (dissector_try_uint_with_data(dof_dpp_dissectors
, dpp_version
, tvb
, pinfo
, dpp_root
, false, data
))
5413 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
5414 col_set_fence(pinfo
->cinfo
, COL_INFO
);
5416 return tvb_reported_length(tvb
);
5424 * This dissector is handed a DNP packet of any version. It is responsible for decoding
5425 * the common header fields and then passing off to the specific DNP dissector
5427 static int dof_dissect_dnp_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, dof_api_data
*api_data
, int offset
)
5429 uint8_t header
= tvb_get_uint8(tvb
, offset
);
5430 uint8_t dnp_version
= header
& 0x7F;
5431 uint8_t dnp_flags_included
= header
& 0x80;
5432 proto_item
*main_ti
;
5433 proto_tree
* dnp_root
,*dnp_tree
;
5435 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "DNPv%u", dnp_version
);
5437 main_ti
= proto_tree_add_protocol_format(tree
, proto_2008_1_dnp
, tvb
, offset
, 0,
5438 DOF_NETWORK_PROTOCOL
" Version %u, Flags: %s", dnp_version
, dnp_flags_included
? "Included" : "Default");
5440 dnp_root
= proto_item_add_subtree(main_ti
, ett_2008_1_dnp
);
5442 dnp_tree
= proto_tree_add_subtree(dnp_root
, tvb
, offset
, 1, ett_2008_1_dnp_header
, NULL
, "Header");
5444 /* Version and Flag bit */
5445 proto_tree_add_item(dnp_tree
, hf_2008_1_dnp_1_flag
, tvb
, offset
, 1, ENC_NA
);
5446 proto_tree_add_item(dnp_tree
, hf_2008_1_dnp_1_version
, tvb
, offset
, 1, ENC_NA
);
5448 /* call the next dissector */
5449 if (dissector_try_uint_with_data(dnp_dissectors
, dnp_version
, tvb
, pinfo
, dnp_root
, false, api_data
))
5451 /* Since the transport may have additional packets in this frame, protect our work. */
5452 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
5453 col_set_fence(pinfo
->cinfo
, COL_INFO
);
5457 proto_item_set_end(main_ti
, tvb
, 1);
5459 /* During negotiation, we can move past DNP even if it is not known. */
5460 if (((header
& 0x80) == 0) && api_data
->transport_session
->negotiation_required
&& ((pinfo
->fd
->num
< api_data
->transport_session
->negotiation_complete_at
) || (api_data
->transport_session
->negotiation_complete_at
== 0)))
5462 offset
+= dof_dissect_dpp_common(tvb_new_subset_remaining(tvb
, offset
+ 1), pinfo
, tree
, api_data
);
5466 if (dnp_flags_included
&& !api_data
->transport_session
->negotiation_complete_at
)
5468 api_data
->transport_session
->negotiation_complete_at
= pinfo
->fd
->num
;
5469 api_data
->transport_session
->negotiation_complete_at_ts
= pinfo
->abs_ts
;
5476 * This dissector is called for each DPS packet. It assumes that the first layer is
5477 * DNP, but it does not know anything about versioning. Further, it only worries
5478 * about decoding DNP (DNP will decode DPP, and so on).
5480 * This routine is given the DPS packet for the first packet, but doesn't know anything
5481 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5482 * worthless for DPS.
5484 static int dissect_dof_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
5486 dof_api_data
*api_data
= (dof_api_data
*)data
;
5487 proto_tree
*dof_root
;
5488 dof_packet_data
*packet
;
5490 DISSECTOR_ASSERT(api_data
!= NULL
);
5491 DISSECTOR_ASSERT(api_data
->transport_session
!= NULL
);
5492 DISSECTOR_ASSERT(api_data
->transport_packet
!= NULL
);
5494 packet
= (dof_packet_data
*)api_data
->packet
;
5496 /* Create the packet if it doesn't exist. */
5499 api_data
->packet
= packet
= create_packet_data(pinfo
);
5500 DISSECTOR_ASSERT(packet
!= NULL
);
5502 /* TODO: This is not correct for reversed sessions. */
5503 packet
->is_sent_by_initiator
= api_data
->transport_packet
->is_sent_by_client
;
5506 /* Assign the transport sequence if it does not exist. */
5507 if (api_data
->transport_session
->transport_session_id
== 0)
5508 api_data
->transport_session
->transport_session_id
= globals
.next_transport_session
++;
5510 /* Compute the DPS information. This is a master holder for general information. */
5514 ti
= proto_tree_add_protocol_format(tree
, proto_2008_1_dof
, tvb
, 0, tvb_reported_length(tvb
), DOF_PROTOCOL_STACK
);
5515 dof_root
= proto_item_add_subtree(ti
, ett_2008_1_dof
);
5517 /* Add the general packet information. */
5519 ti
= proto_tree_add_uint(dof_root
, hf_2008_1_dof_session_transport
, tvb
, 0, 0, api_data
->transport_session
->transport_session_id
);
5520 proto_item_set_generated(ti
);
5522 ti
= proto_tree_add_boolean(dof_root
, hf_2008_1_dof_is_2_node
, tvb
, 0, 0, api_data
->transport_session
->is_2_node
);
5523 proto_item_set_generated(ti
);
5525 ti
= proto_tree_add_boolean(dof_root
, hf_2008_1_dof_is_streaming
, tvb
, 0, 0, api_data
->transport_session
->is_streaming
);
5526 proto_item_set_generated(ti
);
5528 if (api_data
->session
)
5530 ti
= proto_tree_add_uint(dof_root
, hf_2008_1_dof_session
, tvb
, 0, 0, api_data
->session
->session_id
);
5531 proto_item_set_generated(ti
);
5534 if (api_data
->secure_session
)
5536 ti
= proto_tree_add_uint_format(dof_root
, hf_2008_1_dof_session
, tvb
, 0, 0, api_data
->secure_session
->original_session_id
, "DPS Session (Non-secure): %d", api_data
->secure_session
->original_session_id
);
5537 proto_item_set_generated(ti
);
5540 ti
= proto_tree_add_uint(dof_root
, hf_2008_1_dof_frame
, tvb
, 0, 0, packet
->dof_frame
);
5541 proto_item_set_generated(ti
);
5543 ti
= proto_tree_add_boolean(dof_root
, hf_2008_1_dof_is_from_client
, tvb
, 0, 0, api_data
->transport_packet
->is_sent_by_client
);
5544 proto_item_set_generated(ti
);
5548 dof_dissect_dnp_common(tvb
, pinfo
, tree
, api_data
, 0);
5550 packet
->processed
= true;
5551 return tvb_reported_length(tvb
);
5555 * This dissector is called for each DPS packet. It assumes that the first layer is
5556 * ENP, but it does not know anything about versioning. Further, it only worries
5557 * about decoding ENP (ENP will decode EPP, and so on).
5559 * This routine is given the DPS packet for the first packet, but doesn't know anything
5560 * about DPS sessions. It may understand transport sessions, but these are surprisingly
5561 * worthless for DPS.
5563 static int dissect_tunnel_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
5565 /* The packet data is the private_data, and must exist. */
5566 tcp_dof_packet_ref
*ref
= (tcp_dof_packet_ref
*)data
;
5571 /* Compute the APP control information. This is the version and the length bytes.
5572 * The flags byte is either present, or is based on the version (and can be defaulted).
5575 uint8_t version
= tvb_get_uint8(tvb
, offset
);
5578 proto_tree
*app_root
;
5580 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "TUNv%u", version
);
5582 ti
= proto_tree_add_protocol_format(tree
, proto_2012_1_tunnel
, tvb
, offset
, 0,
5583 "DOF Tunnel Protocol, Version: %u", version
);
5585 app_root
= proto_item_add_subtree(ti
, ett_2012_1_tunnel
);
5586 proto_tree_add_item(app_root
, hf_2012_1_tunnel_1_version
, tvb
, offset
, 1, ENC_NA
);
5587 proto_tree_add_item(app_root
, hf_2012_1_tunnel_1_length
, tvb
, offset
+ 1, 2, ENC_BIG_ENDIAN
);
5589 opcode
= tvb_get_uint8(tvb
, offset
+ 3);
5592 tvbuff_t
*next_tvb
= tvb_new_subset_remaining(tvb
, offset
+ 5);
5594 dissect_dof_common(next_tvb
, pinfo
, tree
, &ref
->api_data
);
5598 return tvb_captured_length(tvb
);
5601 static int dissect_tun_app_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
5603 col_clear(pinfo
->cinfo
, COL_INFO
);
5605 /* Compute the APP control information. This is the version and the flags byte.
5606 * The flags byte is either present, or is based on the version (and can be defaulted).
5613 app
= tvb_get_uint8(tvb
, 0);
5616 col_add_fstr(pinfo
->cinfo
, COL_PROTOCOL
, "APP(%u)", app
);
5618 /* call the next dissector */
5619 if (dissector_try_uint(dof_tun_app_dissectors
, app
, tvb
, pinfo
, tree
))
5621 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
5622 col_set_fence(pinfo
->cinfo
, COL_INFO
);
5624 return tvb_captured_length(tvb
);
5628 proto_tree_add_protocol_format(tree
, proto_2012_1_tunnel
, tvb
, 0, app_len
,
5629 DOF_APPLICATION_PROTOCOL
", Version: %u", app
);
5636 /* Packet and Session Data Creation */
5638 static udp_session_data
* create_udp_session_data(packet_info
*pinfo
, conversation_t
*conversation _U_
)
5640 udp_session_data
*packet
= wmem_new0(wmem_file_scope(), udp_session_data
);
5642 /* TODO: Determine if this is valid or not. */
5643 /* WMEM_COPY_ADDRESS( wmem_file_scope(), &packet->server.address, &conversation->key_ptr->addr1 );
5644 packet->server.port = conversation->key_ptr->port1; */
5645 copy_address_wmem(wmem_file_scope(), &packet
->server
.addr
, &pinfo
->dst
);
5646 packet
->server
.port
= pinfo
->destport
;
5648 packet
->common
.transport_id
= proto_2008_1_dof_udp
;
5651 const uint8_t *addr
= (const uint8_t *)packet
->server
.addr
.data
;
5652 if ((packet
->server
.addr
.type
== AT_IPv4
) && (addr
!= NULL
) && (addr
[0] != 224))
5653 packet
->common
.is_2_node
= true;
5655 packet
->common
.is_2_node
= false;
5658 packet
->common
.is_streaming
= false;
5659 packet
->common
.session_start_ts
= pinfo
->abs_ts
;
5660 packet
->common
.negotiation_required
= false;
5661 packet
->common
.negotiation_complete_at
= 0;
5666 static tcp_session_data
* create_tcp_session_data(packet_info
*pinfo
, conversation_t
*conversation
)
5668 tcp_session_data
*packet
= wmem_new0(wmem_file_scope(), tcp_session_data
);
5670 copy_address_wmem(wmem_file_scope(), &packet
->client
.addr
, conversation_key_addr1(conversation
->key_ptr
));
5671 packet
->client
.port
= conversation_key_port1(conversation
->key_ptr
);
5672 copy_address_wmem(wmem_file_scope(), &packet
->server
.addr
, conversation_key_addr2(conversation
->key_ptr
));
5673 packet
->server
.port
= conversation_key_port2(conversation
->key_ptr
);
5675 packet
->not_dps
= false;
5677 packet
->common
.transport_id
= proto_2008_1_dof_tcp
;
5678 packet
->common
.is_2_node
= true;
5679 packet
->common
.is_streaming
= true;
5680 packet
->common
.session_start_ts
= pinfo
->abs_ts
;
5681 packet
->common
.negotiation_required
= true;
5682 packet
->common
.negotiation_complete_at
= 0;
5687 static dof_packet_data
* create_packet_data(packet_info
*pinfo
)
5689 /* Create the packet data. */
5690 dof_packet_data
*packet
= wmem_new0(wmem_file_scope(), dof_packet_data
);
5692 packet
->data_list
= wmem_list_new(wmem_file_scope());
5693 packet
->frame
= pinfo
->fd
->num
;
5694 packet
->dof_frame
= next_dof_frame
++;
5696 /* Add the packet into the list of packets. */
5697 if (!globals
.dof_packet_head
)
5699 globals
.dof_packet_head
= packet
;
5700 globals
.dof_packet_tail
= packet
;
5704 globals
.dof_packet_tail
->next
= packet
;
5705 globals
.dof_packet_tail
= packet
;
5711 /* Dissectors for Transports (UDP/TCP) */
5714 * Dissect a UDP packet. The parent protocol is UDP. No assumptions about DPS
5715 * data structures are made on input, but before calling common they must
5717 * This dissector is registered with the UDP protocol on the standard DPS port.
5718 * It will be used for anything that involves that port (source or destination).
5720 static int dissect_dof_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
5722 dof_api_data
*api_data
= (dof_api_data
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_2008_1_dof_udp
, 0);
5723 if (api_data
== NULL
)
5725 conversation_t
*conversation
;
5726 udp_session_data
*transport_session
;
5727 dof_transport_packet
*transport_packet
;
5728 /* bool mcast = false; */
5731 uint8_t* addr = (uint8_t*) pinfo->dst.data;
5732 if ( (pinfo->dst.type == AT_IPv4) && (addr != NULL) && (addr[0] != 224) )
5736 /* Register the source address as being DPS for the sender UDP port. */
5737 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, conversation_pt_to_conversation_type(pinfo
->ptype
), pinfo
->srcport
, pinfo
->destport
, NO_ADDR_B
| NO_PORT_B
);
5740 conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->src
, &pinfo
->dst
, conversation_pt_to_conversation_type(pinfo
->ptype
), pinfo
->srcport
, pinfo
->destport
, NO_ADDR2
| NO_PORT2
);
5741 conversation_set_dissector(conversation
, dof_udp_handle
);
5744 /* Find or create the conversation for this transport session. For UDP, the transport session is determined entirely by the
5745 * server port. This assumes that the first packet seen is from a client to the server.
5747 conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->dst
, &pinfo
->src
, CONVERSATION_UDP
, pinfo
->destport
, pinfo
->srcport
, NO_ADDR_B
| NO_PORT_B
);
5750 /* TODO: Determine if this is valid or not. */
5751 /*if ( conversation->key_ptr->port1 != pinfo->destport || ! addresses_equal( &conversation->key_ptr->addr1, &pinfo->dst ) )
5752 conversation = NULL; */
5756 conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->dst
, &pinfo
->src
, CONVERSATION_UDP
, pinfo
->destport
, pinfo
->srcport
, NO_ADDR2
| NO_PORT2
| CONVERSATION_TEMPLATE
);
5758 transport_session
= (udp_session_data
*)conversation_get_proto_data(conversation
, proto_2008_1_dof_udp
);
5759 if (transport_session
== NULL
)
5761 transport_session
= create_udp_session_data(pinfo
, conversation
);
5762 conversation_add_proto_data(conversation
, proto_2008_1_dof_udp
, transport_session
);
5765 /* UDP has no framing or retransmission issues, so the dof_api_data is stored directly on the frame. */
5766 api_data
= wmem_new0(wmem_file_scope(), dof_api_data
);
5767 if (api_data
== NULL
)
5770 transport_packet
= wmem_new0(wmem_file_scope(), dof_transport_packet
);
5771 if (transport_packet
== NULL
)
5774 transport_packet
->is_sent_by_client
= true;
5775 if (addresses_equal(&transport_session
->server
.addr
, &pinfo
->src
) && (transport_session
->server
.port
== pinfo
->srcport
))
5776 transport_packet
->is_sent_by_client
= false;
5778 transport_packet
->sender_id
= assign_addr_port_id(&pinfo
->src
, pinfo
->srcport
);
5779 transport_packet
->receiver_id
= assign_addr_port_id(&pinfo
->dst
, pinfo
->destport
);
5781 api_data
->transport_session
= &transport_session
->common
;
5782 api_data
->transport_packet
= transport_packet
;
5783 p_add_proto_data(wmem_file_scope(), pinfo
, proto_2008_1_dof_udp
, 0, api_data
);
5786 return dissect_dof_common(tvb
, pinfo
, tree
, api_data
);
5790 * Determine if the current offset has already been processed.
5791 * This is specific to the TCP dissector.
5793 static bool is_retransmission(packet_info
*pinfo
, tcp_session_data
*session
, tcp_packet_data
*packet
, struct tcpinfo
*tcpinfo
)
5795 /* TODO: Determine why we get big numbers sometimes... */
5796 /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5798 tcp_ignore_data
*id
;
5799 uint32_t sequence
= tcpinfo
->seq
;
5801 if (addresses_equal(&pinfo
->src
, &session
->client
.addr
) && (pinfo
->srcport
== session
->client
.port
))
5803 id
= packet
->from_client_ignore_list
;
5807 id
= packet
->from_server_ignore_list
;
5810 while (id
!= NULL
&& id
->sequence
!= sequence
)
5825 * We have found and processed packets starting at offset, so
5826 * don't allow the same (or previous) packets.
5827 * This only applies to TCP dissector conversations.
5829 static void remember_offset(packet_info
*pinfo
, tcp_session_data
*session
, tcp_packet_data
*packet
, struct tcpinfo
*tcpinfo
)
5831 bool ignore
= false;
5833 /* TODO: Determine why we get big numbers sometimes... */
5834 /* if ( tcpinfo->seq != 0 && tcpinfo->seq < 1000000) */
5836 tcp_ignore_data
**last
;
5837 tcp_ignore_data
*id
;
5839 uint32_t *seqptr
= NULL
;
5841 if (addresses_equal(&pinfo
->src
, &session
->client
.addr
) && (pinfo
->srcport
== session
->client
.port
))
5843 last
= &(packet
->from_client_ignore_list
);
5844 id
= packet
->from_client_ignore_list
;
5845 sequence
= tcpinfo
->seq
;
5846 seqptr
= &session
->from_client_seq
;
5848 if (LE_SEQ(tcpinfo
->seq
, session
->from_client_seq
))
5853 last
= &(packet
->from_server_ignore_list
);
5854 id
= packet
->from_server_ignore_list
;
5855 sequence
= tcpinfo
->seq
;
5856 seqptr
= &session
->from_server_seq
;
5858 if (LE_SEQ(tcpinfo
->seq
, session
->from_server_seq
))
5862 while (id
!= NULL
&& id
->sequence
!= tcpinfo
->seq
)
5871 *last
= wmem_new0(wmem_file_scope(), tcp_ignore_data
);
5873 id
->ignore
= ignore
;
5874 id
->sequence
= tcpinfo
->seq
;
5880 * This dissector is registered with TCP using the standard port. It uses registered
5881 * protocols to determine framing, and those dissectors will call into the base
5882 * DPS dissector for each packet.
5884 static int dissect_dof_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
5886 conversation_t
*conversation
;
5887 tcp_session_data
*session
;
5888 tcp_packet_data
*packet
;
5889 struct tcpinfo
*tcpinfo
= (struct tcpinfo
*)data
;
5892 /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,12
5893 * so we can "mirror" that by attaching our own data to that conversation. If our
5894 * data cannot be found, then it is a new connection (to us).
5896 conversation
= find_conversation_pinfo(pinfo
, 0);
5898 /* This should be impossible - the TCP dissector requires this conversation.
5901 DISSECTOR_ASSERT(conversation
!= NULL
);
5905 /* This requires explanation. TCP will call this dissector, and we know
5906 * that the first byte (offset 0 of this tvb) is the first byte of an
5907 * DPS packet. The TCP dissector ensures this.
5909 * We do *not* know that this is the only packet, and
5910 * so the dissector that we call below must handle framing. All of
5911 * this state must be stored, and so we store it in a transport
5912 * data structure. DPS packet data is created later and associated
5915 * Further, this routine MAY be called MULTIPLE times for the SAME
5916 * frame with DIFFERENT sequence numbers. This makes handling
5917 * retransmissions very difficult - we must track each call to this
5918 * routine with its associated offset and ignore flag. However, due
5919 * to the way that Wireshark handles asking for more data we cannot
5920 * mark an offset as "duplicate" until after it has been processed.
5923 /* TCP packet data is only associated with TCP frames that hold DPS packets. */
5924 session
= (tcp_session_data
*)conversation_get_proto_data(conversation
, proto_2008_1_dof_tcp
);
5925 if (session
== NULL
)
5927 session
= create_tcp_session_data(pinfo
, conversation
);
5928 conversation_add_proto_data(conversation
, proto_2008_1_dof_tcp
, session
);
5931 if (session
->not_dps
)
5934 packet
= (tcp_packet_data
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_2008_1_dof_tcp
, 0);
5937 packet
= wmem_new0(wmem_file_scope(), tcp_packet_data
);
5938 p_add_proto_data(wmem_file_scope(), pinfo
, proto_2008_1_dof_tcp
, 0, packet
);
5941 if (is_retransmission(pinfo
, session
, packet
, tcpinfo
))
5944 /* Loop, checking all the packets in this frame and communicating with the TCP
5945 * desegmenter. The framing dissector entry is used to determine the size
5946 * of the current frame.
5949 /* Note that we must handle fragmentation on TCP... */
5952 while (offset
< (int)tvb_reported_length(tvb
))
5954 int available
= tvb_ensure_captured_length_remaining(tvb
, offset
);
5957 header
= tvb_get_uint8(tvb
, offset
);
5959 /* If we are negotiating, then we do not need the framing dissector
5960 * as we know the packet length is two. Note that for the first byte
5961 * of a TCP session there are only two cases, both handled here. An error
5962 * of not understanding the first byte will trigger that this is not
5965 if (((header
& 0x80) == 0) && session
->common
.negotiation_required
&& ((pinfo
->fd
->num
< session
->common
.negotiation_complete_at
) || (session
->common
.negotiation_complete_at
== 0)))
5968 if (header
> DNP_MAX_VERSION
)
5970 session
->not_dps
= true;
5976 packet_length
= dof_dissect_dnp_length(tvb
, pinfo
, header
& 0x7F, &offset
);
5977 if (packet_length
< 0)
5979 session
->not_dps
= true;
5984 if (packet_length
== 0)
5986 pinfo
->desegment_offset
= offset
;
5987 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
5988 return offset
+ available
;
5991 if (available
< packet_length
)
5993 pinfo
->desegment_offset
= offset
;
5994 pinfo
->desegment_len
= packet_length
- available
;
5995 return offset
+ available
;
5998 remember_offset(pinfo
, session
, packet
, tcpinfo
);
5999 if (is_retransmission(pinfo
, session
, packet
, tcpinfo
))
6002 /* We have a packet. We have to store the dof_packet_data in a list, as there may be
6003 * multiple DPS packets in a single Wireshark frame.
6006 tvbuff_t
*next_tvb
= tvb_new_subset_length(tvb
, offset
, packet_length
);
6007 tcp_dof_packet_ref
*ref
;
6008 int raw_offset
= tvb_raw_offset(tvb
) + offset
;
6009 bool ref_is_new
= false;
6011 /* Get the packet data. This is a list in increasing sequence order. */
6012 if (packet
->dof_packets
== NULL
)
6015 ref
= wmem_new0(wmem_file_scope(), tcp_dof_packet_ref
);
6016 ref
->transport_packet
.sender_id
= assign_addr_port_id(&pinfo
->src
, pinfo
->srcport
);
6017 ref
->transport_packet
.receiver_id
= assign_addr_port_id(&pinfo
->dst
, pinfo
->destport
);
6018 packet
->dof_packets
= ref
;
6019 ref
->start_offset
= raw_offset
;
6022 ref
= packet
->dof_packets
;
6024 /* Find the entry for our offset. */
6025 while (ref
->start_offset
!= raw_offset
)
6034 tcp_dof_packet_ref
*last
= ref
;
6036 /* This is the default state, NULL and 0. */
6038 ref
= wmem_new0(wmem_file_scope(), tcp_dof_packet_ref
);
6039 ref
->transport_packet
.sender_id
= last
->transport_packet
.sender_id
;
6040 ref
->transport_packet
.receiver_id
= last
->transport_packet
.receiver_id
;
6041 ref
->start_offset
= raw_offset
;
6048 dof_transport_packet
*tp
= &(ref
->transport_packet
);
6050 tp
->is_sent_by_client
= false;
6051 if (addresses_equal(&session
->client
.addr
, &pinfo
->src
) &&
6052 (session
->client
.port
== pinfo
->srcport
))
6053 tp
->is_sent_by_client
= true;
6055 ref
->api_data
.transport_session
= (dof_transport_session
*)&(session
->common
);
6056 ref
->api_data
.transport_packet
= tp
;
6060 dissect_dof_common(next_tvb
, pinfo
, tree
, &ref
->api_data
);
6063 offset
+= packet_length
;
6070 #if 0 /* TODO not used yet */
6072 * This dissector is registered with the UDP protocol on the standard DPS port.
6073 * It will be used for anything that involves that port (source or destination).
6076 static int dissect_tunnel_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6078 conversation_t
*conversation
;
6079 dof_packet_data
*packet
;
6081 /* Initialize the default transport session structure. */
6082 if (!udp_transport_session
)
6083 udp_transport_session
= se_alloc0(sizeof(*udp_transport_session
));
6085 conversation
= find_or_create_conversation(pinfo
);
6087 /* Add the packet data. */
6088 packet
= p_get_proto_data(wmem_file_scope(), proto_2012_1_tunnel
, 0);
6091 packet
= wmem_alloc0(wmem_file_scope(), sizeof(dof_packet_data
));
6092 packet
->frame
= pinfo
->fd
->num
;
6093 packet
->next
= NULL
;
6094 packet
->start_offset
= 0;
6095 packet
->session_counter
= &session_counter
;
6096 packet
->transport_session
= udp_transport_session
;
6097 p_add_proto_data(wmem_file_scope(), proto_2012_1_tunnel
, 0, packet
);
6100 pinfo
->private_data
= packet
;
6101 return dissect_tunnel_common(tvb
, pinfo
, tree
);
6103 static int dissect_tunnel_udp(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
)
6112 * This dissector is registered with TCP using the standard port. It uses registered
6113 * protocols to determine framing, and those dissectors will call into the base
6114 * DPS dissector for each packet.
6116 static int dissect_tunnel_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6118 conversation_t
*conversation
;
6119 tcp_session_data
*session
;
6120 tcp_packet_data
*packet
;
6121 struct tcpinfo
*tcpinfo
= (struct tcpinfo
*)data
;
6123 /* Get the TCP conversation. TCP creates a new conversation for each TCP connection,
6124 * so we can "mirror" that by attaching our own data to that conversation. If our
6125 * data cannot be found, then it is a new connection (to us).
6127 conversation
= find_conversation_pinfo(pinfo
, 0);
6129 /* This should be impossible - the TCP dissector requires this conversation.
6132 DISSECTOR_ASSERT(conversation
!= NULL
);
6136 /* This requires explanation. TCP will call this dissector, and we know
6137 * that the first byte (offset 0 of this tvb) is the first byte of an
6138 * DPS packet. The TCP dissector ensures this.
6140 * We do *not* know that this is the only packet, and
6141 * so the dissector that we call below must handle framing. All of
6142 * this state must be stored, and so we store it in a transport
6143 * data structure. DPS packet data is created later and associated
6146 * Further, this routine MAY be called MULTIPLE times for the SAME
6147 * frame with DIFFERENT sequence numbers. This makes handling
6148 * retransmissions very difficult - we must track each call to this
6149 * routine with its associated offset and ignore flag. However, due
6150 * to the way that Wireshark handles asking for more data we cannot
6151 * mark an offset as "duplicate" until after it has been processed.
6154 /* TCP packet data is only associated with TCP frames that hold DPS packets. */
6155 session
= (tcp_session_data
*)conversation_get_proto_data(conversation
, proto_2012_1_tunnel
);
6156 if (session
== NULL
)
6158 session
= create_tcp_session_data(pinfo
, conversation
);
6159 conversation_add_proto_data(conversation
, proto_2012_1_tunnel
, session
);
6162 packet
= (tcp_packet_data
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_2012_1_tunnel
, 0);
6165 packet
= wmem_new0(wmem_file_scope(), tcp_packet_data
);
6166 p_add_proto_data(wmem_file_scope(), pinfo
, proto_2012_1_tunnel
, 0, packet
);
6169 if (is_retransmission(pinfo
, session
, packet
, tcpinfo
))
6172 /* Loop, checking all the packets in this TCP frame.
6175 /* Note that we must handle fragmentation on TCP... */
6178 while (offset
< (int)tvb_reported_length(tvb
))
6180 int available
= tvb_reported_length_remaining(tvb
, offset
);
6187 pinfo
->desegment_offset
= offset
;
6188 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
6189 return offset
+ available
;
6195 for (i
= 0; i
< 2; i
++)
6196 packet_length
= packet_length
* 256 + tvb_get_uint8(tvb
, offset
+ 1 + i
);
6198 packet_length
+= header_length
;
6200 if (available
< packet_length
)
6202 pinfo
->desegment_offset
= offset
;
6203 pinfo
->desegment_len
= packet_length
- available
;
6204 return offset
+ available
;
6207 /* We have a packet. We have to store the dof_packet_data in a list, as there may be
6208 * multiple DPS packets in a single Wireshark frame.
6211 tvbuff_t
*next_tvb
= tvb_new_subset_length(tvb
, offset
, packet_length
);
6212 tcp_dof_packet_ref
*ref
;
6213 int raw_offset
= tvb_raw_offset(tvb
) + offset
;
6214 bool ref_is_new
= false;
6216 /* Get the packet data. This is a list in increasing sequence order. */
6217 if (packet
->dof_packets
== NULL
)
6220 ref
= wmem_new0(wmem_file_scope(), tcp_dof_packet_ref
);
6221 ref
->transport_packet
.sender_id
= assign_addr_port_id(&pinfo
->src
, pinfo
->srcport
);
6222 ref
->transport_packet
.receiver_id
= assign_addr_port_id(&pinfo
->dst
, pinfo
->destport
);
6223 packet
->dof_packets
= ref
;
6224 ref
->start_offset
= raw_offset
;
6227 ref
= packet
->dof_packets
;
6229 /* Find the entry for our offset. */
6230 while (ref
->start_offset
!= raw_offset
)
6239 tcp_dof_packet_ref
*last
= ref
;
6241 /* This is the default state, NULL and 0. */
6243 ref
= wmem_new0(wmem_file_scope(), tcp_dof_packet_ref
);
6244 ref
->transport_packet
.sender_id
= last
->transport_packet
.sender_id
;
6245 ref
->transport_packet
.receiver_id
= last
->transport_packet
.receiver_id
;
6246 ref
->start_offset
= raw_offset
;
6253 dof_transport_packet
*tp
= &(ref
->transport_packet
);
6255 tp
->is_sent_by_client
= false;
6256 if (addresses_equal(&session
->client
.addr
, &pinfo
->src
) &&
6257 (session
->client
.port
== pinfo
->srcport
))
6258 tp
->is_sent_by_client
= true;
6260 ref
->api_data
.transport_session
= (dof_transport_session
*)&(session
->common
);
6261 ref
->api_data
.transport_packet
= tp
;
6264 /* Manage the private data, restoring the existing value. Call the common dissector. */
6266 dissect_tunnel_common(next_tvb
, pinfo
, tree
, ref
);
6270 offset
+= packet_length
;
6273 return tvb_captured_length(tvb
);
6279 static int dissect_dnp_0(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6281 unsigned offset
= 0;
6283 uint8_t dnp_flags_included
= 0;
6286 col_clear(pinfo
->cinfo
, COL_INFO
);
6288 /* Compute the DNP control information. This is the version and the flags byte.
6289 * The flags byte is either present, or is based on the version (and can be defaulted).
6292 uint8_t header
= tvb_get_uint8(tvb
, offset
);
6294 dnp_flags_included
= (header
& 0x80) != 0;
6299 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DNPv0 ");
6301 if (dnp_flags_included
)
6303 /* TODO: Protocol violation. */
6306 if (tvb_reported_length(tvb
) == offset
)
6307 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query");
6310 uint8_t first
= tvb_get_uint8(tvb
, offset
);
6313 /* Query with padding. */
6314 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query");
6315 proto_tree_add_item(tree
, hf_2008_1_dnp_0_1_1_padding
, tvb
, offset
, -1, ENC_NA
);
6320 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query Response");
6323 proto_tree_add_item(tree
, hf_2008_1_dnp_0_1_1_version
, tvb
, offset
, 1, ENC_NA
);
6325 if (offset
== tvb_reported_length(tvb
))
6328 first
= tvb_get_uint8(tvb
, offset
);
6331 if (offset
< tvb_reported_length(tvb
))
6332 proto_tree_add_item(tree
, hf_2008_1_dnp_0_1_1_padding
, tvb
, offset
, -1, ENC_NA
);
6338 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
6339 col_set_fence(pinfo
->cinfo
, COL_INFO
);
6340 return tvb_reported_length(tvb
);
6344 * Determine the length of the packet in tvb, starting at an offset that is passed as a
6345 * pointer in private_data.
6346 * Return 0 if the length cannot be determined because there is not enough data in
6347 * the buffer, otherwise return the length of the packet.
6349 static int determine_packet_length_1(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data
)
6351 /* Note that we must handle fragmentation on TCP... */
6352 int offset
= *((int *)data
);
6355 int available
= tvb_ensure_captured_length_remaining(tvb
, offset
);
6356 uint8_t header
, flags
;
6359 int data_len
, header_len
;
6364 header
= tvb_get_uint8(tvb
, offset
);
6367 if ((header
& 0x80) == 0)
6369 /* The length is fixed in this case... */
6376 flags
= tvb_get_uint8(tvb
, offset
+ 1);
6377 size
= flags
& 0x03;
6378 header_len
= 2 + size
;
6381 if (available
< header_len
)
6384 for (i
= 0; i
< size
; i
++)
6385 data_len
= data_len
* 256 + tvb_get_uint8(tvb
, offset
+ 2 + i
);
6387 return header_len
+ data_len
;
6391 static int dissect_dnp_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6394 dof_api_data
*api_data
= (dof_api_data
*)data
;
6395 dof_packet_data
*packet
;
6397 int8_t dnp_version
= -1;
6398 uint8_t dnp_flags_included
= 0;
6399 uint8_t dnp_length_length
= 0;
6400 uint32_t dnp_flags
= 0;
6402 unsigned length
= 0;
6403 unsigned encapsulated_length
= 0;
6407 proto_tree
*dnp_tree
= tree
;
6411 /* TODO: Print error */
6415 if (!api_data
->packet
)
6417 /* TODO: Print error */
6421 packet
= api_data
->packet
;
6424 col_clear(pinfo
->cinfo
, COL_INFO
);
6426 /* Compute the DNP control information. This is the version and the flags byte.
6427 * The flags byte is either present, or is based on the version (and can be defaulted).
6430 uint8_t header
= tvb_get_uint8(tvb
, offset
);
6431 uint32_t dnp_src_port
= 0;
6432 uint32_t dnp_dst_port
= 0;
6434 dnp_version
= header
& 0x7F;
6435 dnp_flags_included
= (header
& 0x80) != 0;
6441 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DNPv1 ");
6443 if (dnp_flags_included
)
6445 /* Including flags always terminates negotiation. */
6446 /* packet->negotiated = true; */
6448 dnp_flags
= tvb_get_uint8(tvb
, offset
);
6449 if ((dnp_flags
& 0xF0) != 0)
6450 expert_add_info(pinfo
, NULL
, &ei_dof_10_flags_zero
);
6452 proto_tree_add_bitmask(dnp_tree
, tvb
, offset
, hf_2009_9_dnp_1_flags
, ett_2009_9_dnp_1_flags
, bitmask_2009_9_dnp_1_flags
, ENC_BIG_ENDIAN
);
6457 dnp_flags
= DNP_V1_DEFAULT_FLAGS
;
6459 /* Determine the size of the length field. */
6460 dnp_length_length
= dnp_flags
& 0x03;
6461 if (dnp_length_length
)
6462 proto_tree_add_item(dnp_tree
, hf_2009_9_dnp_1_length
, tvb
, offset
, dnp_length_length
, ENC_BIG_ENDIAN
);
6464 /* Read the length. */
6466 for (i
= 0; i
< dnp_length_length
; i
++)
6467 length
= (length
<< 8) | tvb_get_uint8(tvb
, offset
+ i
);
6469 /* Validate the length. */
6471 if ( (length
== 0) && packet
->negotiated
&& session
&& ! session
->connectionless
)
6473 expert_add_info( pinfo
, NULL
, &ei_dof_13_length_specified
);
6477 offset
+= dnp_length_length
;
6479 /* If there isn't a length specified then use the packet size. */
6480 if (dnp_length_length
== 0)
6481 length
= tvb_reported_length(tvb
) - offset
;
6483 encapsulated_length
= length
;
6485 /* Read the srcport */
6486 if (dnp_flags
& 0x04)
6488 int s_offset
= offset
;
6490 int dnp_src_port_len
;
6492 offset
= read_c3(tvb
, offset
, &dnp_src_port
, &dnp_src_port_len
);
6493 item
= proto_tree_add_uint_format(dnp_tree
, hf_2009_9_dnp_1_srcport
, tvb
, s_offset
, offset
- s_offset
, dnp_src_port
, "Source Address: %u", dnp_src_port
);
6494 validate_c3(pinfo
, item
, dnp_src_port
, dnp_src_port_len
);
6495 encapsulated_length
-= (offset
- s_offset
);
6499 proto_item
*item
= proto_tree_add_uint_format(dnp_tree
, hf_2009_9_dnp_1_srcport
, tvb
, 0, 0, 0, "Source Address: %u", 0);
6500 proto_item_set_generated(item
);
6503 /* Read the dstport */
6504 if (dnp_flags
& 0x08)
6506 int s_offset
= offset
;
6507 int dnp_dst_port_len
;
6510 offset
= read_c3(tvb
, offset
, &dnp_dst_port
, &dnp_dst_port_len
);
6511 item
= proto_tree_add_uint_format(dnp_tree
, hf_2009_9_dnp_1_dstport
, tvb
, s_offset
, offset
- s_offset
, dnp_dst_port
, "Destination Address: %u", dnp_dst_port
);
6512 validate_c3(pinfo
, item
, dnp_dst_port
, dnp_dst_port_len
);
6513 encapsulated_length
-= (offset
- s_offset
);
6517 proto_item
*item
= proto_tree_add_uint_format(dnp_tree
, hf_2009_9_dnp_1_dstport
, tvb
, 0, 0, 0, "Destination Address: %u", 0);
6518 proto_item_set_generated(item
);
6522 proto_item_set_end(tree
, tvb
, offset
);
6524 /* Given the transport session and the DPS port information, determine the DPS session. */
6525 if (api_data
->session
== NULL
)
6530 if (api_data
->transport_packet
->is_sent_by_client
)
6532 client
= dnp_src_port
;
6533 server
= dnp_dst_port
;
6537 client
= dnp_dst_port
;
6538 server
= dnp_src_port
;
6541 api_data
->session
= dof_ns_session_retrieve(api_data
->transport_session
->transport_session_id
, client
, server
);
6542 if (api_data
->session
== NULL
)
6544 dof_session_data
*sdata
= wmem_new0(wmem_file_scope(), dof_session_data
);
6545 dof_ns_session_define(api_data
->transport_session
->transport_session_id
, client
, server
, sdata
);
6546 sdata
->session_id
= globals
.next_session
++;
6547 sdata
->dof_id
= dnp_version
;
6548 api_data
->session
= sdata
;
6552 packet
->sender_id
= dnp_src_port
;
6553 packet
->receiver_id
= dnp_dst_port
;
6555 /* Assuming there is more, it must be DPP. */
6557 /* We have a packet. */
6559 tvbuff_t
*next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, encapsulated_length
, tvb_reported_length(tvb
) - offset
);
6560 offset
+= dof_dissect_dpp_common(next_tvb
, pinfo
, proto_item_get_parent(tree
), data
);
6564 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
6565 col_set_fence(pinfo
->cinfo
, COL_INFO
);
6569 static int dissect_dpp_0(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
6571 unsigned offset
= 0;
6573 uint8_t dpp_flags_included
= 0;
6576 col_clear(pinfo
->cinfo
, COL_INFO
);
6578 /* Compute the DPP control information. This is the version and the flags byte.
6579 * The flags byte is either present, or is based on the version (and can be defaulted).
6582 uint8_t header
= tvb_get_uint8(tvb
, offset
);
6584 dpp_flags_included
= (header
& 0x80) != 0;
6589 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DPPv0 ");
6591 if (dpp_flags_included
)
6593 /* TODO: Protocol violation. */
6596 if (tvb_reported_length(tvb
) == offset
)
6597 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query");
6600 uint8_t first
= tvb_get_uint8(tvb
, offset
);
6602 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query Response");
6605 proto_tree_add_item(tree
, hf_2008_1_dpp_0_1_1_version
, tvb
, offset
, 1, ENC_NA
);
6607 if (offset
== tvb_reported_length(tvb
))
6610 first
= tvb_get_uint8(tvb
, offset
);
6616 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
6617 col_set_fence(pinfo
->cinfo
, COL_INFO
);
6618 return tvb_reported_length(tvb
);
6621 static int dissect_dpp_v2_common(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6623 dof_api_data
*api_data
= (dof_api_data
*)data
;
6624 dof_packet_data
*packet_data
;
6630 proto_tree
*dpps_tree
;
6631 proto_tree
*opid_tree
;
6633 if (api_data
== NULL
)
6635 /* TODO: Output error. */
6639 packet_data
= api_data
->packet
;
6640 if (packet_data
== NULL
)
6642 /* TODO: Output error. */
6646 /* Make entries in Protocol column and Info column on summary display */
6647 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DPPs ");
6649 /* Create the protocol tree. */
6651 ti
= proto_tree_add_item(tree
, proto_2009_12_dpp_common
, tvb
, offset
, -1, ENC_NA
);
6652 dpps_tree
= proto_item_add_subtree(ti
, ett_2009_12_dpp_common
);
6654 /* Add the APPID. */
6655 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
6656 ti
= proto_tree_add_uint(dpps_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
6657 validate_c2(pinfo
, ti
, app
, app_len
);
6660 /* Retrieve the opcode. */
6661 opcode
= tvb_get_uint8(tvb
, offset
);
6662 if (!packet_data
->is_command
)
6663 opcode
|= OP_2009_12_RESPONSE_FLAG
;
6665 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(opcode
, strings_2009_12_dpp_common_opcodes
, "Unknown Opcode (%d)"));
6668 proto_tree_add_uint_format(dpps_tree
, hf_2009_12_dpp_2_14_opcode
, tvb
, offset
, 1, opcode
& 0x3F, "Opcode: %s (%u)", val_to_str(opcode
, strings_2009_12_dpp_common_opcodes
, "Unknown Opcode (%d)"), opcode
& 0x3F);
6673 case OP_2009_12_SOURCE_LOST_CMD
:
6674 case OP_2009_12_SOURCE_FOUND_CMD
:
6675 case OP_2009_12_RENAME_CMD
:
6676 packet_data
->has_referenced_opid
= true;
6680 case OP_2009_12_CANCEL_ALL_CMD
:
6681 case OP_2009_12_NODE_DOWN_CMD
:
6682 case OP_2009_12_QUERY_RSP
:
6685 proto_tree
*oid_tree
;
6689 if (packet_data
->has_referenced_opid
)
6691 opid_tree
= proto_tree_add_subtree(dpps_tree
, tvb
, offset
, 0, ett_2009_12_dpp_2_opid
, NULL
, "Operation Identifier");
6695 opid_tree
= dpps_tree
;
6698 oid_tree
= proto_tree_add_subtree(opid_tree
, tvb
, offset
, 0, ett_2009_12_dpp_2_opid
, NULL
, "Source Identifier");
6700 next_tvb
= tvb_new_subset_length(tvb
, offset
, tvb_reported_length(tvb
) - offset
);
6701 opid_len
= call_dissector_only(dof_oid_handle
, next_tvb
, pinfo
, oid_tree
, NULL
);
6703 learn_sender_sid(api_data
, opid_len
, tvb_get_ptr(next_tvb
, 0, opid_len
));
6704 if (packet_data
->has_referenced_opid
)
6705 learn_operation_sid(&packet_data
->ref_op
, opid_len
, tvb_get_ptr(next_tvb
, 0, opid_len
));
6710 if (packet_data
->has_referenced_opid
)
6716 read_c4(tvb
, offset
, &opcnt
, &opcnt_len
);
6717 pi
= proto_tree_add_uint_format(opid_tree
, hf_2009_12_dpp_2_1_opcnt
, tvb
, offset
, opcnt_len
, opcnt
, "Operation Count: %u", opcnt
);
6718 validate_c4(pinfo
, pi
, opcnt
, opcnt_len
);
6719 offset
+= opcnt_len
;
6721 packet_data
->ref_op
.op_cnt
= opcnt
;
6729 static int dissect_dpp_2(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
6731 dof_api_data
*api_data
= (dof_api_data
*)data
;
6732 dof_packet_data
*packet_data
;
6734 proto_item
*ti
= NULL
;
6735 proto_item
*tf
= NULL
;
6736 proto_item
*opid
= NULL
;
6738 int opid_start
= -1;
6739 uint8_t dpp_flags_included
= 0;
6740 uint32_t dpp_flags
= 0;
6741 uint8_t dpp_opid_keytype
= 0;
6743 proto_tree
*dpp_flags_tree
;
6744 proto_tree
*opid_tree
= NULL
;
6749 proto_tree
*dpp_tree
= tree
;
6751 if (api_data
== NULL
)
6753 /* TODO: Output error. */
6757 packet_data
= api_data
->packet
;
6758 if (packet_data
== NULL
)
6760 /* TODO: Output error. */
6764 /* We should have everything required for determining the SID ID. */
6765 assign_sid_id(api_data
);
6768 col_clear(pinfo
->cinfo
, COL_INFO
);
6770 /* Compute the DPP control information. This is the version and the flags byte.
6771 * The flags byte is either present, or is based on the version (and can be defaulted).
6774 uint8_t header
= tvb_get_uint8(tvb
, offset
);
6775 dpp_flags_included
= (header
& 0x80) != 0;
6779 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DPPv2 ");
6781 ti
= proto_tree_add_uint_format(tree
, hf_2008_1_dpp_sid_num
, tvb
,
6782 0, 0, packet_data
->sender_sid_id
, "SID ID: %d", packet_data
->sender_sid_id
);
6783 proto_item_set_generated(ti
);
6785 if (packet_data
->sender_sid
)
6787 const char *SID
= dof_oid_create_standard_string(packet_data
->sender_sid
[0], packet_data
->sender_sid
+ 1, pinfo
);
6788 ti
= proto_tree_add_bytes_format_value(tree
, hf_2008_1_dpp_sid_str
, tvb
, 0, 0, packet_data
->sender_sid
, "%s", SID
);
6789 proto_item_set_generated(ti
);
6792 ti
= proto_tree_add_uint_format(tree
, hf_2008_1_dpp_rid_num
, tvb
,
6793 0, 0, packet_data
->receiver_sid_id
, "RID ID: %d", packet_data
->receiver_sid_id
);
6794 proto_item_set_generated(ti
);
6796 if (packet_data
->receiver_sid
)
6798 const char *SID
= dof_oid_create_standard_string(packet_data
->receiver_sid
[0], packet_data
->receiver_sid
+ 1, pinfo
);
6799 ti
= proto_tree_add_bytes_format_value(tree
, hf_2008_1_dpp_rid_str
, tvb
, 0, 0, packet_data
->receiver_sid
, "%s", SID
);
6800 proto_item_set_generated(ti
);
6803 if (dpp_flags_included
)
6805 dpp_flags
= tvb_get_uint8(tvb
, offset
);
6806 if (((dpp_flags
& 0x10) != 0) && ((dpp_flags
& 0x0F) != 0))
6807 expert_add_info(pinfo
, NULL
, &ei_dpp2_dof_10_flags_zero
);
6808 if (((dpp_flags
& 0x10) == 0) && ((dpp_flags
& 0x09) != 0))
6809 expert_add_info(pinfo
, NULL
, &ei_dpp2_dof_10_flags_zero
);
6811 tf
= proto_tree_add_uint_format(dpp_tree
, hf_2009_12_dpp_2_1_flags
, tvb
,
6812 offset
, 1, dpp_flags
, "Flags: 0x%02x", dpp_flags
);
6814 dpp_flags_tree
= proto_item_add_subtree(tf
, ett_2009_12_dpp_2_1_flags
);
6816 if (dpp_flags
== DPP_V2_DEFAULT_FLAGS
)
6817 expert_add_info(pinfo
, dpp_flags_tree
, &ei_dpp_default_flags
);
6819 proto_tree_add_item(dpp_flags_tree
, hf_2009_12_dpp_2_1_flag_security
, tvb
, offset
, 1, ENC_NA
);
6820 proto_tree_add_item(dpp_flags_tree
, hf_2009_12_dpp_2_1_flag_opid
, tvb
, offset
, 1, ENC_NA
);
6821 proto_tree_add_item(dpp_flags_tree
, hf_2009_12_dpp_2_1_flag_cmdrsp
, tvb
, offset
, 1, ENC_NA
);
6822 if ((dpp_flags
& 0x10) == 0)
6824 proto_tree_add_item(dpp_flags_tree
, hf_2009_12_dpp_2_1_flag_seq
, tvb
, offset
, 1, ENC_NA
);
6825 proto_tree_add_item(dpp_flags_tree
, hf_2009_12_dpp_2_1_flag_retry
, tvb
, offset
, 1, ENC_NA
);
6831 dpp_flags
= DPP_V2_DEFAULT_FLAGS
;
6833 packet_data
->is_command
= (dpp_flags
& 0x10) == 0;
6835 /* We are allowed to be complete here if still negotiating. */
6836 /*if ( ! packet->negotiated && (offset == tvb_reported_length(tvb)) )
6838 col_set_str( pinfo->cinfo, COL_INFO, "DPS Negotiation" );
6842 dpp_opid_keytype
= (dpp_flags
& 0x60) >> 5;
6843 switch (dpp_opid_keytype
)
6845 case 0: /* No OPID */
6846 packet_data
->has_opid
= false;
6849 case 1: /* Implied sender. */
6850 packet_data
->has_opid
= true;
6851 packet_data
->op
.op_sid_id
= packet_data
->sender_sid_id
;
6852 packet_data
->op
.op_sid
= packet_data
->sender_sid
;
6855 case 2: /* Implied receiver. */
6856 packet_data
->has_opid
= true;
6857 packet_data
->op
.op_sid_id
= packet_data
->receiver_sid_id
;
6858 packet_data
->op
.op_sid
= packet_data
->receiver_sid
;
6861 case 3: /* Explicit. */
6862 packet_data
->has_opid
= true;
6866 if (dpp_opid_keytype
!= 0)
6868 opid_start
= offset
;
6869 opid_tree
= proto_tree_add_subtree(dpp_tree
, tvb
, offset
, 0, ett_2009_12_dpp_2_opid
, NULL
, "Operation Identifier");
6872 switch (dpp_opid_keytype
)
6874 case 0: /* We have no opid. */
6877 case 3: /* Explicit. */
6879 proto_tree
*oid_tree
;
6883 oid_tree
= proto_tree_add_subtree(opid_tree
, tvb
, offset
, 0, ett_2009_12_dpp_2_opid
, NULL
, "Source Identifier");
6885 next_tvb
= tvb_new_subset_length(tvb
, offset
, tvb_reported_length(tvb
) - offset
);
6886 opid_len
= call_dissector_only(dof_oid_handle
, next_tvb
, pinfo
, oid_tree
, NULL
);
6887 proto_item_set_len(oid_tree
, opid_len
);
6889 learn_operation_sid(&packet_data
->op
, opid_len
, tvb_get_ptr(next_tvb
, 0, opid_len
));
6891 /* Warn if Explicit SID could be optimized. */
6892 if (packet_data
->op
.op_sid_id
== packet_data
->sender_sid_id
)
6893 expert_add_info(pinfo
, ti
, &ei_dpp_explicit_sender_sid_included
);
6894 if (packet_data
->op
.op_sid_id
== packet_data
->receiver_sid_id
)
6895 expert_add_info(pinfo
, ti
, &ei_dpp_explicit_receiver_sid_included
);
6902 case 1: /* Implied sender. */
6903 case 2: /* Implied receiver. */
6909 /* Display the SID if known. */
6910 if ((dpp_opid_keytype
!= 3) && packet_data
->op
.op_sid
)
6912 proto_tree
*oid_tree
;
6914 tvbuff_t
*next_tvb
= tvb_new_child_real_data(tvb
, packet_data
->op
.op_sid
+ 1, packet_data
->op
.op_sid
[0], packet_data
->op
.op_sid
[0]);
6915 oid_tree
= proto_tree_add_subtree(opid_tree
, tvb
, 0, 0, ett_2009_12_dpp_2_opid
, NULL
, "Source Identifier");
6917 call_dissector_only(dof_oid_handle
, next_tvb
, pinfo
, oid_tree
, NULL
);
6919 proto_item_set_generated(ti
);
6922 read_c4(tvb
, offset
, &opcnt
, &opcnt_len
);
6923 pi
= proto_tree_add_uint_format(opid_tree
, hf_2009_12_dpp_2_1_opcnt
, tvb
, offset
, opcnt_len
, opcnt
, "Operation Count: %u", opcnt
);
6924 validate_c4(pinfo
, pi
, opcnt
, opcnt_len
);
6925 offset
+= opcnt_len
;
6927 proto_item_set_len(opid
, offset
- opid_start
);
6929 packet_data
->op
.op_cnt
= opcnt
;
6931 /* At this point we have a packet with an operation identifier. We need to
6932 * update the master list of operation identifiers, and do any checking that
6933 * we can in order to validate things.
6935 if (packet_data
->has_opid
&& !packet_data
->opid_first
)
6937 dof_packet_data
*first
= (dof_packet_data
*)g_hash_table_lookup(dpp_opid_to_packet_data
, (const void *) & packet_data
->op
);
6940 /* First reference to this operation. */
6941 g_hash_table_insert(dpp_opid_to_packet_data
, (void *) & packet_data
->op
, (void *)packet_data
);
6942 packet_data
->opid_first
= packet_data
;
6943 packet_data
->opid_last
= packet_data
;
6945 /* The first opid must be a command. */
6949 /* Operation exists, time to patch things in. */
6950 packet_data
->opid_first
= first
;
6951 first
->opid_last
->opid_next
= packet_data
;
6952 first
->opid_last
= packet_data
;
6954 if (!packet_data
->is_command
)
6956 if (!first
->opid_first_response
)
6958 first
->opid_first_response
= packet_data
;
6959 first
->opid_last_response
= packet_data
;
6963 first
->opid_last_response
->opid_next_response
= packet_data
;
6964 first
->opid_last_response
= packet_data
;
6971 /* Add all the reference information to the tree. */
6972 if (globals
.track_operations
&& tree
)
6974 proto_tree
*ophistory_tree
= proto_tree_add_subtree(tree
, tvb
, 0, 0, ett_2009_12_dpp_2_opid_history
, NULL
, "Operation History");
6976 dof_packet_data
*ptr
= packet_data
->opid_first
;
6979 proto_tree_add_uint_format(ophistory_tree
, hf_2008_1_dpp_first_command
,
6980 tvb
, 0, 0, ptr
->frame
,
6981 "First Operation: %u",
6984 if (ptr
->opid_last
&& ptr
->opid_last
!= ptr
)
6985 proto_tree_add_uint_format(ophistory_tree
, hf_2008_1_dpp_last_command
,
6986 tvb
, 0, 0, ptr
->opid_last
->frame
,
6987 "Last Operation: %u",
6988 ptr
->opid_last
->frame
);
6990 if (ptr
->opid_first_response
)
6991 proto_tree_add_uint_format(ophistory_tree
, hf_2008_1_dpp_first_response
,
6992 tvb
, 0, 0, ptr
->opid_first_response
->frame
,
6993 "First Response: %u",
6994 ptr
->opid_first_response
->frame
);
6996 if (ptr
->opid_last_response
&& ptr
->opid_last_response
!= ptr
->opid_first_response
)
6997 proto_tree_add_uint_format(ophistory_tree
, hf_2008_1_dpp_last_response
,
6998 tvb
, 0, 0, ptr
->opid_last_response
->frame
,
6999 "Last Response: %u",
7000 ptr
->opid_last_response
->frame
);
7002 /* Determine the window start, then output the number of packets. Output the number of skipped packets before
7006 dof_packet_data
*start
= packet_data
->opid_first
;
7010 if (ptr
== packet_data
)
7013 ptr
= ptr
->opid_next
;
7016 if (diff
> globals
.track_operations_window
)
7018 start
= start
->opid_next
;
7028 const char *THIS
= "";
7030 if (ptr
== packet_data
)
7033 diff
= globals
.track_operations_window
+ 1;
7036 /* (DPS Frame) [ws WS Frame]: (SID)->(RID): (THIS) (SUMMARY) */
7037 proto_tree_add_uint_format(ophistory_tree
, hf_2008_1_dpp_related_frame
,
7038 tvb
, 0, 0, ptr
->frame
,
7039 "%u[ws %u]: %u->%u: %s%s",
7040 ptr
->dof_frame
, ptr
->frame
,
7041 ptr
->sender_sid_id
, ptr
->receiver_sid_id
,
7043 ptr
->summary
? ptr
->summary
: "");
7045 ptr
= ptr
->opid_next
;
7046 if (diff
&& !--diff
)
7055 proto_item_set_len(opid_tree
, offset
- opid_start
);
7058 if ((dpp_flags
& 0x10) == 0)
7060 uint8_t dpp_seq
= 0;
7061 uint8_t dpp_retry
= 0;
7062 uint16_t dpp_delay
= 0;
7065 if (dpp_flags
& 0x04)
7067 dpp_seq
= tvb_get_uint8(tvb
, offset
);
7068 proto_tree_add_uint_format(dpp_tree
, hf_2009_12_dpp_2_1_seq
, tvb
, offset
, 1, dpp_seq
, "Sequence: %u", dpp_seq
);
7073 if (dpp_flags
& 0x02)
7075 dpp_retry
= tvb_get_uint8(tvb
, offset
);
7076 proto_tree_add_uint_format(dpp_tree
, hf_2009_12_dpp_2_1_retry
, tvb
, offset
, 1, dpp_retry
, "Retry: %u", dpp_retry
);
7082 dpp_delay
= tvb_get_uint8(tvb
, offset
);
7083 if (dpp_delay
> 128)
7084 dpp_delay
= 128 + ((dpp_delay
- 128) * 32);
7086 proto_tree_add_uint_format(dpp_tree
, hf_2009_12_dpp_2_1_delay
, tvb
, offset
, 1, dpp_delay
, "Delay: %u seconds", dpp_delay
);
7090 packet_data
->summary
= wmem_strdup_printf(wmem_file_scope(), "command seq %u, retry %u, delay %u", dpp_seq
, dpp_retry
, dpp_delay
);
7093 packet_data
->summary
= "response";
7096 /* Extract session information. */
7097 if (dpp_flags
& 0x80)
7099 uint32_t sec_offset
= offset
;
7102 proto_tree
*security_tree
;
7103 proto_tree
*sec_flags_tree
;
7106 security_tree
= proto_tree_add_subtree(dpp_tree
, tvb
, offset
, -1, ett_2009_12_dpp_2_3_security
, NULL
, "Security Header");
7108 sh_flags
= tvb_get_uint8(tvb
, offset
);
7109 item
= proto_tree_add_uint_format(security_tree
, hf_2009_12_dpp_2_3_sec_flags
, tvb
,
7110 offset
, 1, sh_flags
, "Flags: 0x%02x", sh_flags
);
7112 sec_flags_tree
= proto_item_add_subtree(item
, ett_2009_12_dpp_2_3_sec_flags
);
7113 proto_tree_add_item(sec_flags_tree
, hf_2009_12_dpp_2_3_sec_flag_secure
, tvb
, offset
, 1, ENC_NA
);
7114 proto_tree_add_item(sec_flags_tree
, hf_2009_12_dpp_2_3_sec_flag_rdid
, tvb
, offset
, 1, ENC_NA
);
7115 proto_tree_add_item(sec_flags_tree
, hf_2009_12_dpp_2_3_sec_flag_partition
, tvb
, offset
, 1, ENC_NA
);
7116 proto_tree_add_item(sec_flags_tree
, hf_2009_12_dpp_2_3_sec_flag_as
, tvb
, offset
, 1, ENC_NA
);
7117 proto_tree_add_item(sec_flags_tree
, hf_2009_12_dpp_2_3_sec_flag_ssid
, tvb
, offset
, 1, ENC_NA
);
7121 if (sh_flags
& DPP_V2_SEC_FLAG_S
)
7123 int s_offset
= offset
;
7126 offset
= read_c4(tvb
, offset
, &ssid
, &ssid_len
);
7127 pi
= proto_tree_add_uint_format(security_tree
, hf_2009_12_dpp_2_3_sec_ssid
, tvb
, s_offset
, offset
- s_offset
, ssid
, "Security State Identifier: %u (0x%x)", ssid
, ssid
);
7128 validate_c4(pinfo
, pi
, ssid
, ssid_len
);
7131 /* At this point we know the transport information, DNP port information, and the
7132 * SSID. This means that we can isolate the session that this communication belongs
7133 * to. Note that all uses of an SSID are scoped by the transport.
7135 if (sh_flags
& DPP_V2_SEC_FLAG_A
)
7136 ssid
|= AS_ASSIGNED_SSID
;
7138 if (api_data
->session
&& !api_data
->secure_session
)
7140 dof_secure_session_data
*search
= api_data
->session
->secure_sessions
;
7143 if (ssid
== search
->ssid
)
7146 search
= search
->next
;
7151 api_data
->session
= search
->parent
;
7152 api_data
->secure_session
= search
;
7156 if (sh_flags
& DPP_V2_SEC_FLAG_D
)
7158 int s_offset
= offset
;
7162 offset
= read_c4(tvb
, offset
, &rdid
, &rdid_len
);
7163 pi
= proto_tree_add_uint_format(security_tree
, hf_2009_12_dpp_2_3_sec_rdid
, tvb
, s_offset
, offset
- s_offset
, rdid
, "Remote Domain Identifier: %u (0x%x)", rdid
, rdid
);
7164 validate_c4(pinfo
, pi
, rdid
, rdid_len
);
7166 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_10
, tvb
, pinfo
, security_tree
,
7167 offset
, hf_2009_12_dpp_2_3_sec_remote_partition
, ett_2009_12_dpp_2_3_sec_remote_partition
, NULL
);
7170 if (sh_flags
& DPP_V2_SEC_FLAG_P
)
7172 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_10
, tvb
, pinfo
, security_tree
,
7173 offset
, hf_2009_12_dpp_2_3_sec_partition
, ett_2009_12_dpp_2_3_sec_partition
, NULL
);
7176 if (sh_flags
& DPP_V2_SEC_FLAG_E
)
7178 /* If we get here without success, then we can only bail. */
7179 if (packet_data
->security_session_error
)
7181 col_set_str(pinfo
->cinfo
, COL_INFO
, packet_data
->security_session_error
);
7182 proto_item_set_end(tree
, tvb
, offset
);
7183 expert_add_info(pinfo
, security_tree
, &ei_dpp_no_security_context
);
7185 tvbuff_t
*data_tvb
= tvb_new_subset_remaining(tvb
, offset
);
7186 call_data_dissector(data_tvb
, pinfo
, tree
);
7188 proto_item_set_len(security_tree
, offset
- sec_offset
);
7192 if (!api_data
->secure_session
)
7194 packet_data
->security_session_error
= "[Encrypted - No Session Available]";
7195 proto_item_set_len(security_tree
, offset
- sec_offset
);
7199 /* Security has not failed, and we have a security session. */
7201 dissector_table_t sec_header
= find_dissector_table("dof.secmode");
7202 /* TODO: CCM is hardcoded. We should try all of the sessions, which could mean multiple security modes. */
7203 dissector_handle_t dp
= dissector_get_uint_handle(sec_header
, 0x6001); /* packet_data->security_session->security_mode); */
7206 dof_secmode_api_data sdata
;
7208 sdata
.context
= HEADER
;
7209 sdata
.security_mode_offset
= offset
;
7210 sdata
.dof_api
= api_data
;
7211 sdata
.secure_session
= api_data
->secure_session
;
7212 sdata
.session_key_data
= NULL
;
7214 offset
+= call_dissector_only(dp
, tvb
, pinfo
, security_tree
, &sdata
);
7216 if (!packet_data
->decrypted_buffer
)
7218 proto_item_set_end(tree
, tvb
, offset
);
7219 proto_item_set_len(security_tree
, offset
- sec_offset
);
7225 proto_item_set_len(security_tree
, offset
- sec_offset
);
7228 /* The end of the packet must be called in the original tvb or chaos ensues... */
7229 proto_item_set_end(tree
, tvb
, offset
);
7233 if (packet_data
->decrypted_tvb
)
7235 tvb
= packet_data
->decrypted_tvb
;
7236 offset
= packet_data
->decrypted_offset
;
7239 /* Assuming there is more, it must be DPP. */
7240 /* We have a packet. We must handle the special case of this being *our* application
7241 * protocol (0x7FFF). If it is, then *we* are the dissector...
7245 tvbuff_t
*next_tvb
= tvb_new_subset_length(tvb
, offset
, tvb_reported_length(tvb
) - offset
);
7247 read_c2(tvb
, offset
, &app
, NULL
);
7250 offset
+= dissect_dpp_v2_common(next_tvb
, pinfo
, proto_item_get_parent(tree
), data
);
7254 offset
+= dissect_app_common(next_tvb
, pinfo
, proto_item_get_parent(tree
), data
);
7259 col_set_fence(pinfo
->cinfo
, COL_PROTOCOL
);
7260 col_set_fence(pinfo
->cinfo
, COL_INFO
);
7264 static int dissect_options(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
7266 while (offset
< (int)tvb_captured_length(tvb
))
7268 proto_tree
*subtree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_2008_1_dsp_12_option
, NULL
, "Option");
7269 tvbuff_t
*next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
7270 int len
= dissect_2008_1_dsp_1(next_tvb
, pinfo
, subtree
);
7271 proto_item_set_len(proto_tree_get_parent(subtree
), len
);
7278 static int dissect_dsp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
7280 dof_api_data
*api_data
= (dof_api_data
*)data
;
7281 dof_packet_data
*packet_data
;
7282 unsigned offset
= 0;
7287 proto_tree
*dsp_tree
;
7288 proto_tree
*options_tree
;
7290 if (api_data
== NULL
)
7292 /* TODO: Output error. */
7296 packet_data
= api_data
->packet
;
7297 if (packet_data
== NULL
)
7299 /* TODO: Output error. */
7303 /* Make entries in Protocol column and Info column on summary display */
7304 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DSPv2 ");
7306 /* Create the protocol tree. */
7308 ti
= proto_tree_add_item(tree
, proto_2008_1_dsp
, tvb
, offset
, -1, ENC_NA
);
7309 dsp_tree
= proto_item_add_subtree(ti
, ett_2008_1_dsp_12
);
7311 /* Add the APPID. */
7312 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
7313 ti
= proto_tree_add_uint(dsp_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
7314 validate_c2(pinfo
, ti
, app
, app_len
);
7317 if (!packet
->is_streaming
)
7319 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DSPv2 ");
7321 if (tvb_captured_length(tvb
) == offset
)
7322 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query");
7325 col_set_str(pinfo
->cinfo
, COL_INFO
, "Query Response");
7326 while (offset
< tvb_captured_length(tvb
))
7330 offset
= read_c2(tvb
, offset
, &app
, NULL
);
7331 proto_tree_add_uint(dsp_tree
, hf_2008_1_app_version
, tvb
, start
, offset
- start
, app
);
7339 if (offset
== tvb_captured_length(tvb
))
7341 col_append_str(pinfo
->cinfo
, COL_INFO
, "DSP [nop]");
7342 expert_add_info(pinfo
, dsp_tree
, &ei_implicit_no_op
);
7347 /* Determine the ESP opcode. */
7348 opcode
= tvb_get_uint8(tvb
, offset
);
7350 if (!packet_data
->is_command
)
7351 opcode
|= OP_2008_1_RSP
;
7353 proto_tree_add_uint_format(dsp_tree
, hf_2008_1_dsp_12_opcode
, tvb
, offset
, 1, opcode
, "Opcode: %s (%u)", val_to_str(opcode
, strings_2008_1_dsp_opcodes
, "Unknown Opcode (%d)"), opcode
& 0x7F);
7355 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, "/", val_to_str(opcode
, strings_2008_1_dsp_opcodes
, "Unknown Opcode (%d)"));
7359 case OP_2008_1_OPEN_CMD
: /* 2008.1 DSP.14.1 */
7362 case OP_2008_1_OPEN_RSP
: /* 2008.1 DSP.14.2 */
7363 case OP_2008_1_OPEN_SECURE_RSP
: /* 2008.1 DSP.14.3 */
7365 while (offset
< tvb_captured_length(tvb
))
7371 offset
= read_c2(tvb
, offset
, &ap
, &length
);
7372 pi
= proto_tree_add_uint(dsp_tree
, hf_2008_1_app_version
, tvb
, start
, offset
- start
, ap
);
7373 validate_c2(pinfo
, pi
, ap
, length
);
7378 case OP_2008_1_QUERY_CMD
:
7381 case OP_2008_1_QUERY_RSP
:
7384 case OP_2008_1_CONFIG_ACK
:
7387 case OP_2008_1_CONFIG_REQ
:
7388 /* This will start a session if not existing... */
7391 case OP_2008_1_CONFIG_NAK
:
7393 int length
= tvb_captured_length(tvb
) - offset
;
7395 options_tree
= proto_tree_add_subtree_format(dsp_tree
, tvb
, offset
, length
, ett_2008_1_dsp_12_options
, NULL
,
7396 "DSP Options: (%d byte%s)", length
, plurality(length
, "", "s"));
7397 offset
= dissect_options(tvb
, offset
, pinfo
, options_tree
, NULL
);
7401 case OP_2008_1_CONFIG_REJ
:
7402 /* TODO: Handle reject. */
7405 case OP_2008_1_TERMINATE_CMD
:
7406 case OP_2008_1_TERMINATE_RSP
:
7414 static int dissect_ccm_dsp(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
7416 /* We are handed a buffer that starts with an option and our protocol id. Any options follow that. */
7418 proto_item
*parent
= proto_tree_get_parent(tree
);
7419 uint8_t len
, strength_count
, i
;
7421 proto_tree
*ccm_tree
;
7423 /* Append description to the parent. */
7424 proto_item_append_text(parent
, " (CCM)");
7426 /* Compute the version and flags, masking off other bits. */
7427 offset
+= 3; /* Skip the type and protocol. */
7428 len
= tvb_get_uint8(tvb
, offset
++);
7430 ti
= proto_tree_add_item(tree
, hf_ccm_dsp_option
, tvb
, offset
, len
, ENC_NA
);
7431 ccm_tree
= proto_item_add_subtree(ti
, ett_ccm_dsp_option
);
7433 strength_count
= tvb_get_uint8(tvb
, offset
);
7434 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_strength_count
, tvb
, offset
++, 1, ENC_NA
);
7436 for (i
= 0; i
< strength_count
; i
++)
7437 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_strength
, tvb
, offset
++, 1, ENC_NA
);
7439 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_e_flag
, tvb
, offset
, 1, ENC_NA
);
7440 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_m_flag
, tvb
, offset
, 1, ENC_NA
);
7441 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_tmax
, tvb
, offset
, 1, ENC_NA
);
7442 proto_tree_add_item(ccm_tree
, hf_ccm_dsp_tmin
, tvb
, offset
, 1, ENC_NA
);
7449 * This is the main entry point for the CCM dissector. It is always called from an DPS
7450 * dissector, and is always passed the dof_secmode_data structure.
7452 static int dissect_ccm(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
7454 dof_secmode_api_data
*secmode_api_data
;
7455 dof_session_key_exchange_data
*key_data
;
7457 secmode_api_data
= (dof_secmode_api_data
*)data
;
7458 if (secmode_api_data
== NULL
)
7463 key_data
= secmode_api_data
->session_key_data
;
7465 /* Based on the context of the request, handle the work. */
7466 switch (secmode_api_data
->context
)
7469 /* Parse off the initialization fields, and if necessary create the security mode state
7470 * that is being initialized. This is passed the DPS data, DPS session data, and Key Exchange Data.
7473 ccm_session_data
*ccm_data
= (ccm_session_data
*)key_data
->security_mode_key_data
;
7480 /* We need to parse the initialization data. */
7481 ccm_data
= wmem_new0(wmem_file_scope(), ccm_session_data
);
7484 wmem_register_callback(wmem_file_scope(), dof_sessions_destroy_cb
, ccm_data
);
7486 key_data
->security_mode_key_data
= ccm_data
;
7488 if (!key_data
->security_mode_data
|| key_data
->security_mode_data_length
< 3)
7491 /* TODO: Not sure that these are all right. */
7492 ccm_data
->protocol_id
= DOF_PROTOCOL_CCM
;
7493 ccm_data
->cipher
= key_data
->security_mode_data
[1];
7494 ccm_data
->encrypted
= key_data
->security_mode_data
[key_data
->security_mode_data_length
- 1] & 0x80;
7495 ccm_data
->mac_len
= (key_data
->security_mode_data
[key_data
->security_mode_data_length
- 1] & 0x07) * 2 + 2;
7496 ccm_data
->client_datagram_number
= 0;
7497 ccm_data
->server_datagram_number
= 0;
7499 switch (ccm_data
->protocol_id
)
7501 case DOF_PROTOCOL_CCM
:
7502 if (gcry_cipher_open(&ccm_data
->cipher_data
, GCRY_CIPHER_AES
, GCRY_CIPHER_MODE_ECB
, 0)) {
7512 if (secmode_api_data
->dof_api
->transport_session
->is_2_node
)
7514 switch (ccm_data
->protocol_id
)
7516 case DOF_PROTOCOL_CCM
:
7517 if (gcry_cipher_setkey(ccm_data
->cipher_data
, key_data
->session_key
, 32)) {
7518 gcry_cipher_close(ccm_data
->cipher_data
);
7519 ccm_data
->cipher_data
= NULL
;
7528 /* This mode has a fixed size, so we can return here without parsing further. */
7532 offset
= read_c2(tvb
, offset
, &length
, NULL
);
7533 /* TODO validate C2 */
7534 header
= tvb_get_uint8(tvb
, offset
);
7537 /* Determine the period, and store the key. */
7539 uint8_t period
= (header
& 0x70) >> 4;
7540 if (ccm_data
->cipher_data_table
== NULL
)
7542 gcry_cipher_hd_t ekey
;
7543 if (gcry_cipher_open(&ekey
, GCRY_CIPHER_AES
, GCRY_CIPHER_MODE_ECB
, 0)) {
7547 ccm_data
->cipher_data_table
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
, NULL
, dof_cipher_data_destroy
);
7548 ccm_data
->period
= 1;
7549 ccm_data
->periods
[period
] = ccm_data
->period
;
7551 switch (ccm_data
->protocol_id
)
7553 case DOF_PROTOCOL_CCM
:
7554 if (gcry_cipher_setkey(ekey
, key_data
->session_key
, 32)) {
7555 gcry_cipher_close(ekey
);
7561 gcry_cipher_close(ekey
);
7565 g_hash_table_insert(ccm_data
->cipher_data_table
, GUINT_TO_POINTER(ccm_data
->period
), ekey
);
7569 uint32_t lookup
= ccm_data
->periods
[period
];
7573 gcry_cipher_hd_t ekey
;
7574 if (gcry_cipher_open(&ekey
, GCRY_CIPHER_AES
, GCRY_CIPHER_MODE_ECB
, 0)) {
7577 switch (ccm_data
->protocol_id
)
7579 case DOF_PROTOCOL_CCM
:
7580 if (gcry_cipher_setkey(ekey
, key_data
->session_key
, 32)) {
7581 gcry_cipher_close(ekey
);
7587 gcry_cipher_close(ekey
);
7591 ccm_data
->period
+= 1;
7592 ccm_data
->periods
[period
] = ccm_data
->period
;
7593 g_hash_table_insert(ccm_data
->cipher_data_table
, GUINT_TO_POINTER(ccm_data
->period
), ekey
);
7597 uint8_t *in_table
= (uint8_t *)g_hash_table_lookup(ccm_data
->cipher_data_table
, GUINT_TO_POINTER(lookup
));
7598 if (memcmp(key_data
->session_key
, in_table
, 32) != 0)
7600 gcry_cipher_hd_t ekey
;
7601 if (gcry_cipher_open(&ekey
, GCRY_CIPHER_AES
, GCRY_CIPHER_MODE_ECB
, 0)) {
7604 switch (ccm_data
->protocol_id
)
7606 case DOF_PROTOCOL_CCM
:
7607 if (gcry_cipher_setkey(ekey
, key_data
->session_key
, 32)) {
7608 gcry_cipher_close(ekey
);
7614 gcry_cipher_close(ekey
);
7618 ccm_data
->period
+= 1;
7619 ccm_data
->periods
[period
] = ccm_data
->period
;
7620 g_hash_table_insert(ccm_data
->cipher_data_table
, GUINT_TO_POINTER(ccm_data
->period
), ekey
);
7626 return offset
+ length
- 1;
7631 ccm_session_data
*session
;
7632 dof_transport_session
*transport_session
= (dof_transport_session
*)secmode_api_data
->dof_api
->transport_session
;
7633 dof_secure_session_data
*secure_session
= secmode_api_data
->secure_session
;
7634 dof_session_key_exchange_data
*security_data
= NULL
;
7635 dof_packet_data
*dof_packet
= secmode_api_data
->dof_api
->packet
;
7640 bool pn_present
= false;
7643 proto_tree
*ccm_flags_tree
;
7644 proto_tree
*header_tree
;
7645 proto_item
* item
,*header
;
7646 ccm_packet_data
*pdata
;
7649 if (!dof_packet
->security_session
)
7651 if (transport_session
->is_streaming
)
7653 /* Find the first security data that is applicable - they are in order of packet sequence. */
7654 security_data
= secure_session
->session_security_data
;
7655 while (security_data
)
7657 if (dof_packet
->is_sent_by_initiator
&& (dof_packet
->dof_frame
> security_data
->i_valid
))
7660 if (!dof_packet
->is_sent_by_initiator
&& (dof_packet
->dof_frame
> security_data
->r_valid
))
7663 security_data
= security_data
->next
;
7667 dof_packet
->security_session
= security_data
;
7670 dof_packet
->security_session_error
= "[Encrypted - No Session Available]";
7676 dof_packet
->security_session
= secure_session
->session_security_data
;
7677 security_data
= dof_packet
->security_session
;
7682 security_data
= dof_packet
->security_session
;
7685 if (!security_data
|| !security_data
->session_key
|| !security_data
->security_mode_key_data
)
7687 dof_packet
->security_session_error
= "[Encrypted - No Session Available]";
7691 session
= (ccm_session_data
*)security_data
->security_mode_key_data
;
7692 offset
= secmode_api_data
->security_mode_offset
;
7694 /* Add a master header for this protocol. */
7695 header
= proto_tree_add_protocol_format(tree
, proto_ccm
, tvb
, offset
, 0,
7696 "CCM Security Mode, Version: 1");
7697 header_tree
= proto_item_add_subtree(header
, ett_header
);
7700 ccm_flags
= tvb_get_uint8(tvb
, offset
);
7701 item
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_flags
, tvb
,
7702 offset
, 1, ccm_flags
, "Flags: 0x%02x", ccm_flags
);
7704 ccm_flags_tree
= proto_item_add_subtree(item
, ett_epp_v1_ccm_flags
);
7705 proto_tree_add_item(ccm_flags_tree
, hf_epp_v1_ccm_flags_manager
, tvb
, offset
, 1, ENC_NA
);
7706 proto_tree_add_item(ccm_flags_tree
, hf_epp_v1_ccm_flags_period
, tvb
, offset
, 1, ENC_NA
);
7707 proto_tree_add_item(ccm_flags_tree
, hf_epp_v1_ccm_flags_target
, tvb
, offset
, 1, ENC_NA
);
7708 proto_tree_add_item(ccm_flags_tree
, hf_epp_v1_ccm_flags_next_nid
, tvb
, offset
, 1, ENC_NA
);
7709 proto_tree_add_item(ccm_flags_tree
, hf_epp_v1_ccm_flags_packet
, tvb
, offset
, 1, ENC_NA
);
7712 if (ccm_flags
& 0x01)
7715 pdata
= (ccm_packet_data
*)dof_packet
->security_packet
;
7718 pdata
= wmem_new0(wmem_file_scope(), ccm_packet_data
);
7721 dof_packet
->security_packet
= pdata
;
7723 if (transport_session
->is_2_node
)
7725 if (dof_packet
->is_sent_by_initiator
)
7728 if (pn_present
== false)
7729 pdata
->dn
= ++session
->client_datagram_number
;
7736 if (pn_present
== 0)
7737 pdata
->dn
= ++session
->server_datagram_number
;
7744 uint8_t packet_period
= (ccm_flags
& 0x70) >> 4;
7745 pdata
->period
= session
->periods
[packet_period
];
7751 return offset
- secmode_api_data
->security_mode_offset
;
7753 if (!secure_session
->is_2_node
)
7757 read_c4(tvb
, offset
, &nid
, &nid_len
);
7758 /* TODO: Do this right, as offset from BNID. */
7761 pi
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_nid
, tvb
, offset
, nid_len
, nid
, "Node ID: %u", nid
);
7762 validate_c4(pinfo
, pi
, nid
, nid_len
);
7767 item
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_nid
, tvb
, 0, 0, pdata
->nid
, "Node ID: %u", pdata
->nid
);
7768 proto_item_set_generated(item
);
7771 if (!secure_session
->is_2_node
)
7775 read_c2(tvb
, offset
, &slot
, &slot_len
);
7776 pi
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_slot
, tvb
, offset
, slot_len
, slot
, "Slot: %hu", slot
);
7777 validate_c2(pinfo
, pi
, slot
, slot_len
);
7782 item
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_slot
, tvb
, 0, 0, 0, "Slot: %u", 0);
7783 proto_item_set_generated(item
);
7786 if (ccm_flags
& 0x01)
7790 read_c4(tvb
, offset
, &pn
, &pn_len
);
7791 pi
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_pn
, tvb
, offset
, pn_len
, pn
, "Packet Number: %u", pn
);
7792 validate_c4(pinfo
, pi
, pn
, pn_len
);
7798 item
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_pn
, tvb
, 0, 0, pdata
->dn
, "Packet Number: %u", pdata
->dn
);
7799 proto_item_set_generated(item
);
7802 if (ccm_flags
& 0x08)
7806 read_c4(tvb
, offset
, &tnid
, &tnid_len
);
7807 pi
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_tnid
, tvb
, offset
, tnid_len
, tnid
, "Target Node ID: %u", tnid
);
7808 validate_c4(pinfo
, pi
, tnid
, tnid_len
);
7812 if (ccm_flags
& 0x02)
7816 read_c4(tvb
, offset
, &nnid
, &nnid_len
);
7817 pi
= proto_tree_add_uint_format(tree
, hf_epp_v1_ccm_nnid
, tvb
, offset
, nnid_len
, nnid
, "Next Node ID: %u", nnid
);
7818 validate_c4(pinfo
, pi
, nnid
, nnid_len
);
7822 proto_item_set_len(header
, offset
- secmode_api_data
->security_mode_offset
);
7824 if (dof_packet
->decrypted_buffer_error
)
7826 col_set_str(pinfo
->cinfo
, COL_INFO
, dof_packet
->decrypted_buffer_error
);
7827 expert_add_info(pinfo
, tree
, &ei_decode_failure
);
7828 return offset
- secmode_api_data
->security_mode_offset
;
7831 /* We have reached the encryption boundary. At this point the rest of the packet
7832 * is encrypted, and we may or may not be able to decrypt it.
7834 * If we can decrypt it (which for now means that it uses a Session Key of [0]
7835 * the we switch to decoding the decrypted PDU. Otherwise we create an entry
7836 * for the encrypted bytes and move on...
7840 int e_len
= tvb_captured_length(tvb
) - offset
;
7841 const uint8_t *epp_buf
= tvb_get_ptr(tvb
, 0, -1);
7842 unsigned a_len
= offset
;
7843 uint8_t *buf
= (uint8_t *)tvb_memdup(pinfo
->pool
, tvb
, offset
, e_len
);
7846 /* The default nonce is a function of whether or not this is the server
7847 * or the client and the packet count. The packet count either comes from
7848 * the PDU or is a function of the previous value (of the sending node).
7852 nonce
[0] = (pdata
->nid
) >> 24;
7853 nonce
[1] = (pdata
->nid
) >> 16;
7854 nonce
[2] = (pdata
->nid
) >> 8;
7855 nonce
[3] = (uint8_t)(pdata
->nid
);
7856 nonce
[4] = slot
>> 8;
7857 nonce
[5] = (uint8_t)slot
;
7858 nonce
[7] = (pdata
->dn
) >> 24;
7859 nonce
[8] = (pdata
->dn
) >> 16;
7860 nonce
[9] = (pdata
->dn
) >> 8;
7861 nonce
[10] = (uint8_t)(pdata
->dn
);
7863 /* Now the hard part. We need to determine the current packet number.
7864 * This is a function of the sending node, the previous state and the
7870 proto_item_set_end(tree
, tvb
, offset
);
7871 if (!session
->encrypted
)
7873 /* There is still a MAC involved, and even though we don't need a new
7874 * buffer we need to adjust the length of the existing buffer.
7876 app
= tvb_new_subset_length(tvb
, offset
, e_len
- session
->mac_len
);
7877 dof_packet
->decrypted_tvb
= app
;
7878 dof_packet
->decrypted_offset
= 0;
7882 if (dof_packet
->decrypted_buffer
)
7884 /* No need to decrypt, but still need to create buffer. */
7885 app
= tvb_new_real_data((const uint8_t *)dof_packet
->decrypted_buffer
, e_len
- session
->mac_len
, e_len
- session
->mac_len
);
7886 tvb_set_child_real_data_tvbuff(tvb
, app
);
7887 add_new_data_source(pinfo
, app
, "Decrypted DOF");
7888 dof_packet
->decrypted_tvb
= app
;
7889 dof_packet
->decrypted_offset
= 0;
7893 if (decrypt(session
, pdata
, nonce
, epp_buf
, a_len
, buf
, e_len
))
7895 /* store decrypted buffer in file scope for reuse in next pass */
7896 uint8_t *cache
= (uint8_t *)wmem_alloc0(wmem_file_scope(), e_len
- session
->mac_len
);
7897 memcpy(cache
, buf
, e_len
- session
->mac_len
);
7898 app
= tvb_new_real_data(cache
, e_len
- session
->mac_len
, e_len
- session
->mac_len
);
7899 tvb_set_child_real_data_tvbuff(tvb
, app
);
7900 add_new_data_source(pinfo
, app
, "Decrypted DOF");
7901 dof_packet
->decrypted_buffer
= cache
;
7902 dof_packet
->decrypted_offset
= 0;
7903 dof_packet
->decrypted_tvb
= app
;
7907 /* Failure to decrypt or validate the MAC.
7908 * The packet is secure, so there is nothing we can do!
7910 dof_packet
->decrypted_buffer_error
= "[Encrypted packet - decryption failure]";
7916 return offset
- secmode_api_data
->security_mode_offset
;
7921 /* TODO check this case */
7929 static int dissect_ccm_app(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
7937 proto_tree
*ccm_tree
;
7939 /* Make entries in Protocol column and Info column on summary display */
7940 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CCM ");
7942 /* Create the protocol tree. */
7944 ti
= proto_tree_add_item(tree
, proto_ccm_app
, tvb
, offset
, -1, ENC_NA
);
7945 ccm_tree
= proto_item_add_subtree(ti
, ett_ccm
);
7947 /* Add the APPID. */
7948 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
7949 ti
= proto_tree_add_uint(ccm_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
7950 validate_c2(pinfo
, ti
, app
, app_len
);
7952 /* Retrieve the opcode. */
7953 opcode
= tvb_get_uint8(tvb
, offset
);
7955 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(opcode
, ccm_opcode_strings
, "Unknown Opcode (%d)"));
7960 proto_tree_add_item(ccm_tree
, hf_ccm_opcode
, tvb
, offset
, 1, ENC_NA
);
7961 #if 0 /* this needs completion */
7978 #if 0 /* TODO not used yet */
7979 static int dissect_ccm_validate(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data
)
7981 dof_api_data
*api_data
= (dof_api_data
*)data
;
7982 dof_packet_data
*packet
;
7983 ccm_session_data
*session
;
7991 if (api_data
== NULL
)
7993 fprintf(stderr
, "api_data is NULL.");
7997 packet
= api_data
->packet
;
8000 fprintf(stderr
, "api_data->packet is NULL.");
8004 if (!packet
->security_session
)
8006 fprintf(stderr
, "packet->security_session is NULL");
8010 if (packet
->security_session
->security_mode
!= DOF_PROTOCOL_CCM
)
8012 fprintf(stderr
, "packet->security_session->security_mode != DOF_PROTOCOL_CCM");
8016 session
= (ccm_session_data
*)packet
->security_session
->security_mode_key_data
;
8018 /* The buffer we have been passed includes the entire EPP frame. The packet
8019 * structure gives us the offset to our header.
8023 ccm_flags
= tvb_get_uint8(tvb
, offset
);
8026 /* TODO validate the C2 and C4 fields below? */
8027 if (ccm_flags
& 0x04)
8028 offset
= read_c4(tvb
, offset
, &nid
, NULL
);
8030 if (ccm_flags
& 0x02)
8031 offset
= read_c2(tvb
, offset
, &slot
, NULL
);
8033 if (ccm_flags
& 0x01)
8034 offset
= read_c4(tvb
, offset
, &pn
, NULL
);
8036 if (ccm_flags
& 0x08)
8037 offset
= read_c4(tvb
, offset
, &tnid
, NULL
);
8040 /* We have reached the encryption boundary. At this point the rest of the packet
8041 * is encrypted, and we may or may not be able to decrypt it.
8043 * If we can decrypt it (which for now means that it uses a Session Key of [0]
8044 * the we switch to decoding the decrypted PDU. Otherwise we create an entry
8045 * for the encrypted bytes and move on...
8049 int e_len
= tvb_captured_length(tvb
) - offset
;
8050 const uint8_t *epp_buf
= tvb_get_ptr(tvb
, 0, -1);
8051 unsigned a_len
= offset
- 0;
8053 uint8_t *buf
= (uint8_t *)g_malloc(e_len
);
8055 /* The default nonce is a function of whether or not this is the server
8056 * or the client and the packet count. The packet count either comes from
8057 * the PDU or is a function of the previous value (of the sending node).
8059 uint8_t nonce
[] = { 0x00, 0x00, 0x00, 0x01,
8062 0x00, 0x00, 0x00, 0x00 };
8064 nonce
[0] = nid
>> 24;
8065 nonce
[1] = nid
>> 16;
8066 nonce
[2] = nid
>> 8;
8067 nonce
[3] = (uint8_t)nid
;
8068 nonce
[4] = slot
>> 8;
8069 nonce
[5] = (uint8_t)slot
;
8070 nonce
[7] = pn
>> 24;
8071 nonce
[8] = pn
>> 16;
8073 nonce
[10] = (uint8_t)pn
;
8075 /* Now the hard part. We need to determine the current packet number.
8076 * This is a function of the sending node, the previous state and the
8079 for (e_off
= 0; e_off
< e_len
; e_off
++)
8080 buf
[e_off
] = tvb_get_uint8(tvb
, offset
+ e_off
);
8082 /* TODO: This is hardcoded for a 4-byte MAC */
8084 proto_item_set_end(tree
, tvb
, offset
);
8085 if (decrypt(session
, (ccm_packet_data
*)packet
->security_packet
, nonce
, epp_buf
, a_len
, buf
, e_len
))
8092 /* Failure to decrypt or validate the MAC.
8093 * The packet is secure, so there is nothing we can do!
8102 static int dissect_oap_dsp(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
8104 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
8107 /* We don't care except for the treeview. */
8111 /* Compute the version and flags, masking off other bits. */
8112 offset
+= 4; /* Skip the type and protocol. */
8114 proto_tree_add_item(tree
, hf_oap_1_dsp_option
, tvb
, 0, -1, ENC_NA
);
8118 static int dissect_oap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
8120 dof_api_data
*api_data
= (dof_api_data
*)data
;
8121 dof_packet_data
*packet_data
;
8126 uint16_t item_id
= 0;
8130 oap_1_packet_data
*oap_packet
= NULL
;
8133 proto_tree
*oap_tree
;
8135 if (api_data
== NULL
)
8140 packet_data
= api_data
->packet
;
8141 if (packet_data
== NULL
)
8147 /* Make entries in Protocol column and Info column on summary display */
8148 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "OAPv1 ");
8150 /* Create the protocol tree. */
8152 ti
= proto_tree_add_item(tree
, proto_oap_1
, tvb
, offset
, -1, ENC_NA
);
8153 oap_tree
= proto_item_add_subtree(ti
, ett_oap_1
);
8155 /* Add the APPID. */
8156 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
8157 ti
= proto_tree_add_uint(oap_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
8158 validate_c2(pinfo
, ti
, app
, app_len
);
8160 if (app_len
== tvb_captured_length(tvb
))
8162 col_append_str(pinfo
->cinfo
, COL_INFO
, "OAP [nop]");
8163 expert_add_info(pinfo
, oap_tree
, &ei_implicit_no_op
);
8168 oap_packet
= (oap_1_packet_data
*)dof_packet_get_proto_data(packet_data
, proto_oap_1
);
8171 oap_packet
= wmem_new0(wmem_file_scope(), oap_1_packet_data
);
8172 dof_packet_add_proto_data(packet_data
, proto_oap_1
, oap_packet
);
8175 /* Compute the version and flags, masking off other bits. */
8176 opcode
= tvb_get_uint8(tvb
, offset
) & 0x1F;
8177 if (!packet_data
->is_command
)
8178 opcode
|= OAP_1_RESPONSE
;
8180 flags
= tvb_get_uint8(tvb
, offset
) & 0xE0;
8182 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(opcode
, oap_opcode_strings
, "Unknown Opcode (%d)"));
8187 uint8_t mask
= 0x10;
8189 uint8_t no_of_bits
= 5;
8192 (void) g_strlcpy(str
, "...", 20);
8194 /* read the bits for the int */
8195 for (i
= 0; i
< no_of_bits
; i
++)
8197 if (bit
&& (!(bit
% 4)))
8198 (void) g_strlcat(str
, " ", 20);
8203 (void) g_strlcat(str
, "1", 20);
8205 (void) g_strlcat(str
, "0", 20);
8210 proto_tree_add_uint_format(oap_tree
, hf_oap_1_opcode
, tvb
, offset
, 1, opcode
& 0x1F, "%s = Opcode: %s (%u)", str
, val_to_str(opcode
, oap_opcode_strings
, "Unknown Opcode (%d)"), opcode
& 0x1F);
8214 /* Flags, based on opcode.
8215 * Each opcode needs to define the flags, however, the fall into major categories...
8219 /* Both alias and a flag that equals command control. */
8220 case OAP_1_CMD_ACTIVATE
:
8221 case OAP_1_CMD_CONNECT
:
8222 case OAP_1_CMD_FULL_CONNECT
:
8224 case OAP_1_CMD_INVOKE
:
8225 case OAP_1_CMD_REGISTER
:
8227 case OAP_1_CMD_SUBSCRIBE
:
8228 case OAP_1_CMD_WATCH
:
8229 proto_tree_add_item(oap_tree
, hf_oap_1_alias_size
, tvb
, offset
, 1, ENC_NA
);
8230 proto_tree_add_item(oap_tree
, hf_oap_1_flags
, tvb
, offset
, 1, ENC_NA
);
8234 offset
= oap_1_tree_add_cmdcontrol(pinfo
, oap_tree
, tvb
, offset
);
8241 /* No alias, but flags for command control. */
8242 case OAP_1_CMD_ADVERTISE
:
8243 /* TODO: Expert info on top two bits.*/
8244 proto_tree_add_item(oap_tree
, hf_oap_1_flags
, tvb
, offset
, 1, ENC_NA
);
8247 offset
= oap_1_tree_add_cmdcontrol(pinfo
, oap_tree
, tvb
, ENC_BIG_ENDIAN
);
8254 /* No alias, but flag for provider. */
8256 case OAP_1_RSP_INVOKE
:
8257 case OAP_1_RSP_REGISTER
:
8259 case OAP_1_RSP_SUBSCRIBE
:
8260 /* TODO: Expert info on top two bits.*/
8261 proto_tree_add_item(oap_tree
, hf_oap_1_flags
, tvb
, offset
, 1, ENC_NA
);
8265 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, oap_tree
,
8266 offset
, hf_oap_1_providerid
, ett_oap_1_1_providerid
, NULL
);
8270 if ((opcode
== OAP_1_RSP_GET
) || (opcode
== OAP_1_RSP_INVOKE
))
8272 proto_tree_add_item(oap_tree
, hf_oap_1_value_list
, tvb
, offset
, -1, ENC_NA
);
8273 offset
+= tvb_reported_length_remaining(tvb
, offset
);
8278 /* Alias, but no flags. */
8279 case OAP_1_CMD_CHANGE
:
8280 case OAP_1_CMD_OPEN
:
8281 case OAP_1_CMD_PROVIDE
:
8282 case OAP_1_CMD_SIGNAL
:
8283 proto_tree_add_item(oap_tree
, hf_oap_1_alias_size
, tvb
, offset
, 1, ENC_NA
);
8287 /* Special flags. */
8288 case OAP_1_RSP_EXCEPTION
:
8289 proto_tree_add_item(oap_tree
, hf_oap_1_exception_internal_flag
, tvb
, offset
, 1, ENC_NA
);
8290 proto_tree_add_item(oap_tree
, hf_oap_1_exception_final_flag
, tvb
, offset
, 1, ENC_NA
);
8291 proto_tree_add_item(oap_tree
, hf_oap_1_exception_provider_flag
, tvb
, offset
, 1, ENC_NA
);
8296 case OAP_1_CMD_DEFINE
:
8297 case OAP_1_RSP_DEFINE
:
8298 case OAP_1_RSP_OPEN
:
8299 /* TODO: Non-zero not allowed.*/
8304 /* TODO: Illegal opcode.*/
8308 /* Parse off arguments based on opcodes. */
8311 case OAP_1_CMD_SUBSCRIBE
:
8313 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8317 /* The item identifier comes first, but it is compressed. */
8322 read_c2(tvb
, offset
, &item_id
, &item_id_len
);
8323 pi
= proto_tree_add_uint_format(oap_tree
, hf_oap_1_itemid
, tvb
, offset
, item_id_len
, item_id
, "Item ID: %u", item_id
);
8324 validate_c2(pinfo
, pi
, item_id
, item_id_len
);
8325 offset
+= item_id_len
;
8330 if (api_data
->session
== NULL
)
8332 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8335 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8338 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8340 /* Read the minimum delta. */
8346 read_c2(tvb
, offset
, &delta
, &delta_len
);
8347 pi
= proto_tree_add_uint_format(oap_tree
, hf_oap_1_subscription_delta
, tvb
, offset
, delta_len
, delta
, "Minimum Delta: %u", delta
);
8348 validate_c2(pinfo
, pi
, delta
, delta_len
);
8349 offset
+= delta_len
;
8354 case OAP_1_CMD_REGISTER
:
8356 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8360 /* The item identifier comes first, but it is compressed. */
8365 read_c2(tvb
, offset
, &item_id
, &item_id_len
);
8366 pi
= proto_tree_add_uint_format(oap_tree
, hf_oap_1_itemid
, tvb
, offset
, item_id_len
, item_id
, "Item ID: %u", item_id
);
8367 validate_c2(pinfo
, pi
, item_id
, item_id_len
);
8368 offset
+= item_id_len
;
8373 if (api_data
->session
== NULL
)
8375 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8378 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8381 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8385 case OAP_1_RSP_REGISTER
:
8389 /* offset = add_oid( tvb, offset, NULL, oap_tree ); */
8392 /* Sequence is next. */
8393 proto_tree_add_item(oap_tree
, hf_oap_1_update_sequence
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8398 case OAP_1_CMD_WATCH
:
8399 case OAP_1_CMD_ACTIVATE
:
8400 case OAP_1_CMD_CONNECT
:
8401 case OAP_1_CMD_FULL_CONNECT
:
8403 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8409 if (api_data
->session
== NULL
)
8411 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8414 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8417 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8421 case OAP_1_CMD_ADVERTISE
:
8422 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8426 case OAP_1_CMD_INVOKE
:
8429 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8433 /* The item identifier comes first, but it is compressed. */
8438 read_c2(tvb
, offset
, &item_id
, &item_id_len
);
8439 pi
= proto_tree_add_uint_format(oap_tree
, hf_oap_1_itemid
, tvb
, offset
, item_id_len
, item_id
, "Item ID: %u", item_id
);
8440 validate_c2(pinfo
, pi
, item_id
, item_id_len
);
8441 offset
+= item_id_len
;
8446 if (api_data
->session
== NULL
)
8448 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8451 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8454 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8456 if ((opcode
== OAP_1_CMD_SET
) || (opcode
== OAP_1_CMD_INVOKE
))
8458 proto_tree_add_item(oap_tree
, hf_oap_1_value_list
, tvb
, offset
, -1, ENC_NA
);
8459 offset
+= tvb_reported_length_remaining(tvb
, offset
);
8464 case OAP_1_CMD_OPEN
:
8466 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8472 if (api_data
->session
== NULL
)
8474 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8477 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8480 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8482 offset
= oap_1_tree_add_interface(oap_tree
, tvb
, offset
);
8484 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, oap_tree
,
8485 offset
, hf_oap_1_objectid
, ett_oap_1_objectid
, NULL
);
8489 case OAP_1_CMD_PROVIDE
:
8491 uint8_t alias_length
= flags
>> 6;
8496 if (alias_length
== 3)
8499 alias_offset
= offset
;
8500 if (alias_length
== 0)
8502 expert_add_info_format(pinfo
, ti
, &ei_malformed
, "alias_length == 0");
8505 if (api_data
->session
== NULL
)
8507 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8510 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_length
, false);
8512 iid_offset
= offset
;
8513 offset
= oap_1_tree_add_interface(oap_tree
, tvb
, offset
);
8515 oid_offset
= offset
;
8516 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, oap_tree
,
8517 offset
, hf_oap_1_objectid
, ett_oap_1_objectid
, NULL
);
8519 if (alias_length
&& !packet_data
->processed
)
8522 oap_1_binding
*binding
= wmem_new0(wmem_file_scope(), oap_1_binding
);
8526 for (i
= 0; i
< alias_length
; i
++)
8527 alias
= (alias
<< 8) | tvb_get_uint8(tvb
, alias_offset
+ i
);
8529 binding
->iid_length
= oid_offset
- iid_offset
;
8530 binding
->iid
= (uint8_t *)wmem_alloc0(wmem_file_scope(), binding
->iid_length
);
8531 tvb_memcpy(tvb
, binding
->iid
, iid_offset
, binding
->iid_length
);
8533 binding
->oid_length
= offset
- oid_offset
;
8534 binding
->oid
= (uint8_t *)wmem_alloc0(wmem_file_scope(), binding
->oid_length
);
8535 tvb_memcpy(tvb
, binding
->oid
, oid_offset
, binding
->oid_length
);
8537 binding
->frame
= pinfo
->fd
->num
;
8538 oap_1_define_alias(api_data
, alias
, binding
);
8543 case OAP_1_CMD_CHANGE
:
8544 case OAP_1_CMD_SIGNAL
:
8546 uint8_t alias_len
= (flags
& 0xC0) >> 6;
8550 /* The item identifier comes first, but it is compressed. */
8555 read_c2(tvb
, offset
, &item_id
, &item_id_len
);
8556 pi
= proto_tree_add_uint_format(oap_tree
, hf_oap_1_itemid
, tvb
, offset
, item_id_len
, item_id
, "Item ID: %u", item_id
);
8557 validate_c2(pinfo
, pi
, item_id
, item_id_len
);
8558 offset
+= item_id_len
;
8563 if (api_data
->session
== NULL
)
8565 expert_add_info(pinfo
, ti
, &ei_oap_no_session
);
8568 offset
= oap_1_tree_add_alias(api_data
, oap_packet
, packet_data
, oap_tree
, tvb
, pinfo
, offset
, alias_len
, true);
8571 offset
= oap_1_tree_add_binding(oap_tree
, pinfo
, tvb
, offset
);
8573 /* Sequence is next. */
8574 proto_tree_add_item(oap_tree
, hf_oap_1_update_sequence
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8577 proto_tree_add_item(oap_tree
, hf_oap_1_value_list
, tvb
, offset
, -1, ENC_NA
);
8578 offset
+= tvb_reported_length_remaining(tvb
, offset
);
8582 case OAP_1_RSP_EXCEPTION
:
8586 /* offset = add_oid( tvb, offset, NULL, oap_tree );*/
8589 /* The response code, compressed. */
8595 read_c2(tvb
, offset
, &rsp
, &rsp_len
);
8596 /* TODO: Add to tree with error codes. */
8599 proto_tree_add_item(oap_tree
, hf_oap_1_value_list
, tvb
, offset
, -1, ENC_NA
);
8600 offset
+= tvb_reported_length_remaining(tvb
, offset
);
8605 /* TODO: Bad opcode!*/
8612 static int dissect_sgmp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
8614 dof_api_data
*api_data
= (dof_api_data
*)data
;
8615 dof_packet_data
*packet_data
;
8616 unsigned offset
= 0;
8621 proto_tree
*sgmp_tree
;
8623 if (api_data
== NULL
)
8625 /* TODO: Output error. */
8629 packet_data
= api_data
->packet
;
8630 if (packet_data
== NULL
)
8632 /* TODO: Output error. */
8636 /* Make entries in Protocol column and Info column on summary display */
8637 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SGMPv1 ");
8639 /* Create the protocol tree. */
8641 ti
= proto_tree_add_item(tree
, proto_sgmp
, tvb
, offset
, -1, ENC_NA
);
8642 sgmp_tree
= proto_item_add_subtree(ti
, ett_sgmp
);
8644 /* Add the APPID. */
8645 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
8646 ti
= proto_tree_add_uint(sgmp_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
8647 validate_c2(pinfo
, ti
, app
, app_len
);
8649 if (offset
== tvb_captured_length(tvb
))
8651 col_append_str(pinfo
->cinfo
, COL_INFO
, "SGMP [nop]");
8652 expert_add_info(pinfo
, sgmp_tree
, &ei_implicit_no_op
);
8658 /* Retrieve the opcode. */
8659 opcode
= tvb_get_uint8(tvb
, offset
);
8660 if (!packet_data
->is_command
)
8661 opcode
|= SGMP_RESPONSE
;
8663 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(opcode
, sgmp_opcode_strings
, "Unknown Opcode (%d)"));
8666 proto_tree_add_item(sgmp_tree
, hf_opcode
, tvb
, offset
, 1, ENC_NA
);
8671 case SGMP_CMD_EPOCH_CHANGED
:
8673 /* TMIN - 2 bytes */
8675 proto_tree_add_item(sgmp_tree
, hf_sgmp_tmin
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8679 /* EPOCH - 2 bytes */
8681 proto_tree_add_item(sgmp_tree
, hf_sgmp_epoch
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8687 case SGMP_CMD_HEARTBEAT
:
8691 /* Latest SGMP Version - Type.1 */
8697 start_offset
= offset
;
8698 offset
= read_c2(tvb
, offset
, &version
, &length
);
8699 pi
= proto_tree_add_uint(sgmp_tree
, hf_latest_version
, tvb
, start_offset
, offset
- start_offset
, version
);
8700 validate_c2(pinfo
, pi
, version
, length
);
8703 /* Desire - 1 byte */
8705 proto_tree_add_item(sgmp_tree
, hf_desire
, tvb
, offset
, 1, ENC_NA
);
8709 /* Tie Breaker - 4 bytes */
8711 proto_tree_add_item(sgmp_tree
, hf_tie_breaker
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
8717 case SGMP_CMD_REKEY
:
8718 case SGMP_CMD_REKEY_EPOCH
:
8719 case SGMP_CMD_REKEY_MERGE
:
8721 #if 0 /*TODO check this */
8723 tvbuff_t
*initial_state
;
8727 /* Delay - one byte */
8728 if (opcode
!= SGMP_CMD_REKEY_MERGE
)
8730 proto_tree_add_item(sgmp_tree
, hf_delay
, tvb
, offset
, 1, ENC_NA
);
8734 /* Initial State - Security.9 (not REKEY_MERGE) */
8736 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_9
, tvb
, pinfo
, sgmp_tree
,
8737 offset
, hf_initial_state
, ett_initial_state
, NULL
);
8738 #if 0 /*TODO check this */
8739 initial_state
= tvb_new_subset_length(tvb
, start_offset
, offset
- start_offset
);
8743 /* Epoch - 2 bytes (only REKEY_EPOCH) */
8744 if (opcode
== SGMP_CMD_REKEY_EPOCH
)
8746 proto_tree_add_item(sgmp_tree
, hf_sgmp_epoch
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8750 /* Kgm - 32 bytes */
8752 proto_tree_add_item(sgmp_tree
, hf_key
, tvb
, offset
, 32, ENC_NA
);
8753 tvb_memcpy(tvb
, key
, offset
, 32);
8757 /* Handle the initialization block. */
8758 if (!packet_data
->processed
&& api_data
->session
)
8760 /*dof_session_data* session = (dof_session_data*)api_data->session;*/
8762 /* Look up the field-dissector table, and determine if it is registered. */
8763 dissector_table_t field_dissector
= find_dissector_table("dof.secmode");
8764 if (field_dissector
!= NULL
)
8767 dissector_handle_t field_handle
= dissector_get_port_handle(field_dissector
, packet_data
->security_mode
);
8768 if (field_handle
!= NULL
)
8770 void *saved_private
= pinfo
->private_data
;
8771 dof_secmode_api_data setup_data
;
8774 setup_data
.version
= DOF_API_VERSION
;
8775 setup_data
.context
= INITIALIZE
;
8776 setup_data
.dof_api
= api_data
;
8777 setup_data
.secure_session
= rekey_data
->security_session
;
8778 /* TODO FIX THIS setup_data.session_key = session_key; */
8779 pinfo
->private_data
= &setup_data
;
8780 block_length
= call_dissector_only(field_handle
, NULL
, pinfo
, NULL
);
8781 pinfo
->private_data
= saved_private
;
8789 case SGMP_CMD_REQUEST_GROUP
:
8791 uint8_t *domain_buf
= NULL
;
8792 uint8_t domain_length
= 0;
8794 unsigned I_offset
= offset
;
8795 sgmp_packet_data
*sgmp_data
= NULL
;
8798 /* START OF I BLOCK */
8799 /* Domain - Security.7 */
8801 start_offset
= offset
;
8802 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, sgmp_tree
,
8803 offset
, hf_sgmp_domain
, ett_sgmp_domain
, NULL
);
8804 if (!packet_data
->processed
)
8806 domain_length
= offset
- start_offset
;
8807 domain_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), domain_length
);
8808 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
8812 /* Epoch - 2 bytes */
8814 epoch
= tvb_get_ntohs(tvb
, offset
);
8815 proto_tree_add_item(sgmp_tree
, hf_sgmp_epoch
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
8819 /* Initiator Block - SGMP.6.3 */
8821 /* SGMP Key Request - Security.4 */
8823 dof_2008_16_security_4 response
;
8824 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_4
, tvb
, pinfo
, sgmp_tree
,
8825 offset
, hf_initiator_block
, ett_initiator_block
, &response
);
8826 if (!packet_data
->processed
)
8828 tvbuff_t
*identity
= response
.identity
;
8829 uint8_t identity_length
= tvb_reported_length(identity
);
8830 uint8_t *identity_buf
= (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length
);
8832 /* Get the buffer. */
8833 tvb_memcpy(identity
, identity_buf
, 0, identity_length
);
8836 sgmp_data
= wmem_new0(wmem_file_scope(), sgmp_packet_data
);
8837 dof_packet_add_proto_data(packet_data
, proto_sgmp
, sgmp_data
);
8839 sgmp_data
->domain_length
= domain_length
;
8840 sgmp_data
->domain
= (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length
);
8841 memcpy(sgmp_data
->domain
, domain_buf
, domain_length
);
8843 sgmp_data
->group_length
= identity_length
;
8844 sgmp_data
->group
= (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length
);
8845 memcpy(sgmp_data
->group
, identity_buf
, identity_length
);
8847 sgmp_data
->epoch
= epoch
;
8848 sgmp_data
->request_session
= api_data
->session
;
8854 /* Security Scope - Security.10 */
8856 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_10
, tvb
, pinfo
, sgmp_tree
,
8857 offset
, hf_sgmp_security_scope
, ett_sgmp_security_scope
, NULL
);
8860 /* END OF I BLOCK */
8861 if (sgmp_data
&& !sgmp_data
->I
)
8863 sgmp_data
->I_length
= offset
- I_offset
;
8864 sgmp_data
->I
= (uint8_t *)wmem_alloc0(wmem_file_scope(), sgmp_data
->I_length
);
8865 tvb_memcpy(tvb
, sgmp_data
->I
, I_offset
, sgmp_data
->I_length
);
8870 case SGMP_RSP_REQUEST_GROUP
:
8873 #if 0 /*TODO check this */
8875 tvbuff_t
*initial_state
;
8879 /* START OF A BLOCK */
8880 /* Initial State - SGMP.6.2.1 */
8882 /* A_offset = offset;*/
8884 /* Initial State - Security.9 */
8886 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_9
, tvb
, pinfo
, sgmp_tree
,
8887 offset
, hf_initial_state
, ett_initial_state
, NULL
);
8888 #if 0 /*TODO check this */
8889 initial_state
= tvb_new_subset_length(tvb
, start_offset
, offset
- start_offset
);
8893 /* Latest SGMP Version - Type.1 */
8899 start_offset
= offset
;
8900 offset
= read_c2(tvb
, offset
, &version
, &length
);
8901 pi
= proto_tree_add_uint(sgmp_tree
, hf_latest_version
, tvb
, start_offset
, offset
- start_offset
, version
);
8902 validate_c2(pinfo
, pi
, version
, length
);
8905 /* Desire - 1 byte */
8907 proto_tree_add_item(sgmp_tree
, hf_desire
, tvb
, offset
, 1, ENC_NA
);
8912 /* END OF A BLOCK */
8913 /* A block data handled in first part of the next block. */
8914 #if 0 /*TODO check this */
8918 /* Ticket - Security.5 */
8920 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, sgmp_tree
,
8921 offset
, hf_ticket
, ett_ticket
, NULL
);
8924 /* Try to match up the information learned here with any groups that exist.
8925 * Note that we do not know the SSID, and so we can only match based on the
8926 * domain and group identifier. We will learn the SSID based on a successful
8927 * match to a secure session.
8929 if (packet_data
->opid_first
&& !api_data
->secure_session
)
8932 sgmp_packet_data
* cmd_data
= (sgmp_packet_data
*)dof_packet_get_proto_data(packet_data
->opid_first
, proto_sgmp
);
8933 extern struct BlockCipher BlockCipher_AES_256
;
8934 struct BlockCipher
* cipher
= &BlockCipher_AES_256
;
8935 uint8_t* ekey
= (uint8_t*)ep_alloc(cipher
->keyStateSize
);
8937 if (cmd_data
&& !cmd_data
->A
)
8939 cmd_data
->A_length
= A_end
- A_offset
;
8940 cmd_data
->A
= (uint8_t*)wmem_alloc0(wmem_file_scope(), cmd_data
->A_length
);
8941 tvb_memcpy(tvb
, cmd_data
->A
, A_offset
, cmd_data
->A_length
);
8944 /* Search through the appropriate keks to find a match. */
8946 dof_learned_group_data
* group
= globals
.learned_group_data
;
8949 { dof_learned_group_data
*group
;
8950 struct list
*next
; };
8951 struct list
*to_try
= NULL
;
8952 uint8_t confirmation
[32];
8953 uint8_t* discovered_kek
= NULL
;
8954 dof_learned_group_auth_data
*auth
= NULL
;
8956 tvb_memcpy(tvb
, confirmation
, start_offset
, 32);
8960 if ((cmd_data
->domain_length
== group
->domain_length
) &&
8961 (memcmp(cmd_data
->domain
, group
->domain
, group
->domain_length
) == 0) &&
8962 (cmd_data
->group_length
== group
->group_length
) &&
8963 (memcmp(cmd_data
->group
, group
->group
, group
->group_length
) == 0))
8965 struct list
*n
= (struct list
*) ep_alloc0(sizeof(struct list
));
8971 group
= group
->next
;
8974 /* At this point we may be able to learn the session key. */
8975 while (to_try
&& !discovered_kek
)
8977 group
= to_try
->group
;
8981 while (auth
&& !discovered_kek
)
8987 /* It only makes sense to check matching epochs. */
8988 if (auth
->epoch
== cmd_data
->epoch
)
8990 tvb_memcpy(tvb
, mac
, start_offset
, 32);
8991 tvb_memcpy(tvb
, key
, start_offset
+ 32, 32);
8995 cipher
->GenerateKeyState(ekey
, auth
->kek
);
8996 cipher
->Encrypt(ekey
, mac
);
8997 cipher
->Encrypt(ekey
, mac
+ 16);
9000 for (j
= 0; j
< 32; j
++)
9003 if (sgmp_validate_session_key(cmd_data
, confirmation
, auth
->kek
, key
))
9005 discovered_kek
= (uint8_t*)se_alloc0(32);
9006 memcpy(discovered_kek
, key
, 32);
9014 to_try
= to_try
->next
;
9017 /* Determine if there is already a secure session for this information. If there is, then
9018 * EPP will find it to decode any packets. If there is not, then we must create a secure
9019 * session and initialize it so that future packets can be decoded.
9020 * NOTE: None of the actual decoding is done here, because this packet is not encrypted
9021 * in the session that it defines.
9022 * NOTE: SGMP secure sessions are always attached to the DPS session, which is always
9023 * associated with the transport session (server address).
9027 dissector_table_t field_dissector
;
9028 dissector_handle_t field_handle
;
9029 dof_session_key_exchange_data
*key_exchange
= NULL
;
9031 dof_secure_session_data
*dof_secure_session
= cmd_data
->request_session
->secure_sessions
;
9032 while (dof_secure_session
)
9034 if ((dof_secure_session
->ssid
== group
->ssid
) &&
9035 (dof_secure_session
->domain_length
== group
->domain_length
) &&
9036 (memcmp(dof_secure_session
->domain
, group
->domain
, group
->domain_length
) == 0))
9039 dof_secure_session
= dof_secure_session
->next
;
9042 if (!dof_secure_session
)
9044 dof_session_data
*dof_session
= wmem_alloc0(wmem_file_scope(), sizeof(dof_session_data
));
9045 dof_session
->session_id
= globals
.next_session
++;
9046 dof_session
->dof_id
= api_data
->session
->dof_id
;
9048 dof_secure_session
= wmem_alloc0(wmem_file_scope(), sizeof(dof_secure_session_data
));
9049 dof_secure_session
->ssid
= group
->ssid
;
9050 dof_secure_session
->domain_length
= group
->domain_length
;
9051 dof_secure_session
->domain
= group
->domain
;
9052 dof_secure_session
->original_session_id
= cmd_data
->request_session
->session_id
;
9053 dof_secure_session
->parent
= dof_session
;
9054 dof_secure_session
->is_2_node
= false;
9055 dof_secure_session
->next
= cmd_data
->request_session
->secure_sessions
;
9056 cmd_data
->request_session
->secure_sessions
= dof_secure_session
;
9059 /* This packet represents a new key exchange, and so a new key exchange data
9060 * structure needs to be created.
9063 key_exchange
= wmem_alloc0(wmem_file_scope(), sizeof(dof_session_key_exchange_data
));
9067 key_exchange
->i_valid
= packet_data
->opid_first
->dof_frame
;
9068 key_exchange
->r_valid
= packet_data
->dof_frame
;
9069 key_exchange
->security_mode
= auth
->security_mode
;
9070 key_exchange
->security_mode_data
= auth
->mode
;
9071 key_exchange
->security_mode_data_length
= auth
->mode_length
;
9072 key_exchange
->session_key
= discovered_kek
;
9074 /* Insert the new key information at the front of the list. */
9075 if (!dof_secure_session
->session_security_data_last
)
9076 dof_secure_session
->session_security_data
= key_exchange
;
9078 dof_secure_session
->session_security_data_last
->next
= key_exchange
;
9080 dof_secure_session
->session_security_data_last
= key_exchange
;
9083 /* Look up the field-dissector table, and determine if it is registered. */
9084 field_dissector
= find_dissector_table("dps.secmode");
9085 if (field_dissector
!= NULL
)
9087 field_handle
= dissector_get_uint_handle(field_dissector
, auth
->security_mode
);
9088 if (field_handle
!= NULL
)
9090 dof_secmode_api_data setup_data
;
9092 tvbuff_t
*ntvb
= tvb_new_subset_remaining(tvb
, A_offset
);
9094 setup_data
.context
= INITIALIZE
;
9095 setup_data
.security_mode_offset
= 0;
9096 setup_data
.dof_api
= api_data
;
9097 setup_data
.secure_session
= dof_secure_session
;
9098 setup_data
.session_key_data
= key_exchange
;
9099 block_length
= call_dissector_only(field_handle
, ntvb
, pinfo
, tree
, &setup_data
);
9116 static bool validate_session_key(tep_rekey_data
*rekey
, unsigned S_length
, uint8_t *S
, uint8_t *confirmation
, uint8_t *key
)
9120 gcry_error_t result
;
9122 memset(pad
, 0, sizeof(pad
));
9123 result
= gcry_mac_open(&hmac
, GCRY_MAC_HMAC_SHA256
, 0, NULL
);
9127 gcry_mac_setkey(hmac
, key
, 32);
9128 gcry_mac_write(hmac
, pad
, 16 - rekey
->i_nonce_length
);
9129 gcry_mac_write(hmac
, rekey
->i_nonce
, rekey
->i_nonce_length
);
9130 gcry_mac_write(hmac
, pad
, 16 - rekey
->r_nonce_length
);
9131 gcry_mac_write(hmac
, rekey
->r_nonce
, rekey
->r_nonce_length
);
9132 gcry_mac_write(hmac
, S
, S_length
);
9133 gcry_mac_write(hmac
, rekey
->r_identity
, rekey
->r_identity_length
);
9134 result
= gcry_mac_verify(hmac
, confirmation
, 32);
9138 static int dissect_tep_dsp(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
9140 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9143 /* We don't care except for the treeview. */
9147 /* Compute the version and flags, masking off other bits. */
9148 offset
+= 4; /* Skip the type and protocol. */
9150 proto_tree_add_item(tree
, hf_dsp_option
, tvb
, 0, -1, ENC_NA
);
9154 static int dissect_2008_4_tep_2_2_1(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t *ssid
, void *data
)
9158 dof_api_data
*api_data
= (dof_api_data
*)data
;
9159 dof_packet_data
*packet_data
;
9161 if (api_data
== NULL
)
9163 /* TODO: Output error. */
9167 packet_data
= api_data
->packet
;
9168 if (packet_data
== NULL
)
9170 /* TODO: Output error. */
9174 /* State Identifier - Only if Unsecured */
9175 if (packet_data
->decrypted_buffer
== NULL
)
9180 offset
= read_c4(tvb
, offset
, ssid
, &ssid_len
);
9181 pi
= proto_tree_add_uint(tree
, hf_tep_2_2_1_state_identifier
, tvb
, start
, offset
- start
, *ssid
);
9182 validate_c4(pinfo
, pi
, *ssid
, ssid_len
);
9188 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
9189 ti
= proto_tree_add_item(tree
, hf_tep_2_2_1_initial_state
, tvb
, offset
, 0, ENC_NA
);
9190 ti
= proto_item_add_subtree(ti
, ett_tep_2_2_1_initial_state
);
9191 block_length
= dof_dissect_pdu(dissect_2008_16_security_9
, start
, pinfo
, ti
, NULL
);
9192 proto_item_set_len(ti
, block_length
);
9193 offset
+= block_length
;
9200 * This is the main entry point for the CCM dissector.
9201 * TEP operations create security periods.
9202 * They can also create sessions when used with "None" sessions.
9203 * In any case, these PDUs need to pass information between
9205 * They also must maintain state for each rekey request, some of
9206 * which modify the session key, some of which create new
9207 * sessions, and others that determine new session information
9208 * like permission sets.
9210 * In order to store information appropriately, the following structures are
9212 * 1. api_data (dof_api_data*) source for all other state.
9213 * 2. packet (dof_packet_data*) dps packet information.
9214 * 3. rekey_data (tep_rekey_data*) tep information for rekey/accept/confirm.
9216 static int dissect_tep(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
9218 dof_api_data
*api_data
= (dof_api_data
*)data
;
9219 dof_packet_data
*packet
;
9220 tep_rekey_data
*rekey_data
;
9222 unsigned offset
= 0;
9227 proto_tree
*tep_tree
, *operation_tree
;
9229 if (api_data
== NULL
)
9231 /* TODO: Output error. */
9235 packet
= api_data
->packet
;
9238 /* TODO: Output error. */
9242 /* Make entries in Protocol column and Info column on summary display */
9243 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TEPv1 ");
9245 /* Create the protocol tree. */
9247 ti
= proto_tree_add_item(tree
, proto_tep
, tvb
, offset
, -1, ENC_NA
);
9248 tep_tree
= proto_item_add_subtree(ti
, ett_tep
);
9250 /* Add the APPID. */
9251 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
9252 ti
= proto_tree_add_uint(tep_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
9253 validate_c2(pinfo
,ti
, app
, app_len
);
9255 /* Check for empty packet. */
9256 if (offset
== tvb_captured_length(tvb
))
9258 col_append_str(pinfo
->cinfo
, COL_INFO
, "TEP [nop]");
9259 expert_add_info(pinfo
, tep_tree
, &ei_implicit_no_op
);
9264 /* Retrieve the opcode. */
9265 operation
= tvb_get_uint8(tvb
, offset
);
9266 if (!packet
->is_command
)
9267 operation
|= TEP_OPCODE_RSP
;
9269 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(operation
, tep_opcode_strings
, "Unknown Opcode (%d)"));
9271 ti
= proto_tree_add_uint_format(tep_tree
, hf_tep_operation
, tvb
, offset
, 1, operation
, "Operation: %s (%u)", val_to_str(operation
, tep_opcode_strings
, "Unknown Opcode (%d)"), operation
);
9273 operation_tree
= proto_item_add_subtree(ti
, ett_tep_operation
);
9274 ti
= proto_tree_add_boolean(operation_tree
, hf_tep_operation_type
, tvb
, offset
, 0, operation
);
9275 proto_item_set_generated(ti
);
9277 /* The flags are reserved except for OPCODE=1 & COMMAND */
9278 if ((operation
& 0x8F) == 0x01)
9280 proto_tree_add_item(operation_tree
, hf_tep_c
, tvb
, offset
, 1, ENC_NA
);
9281 proto_tree_add_item(operation_tree
, hf_tep_k
, tvb
, offset
, 1, ENC_NA
);
9284 proto_tree_add_item(operation_tree
, hf_tep_opcode
, tvb
, offset
, 1, ENC_NA
);
9289 case TEP_PDU_REQUEST_KEY
:
9290 /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9292 /* Remember the current request. */
9293 rekey_data
= (tep_rekey_data
*)packet
->opid_data
;
9296 packet
->opid_data
= rekey_data
= wmem_new0(wmem_file_scope(), tep_rekey_data
);
9299 rekey_data
->key_data
= wmem_new0(wmem_file_scope(), dof_session_key_exchange_data
);
9300 rekey_data
->is_rekey
= true;
9302 /* The K bit must be set, so there is a domain ONLY IF NOT SECURED. */
9303 if (packet
->decrypted_buffer
== NULL
)
9305 int start_offset
= offset
;
9307 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, tep_tree
,
9308 offset
, hf_tep_2_1_domain
, ett_tep_2_1_domain
, NULL
);
9310 if (!rekey_data
->domain
)
9312 rekey_data
->domain_length
= offset
- start_offset
;
9313 rekey_data
->domain
= (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data
->domain_length
);
9315 /* Get the buffer. */
9316 tvb_memcpy(tvb
, rekey_data
->domain
, start_offset
, rekey_data
->domain_length
);
9321 /* The domain is not present, but this is a secure packet and so the domain can be obtained
9322 * through the session.
9324 if (!rekey_data
->domain
)
9326 rekey_data
->domain_length
= api_data
->secure_session
->domain_length
;
9327 rekey_data
->domain
= api_data
->secure_session
->domain
;
9333 case TEP_PDU_REQUEST
:
9335 /* Remember the current request. */
9336 rekey_data
= (tep_rekey_data
*)packet
->opid_data
;
9339 if (api_data
->secure_session
== NULL
)
9341 /* TODO: Output error. */
9344 packet
->opid_data
= rekey_data
= wmem_new0(wmem_file_scope(), tep_rekey_data
);
9345 rekey_data
->domain_length
= api_data
->secure_session
->domain_length
;
9346 rekey_data
->domain
= api_data
->secure_session
->domain
;
9349 /* The C bit must be clear, so there is an Initiator Block. */
9351 dof_2008_16_security_6_1 response
;
9352 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_1
, tvb
, pinfo
, tep_tree
,
9353 offset
, hf_tep_2_1_initiator_block
, ett_tep_2_1_initiator_block
, &response
);
9354 if (!packet
->processed
)
9356 tvbuff_t
*inonce
= response
.i_nonce
;
9357 tvbuff_t
*iidentity
= response
.i_identity
;
9359 rekey_data
->i_nonce_length
= tvb_reported_length(inonce
);
9360 rekey_data
->i_nonce
= (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data
->i_nonce_length
);
9361 tvb_memcpy(inonce
, rekey_data
->i_nonce
, 0, rekey_data
->i_nonce_length
);
9363 rekey_data
->i_identity_length
= tvb_reported_length(iidentity
);
9364 rekey_data
->i_identity
= (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data
->i_identity_length
);
9365 tvb_memcpy(iidentity
, rekey_data
->i_identity
, 0, rekey_data
->i_identity_length
);
9367 rekey_data
->security_mode
= response
.security_mode
;
9368 rekey_data
->security_mode_data_length
= response
.security_mode_data_length
;
9369 rekey_data
->security_mode_data
= response
.security_mode_data
;
9374 case TEP_PDU_ACCEPT
:
9378 uint8_t S_length
= 0;
9379 uint8_t confirmation
[32];
9380 typedef struct identity_key
9382 uint8_t *session_key
;
9383 struct identity_key
*next
;
9385 identity_key
*identity_key_list
= NULL
;
9386 dof_secure_session_data
*dof_secure_session
= NULL
;
9388 if (!packet
->opid_first
)
9390 /* TODO: Print error */
9394 rekey_data
= (tep_rekey_data
*)packet
->opid_first
->opid_data
;
9396 return tvb_captured_length(tvb
);
9398 /* Initiator Ticket */
9403 start_offset
= offset
;
9404 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, tep_tree
,
9405 offset
, hf_tep_2_2_initiator_ticket
, ett_tep_2_2_initiator_ticket
, NULL
);
9407 if (!packet
->processed
&& rekey_data
)
9411 /* Produce a (possibly empty) list of potential keys based on our
9412 * initiator secrets based on identity. These will be validated
9415 for (i
= 0; i
< globals
.global_security
->identity_data_count
; i
++)
9417 dof_identity_data
*identity
= globals
.global_security
->identity_data
+ i
;
9418 gcry_cipher_hd_t rijndael_handle
;
9421 if (identity
->domain_length
!= rekey_data
->domain_length
)
9423 if (memcmp(identity
->domain
, rekey_data
->domain
, identity
->domain_length
) != 0)
9425 if (identity
->identity_length
!= rekey_data
->i_identity_length
)
9427 if (memcmp(identity
->identity
, rekey_data
->i_identity
, identity
->identity_length
) != 0)
9430 tvb_memcpy(tvb
, ticket
, start_offset
, 64);
9432 if (!gcry_cipher_open(&rijndael_handle
, GCRY_CIPHER_AES
, GCRY_CIPHER_MODE_ECB
, 0)) {
9433 if (!gcry_cipher_setkey(rijndael_handle
, identity
->secret
, 32)) {
9434 gcry_cipher_encrypt(rijndael_handle
, ticket
, 16, NULL
, 0);
9435 gcry_cipher_encrypt(rijndael_handle
, ticket
+ 16, 16, NULL
, 0);
9437 gcry_cipher_close(rijndael_handle
);
9440 for (j
= 0; j
< 32; j
++)
9441 ticket
[j
+ 32] = ticket
[j
+ 32] ^ ticket
[j
];
9443 /* Add the key to the list - ep memory. */
9445 identity_key
*key
= (identity_key
*)wmem_alloc0(wmem_file_scope(), sizeof(*key
));
9446 key
->session_key
= (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9447 memcpy(key
->session_key
, ticket
+ 32, 32);
9448 key
->next
= identity_key_list
;
9449 identity_key_list
= key
;
9455 /* Ticket Confirmation */
9457 if (!packet
->processed
)
9458 tvb_memcpy(tvb
, confirmation
, offset
, sizeof(confirmation
));
9459 proto_tree_add_item(tep_tree
, hf_tep_2_2_ticket_confirmation
, tvb
, offset
, 32, ENC_NA
);
9463 /* Add a field to show the session key that has been learned. */
9464 if (rekey_data
->key_data
&& rekey_data
->key_data
->session_key
&& tep_tree
)
9466 ti
= proto_tree_add_bytes_with_length(tree
, hf_tep_session_key
, tvb
, 0, 0, rekey_data
->key_data
->session_key
, 32);
9467 proto_item_set_generated(ti
);
9470 /* Responder Initialization - present based on whether the command was a rekey */
9473 if (rekey_data
&& rekey_data
->is_rekey
)
9476 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
9477 ti
= proto_tree_add_item(tep_tree
, hf_tep_2_2_responder_initialization
, tvb
, offset
, 0, ENC_NA
);
9478 ti
= proto_item_add_subtree(ti
, ett_tep_2_2_responder_initialization
);
9479 block_length
= dissect_2008_4_tep_2_2_1(start
, pinfo
, ti
, &ssid
, data
);
9480 proto_item_set_len(ti
, block_length
);
9481 offset
+= block_length
;
9483 if (!packet
->processed
)
9485 S_length
= block_length
;
9486 S
= (uint8_t *)wmem_alloc0(wmem_file_scope(), S_length
);
9487 tvb_memcpy(start
, S
, 0, S_length
);
9490 /* TEP can create new sessions when not used inside an existing secure
9491 * session. Each session can use an SSID, present in TEP.2.2.1.
9492 * Note that in this case there may be no existing session, and so
9493 * we need to "backpedal" and create one.
9495 if (packet
->decrypted_buffer
== NULL
&& !packet
->processed
)
9498 if (api_data
->session
)
9499 tep_session
= (tep_session_data
*)dof_session_get_proto_data((dof_session_data
*)api_data
->session
, proto_tep
);
9500 if (!tep_session
&& api_data
->session
)
9502 tep_session
= (tep_session_data
*)se_alloc0(sizeof(*tep_session
));
9503 dof_session_add_proto_data((dof_session_data
*)api_data
->session
, proto_tep
, tep_session
);
9506 tep_session
->pending_rekey
= cmd
;
9507 tep_session
->pending_confirm
= packet
;
9513 /* Responder Block */
9515 dof_2008_16_security_6_2 response
;
9516 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_2
, tvb
, pinfo
, tep_tree
,
9517 offset
, hf_tep_2_2_responder_block
, ett_tep_2_2_responder_block
, &response
);
9518 if (!packet
->processed
)
9520 tvbuff_t
*rnonce
= response
.r_nonce
;
9521 tvbuff_t
*ridentity
= response
.r_identity
;
9523 rekey_data
->r_nonce_length
= tvb_reported_length(rnonce
);
9524 rekey_data
->r_nonce
= (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data
->r_nonce_length
);
9525 tvb_memcpy(rnonce
, rekey_data
->r_nonce
, 0, rekey_data
->r_nonce_length
);
9527 rekey_data
->r_identity_length
= tvb_reported_length(ridentity
);
9528 rekey_data
->r_identity
= (uint8_t *)wmem_alloc0(wmem_file_scope(), rekey_data
->r_identity_length
);
9529 tvb_memcpy(ridentity
, rekey_data
->r_identity
, 0, rekey_data
->r_identity_length
);
9533 /* Authentication Initialization */
9535 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_3
, tvb
, pinfo
, tep_tree
,
9536 offset
, hf_tep_2_2_authenticator_initialization
, ett_tep_2_2_authenticator_initialization
, NULL
);
9540 /* The request was accepted, and so a new secure session exists. We define the session,
9541 * add it to the list of secure sessions for the unsecure session, and EPP will do the
9544 if (packet
->decrypted_buffer
== NULL
)
9546 /* This triggers the creation of the corresponding secure DPS session if it is not already
9547 * created. This allows information to be stored in that session even though no packets
9548 * have used it yet. There is a problem, however, because at this point we do not know
9549 * the SSID that (may) be associated with this session.
9552 dof_session_data
*dof_session
= api_data
->session
;
9554 dof_secure_session
= dof_session
->secure_sessions
;
9555 while (dof_secure_session
!= NULL
)
9557 /* Determine matching session. The session list already is scoped by transport and DPS
9558 * session, so the only thing remaining is the domain and secure session ID.
9560 if ((dof_secure_session
->ssid
== ssid
) &&
9561 (dof_secure_session
->domain_length
== rekey_data
->domain_length
) &&
9562 (memcmp(dof_secure_session
->domain
, rekey_data
->domain
, rekey_data
->domain_length
) == 0))
9565 dof_secure_session
= dof_secure_session
->next
;
9568 if (!dof_secure_session
)
9570 dof_session
= wmem_new0(wmem_file_scope(), dof_session_data
);
9571 dof_session
->session_id
= globals
.next_session
++;
9572 dof_session
->dof_id
= api_data
->session
->dof_id
;
9574 dof_secure_session
= wmem_new0(wmem_file_scope(), dof_secure_session_data
);
9575 dof_secure_session
->ssid
= ssid
;
9576 dof_secure_session
->domain_length
= rekey_data
->domain_length
;
9577 dof_secure_session
->domain
= rekey_data
->domain
;
9578 dof_secure_session
->original_session_id
= api_data
->session
->session_id
;
9579 dof_secure_session
->parent
= dof_session
;
9580 dof_secure_session
->is_2_node
= true;
9581 dof_secure_session
->next
= api_data
->session
->secure_sessions
;
9582 api_data
->session
->secure_sessions
= dof_secure_session
;
9584 if (!dof_secure_session
->session_security_data_last
)
9585 dof_secure_session
->session_security_data
= rekey_data
->key_data
;
9587 dof_secure_session
->session_security_data_last
->next
= rekey_data
->key_data
;
9589 dof_secure_session
->session_security_data_last
= rekey_data
->key_data
;
9594 /* This PDU indicates the beginning of security for the responder. The next PDU
9595 * sent will be encrypted with these settings. This means that we must determine
9596 * the security settings and set them in the session.
9598 if (!packet
->processed
&& rekey_data
->is_rekey
)
9601 uint8_t *session_key
= NULL
;
9603 /* We have everything that we need. Determine the session secret if we can. */
9605 /* Check any keys determined above by initiator identity. */
9606 while (session_key
== NULL
&& identity_key_list
)
9608 if (validate_session_key(rekey_data
, S_length
, S
, confirmation
, identity_key_list
->session_key
))
9610 session_key
= (uint8_t *)wmem_alloc0(wmem_file_scope(), 32);
9611 memcpy(session_key
, identity_key_list
->session_key
, 32);
9614 identity_key_list
= identity_key_list
->next
;
9617 /* For each key in the global configuration, see if we can validate the confirmation. */
9618 for (i
= 0; session_key
== NULL
&& i
< globals
.global_security
->session_key_count
; i
++)
9620 if (validate_session_key(rekey_data
, S_length
, S
, confirmation
, globals
.global_security
->session_key
[i
].session_key
))
9621 session_key
= globals
.global_security
->session_key
[i
].session_key
;
9625 /* Whether or not this can be decrypted, the security mode information
9626 * should be kept with the session.
9629 rekey_data
->key_data
->r_valid
= packet
->dof_frame
;
9630 rekey_data
->key_data
->i_valid
= UINT32_MAX
;
9631 rekey_data
->key_data
->session_key
= session_key
;
9632 rekey_data
->key_data
->security_mode
= rekey_data
->security_mode
;
9633 rekey_data
->key_data
->security_mode_data_length
= rekey_data
->security_mode_data_length
;
9634 rekey_data
->key_data
->security_mode_data
= rekey_data
->security_mode_data
;
9636 if (session_key
&& dof_secure_session
)
9638 /* Look up the field-dissector table, and determine if it is registered. */
9639 dissector_table_t field_dissector
= find_dissector_table("dof.secmode");
9640 if (field_dissector
!= NULL
)
9642 dissector_handle_t field_handle
= dissector_get_uint_handle(field_dissector
, rekey_data
->key_data
->security_mode
);
9643 if (field_handle
!= NULL
)
9645 dof_secmode_api_data setup_data
;
9647 setup_data
.context
= INITIALIZE
;
9648 setup_data
.security_mode_offset
= 0;
9649 setup_data
.dof_api
= api_data
;
9650 setup_data
.secure_session
= dof_secure_session
;
9651 setup_data
.session_key_data
= rekey_data
->key_data
;
9653 call_dissector_only(field_handle
, NULL
, pinfo
, NULL
, &setup_data
);
9662 case TEP_PDU_CONFIRM
:
9664 /* C is set, K is clear. */
9665 /* Ticket Confirmation */
9666 proto_tree_add_item(tep_tree
, hf_tep_2_1_ticket_confirmation
, tvb
, offset
, 32, ENC_NA
);
9669 if (!packet
->processed
&& api_data
->session
&& packet
->opid_first
&& packet
->opid_first
->opid_data
)
9671 dof_session_key_exchange_data
*sk_data
;
9673 rekey_data
= (tep_rekey_data
*)packet
->opid_first
->opid_data
;
9674 sk_data
= rekey_data
->key_data
;
9676 /* TODO: Error if not found or if already set. */
9678 sk_data
->i_valid
= packet
->dof_frame
;
9683 case TEP_PDU_END_SESSION
:
9684 case TEP_PDU_SESSION_ENDING
:
9687 case TEP_PDU_REJECT
:
9690 proto_tree_add_item(tep_tree
, hf_tep_reject_code
, tvb
, offset
, 1, ENC_NA
);
9693 /* Error Description */
9694 if (tvb_captured_length(tvb
) > offset
)
9695 proto_tree_add_item(tep_tree
, hf_tep_reject_data
, tvb
, offset
, -1, ENC_NA
);
9705 static int dissect_trp_dsp(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
, void *data _U_
)
9707 /* We are handed a buffer that starts with our protocol id. Any options follow that. */
9710 /* We don't care except for the treeview. */
9714 /* Compute the version and flags, masking off other bits. */
9715 offset
+= 4; /* Skip the type and protocol. */
9717 proto_tree_add_item(tree
, hf_trp_dsp_option
, tvb
, 0, -1, ENC_NA
);
9721 static int dissect_trp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
9723 dof_api_data
*api_data
= (dof_api_data
*)data
;
9724 dof_packet_data
*packet_data
;
9725 unsigned offset
= 0;
9730 proto_tree
*trp_tree
;
9731 trp_packet_data
*trp_data
;
9733 /* Make entries in Protocol column and Info column on summary display */
9734 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TRP ");
9736 /* Create the protocol tree. */
9738 ti
= proto_tree_add_item(tree
, proto_trp
, tvb
, offset
, -1, ENC_NA
);
9739 trp_tree
= proto_item_add_subtree(ti
, ett_trp
);
9741 /* Add the APPID. */
9742 offset
= read_c2(tvb
, offset
, &app
, &app_len
);
9743 ti
= proto_tree_add_uint(trp_tree
, hf_2008_1_app_version
, tvb
, 0, app_len
, app
);
9744 validate_c2(pinfo
, ti
, app
, app_len
);
9746 if (api_data
== NULL
)
9748 expert_add_info_format(pinfo
, ti
, &ei_malformed
, "api_data == NULL");
9752 packet_data
= api_data
->packet
;
9753 if (packet_data
== NULL
)
9755 expert_add_info_format(pinfo
, ti
, &ei_malformed
, "api_data == NULL");
9759 trp_data
= (trp_packet_data
*)dof_packet_get_proto_data(packet_data
, proto_trp
);
9761 if (offset
== tvb_captured_length(tvb
))
9763 col_append_str(pinfo
->cinfo
, COL_INFO
, "TRP [nop]");
9764 expert_add_info(pinfo
, trp_tree
, &ei_implicit_no_op
);
9769 /* Retrieve the opcode. */
9770 opcode
= tvb_get_uint8(tvb
, offset
);
9771 if (!packet_data
->is_command
)
9772 opcode
|= TRP_RESPONSE
;
9774 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str(opcode
, trp_opcode_strings
, "Unknown Opcode (%d)"));
9777 ti
= proto_tree_add_uint_format(trp_tree
, hf_trp_opcode
, tvb
, offset
, 1, opcode
& 0x7F, "Opcode: %s (%u)", val_to_str(opcode
, trp_opcode_strings
, "Unknown Opcode (%d)"), opcode
& 0x7F);
9782 case TRP_RSP_REJECT
:
9785 proto_tree_add_item(trp_tree
, hf_trp_errorcode
, tvb
, offset
, 1, ENC_NA
);
9790 case TRP_CMD_REQUEST_KEK
:
9792 uint8_t *domain_buf
= NULL
;
9793 uint8_t domain_length
= 0;
9796 if (trp_data
&& trp_data
->identity_length
)
9798 expert_add_info(pinfo
, ti
, &ei_trp_initiator_id_known
);
9801 /* Domain - Security.7 */
9802 start_offset
= offset
;
9803 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
, offset
, hf_domain
, ett_domain
, NULL
);
9804 if (!packet_data
->processed
)
9806 domain_length
= offset
- start_offset
;
9807 domain_buf
= (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length
);
9808 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
9811 /* Initiator Block - TRP.4.1.1 */
9813 dof_2008_16_security_4 response
;
9814 trp_packet_data
*trp_pkt_data
= NULL
;
9816 start_offset
= offset
;
9818 /* Initiator Key Request - Security.4 */
9819 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_4
, tvb
, pinfo
, trp_tree
,
9820 offset
, hf_initiator_request
, ett_initiator_request
, &response
);
9821 if (!packet_data
->processed
)
9823 tvbuff_t
*identity
= response
.identity
;
9824 uint8_t identity_length
= tvb_reported_length(identity
);
9825 uint8_t *identity_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), identity_length
);
9828 /* Get the buffer. */
9829 tvb_memcpy(identity
, identity_buf
, 0, identity_length
);
9831 /* Check to see if there is a matching identity. */
9832 for (i
= 0; i
< globals
.global_security
->identity_data_count
; i
++)
9834 dof_identity_data
*gidentity
= globals
.global_security
->identity_data
+ i
;
9836 if (domain_length
!= gidentity
->domain_length
||
9837 memcmp(domain_buf
, gidentity
->domain
, domain_length
) != 0)
9840 if (identity_length
== gidentity
->identity_length
&&
9841 memcmp(identity_buf
, gidentity
->identity
, identity_length
) == 0)
9843 trp_pkt_data
= wmem_new0(wmem_file_scope(), trp_packet_data
);
9844 dof_packet_add_proto_data(packet_data
, proto_trp
, trp_pkt_data
);
9846 trp_pkt_data
->domain_length
= domain_length
;
9847 trp_pkt_data
->domain
= (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length
);
9848 memcpy(trp_pkt_data
->domain
, domain_buf
, domain_length
);
9850 trp_pkt_data
->identity_length
= identity_length
;
9851 trp_pkt_data
->identity
= (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length
);
9852 memcpy(trp_pkt_data
->identity
, identity_buf
, identity_length
);
9854 trp_pkt_data
->secret
= gidentity
->secret
;
9859 /* Group Identifier - Security.8 */
9861 int gid_start
= offset
;
9862 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_8
, tvb
, pinfo
, trp_tree
,
9863 offset
, hf_group_identifier
, ett_group_identifier
, NULL
);
9867 trp_pkt_data
->group_length
= offset
- gid_start
;
9868 trp_pkt_data
->group
= (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data
->group_length
);
9869 tvb_memcpy(tvb
, trp_pkt_data
->group
, gid_start
, trp_pkt_data
->group_length
);
9875 /* We need to store the entire block_I for later use. */
9876 trp_pkt_data
->block_I_length
= offset
- start_offset
;
9877 trp_pkt_data
->block_I
= (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data
->block_I_length
);
9878 tvb_memcpy(tvb
, trp_pkt_data
->block_I
, start_offset
, trp_pkt_data
->block_I_length
);
9884 case TRP_RSP_REQUEST_KEK
:
9889 uint8_t mode_length
;
9891 uint8_t block_A_length
;
9893 if (trp_data
&& trp_data
->kek_known
)
9895 expert_add_info(pinfo
, ti
, &ei_trp_kek_discovered
);
9898 /* Initiator Ticket - Security.5 */
9899 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, trp_tree
,
9900 offset
, hf_initiator_ticket
, ett_initiator_ticket
, NULL
);
9902 /* Initialization Block - TRP.4.2.1 */
9905 start_offset
= offset
;
9909 proto_tree_add_item(trp_tree
, hf_thb
, tvb
, offset
, 1, ENC_NA
);
9915 proto_tree_add_item(trp_tree
, hf_tmin
, tvb
, offset
, 1, ENC_NA
);
9921 proto_tree_add_item(trp_tree
, hf_tmax
, tvb
, offset
, 1, ENC_NA
);
9927 proto_tree_add_item(trp_tree
, hf_trp_epoch
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
9933 offset
= dof_dissect_pdu_as_field(dissect_2009_11_type_4
, tvb
, pinfo
, trp_tree
,
9934 offset
, hf_sidg
, ett_sidg
, NULL
);
9937 /* Initiator Node Security Scope - Security.10 */
9939 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_10
, tvb
, pinfo
, trp_tree
,
9940 offset
, hf_security_scope
, ett_security_scope
, NULL
);
9943 /* Security Mode - Security.13 */
9945 int mode_start
= offset
;
9946 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_13
, tvb
, pinfo
, trp_tree
,
9947 offset
, hf_security_mode
, ett_security_mode
, NULL
);
9948 if (!packet_data
->processed
)
9950 mode_length
= offset
- mode_start
;
9951 mode
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), mode_length
);
9952 tvb_memcpy(tvb
, mode
, mode_start
, mode_length
);
9956 /* State Identifier - Type.3 */
9958 int s_offset
= offset
;
9961 offset
= read_c4(tvb
, offset
, &ssid
, &ssid_len
);
9962 ssid
|= AS_ASSIGNED_SSID
; /* TRP SSID are *always* assigned by the AS. */
9963 pi
= proto_tree_add_uint_format(trp_tree
, hf_ssid
, tvb
, s_offset
, offset
- s_offset
, ssid
, "SSID: %u", ssid
);
9964 validate_c4(pinfo
, pi
, ssid
, ssid_len
);
9967 /* PG - Security.2 */
9968 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_2
, tvb
, pinfo
, trp_tree
,
9969 offset
, hf_responder_pg
, ett_responder_pg
, NULL
);
9971 /* Group Validation - Security.11 */
9972 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_11
, tvb
, pinfo
, trp_tree
,
9973 offset
, hf_responder_validation
, ett_responder_validation
, NULL
);
9975 /* Initiator Validation - Security.11 */
9976 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_11
, tvb
, pinfo
, trp_tree
,
9977 offset
, hf_initiator_validation
, ett_initiator_validation
, NULL
);
9979 block_A_length
= offset
- start_offset
;
9980 block_A
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), block_A_length
);
9981 tvb_memcpy(tvb
, block_A
, start_offset
, block_A_length
);
9984 /* Determine the KEK, if possible. This requires that either the initiator node's secret
9985 * is known or that the group has been configured. In either case this requires knowledge
9986 * from the matching command, including the domain, identity, and group information.
9988 if (packet_data
->opid_first
&& !packet_data
->processed
)
9991 trp_packet_data
* cmd_data
= (trp_packet_data
*)dof_packet_get_proto_data(packet_data
->opid_first
, proto_trp
);
9993 extern struct BlockCipher BlockCipher_AES_256
;
9994 struct BlockCipher
* cipher
= &BlockCipher_AES_256
;
9995 uint8_t* ekey
= (uint8_t*)ep_alloc(cipher
->keyStateSize
);
10003 tvb_memcpy(tvb
, mac
, mac_offset
, 32);
10004 tvb_memcpy(tvb
, kek
, mac_offset
+ 32, 32);
10006 if (cipher
!= NULL
)
10008 cipher
->GenerateKeyState(ekey
, cmd_data
->secret
);
10009 cipher
->Encrypt(ekey
, mac
);
10010 cipher
->Encrypt(ekey
, mac
+ 16);
10013 for (i
= 0; i
< 32; i
++)
10017 OALSecureHMACContext ctx
;
10018 OALSecureHMACDigest digest
;
10020 OALSecureHMAC_Start(&ctx
, cmd_data
->secret
);
10021 OALSecureHMAC_Digest(&ctx
, cmd_data
->domain_length
, cmd_data
->domain
);
10022 OALSecureHMAC_Digest(&ctx
, cmd_data
->block_I_length
, cmd_data
->block_I
);
10023 OALSecureHMAC_Digest(&ctx
, block_A_length
, block_A
);
10024 OALSecureHMAC_Digest(&ctx
, 32, kek
);
10025 OALSecureHMAC_Finish(&ctx
, digest
);
10027 tvb_memcpy(tvb
, mac
, mac_offset
, 32);
10028 if (memcmp(mac
, digest
, 32) == 0)
10030 dof_learned_group_data
* group
= globals
.learned_group_data
;
10031 dof_learned_group_auth_data
*auth
= NULL
;
10033 /* The KEK has been discovered, flag this for output on the PDU. */
10036 trp_data
= wmem_alloc0(wmem_file_scope(), sizeof(trp_packet_data
));
10037 dof_packet_add_proto_data(packet_data
, proto_trp
, trp_data
);
10040 trp_data
->kek_known
= true;
10044 if ((cmd_data
->domain_length
== group
->domain_length
) &&
10045 (memcmp(cmd_data
->domain
, group
->domain
, group
->domain_length
) == 0) &&
10046 (cmd_data
->group_length
== group
->group_length
) &&
10047 (memcmp(cmd_data
->group
, group
->group
, group
->group_length
) == 0) &&
10048 (ssid
== group
->ssid
))
10051 group
= group
->next
;
10056 group
= wmem_alloc0(wmem_file_scope
, sizeof(dof_learned_group_data
));
10057 group
->domain_length
= cmd_data
->domain_length
;
10058 group
->domain
= cmd_data
->domain
;
10059 group
->group_length
= cmd_data
->group_length
;
10060 group
->group
= cmd_data
->group
;
10061 group
->ssid
= ssid
;
10062 group
->next
= globals
.learned_group_data
;
10063 globals
.learned_group_data
= group
;
10066 auth
= group
->keys
;
10070 if (epoch
== auth
->epoch
)
10078 auth
= wmem_alloc0(wmem_file_scope(), sizeof(dof_learned_group_auth_data
));
10079 auth
->epoch
= epoch
;
10080 auth
->next
= group
->keys
;
10081 group
->keys
= auth
;
10083 auth
->kek
= (uint8_t*)wmem_alloc0(wmem_file_scope(), 32);
10084 memcpy(auth
->kek
, kek
, 32);
10086 auth
->mode_length
= mode_length
;
10087 auth
->mode
= (uint8_t*)wmem_alloc0(wmem_file_scope(), mode_length
);
10088 memcpy(auth
->mode
, mode
, mode_length
);
10090 auth
->security_mode
= (mode
[1] * 256) | mode
[2];
10091 auth
->parent
= group
;
10101 case TRP_CMD_REQUEST_RANDOM
:
10103 uint8_t *domain_buf
= NULL
;
10104 uint8_t domain_length
= 0;
10107 if (trp_data
&& trp_data
->identity_length
)
10109 expert_add_info(pinfo
, ti
, &ei_trp_initiator_id_known
);
10112 /* Domain - Security.7 */
10113 start_offset
= offset
;
10114 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
,
10115 offset
, hf_domain
, ett_domain
, NULL
);
10116 if (!packet_data
->processed
)
10118 domain_length
= offset
- start_offset
;
10119 domain_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), domain_length
);
10120 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
10123 /* Initiator Block - TRP.6.1.1 */
10125 dof_2008_16_security_4 response
;
10126 trp_packet_data
*trp_pkt_data
= NULL
;
10128 start_offset
= offset
;
10130 /* Initiator Key Request - Security.4 */
10131 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_4
, tvb
, pinfo
, trp_tree
,
10132 offset
, hf_initiator_request
, ett_initiator_request
, &response
);
10133 if (!packet_data
->processed
)
10135 tvbuff_t
*identity
= response
.identity
;
10136 uint8_t identity_length
= tvb_reported_length(identity
);
10137 uint8_t *identity_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), identity_length
);
10140 /* Get the buffer. */
10141 tvb_memcpy(identity
, identity_buf
, 0, identity_length
);
10143 /* Check to see if there is a matching identity. */
10144 for (i
= 0; i
< globals
.global_security
->identity_data_count
; i
++)
10146 dof_identity_data
*gidentity
= globals
.global_security
->identity_data
+ i
;
10148 if (domain_length
!= gidentity
->domain_length
||
10149 memcmp(domain_buf
, gidentity
->domain
, domain_length
) != 0)
10152 if (identity_length
== gidentity
->identity_length
&&
10153 memcmp(identity_buf
, gidentity
->identity
, identity_length
) == 0)
10155 trp_pkt_data
= wmem_new0(wmem_file_scope(), trp_packet_data
);
10156 dof_packet_add_proto_data(packet_data
, proto_trp
, trp_pkt_data
);
10158 trp_pkt_data
->domain_length
= domain_length
;
10159 trp_pkt_data
->domain
= (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length
);
10160 memcpy(trp_pkt_data
->domain
, domain_buf
, domain_length
);
10162 trp_pkt_data
->identity_length
= identity_length
;
10163 trp_pkt_data
->identity
= (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length
);
10164 memcpy(trp_pkt_data
->identity
, identity_buf
, identity_length
);
10166 trp_pkt_data
->secret
= gidentity
->secret
;
10173 /* We need to store the entire block_I for later use. */
10174 trp_pkt_data
->block_I_length
= offset
- start_offset
;
10175 trp_pkt_data
->block_I
= (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pkt_data
->block_I_length
);
10176 tvb_memcpy(tvb
, trp_pkt_data
->block_I
, start_offset
, trp_pkt_data
->block_I_length
);
10182 case TRP_RSP_REQUEST_RANDOM
:
10184 /* Initiator Ticket - Security.5 */
10185 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, trp_tree
,
10186 offset
, hf_initiator_ticket
, ett_initiator_ticket
, NULL
);
10190 case TRP_CMD_REQUEST_SECURITY_SCOPES
:
10192 uint8_t *domain_buf
= NULL
;
10193 uint8_t domain_length
= 0;
10196 if (trp_data
&& trp_data
->identity_length
)
10198 expert_add_info(pinfo
, ti
, &ei_trp_initiator_id_known
);
10201 /* Domain - Security.7 */
10202 start_offset
= offset
;
10203 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
,
10204 offset
, hf_domain
, ett_domain
, NULL
);
10205 if (!packet_data
->processed
)
10207 domain_length
= offset
- start_offset
;
10208 domain_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), domain_length
);
10209 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
10212 /* Initiator Block - TRP.5.1.1 */
10214 dof_2008_16_security_4 response
;
10215 trp_packet_data
*trp_pk_data
= NULL
;
10217 start_offset
= offset
;
10219 /* Initiator Duration Request */
10220 proto_tree_add_item(trp_tree
, hf_trp_duration
, tvb
, offset
, 1, ENC_NA
);
10223 /* Initiator Key Request - Security.4 */
10224 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_4
, tvb
, pinfo
, trp_tree
,
10225 offset
, hf_initiator_request
, ett_initiator_request
, &response
);
10226 if (!packet_data
->processed
)
10228 tvbuff_t
*identity
= response
.identity
;
10229 uint8_t identity_length
= tvb_reported_length(identity
);
10230 uint8_t *identity_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), identity_length
);
10233 /* Get the buffer. */
10234 tvb_memcpy(identity
, identity_buf
, 0, identity_length
);
10236 /* Check to see if there is a matching identity. */
10237 for (i
= 0; i
< globals
.global_security
->identity_data_count
; i
++)
10239 dof_identity_data
*gidentity
= globals
.global_security
->identity_data
+ i
;
10241 if (domain_length
!= gidentity
->domain_length
||
10242 memcmp(domain_buf
, gidentity
->domain
, domain_length
) != 0)
10245 if (identity_length
== gidentity
->identity_length
&&
10246 memcmp(identity_buf
, gidentity
->identity
, identity_length
) == 0)
10248 trp_pk_data
= wmem_new0(wmem_file_scope(), trp_packet_data
);
10249 dof_packet_add_proto_data(packet_data
, proto_trp
, trp_pk_data
);
10251 trp_pk_data
->domain_length
= domain_length
;
10252 trp_pk_data
->domain
= (uint8_t *)wmem_alloc0(wmem_file_scope(), domain_length
);
10253 memcpy(trp_pk_data
->domain
, domain_buf
, domain_length
);
10255 trp_pk_data
->identity_length
= identity_length
;
10256 trp_pk_data
->identity
= (uint8_t *)wmem_alloc0(wmem_file_scope(), identity_length
);
10257 memcpy(trp_pk_data
->identity
, identity_buf
, identity_length
);
10259 trp_pk_data
->secret
= gidentity
->secret
;
10264 /* Node - Security.8 */
10266 int gid_start
= offset
;
10267 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_8
, tvb
, pinfo
, trp_tree
,
10268 offset
, hf_node_identifier
, ett_node_identifier
, NULL
);
10272 trp_pk_data
->group_length
= offset
- gid_start
;
10273 trp_pk_data
->group
= (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data
->group_length
);
10274 tvb_memcpy(tvb
, trp_pk_data
->group
, gid_start
, trp_pk_data
->group_length
);
10280 /* We need to store the entire block_I for later use. */
10281 trp_pk_data
->block_I_length
= offset
- start_offset
;
10282 trp_pk_data
->block_I
= (uint8_t *)wmem_alloc0(wmem_file_scope(), trp_pk_data
->block_I_length
);
10283 tvb_memcpy(tvb
, trp_pk_data
->block_I
, start_offset
, trp_pk_data
->block_I_length
);
10289 case TRP_RSP_REQUEST_SECURITY_SCOPES
:
10293 uint8_t block_A_length
;
10295 /* Initiator Ticket - Security.5 */
10296 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, trp_tree
,
10297 offset
, hf_initiator_ticket
, ett_initiator_ticket
, NULL
);
10299 /* Initialization Block - TRP.5.2.1 */
10302 start_offset
= offset
;
10304 /* Initiator Duration Request */
10305 proto_tree_add_item(trp_tree
, hf_trp_duration
, tvb
, offset
, 1, ENC_NA
);
10308 /* Initiator Node Security Scope - Security.10 */
10310 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_10
, tvb
, pinfo
, trp_tree
,
10311 offset
, hf_security_scope
, ett_security_scope
, NULL
);
10314 /* Validation - Security.11 */
10315 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_11
, tvb
, pinfo
, trp_tree
,
10316 offset
, hf_initiator_validation
, ett_initiator_validation
, NULL
);
10318 block_A_length
= offset
- start_offset
;
10319 block_A
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), block_A_length
);
10320 tvb_memcpy(tvb
, block_A
, start_offset
, block_A_length
);
10325 case TRP_CMD_RESOLVE_CREDENTIAL
:
10327 uint8_t *domain_buf
= NULL
;
10328 uint8_t domain_length
= 0;
10331 /* Domain - Security.7 */
10332 start_offset
= offset
;
10333 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
,
10334 offset
, hf_domain
, ett_domain
, NULL
);
10335 if (!packet_data
->processed
)
10337 domain_length
= offset
- start_offset
;
10338 domain_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), domain_length
);
10339 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
10342 /* Identity Resolution - Security.3.2 */
10343 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_3_2
, tvb
, pinfo
, trp_tree
,
10344 offset
, hf_identity_resolution
, ett_identity_resolution
, NULL
);
10348 case TRP_RSP_RESOLVE_CREDENTIAL
:
10350 /* Identity Resolution - Security.3.2 */
10351 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_3_2
, tvb
, pinfo
, trp_tree
,
10352 offset
, hf_identity_resolution
, ett_identity_resolution
, NULL
);
10356 case TRP_CMD_REQUEST_SESSION
:
10358 uint8_t *domain_buf
= NULL
;
10359 uint8_t domain_length
= 0;
10362 if (trp_data
&& trp_data
->identity_length
)
10364 expert_add_info(pinfo
, ti
, &ei_trp_initiator_id_known
);
10367 /* Domain - Security.7 */
10368 start_offset
= offset
;
10369 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
,
10370 offset
, hf_domain
, ett_domain
, NULL
);
10371 if (!packet_data
->processed
)
10373 domain_length
= offset
- start_offset
;
10374 domain_buf
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), domain_length
);
10375 tvb_memcpy(tvb
, domain_buf
, start_offset
, domain_length
);
10378 /* Responder Block - Security.6.2 */
10379 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_2
, tvb
, pinfo
, trp_tree
,
10380 offset
, hf_responder_request
, ett_responder_request
, NULL
);
10382 /* Initiator Block - Security.6.1 */
10383 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_1
, tvb
, pinfo
, trp_tree
,
10384 offset
, hf_initiator_request
, ett_initiator_request
, NULL
);
10388 case TRP_RSP_REQUEST_SESSION
:
10392 uint8_t block_A_length
;
10394 /* Responder Ticket - Security.5 */
10395 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, trp_tree
,
10396 offset
, hf_responder_ticket
, ett_responder_ticket
, NULL
);
10398 /* Initiator Ticket - Security.5 */
10399 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_5
, tvb
, pinfo
, trp_tree
,
10400 offset
, hf_initiator_ticket
, ett_initiator_ticket
, NULL
);
10403 /* Initialization Block - Security.6.3 */
10406 start_offset
= offset
;
10408 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_6_3
, tvb
, pinfo
, trp_tree
,
10409 offset
, hf_authentication_block
, ett_authentication_block
, NULL
);
10411 block_A_length
= offset
- start_offset
;
10412 block_A
= (uint8_t *)wmem_alloc0(wmem_packet_scope(), block_A_length
);
10413 tvb_memcpy(tvb
, block_A
, start_offset
, block_A_length
);
10418 case TRP_CMD_VALIDATE_CREDENTIAL
:
10420 tvbuff_t
*data_tvb
;
10422 /* Domain - Security.7 */
10423 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_7
, tvb
, pinfo
, trp_tree
,
10424 offset
, hf_domain
, ett_domain
, NULL
);
10426 offset
= dof_dissect_pdu_as_field(dissect_2008_16_security_3_1
, tvb
, pinfo
, trp_tree
,
10427 offset
, hf_identity_resolution
, ett_identity_resolution
, NULL
);
10428 data_tvb
= tvb_new_subset_remaining(tvb
, offset
);
10429 call_data_dissector(data_tvb
, pinfo
, trp_tree
);
10433 case TRP_RSP_VALIDATE_CREDENTIAL
:
10435 tvbuff_t
*data_tvb
= tvb_new_subset_remaining(tvb
, offset
);
10436 call_data_dissector(data_tvb
, pinfo
, trp_tree
);
10444 /* Initialize Core Tunnel Functionality */
10445 static void dof_tun_register(void)
10447 static hf_register_info hf
[] =
10449 { &hf_2012_1_tunnel_1_version
,
10450 { "Version", "dof.2012_1.tunnel_1.version", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
10452 { &hf_2012_1_tunnel_1_length
,
10453 { "Length", "dof.2012_1.tunnel_1.length", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
10457 static int *ett
[] = {
10458 &ett_2012_1_tunnel
,
10461 proto_2012_1_tunnel
= proto_register_protocol(TUNNEL_PROTOCOL_STACK
, "DTPS", "dtps");
10462 proto_register_field_array(proto_2012_1_tunnel
, hf
, array_length(hf
));
10463 proto_register_subtree_array(ett
, array_length(ett
));
10465 register_dissector_with_description("dof.tunnel", TUNNEL_PROTOCOL_STACK
, dissect_tunnel_common
, proto_2012_1_tunnel
);
10466 dof_tun_app_dissectors
= register_dissector_table("dof.tunnel.app", "DOF Tunnel Version", proto_2012_1_tunnel
, FT_UINT8
, BASE_DEC
);
10469 static void dof_tun_reset(void)
10473 static void dof_tun_cleanup(void)
10477 /* The registration hand-off routine */
10478 static void dof_tun_handoff(void)
10480 static dissector_handle_t tcp_handle
;
10482 register_dissector_with_description("dof.app", TUNNEL_APPLICATION_PROTOCOL
, dissect_tun_app_common
, proto_2008_1_app
);
10484 tcp_handle
= create_dissector_handle(dissect_tunnel_tcp
, proto_2012_1_tunnel
);
10486 dissector_add_uint_with_preference("tcp.port", DOF_TUN_NON_SEC_TCP_PORT
, tcp_handle
);
10489 /* Main DOF Registration Support */
10491 static void dof_reset(void)
10493 globals
.next_session
= 1;
10494 globals
.next_transport_session
= 1;
10495 globals
.dof_packet_head
= globals
.dof_packet_tail
= NULL
;
10496 globals
.global_security
= &global_security
;
10497 globals
.learned_group_data
= NULL
;
10498 globals
.decrypt_all_packets
= decrypt_all_packets
;
10499 globals
.track_operations
= track_operations
;
10500 globals
.track_operations_window
= track_operations_window
;
10502 init_addr_port_tables();
10504 /* Reset the packet counter. */
10505 next_dof_frame
= 1;
10507 /* Load the template values for different groups. */
10509 secmode_field_t
*list
= secmode_list
;
10512 global_security
.group_data
= g_new0(dof_group_data
, num_secmode_list
);
10513 global_security
.group_data_count
= num_secmode_list
;
10514 for (i
= 0; i
< num_secmode_list
; i
++)
10517 dof_group_data
*group_data
= global_security
.group_data
+ i
;
10518 parse_hex_string(list
[i
].domain
, &(group_data
->domain
), &(group_data
->domain_length
));
10519 parse_hex_string(list
[i
].identity
, &(group_data
->identity
), &(group_data
->identity_length
));
10520 parse_hex_string(list
[i
].kek
, &(group_data
->kek
), &kek_len
);
10524 /* Load the template values for different secrets. */
10526 seckey_field_t
*list
= seckey_list
;
10529 /* Clear existing. */
10530 for (i
= 0; i
< global_security
.session_key_count
; i
++)
10532 dof_session_key_data
*session_data
= &global_security
.session_key
[i
];
10533 g_free(session_data
->session_key
);
10536 g_free(global_security
.session_key
);
10537 global_security
.session_key
= NULL
;
10538 global_security
.session_key_count
= 0;
10540 global_security
.session_key
= g_new0(dof_session_key_data
, num_seckey_list
);
10541 global_security
.session_key_count
= num_seckey_list
;
10542 for (i
= 0; i
< num_seckey_list
; i
++)
10545 dof_session_key_data
*session_data
= global_security
.session_key
+ i
;
10546 parse_hex_string(list
[i
].key
, &(session_data
->session_key
), &key_len
);
10550 /* Load the template values for different identities. */
10552 identsecret_field_t
*list
= identsecret_list
;
10555 /* Clear existing. */
10556 for (i
= 0; i
< global_security
.identity_data_count
; i
++)
10558 dof_identity_data
*identity_data
= &global_security
.identity_data
[i
];
10559 g_free(identity_data
->domain
);
10560 g_free(identity_data
->identity
);
10561 g_free(identity_data
->secret
);
10564 g_free(global_security
.identity_data
);
10565 global_security
.identity_data
= NULL
;
10566 global_security
.identity_data_count
= 0;
10568 global_security
.identity_data
= g_new0(dof_identity_data
, num_identsecret_list
);
10569 global_security
.identity_data_count
= num_identsecret_list
;
10570 for (i
= 0; i
< num_identsecret_list
; i
++)
10575 dof_identity_data
*identity_data
= global_security
.identity_data
+ i
;
10576 if (VALIDHEX(list
[i
].domain
[0]))
10578 parse_hex_string(list
[i
].domain
, &(identity_data
->domain
), &(identity_data
->domain_length
));
10582 size
= (uint32_t)strlen(list
[i
].domain
);
10583 dof_oid_new_standard_string(list
[i
].domain
, &size
, &(identity_data
->domain
));
10584 identity_data
->domain_length
= size
;
10587 if (VALIDHEX(list
[i
].identity
[0]))
10589 parse_hex_string(list
[i
].identity
, &(identity_data
->identity
), &(identity_data
->identity_length
));
10593 size
= (uint32_t)strlen(list
[i
].identity
);
10594 dof_oid_new_standard_string(list
[i
].identity
, &size
, &(identity_data
->identity
));
10595 identity_data
->identity_length
= size
;
10598 parse_hex_string(list
[i
].secret
, &(identity_data
->secret
), &key_len
);
10603 static void dof_cleanup(void)
10607 /* Clear existing. */
10608 for (i
= 0; i
< global_security
.group_data_count
; i
++)
10610 dof_group_data
*group_data
= &global_security
.group_data
[i
];
10611 g_free(group_data
->domain
);
10612 g_free(group_data
->identity
);
10613 g_free(group_data
->kek
);
10616 g_free(global_security
.group_data
);
10617 global_security
.group_data
= NULL
;
10618 global_security
.group_data_count
= 0;
10623 * Initialize Core DPS Functionality
10625 static void dof_register(void)
10627 static hf_register_info hf
[] =
10629 { &hf_security_1_permission_type
,
10630 { "Permission Type", "dof.2008.16.security.1.desired-duration", FT_UINT16
, BASE_DEC
, VALS(dof_2008_16_permission_type
), 0, NULL
, HFILL
} },
10632 { &hf_security_1_length
,
10633 { "Length", "dof.2008.16.security.1.length", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10635 { &hf_security_1_data
,
10636 { "Data", "dof.2008.16.security.1.data", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10639 { &hf_security_2_count
,
10640 { "Count", "dof.2008.16.security.2.count", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10642 { &hf_security_2_permission
,
10643 { "Permission", "dof.2008.16.security.2.permission", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10646 { &hf_security_3_1_credential_type
,
10647 { "Credential Type", "dof.2008.16.security.3.1.credential_type", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10649 { &hf_security_3_1_stage
,
10650 { "Stage", "dof.2008.16.security.3.1.stage", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10652 { &hf_security_3_1_security_node_identifier
,
10653 { "Security Node Identifier", "dof.2008.16.security.3.1.security_node_identifier", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10656 { &hf_security_3_2_credential_type
,
10657 { "Credential Type", "dof.2008.16.security.3.2.credential_type", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10659 { &hf_security_3_2_stage
,
10660 { "Stage", "dof.2008.16.security.3.2.stage", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10662 { &hf_security_3_2_length
,
10663 { "Length", "dof.2008.16.security.3.2.length", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10665 { &hf_security_3_2_public_data
,
10666 { "Public Data", "dof.2008.16.security.3.2.public_data", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10669 { &hf_security_4_l
,
10670 { "L", "dof.2008.16.security.4.l", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
10672 { &hf_security_4_f
,
10673 { "F", "dof.2008.16.security.4.f", FT_UINT8
, BASE_DEC
, NULL
, 0x40, NULL
, HFILL
} },
10675 { &hf_security_4_ln
,
10676 { "Ln", "dof.2008.16.security.4.ln", FT_UINT8
, BASE_DEC
, NULL
, 0x0F, NULL
, HFILL
} },
10678 { &hf_security_4_identity
,
10679 { "Identity", "dof.2008.16.security.4.identity", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10681 { &hf_security_4_nonce
,
10682 { "Nonce", "dof.2008.16.security.4.nonce", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10684 { &hf_security_4_permission_set
,
10685 { "Permission Set", "dof.2008.16.security.4.permission_set", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10688 { &hf_security_5_mac
,
10689 { "MAC", "dof.2008.16.security.5.mac", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10691 { &hf_security_5_key
,
10692 { "KEY", "dof.2008.16.security.5.key", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10695 { &hf_security_6_1_desired_duration
,
10696 { "Desired Duration", "dof.2008.16.security.6.1.desired_duration", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10698 { &hf_security_6_1_desired_security_mode
,
10699 { "Desired Security Mode", "dof.2008.16.security.6.1.desired_security_mode", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10701 { &hf_security_6_1_initiator_request
,
10702 { "Initiator Request", "dof.2008.16.security.6.1.initiator_request", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10705 { &hf_security_6_2_responder_request
,
10706 { "Responder Request", "dof.2008.16.security.6.2.responder_request", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10709 { &hf_security_6_3_granted_duration
,
10710 { "Granted Duration", "dof.2008.16.security.6.3.granted_duration", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10712 { &hf_security_6_3_session_security_scope
,
10713 { "Session Security Scope", "dof.2008.16.security.6.3.session_security_scope", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10715 { &hf_security_6_3_initiator_validation
,
10716 { "Initiator Validation", "dof.2008.16.security.6.3.initiator_validation", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10718 { &hf_security_6_3_responder_validation
,
10719 { "Responder Validation", "dof.2008.16.security.6.3.responder_validation", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10722 { &hf_security_9_length
,
10723 { "Length", "dof.2008.16.security.9.length", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10725 { &hf_security_9_initial_state
,
10726 { "Initial State", "dof.2008.16.security.9.initial_state", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10729 { &hf_security_10_count
,
10730 { "Count", "dof.2008.16.security.10.count", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
10732 { &hf_security_10_permission_group_identifier
,
10733 { "Permission Group Identifier", "dof.2008.16.security.10.permission_group_identifier", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
10736 { &hf_security_11_count
,
10737 { "Count", "dof.2008.16.security.11.count", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
10739 { &hf_security_11_permission_security_scope
,
10740 { "Permission Security Scope", "dof.2008.16.security.11.permission_security_scope", FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
10743 { &hf_security_12_m
,
10744 { "M", "dof.2008.16.security.12.m", FT_UINT8
, BASE_DEC
, VALS(dof_2008_16_security_12_m
), 0xC0, NULL
, HFILL
} },
10746 { &hf_security_12_count
,
10747 { "Count", "dof.2008.16.security.12.count", FT_UINT8
, BASE_DEC
, NULL
, 0x3F, NULL
, HFILL
} },
10749 { &hf_security_12_permission_group_identifier
,
10750 { "Permission Group Identifier", "dof.2008.16.security.12.permission_group_identifier", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
10752 { &hf_2008_1_dof_session_transport
,
10753 { "Transport Session", "dof.transport_session", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
10755 { &hf_2008_1_dof_session
,
10756 { "DPS Session", "dof.session", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
10758 { &hf_2008_1_dof_frame
,
10759 { "DPS Frame", "dof.frame", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
}
10761 { &hf_2008_1_dof_is_2_node
,
10762 { "DPS Is 2 Node", "dof.is_2_node", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
10764 { &hf_2008_1_dof_is_streaming
,
10765 { "DPS Is Streaming", "dof.is_streaming", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
10767 { &hf_2008_1_dof_is_from_client
,
10768 { "DPS Is From Client", "dof.is_from_client", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
}
10772 static int *ett
[] = {
10774 &ett_security_2_permission
,
10775 &ett_security_3_1_security_node_identifier
,
10778 &ett_security_11_permission_security_scope
,
10780 &ett_security_6_1_desired_security_mode
,
10781 &ett_security_6_1_initiator_request
,
10783 &ett_security_6_2_responder_request
,
10784 &ett_security_6_3_session_security_scope
,
10785 &ett_security_6_3_initiator_validation
,
10786 &ett_security_6_3_responder_validation
,
10788 &ett_security_4_identity
,
10789 &ett_security_4_permission_set
,
10794 static ei_register_info ei
[] =
10797 { &ei_undecoded
, { "dof.undecoded", PI_UNDECODED
, PI_WARN
, "DOF: Some protocol octets were not decoded", EXPFILL
} },
10799 { &ei_malformed
, { "dof.malformed", PI_MALFORMED
, PI_ERROR
, "Malformed:", EXPFILL
} },
10800 { &ei_implicit_no_op
, { "dof.implicit_no_op", PI_PROTOCOL
, PI_COMMENT
, "Implicit No-op", EXPFILL
} },
10801 { &ei_c2_c3_c4_format
, { "dof.c2_c3_c4_format", PI_MALFORMED
, PI_WARN
, "DOF: Cx IE format", EXPFILL
} },
10802 { &ei_security_3_1_invalid_stage
, { "dof.security.3.1.invalid_stage", PI_MALFORMED
, PI_ERROR
, "DPS: Security.3.1: Stage invalid.", EXPFILL
} },
10803 { &ei_security_4_invalid_bit
, { "dof.security.4.invalid_bit", PI_MALFORMED
, PI_WARN
, "DPS: Security.4: Reserved bit set.", EXPFILL
} },
10804 { &ei_security_13_out_of_range
, { "dof.security.13.out_of_range", PI_MALFORMED
, PI_ERROR
, "DPS: Security.13: Attribute Data out of range.", EXPFILL
} },
10807 /* Security mode of operation templates. */
10808 static uat_field_t secmode_uat_fields
[] = {
10809 UAT_FLD_CSTRING(secmode_list
, domain
, "Domain", "The domain, coded as hex digits of PDU Security.7."),
10810 UAT_FLD_CSTRING(secmode_list
, identity
, "Group ID", "The group identifier, coded as hex digits of PDU Security.8."),
10811 UAT_FLD_CSTRING(secmode_list
, kek
, "KEK", "The KEK, coded as hex digits representing the KEK (256-bit)."),
10815 /* Security keys. */
10816 static uat_field_t seckey_uat_fields
[] = {
10817 UAT_FLD_CSTRING(seckey_list
, key
, "Session Key", "The session key to try to use, coded as hex digits representing the key (256-bit)."),
10821 /* Identity secrets. */
10822 static uat_field_t identsecret_uat_fields
[] = {
10823 UAT_FLD_CSTRING(identsecret_list
, domain
, "Domain", "The domain, coded as hex digits of PDU Security.7."),
10824 UAT_FLD_CSTRING(identsecret_list
, identity
, "Identity", "The group identifier, coded as hex digits of PDU Security.8."),
10825 UAT_FLD_CSTRING_OTHER(identsecret_list
, secret
, "Secret", identsecret_chk_cb
, "The resolved secret for a given identity, coded as hex digits representing the secret (256-bit)."),
10829 module_t
*dof_module
;
10830 uat_t
*secmode_uat
;
10832 uat_t
*identsecret_uat
;
10833 expert_module_t
*expert_security
;
10835 dsp_option_dissectors
= register_dissector_table("dof.dsp.options", "DSP Protocol Options", proto_2008_1_dsp
, FT_UINT32
, BASE_DEC
);
10836 dof_sec_dissectors
= register_dissector_table("dof.secmode", "DOF Security Mode of Operation", proto_2008_1_dof
, FT_UINT16
, BASE_DEC
);
10837 register_dissector_table("dof.2008.1", "DOF Common PDU", proto_2008_1_dof
, FT_STRING
, BASE_DEC
);
10839 proto_2008_1_dof
= proto_register_protocol(DOF_PROTOCOL_STACK
, "DOF", "dof");
10841 proto_2008_1_dof_tcp
= proto_register_protocol(DOF_PROTOCOL_STACK
" TCP", "DOF-TCP", "dof-tcp");
10842 proto_2008_1_dof_udp
= proto_register_protocol(DOF_PROTOCOL_STACK
" UDP", "DOF-UDP", "dof-udp");
10844 proto_register_field_array(proto_2008_1_dof
, hf
, array_length(hf
));
10845 proto_register_subtree_array(ett
, array_length(ett
));
10847 expert_security
= expert_register_protocol(proto_2008_1_dof
);
10848 expert_register_field_array(expert_security
, ei
, array_length(ei
));
10850 dof_module
= prefs_register_protocol(proto_2008_1_dof
, dof_reset
);
10851 secmode_uat
= uat_new("DPS Security Mode Templates",
10852 sizeof(secmode_field_t
),
10853 "custom_dof_secmode_list",
10857 (UAT_AFFECTS_DISSECTION
| UAT_AFFECTS_FIELDS
),
10859 secmode_list_copy_cb
,
10860 secmode_list_update_cb
,
10861 secmode_list_free_cb
,
10862 secmode_list_post_update_cb
,
10867 seckey_uat
= uat_new("DPS Session Keys",
10868 sizeof(seckey_field_t
),
10869 "custom_dof_seckey_list",
10873 (UAT_AFFECTS_DISSECTION
| UAT_AFFECTS_FIELDS
),
10875 seckey_list_copy_cb
,
10876 seckey_list_update_cb
,
10877 seckey_list_free_cb
,
10878 seckey_list_post_update_cb
,
10883 identsecret_uat
= uat_new("DPS Identity Secrets",
10884 sizeof(identsecret_field_t
),
10885 "custom_dof_identsecret_list",
10888 &num_identsecret_list
,
10889 (UAT_AFFECTS_DISSECTION
| UAT_AFFECTS_FIELDS
),
10891 identsecret_list_copy_cb
,
10892 identsecret_list_update_cb
,
10893 identsecret_list_free_cb
,
10894 identsecret_list_post_update_cb
,
10896 identsecret_uat_fields
10899 prefs_register_bool_preference(dof_module
, "custom_dof_decrypt_all",
10900 "Attempt to decrypt all packets",
10901 "Specifies that decryption should be attempted on all packets, even if the session initialization wasn't captured.",
10902 &decrypt_all_packets
);
10904 prefs_register_bool_preference(dof_module
, "custom_dof_track_operations",
10905 "Track DPS operations",
10906 "Specifies that operations should be tracked across multiple packets, providing summary lists. This takes time and memory.",
10907 &track_operations
);
10909 prefs_register_uint_preference(dof_module
, "custom_dof_track_operations_window",
10910 "Track DPS window",
10911 "Limits the number of operations shown before and after the current operations",
10912 10, &track_operations_window
);
10914 prefs_register_static_text_preference(dof_module
, "name4567", "The following are tables not preferences.", "These tables are not controlled by OK, Apply, and Cancel of this dialog.");
10916 prefs_register_uat_preference(dof_module
, "custom_dof_secmode_list", "DPS Security Mode Templates",
10917 "A table of security modes and initialization data that will be tried if no security mode is found.",
10920 prefs_register_uat_preference(dof_module
, "custom_dof_seckey_list", "DPS Session Keys",
10921 "A table of session keys to attempt if none is known.",
10924 prefs_register_uat_preference(dof_module
, "custom_dof_identsecret_list", "DPS Identity Secrets",
10925 "A table of secrets for different identities.",
10929 static void dof_handoff(void)
10931 static dissector_handle_t tcp_handle
;
10933 dof_oid_handle
= register_dissector_with_description("dof.oid", DOF_OBJECT_IDENTIFIER
, dissect_2009_11_type_4
, oid_proto
);
10935 tcp_handle
= create_dissector_handle(dissect_dof_tcp
, proto_2008_1_dof
);
10936 dof_udp_handle
= create_dissector_handle(dissect_dof_udp
, proto_2008_1_dof
);
10938 dissector_add_uint_with_preference("tcp.port", DOF_P2P_NEG_SEC_TCP_PORT
, tcp_handle
);
10939 dissector_add_uint_range_with_preference("udp.port", DOF_NEG_SEC_UDP_PORT_RANGE
, dof_udp_handle
);
10942 /* OID Registration Support */
10944 static void oid_reset(void)
10948 static void oid_cleanup(void)
10952 /* Initialize OID */
10953 static void oid_register(void)
10955 static hf_register_info hf
[] = {
10957 { "Class", "dof.oid.class", FT_UINT32
, BASE_DEC
, NULL
, 0, "DPS Object Identifier Class", HFILL
}
10960 { "Header", "dof.oid.header", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
10962 { &hf_oid_attribute
,
10963 { "Attribute", "dof.oid.attribute", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
}
10966 { "Length", "dof.oid.length", FT_UINT8
, BASE_DEC
, NULL
, 0x3F, NULL
, HFILL
}
10969 { "Data", "dof.oid.data", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
10971 { &hf_oid_all_attribute_data
,
10972 { "Attribute Data", "dof.oid.attribute-data", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
10974 { &hf_oid_attribute_header
,
10975 { "Header", "dof.attribute.header", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
10977 { &hf_oid_attribute_attribute
,
10978 { "Attribute", "dof.attribute.attribute", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
}
10980 { &hf_oid_attribute_id
,
10981 { "ID", "dof.attribute.id", FT_UINT8
, BASE_DEC
, NULL
, 0x7F, NULL
, HFILL
}
10983 { &hf_oid_attribute_length
,
10984 { "Length", "dof.attribute.length", FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
}
10986 { &hf_oid_attribute_data
,
10987 { "Data", "dof.attribute.data", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
10989 { &hf_oid_attribute_oid
,
10990 { "OID", "dof.attribute.oid", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
10994 static int *ett
[] = {
10997 &ett_oid_attribute
,
10998 &ett_oid_attribute_header
,
10999 &ett_oid_attribute_oid
,
11002 static ei_register_info ei
[] =
11004 { &ei_type_4_header_zero
, { "dof.oid.header_zero", PI_MALFORMED
, PI_ERROR
, "DOF Violation: Type.4: Header bit mandated 0.", EXPFILL
} },
11007 if (oid_proto
== -1)
11009 expert_module_t
*expert_oid
;
11011 oid_proto
= proto_register_protocol(DOF_OBJECT_IDENTIFIER
, "DPS.OID", "dof.oid");
11012 proto_register_field_array(oid_proto
, hf
, array_length(hf
));
11013 proto_register_subtree_array(ett
, array_length(ett
));
11014 expert_oid
= expert_register_protocol(oid_proto
);
11015 expert_register_field_array(expert_oid
, ei
, array_length(ei
));
11019 static void oid_handoff(void)
11023 /* DNP Registration Support */
11025 static unsigned dof_ns_session_key_hash_fn(const void *key
)
11027 const dof_ns_session_key
*session_key
= (const dof_ns_session_key
*)key
;
11028 unsigned result
= 0;
11030 result
+= g_int_hash(&session_key
->transport_session_id
);
11031 result
+= g_int_hash(&session_key
->client
);
11032 result
+= g_int_hash(&session_key
->server
);
11037 static gboolean
dof_ns_session_key_equal_fn(const void *key1
, const void *key2
)
11039 const dof_ns_session_key
*session_key_ptr1
= (const dof_ns_session_key
*)key1
;
11040 const dof_ns_session_key
*session_key_ptr2
= (const dof_ns_session_key
*)key2
;
11042 if (session_key_ptr1
->transport_session_id
!= session_key_ptr2
->transport_session_id
)
11045 if (session_key_ptr1
->client
!= session_key_ptr2
->client
)
11048 if (session_key_ptr1
->server
!= session_key_ptr2
->server
)
11054 static void dof_dnp_reset(void)
11056 dof_ns_session_lookup
= g_hash_table_new_full(dof_ns_session_key_hash_fn
, dof_ns_session_key_equal_fn
, g_free
, NULL
);
11059 static void dof_dnp_cleanup(void)
11061 g_hash_table_destroy(dof_ns_session_lookup
);
11062 dof_ns_session_lookup
= NULL
;
11065 static void dof_register_dnp_0(void)
11067 static hf_register_info hf
[] =
11069 { &hf_2008_1_dnp_0_1_1_padding
,
11070 { "Padding", "dof.dnp.v0.padding", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
}
11072 { &hf_2008_1_dnp_0_1_1_version
,
11073 { "Version", "dof.dnp.v0.version", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
11077 if (proto_2008_1_dnp_0
<= 0)
11079 proto_2008_1_dnp_0
= proto_register_protocol(DOF_NETWORK_PROTOCOL
" V0", "DPS.DNP.V0", "dof.dnp.v0");
11081 proto_register_field_array(proto_2008_1_dnp_0
, hf
, array_length(hf
));
11086 * The registration hand-off routine
11088 static void dof_reg_handoff_dnp_0(void)
11090 dissector_handle_t dnp_handle
;
11091 dnp_handle
= create_dissector_handle(dissect_dnp_0
, proto_2008_1_dnp_0
);
11093 dissector_add_uint("dof.dnp", 0, dnp_handle
);
11096 static void dof_register_dnp_1(void)
11098 expert_module_t
*expert_dnp
;
11100 static hf_register_info hf
[] =
11102 { &hf_2009_9_dnp_1_flags
,
11103 { "Flags", "dof.2009_9.dnp_1.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
11105 { &hf_2009_9_dnp_1_flag_length
,
11106 { "Length Size", "dof.2009_9.dnp_1.flags.lengthsize", FT_UINT8
, BASE_DEC
, NULL
, 0x03, NULL
, HFILL
}
11108 { &hf_2009_9_dnp_1_flag_srcport
,
11109 { "Source Port", "dof.2009_9.dnp_1.flags.srcport", FT_UINT8
, BASE_DEC
, NULL
, 0x04, NULL
, HFILL
}
11111 { &hf_2009_9_dnp_1_flag_dstport
,
11112 { "Destination Port", "dof.2009_9.dnp_1.flags.dstport", FT_UINT8
, BASE_DEC
, NULL
, 0x08, NULL
, HFILL
}
11115 { &hf_2009_9_dnp_1_length
,
11116 { "Length", "dof.2009_9.dnp_1.length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
11118 { &hf_2009_9_dnp_1_srcport
,
11119 { "Source Port", "dof.2009_9.dnp_1.srcport", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
11121 { &hf_2009_9_dnp_1_dstport
,
11122 { "Destination Port", "dof.2009_9.dnp_1.dstport", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
11126 static int *ett
[] =
11128 &ett_2009_9_dnp_1_flags
,
11131 static ei_register_info ei
[] =
11133 { &ei_dof_10_flags_zero
, { "dof.dnp.v1.flags_zero", PI_UNDECODED
, PI_ERROR
, "DPS-10: Reserved flag bits must be zero.", EXPFILL
} },
11135 { &ei_dof_13_length_specified
, { "dof.dnp.v1.length_specified", PI_UNDECODED
, PI_ERROR
, "DPS-13: Length must be specified on a connection.", EXPFILL
} },
11139 if (proto_2009_9_dnp_1
<= 0)
11141 proto_2009_9_dnp_1
= proto_register_protocol(DOF_NETWORK_PROTOCOL
" V1", "DOF.DNP.V1", "dof.dnp.v1");
11143 proto_register_field_array(proto_2009_9_dnp_1
, hf
, array_length(hf
));
11144 proto_register_subtree_array(ett
, array_length(ett
));
11146 expert_dnp
= expert_register_protocol(proto_2009_9_dnp_1
);
11147 expert_register_field_array(expert_dnp
, ei
, array_length(ei
));
11152 * The registration hand-off routine
11154 static void dof_reg_handoff_dnp_1(void)
11156 dissector_handle_t dnp_handle
, dnp_frame_handle
;
11157 dnp_handle
= create_dissector_handle(dissect_dnp_1
, proto_2009_9_dnp_1
);
11158 dnp_frame_handle
= create_dissector_handle(determine_packet_length_1
, proto_2009_9_dnp_1
);
11160 dissector_add_uint("dof.dnp", 1, dnp_handle
);
11161 dissector_add_uint("dof.dnp.frame", 1, dnp_frame_handle
);
11164 static void dof_dnp_handoff(void)
11166 dof_reg_handoff_dnp_0();
11167 dof_reg_handoff_dnp_1();
11171 * Initialize Core DNP Functionality
11173 static void dof_dnp_register(void)
11175 static hf_register_info hf
[] =
11177 { &hf_2008_1_dnp_1_flag
,
11178 { "Flag", "dof.2008_1.dnp_1.flag", FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), 0x80, NULL
, HFILL
}
11180 { &hf_2008_1_dnp_1_version
,
11181 { "Version", "dof.2008_1.dnp_1.version", FT_UINT8
, BASE_DEC
, NULL
, 0x7F, NULL
, HFILL
}
11185 static int *ett
[] =
11188 &ett_2008_1_dnp_header
,
11191 proto_2008_1_dnp
= proto_register_protocol(DOF_NETWORK_PROTOCOL
, "DPS.DNP", "dof.dnp");
11193 proto_register_field_array(proto_2008_1_dnp
, hf
, array_length(hf
));
11194 proto_register_subtree_array(ett
, array_length(ett
));
11195 dnp_dissectors
= register_dissector_table("dof.dnp", "DOF DNP Version", proto_2008_1_dnp
, FT_UINT8
, BASE_DEC
);
11196 dnp_framing_dissectors
= register_dissector_table("dof.dnp.frame", "DOF DNP Framing", proto_2008_1_dnp
, FT_UINT8
, BASE_DEC
);
11198 dof_register_dnp_0();
11199 dof_register_dnp_1();
11202 /* DPP Registration Support */
11205 * This routine is called each time the system is reset (file load, capture)
11206 * and so it should take care of freeing any of our persistent stuff.
11208 static void dof_dpp_reset(void)
11210 dpp_reset_opid_support();
11211 dpp_reset_sid_support();
11214 static void dof_dpp_cleanup(void)
11218 static void dof_register_dpp_0(void)
11220 static hf_register_info hf
[] =
11222 { &hf_2008_1_dpp_0_1_1_version
,
11223 { "Version", "dof.dpp.v0.version", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
11227 if (proto_2008_1_dpp_0
<= 0)
11229 proto_2008_1_dpp_0
= proto_register_protocol(DOF_PRESENTATION_PROTOCOL
" V0", "DPS.DPP.V0", "dof.dpp.v0");
11231 proto_register_field_array(proto_2008_1_dpp_0
, hf
, array_length(hf
));
11236 * The registration hand-off routine
11238 static void dof_reg_handoff_dpp_0(void)
11240 dissector_handle_t dpp_handle
;
11241 dpp_handle
= create_dissector_handle(dissect_dpp_0
, proto_2008_1_dpp_0
);
11243 dissector_add_uint("dof.dpp", 0, dpp_handle
);
11246 static void dof_register_dpp_2(void)
11248 expert_module_t
*expert_dpp
;
11250 static hf_register_info hf
[] =
11252 { &hf_2009_12_dpp_2_1_flags
,
11253 { "Flags", "dof.dpp.v2.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
11255 { &hf_2009_12_dpp_2_1_flag_security
,
11256 { "Secure", "dof.dpp.v2.flags.security", FT_BOOLEAN
, 8, NULL
, 0x80, NULL
, HFILL
}
11258 { &hf_2009_12_dpp_2_1_flag_opid
,
11259 { "Operation ID Type", "dof.dpp.v2.flags.opidtype", FT_UINT8
, BASE_DEC
, VALS(strings_2009_12_dpp_opid_types
), 0x60, NULL
, HFILL
} },
11260 { &hf_2009_12_dpp_2_1_flag_cmdrsp
,
11261 { "Command/Response", "dof.dpp.v2.flags.cmdrsp", FT_BOOLEAN
, 8, TFS(&tfs_response_command
), 0x10, NULL
, HFILL
} },
11262 { &hf_2009_12_dpp_2_1_flag_seq
,
11263 { "Sequence", "dof.dpp.v2.flags.sequence", FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), 0x04, NULL
, HFILL
} },
11264 { &hf_2009_12_dpp_2_1_flag_retry
,
11265 { "Retry", "dof.dpp.v2.flags.retry", FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), 0x02, NULL
, HFILL
} },
11267 { &hf_2009_12_dpp_2_3_sec_flags
,
11268 { "Flags", "dof.dpp.v2.security.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
11269 { &hf_2009_12_dpp_2_3_sec_flag_secure
,
11270 { "Security Mode Header", "dof.dpp.v2.security.flags.securitymodeheader", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
11271 { &hf_2009_12_dpp_2_3_sec_flag_rdid
,
11272 { "Remote Domain ID", "dof.dpp.v2.security.flags.rdid", FT_UINT8
, BASE_DEC
, NULL
, 0x08, NULL
, HFILL
} },
11273 { &hf_2009_12_dpp_2_3_sec_flag_partition
,
11274 { "Partition Present", "dof.dpp.v2.security.flags.partition", FT_UINT8
, BASE_DEC
, NULL
, 0x04, NULL
, HFILL
} },
11275 { &hf_2009_12_dpp_2_3_sec_flag_ssid
,
11276 { "SSID Present", "dof.dpp.v2.security.flags.ssid", FT_UINT8
, BASE_DEC
, NULL
, 0x01, NULL
, HFILL
} },
11277 { &hf_2009_12_dpp_2_3_sec_flag_as
,
11278 { "AS Present", "dof.dpp.v2.security.flags.as", FT_UINT8
, BASE_DEC
, NULL
, 0x02, NULL
, HFILL
} },
11279 { &hf_2009_12_dpp_2_3_sec_ssid
,
11280 { "Security State Identifier", "dof.dpp.v2.security.ssid", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11281 { &hf_2009_12_dpp_2_3_sec_rdid
,
11282 { "Remote Domain Identifier", "dof.dpp.v2.security.rdid", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11283 { &hf_2009_12_dpp_2_3_sec_remote_partition
,
11284 { "Remote Security Scope", "dof.dpp.v2.security.remote-scope", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11285 { &hf_2009_12_dpp_2_3_sec_partition
,
11286 { "Security Scope", "dof.dpp.v2.security.scope", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11288 { &hf_2009_12_dpp_2_1_opcnt
,
11289 { "Operation Count", "dof.dpp.v2.opcnt", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11290 { &hf_2009_12_dpp_2_1_seq
,
11291 { "Sequence", "dof.dpp.v2.sequence", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11292 { &hf_2009_12_dpp_2_1_retry
,
11293 { "Retry", "dof.dpp.v2.retry", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11294 { &hf_2009_12_dpp_2_1_delay
,
11295 { "Delay", "dof.dpp.v2.delay", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11298 static hf_register_info shf
[] =
11300 { &hf_2009_12_dpp_2_14_opcode
,
11301 { "Opcode", "dof.dpp.v2s.opcode", FT_UINT8
, BASE_DEC
, VALS(strings_2009_12_dpp_common_opcodes
), 0x0, NULL
, HFILL
} },
11304 static int *ett
[] =
11306 &ett_2009_12_dpp_2_1_flags
,
11307 &ett_2009_12_dpp_2_opid
,
11308 &ett_2009_12_dpp_2_opid_history
,
11309 &ett_2009_12_dpp_2_3_security
,
11310 &ett_2009_12_dpp_2_3_sec_flags
,
11311 &ett_2009_12_dpp_2_3_sec_remote_partition
,
11312 &ett_2009_12_dpp_2_3_sec_partition
,
11315 static ei_register_info ei
[] =
11317 { &ei_dpp2_dof_10_flags_zero
, { "dof.dpp.v2.flags_zero", PI_UNDECODED
, PI_ERROR
, "DPS-10: Reserved flag bits must be zero.", EXPFILL
} },
11318 { &ei_dpp_default_flags
, { "dof.dpp.v2.flags_included", PI_COMMENTS_GROUP
, PI_NOTE
, "Default flag value is included explicitly.", EXPFILL
} },
11319 { &ei_dpp_explicit_sender_sid_included
, { "dof.dpp.v2.sender_sid_included", PI_PROTOCOL
, PI_NOTE
, "Explicit SID could be optimized, same as sender.", EXPFILL
} },
11320 { &ei_dpp_explicit_receiver_sid_included
, { "dof.dpp.v2.receiver_sid_included", PI_PROTOCOL
, PI_NOTE
, "Explicit SID could be optimized, same as receiver.", EXPFILL
} },
11321 { &ei_dpp_no_security_context
, { "dof.dpp.v2.no_context", PI_UNDECODED
, PI_WARN
, "No security context to enable packet decryption.", EXPFILL
} },
11324 static int *sett
[] =
11326 &ett_2009_12_dpp_common
,
11329 if (proto_2009_12_dpp
<= 0)
11331 proto_2009_12_dpp
= proto_register_protocol(DOF_PRESENTATION_PROTOCOL
" V2", "DPS.DPP.V2", "dof.dpp.v2");
11332 proto_register_field_array(proto_2009_12_dpp
, hf
, array_length(hf
));
11333 proto_register_subtree_array(ett
, array_length(ett
));
11336 if (proto_2009_12_dpp_common
<= 0)
11338 proto_2009_12_dpp_common
= proto_register_protocol(DOF_PRESENTATION_PROTOCOL
" V2 Support", "DPS.DPP.V2S", "dof.dpp.v2s");
11340 proto_register_field_array(proto_2009_12_dpp
, shf
, array_length(shf
));
11341 proto_register_subtree_array(sett
, array_length(sett
));
11343 expert_dpp
= expert_register_protocol(proto_2009_12_dpp
);
11344 expert_register_field_array(expert_dpp
, ei
, array_length(ei
));
11349 * The registration hand-off routine
11351 static void dof_reg_handoff_dpp_2(void)
11353 dissector_handle_t dpp_handle
;
11354 dpp_handle
= create_dissector_handle(dissect_dpp_2
, proto_2009_12_dpp
);
11355 dissector_add_uint("dof.dpp", 2, dpp_handle
);
11359 * Initialize Core DPP Functionality
11361 static void dof_dpp_register(void)
11363 static hf_register_info hf
[] =
11365 { &hf_2008_1_dpp_sid_num
,
11366 { "SID ID", "dof.dpp.v2.sid-id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
11368 { &hf_2008_1_dpp_sid_str
,
11369 { "SID", "dof.dpp.v2.sid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
11371 { &hf_2008_1_dpp_rid_num
,
11372 { "RID ID", "dof.dpp.v2.rid-id", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
11374 { &hf_2008_1_dpp_rid_str
,
11375 { "RID", "dof.dpp.v2.rid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
11377 { &hf_2008_1_dpp_first_command
,
11378 { "First Operation", "dof.dpp.v2.first-operation", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11379 { &hf_2008_1_dpp_last_command
,
11380 { "Last Operation", "dof.dpp.v2.last-operation", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11381 { &hf_2008_1_dpp_first_response
,
11382 { "First Response", "dof.dpp.v2.first-response", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11383 { &hf_2008_1_dpp_last_response
,
11384 { "Last Response", "dof.dpp.v2.last-response", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11385 { &hf_2008_1_dpp_related_frame
,
11386 { "Related Frame", "dof.dpp.v2.related-frame", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11387 { &hf_2008_1_dpp_1_flag
,
11388 { "Flags", "dof.dpp.flag", FT_BOOLEAN
, 8, TFS(&tfs_present_not_present
), 0x80, NULL
, HFILL
}
11390 { &hf_2008_1_dpp_1_version
,
11391 { "Version", "dof.dpp.version", FT_UINT8
, BASE_DEC
, NULL
, 0x7F, NULL
, HFILL
}
11395 static int *ett
[] =
11398 &ett_2008_1_dpp_1_header
,
11401 static ei_register_info ei
[] =
11403 { &ei_dof_6_timeout
, { "dof.dpp.timeout", PI_PROTOCOL
, PI_ERROR
, "DOF Violation: DPS.6: Negotiation not complete within 10 seconds.", EXPFILL
} },
11406 if (proto_2008_1_dpp
<= 0)
11408 expert_module_t
*expert_dpp
;
11410 proto_2008_1_dpp
= proto_register_protocol(DOF_PRESENTATION_PROTOCOL
, "DPS.DPP", "dof.dpp");
11412 proto_register_field_array(proto_2008_1_dpp
, hf
, array_length(hf
));
11413 proto_register_subtree_array(ett
, array_length(ett
));
11414 dof_dpp_dissectors
= register_dissector_table("dof.dpp", "DOF DPP Version", proto_2008_1_dpp
, FT_UINT8
, BASE_DEC
);
11416 expert_dpp
= expert_register_protocol(proto_2008_1_dpp
);
11417 expert_register_field_array(expert_dpp
, ei
, array_length(ei
));
11420 dof_register_dpp_0();
11421 dof_register_dpp_2();
11424 static void dof_dpp_handoff(void)
11426 dof_reg_handoff_dpp_0();
11427 dof_reg_handoff_dpp_2();
11430 /* General Application Registration Support */
11432 static void app_reset(void)
11436 static void app_cleanup(void)
11441 * Initialize Core DPP Functionality
11443 static void app_register(void)
11445 if (proto_2008_1_app
<= 0)
11447 proto_2008_1_app
= proto_register_protocol(DOF_APPLICATION_PROTOCOL
, "DPS.APP", "dof.app");
11448 app_dissectors
= register_dissector_table("dof.app", "DOF APP Version", proto_2008_1_app
, FT_UINT16
, BASE_DEC
);
11452 static void app_handoff(void)
11456 /* DSP Registration Support */
11458 static void dof_dsp_reset(void)
11462 static void dof_dsp_cleanup(void)
11466 static void dof_register_dsp_0(void)
11468 static hf_register_info hf
[] =
11470 { &hf_2008_1_app_version
,
11471 { "APPID", "dof.app.v0.appid", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
11474 { &hf_2008_1_dsp_12_opcode
,
11475 { "Opcode", "dof.dsp.opcode", FT_UINT8
, BASE_DEC
, VALS(strings_2008_1_dsp_opcodes
), 0x0, NULL
, HFILL
} },
11477 { &hf_2008_1_dsp_attribute_code
,
11478 { "Attribute Code", "dof.dsp.avp.attribute-code", FT_UINT8
, BASE_DEC
, VALS(strings_2008_1_dsp_attribute_codes
), 0x00, NULL
, HFILL
} },
11480 { &hf_2008_1_dsp_attribute_data
,
11481 { "Attribute Data", "dof.dsp.avp.attribute-data", FT_UINT16
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
} },
11483 { &hf_2008_1_dsp_value_length
,
11484 { "Value Length", "dof.dsp.avp.value-length", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11486 { &hf_2008_1_dsp_value_data
,
11487 { "Value Data", "dof.dsp.avp.value-data", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11490 static int *ett
[] =
11492 &ett_2008_1_dsp_12
,
11493 &ett_2008_1_dsp_12_options
,
11494 &ett_2008_1_dsp_12_option
,
11497 proto_2008_1_dsp
= proto_register_protocol("DOF Session Protocol", "DOF.ESP", "dof.esp");
11499 proto_register_field_array(proto_2008_1_dsp
, hf
, array_length(hf
));
11500 proto_register_subtree_array(ett
, array_length(ett
));
11504 * The registration hand-off routine
11506 static void dof_reg_handoff_dsp_0(void)
11508 dissector_handle_t dsp_handle
= create_dissector_handle(dissect_dsp
, proto_2008_1_dsp
);
11509 dissector_add_uint("dof.app", 0, dsp_handle
);
11512 static void dof_dsp_register(void)
11514 dof_register_dsp_0();
11517 static void dof_dsp_handoff(void)
11519 dof_reg_handoff_dsp_0();
11522 /* CCM Registration Support */
11524 static void dof_ccm_reset(void)
11528 static void dof_ccm_cleanup(void)
11532 static void dof_register_ccm_24577(void)
11534 expert_module_t
*expert_ccm
;
11536 static hf_register_info hfdsp
[] =
11538 { &hf_ccm_dsp_option
,
11539 { "CCM Security Mode", "dof.ccm.dsp_opt", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11540 { &hf_ccm_dsp_strength_count
,
11541 { "CCM Strength Count", "dof.ccm.strength-count", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11542 { &hf_ccm_dsp_strength
,
11543 { "CCM Strength", "dof.ccm.strength", FT_UINT8
, BASE_DEC
, VALS(ccm_strengths
), 0x0, NULL
, HFILL
} },
11544 { &hf_ccm_dsp_e_flag
,
11545 { "CCM Minimum Encrypt", "dof.ccm.encrypt.min", FT_BOOLEAN
, 8, TFS(&tfs_encrypt_do_not_encrypt
), 0x80, NULL
, HFILL
} },
11546 { &hf_ccm_dsp_m_flag
,
11547 { "CCM Maximum Encrypt", "dof.ccm.encrypt.max", FT_BOOLEAN
, 8, TFS(&tfs_encrypt_do_not_encrypt
), 0x40, NULL
, HFILL
} },
11548 { &hf_ccm_dsp_tmax
,
11549 { "CCM Maximum MAC", "dof.ccm.mac.max", FT_UINT8
, BASE_DEC
, NULL
, 0x38, NULL
, HFILL
} },
11550 { &hf_ccm_dsp_tmin
,
11551 { "CCM Minimum MAC", "dof.ccm.mac.min", FT_UINT8
, BASE_DEC
, NULL
, 0x07, NULL
, HFILL
} },
11554 static hf_register_info hf
[] =
11557 { "Opcode", "dof.ccm.opcode", FT_UINT8
, BASE_DEC
, VALS(ccm_opcode_strings
), 0x0, NULL
, HFILL
} },
11560 static int *ett
[] =
11562 &ett_ccm_dsp_option
,
11567 static hf_register_info hfheader
[] =
11569 { &hf_epp_v1_ccm_flags
,
11570 { "Flags", "dof.epp.v1.ccm.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
11571 { &hf_epp_v1_ccm_flags_manager
,
11572 { "Manager", "dof.epp.v1.ccm.flags.manager", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
11573 { &hf_epp_v1_ccm_flags_period
,
11574 { "Period", "dof.epp.v1.ccm.flags.period", FT_UINT8
, BASE_DEC
, NULL
, 0x70, NULL
, HFILL
} },
11575 { &hf_epp_v1_ccm_flags_target
,
11576 { "Target", "dof.epp.v1.ccm.flags.target", FT_UINT8
, BASE_DEC
, NULL
, 0x08, NULL
, HFILL
} },
11577 { &hf_epp_v1_ccm_flags_next_nid
,
11578 { "Next Node Identifier", "dof.epp.v1.ccm.flags.next-nid", FT_UINT8
, BASE_DEC
, NULL
, 0x02, NULL
, HFILL
} },
11579 { &hf_epp_v1_ccm_flags_packet
,
11580 { "Packet", "dof.epp.v1.ccm.flags.packet", FT_UINT8
, BASE_DEC
, NULL
, 0x01, NULL
, HFILL
} },
11581 { &hf_epp_v1_ccm_nid
,
11582 { "Node ID", "dof.epp.v1.ccm.nodeid", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11583 { &hf_epp_v1_ccm_slot
,
11584 { "Slot", "dof.epp.v1.ccm.slot", FT_UINT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11585 { &hf_epp_v1_ccm_pn
,
11586 { "Packet", "dof.epp.v1.ccm.packet", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11587 { &hf_epp_v1_ccm_tnid
,
11588 { "Target Node ID", "dof.epp.v1.ccm.target", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11589 { &hf_epp_v1_ccm_nnid
,
11590 { "Next Node ID", "dof.epp.v1.ccm.nnid", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11593 static int *ettheader
[] =
11595 &ett_epp_v1_ccm_flags
,
11599 static ei_register_info ei
[] =
11601 { &ei_decode_failure
, { "dof.ccm.decode_failure", PI_UNDECODED
, PI_WARN
, "Failure to decrypt packet.", EXPFILL
} },
11604 /* No Configuration options to register? */
11606 proto_ccm_app
= proto_register_protocol("DOF CCM Security Mode App", "DOF.CCM.APP", "dof.ccm.app");
11607 proto_ccm
= proto_register_protocol("DOF CCM Security Mode of Operation", "DOF.CCM", "dof.ccm");
11608 proto_ccm_dsp
= proto_register_protocol("DOF CCM Security Mode DSP Options", "DOF.CCM.DSP", "dof.ccm.dsp");
11610 proto_register_field_array(proto_ccm_app
, hf
, array_length(hf
));
11611 proto_register_field_array(proto_ccm_dsp
, hfdsp
, array_length(hfdsp
));
11612 proto_register_subtree_array(ett
, array_length(ett
));
11614 proto_register_field_array(proto_ccm
, hfheader
, array_length(hfheader
));
11615 proto_register_subtree_array(ettheader
, array_length(ettheader
));
11617 expert_ccm
= expert_register_protocol(proto_ccm
);
11618 expert_register_field_array(expert_ccm
, ei
, array_length(ei
));
11622 * The registration hand-off routine
11624 static void dof_reg_handoff_ccm_24577(void)
11626 static dissector_handle_t ccm_app_handle
;
11627 static dissector_handle_t dsp_handle
;
11628 static dissector_handle_t ccm_handle
;
11630 ccm_app_handle
= create_dissector_handle(dissect_ccm_app
, proto_ccm_app
);
11631 dsp_handle
= create_dissector_handle(dissect_ccm_dsp
, proto_ccm_dsp
);
11632 ccm_handle
= create_dissector_handle(dissect_ccm
, proto_ccm
);
11634 dissector_add_uint("dof.app", DOF_PROTOCOL_CCM
, ccm_app_handle
);
11635 dissector_add_uint("dof.dsp.options", DSP_CCM_FAMILY
| DOF_PROTOCOL_CCM
, dsp_handle
);
11636 dissector_add_uint("dof.secmode", DOF_PROTOCOL_CCM
, ccm_handle
);
11639 static void dof_ccm_register(void)
11641 dof_register_ccm_24577();
11644 static void dof_ccm_handoff(void)
11646 dof_reg_handoff_ccm_24577();
11649 /* OAP Registration Support */
11651 static void dof_oap_reset(void)
11653 /* The value is not allocated, so does not need to be freed. */
11654 oap_1_alias_to_binding
= g_hash_table_new_full(oap_1_alias_hash_func
, oap_1_alias_equal_func
, NULL
, NULL
);
11657 static void dof_oap_cleanup(void)
11659 g_hash_table_destroy(oap_1_alias_to_binding
);
11660 oap_1_alias_to_binding
= NULL
;
11663 static void dof_register_oap_1(void)
11665 expert_module_t
*expert_oap
;
11667 static hf_register_info hfdsp
[] =
11669 { &hf_oap_1_dsp_option
,
11670 { "Object Access Protocol", "dof.oap.dsp_opt", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11673 static hf_register_info hf
[] =
11675 { &hf_oap_1_opcode
,
11676 { "Opcode", "dof.oap.opcode", FT_UINT8
, BASE_DEC
, VALS(oap_opcode_strings
), 0x1F, NULL
, HFILL
} },
11678 { &hf_oap_1_alias_size
,
11679 { "Alias Length", "dof.oap.aliaslen", FT_UINT8
, BASE_DEC
, NULL
, 0xC0, NULL
, HFILL
} },
11682 { "Flags", "dof.oap.flags", FT_UINT8
, BASE_DEC
, NULL
, 0x20, NULL
, HFILL
} },
11684 { &hf_oap_1_exception_internal_flag
,
11685 { "Internal Exception", "dof.oap.exception.internal", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
} },
11687 { &hf_oap_1_exception_final_flag
,
11688 { "Final Exception", "dof.oap.exception.final", FT_UINT8
, BASE_DEC
, NULL
, 0x40, NULL
, HFILL
} },
11690 { &hf_oap_1_exception_provider_flag
,
11691 { "Exception Provider", "dof.oap.exception.provider", FT_UINT8
, BASE_DEC
, NULL
, 0x20, NULL
, HFILL
} },
11693 { &hf_oap_1_cmdcontrol
,
11694 { "Command Control", "dof.oap.cmdcontrol", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
11696 { &hf_oap_1_cmdcontrol_cache_flag
,
11697 { "Cache Delay Flag", "dof.oap.cmdcontrol.flag.cache", FT_UINT8
, BASE_HEX
, NULL
, 0x40, NULL
, HFILL
} },
11699 { &hf_oap_1_cmdcontrol_cache
,
11700 { "Cache Delay", "dof.oap.cmdcontrol.cache", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
} },
11702 { &hf_oap_1_cmdcontrol_verbosity_flag
,
11703 { "Verbosity Flag", "dof.oap.cmdcontrol.flag.verbosity", FT_UINT8
, BASE_HEX
, NULL
, 0x30, NULL
, HFILL
} },
11705 { &hf_oap_1_cmdcontrol_noexecute_flag
,
11706 { "No Execute Flag", "dof.oap.cmdcontrol.flag.noexecute", FT_UINT8
, BASE_HEX
, NULL
, 0x08, NULL
, HFILL
} },
11708 { &hf_oap_1_cmdcontrol_ack_flag
,
11709 { "Ack List Flag", "dof.oap.cmdcontrol.flag.ack", FT_UINT8
, BASE_HEX
, NULL
, 0x04, NULL
, HFILL
} },
11711 { &hf_oap_1_cmdcontrol_ackcnt
,
11712 { "Ack List Count", "dof.oap.cmdcontrol.ackcnt", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
} },
11714 { &hf_oap_1_cmdcontrol_ack
,
11715 { "Ack", "dof.oap.cmdcontrol.ack", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11717 { &hf_oap_1_cmdcontrol_delay_flag
,
11718 { "Execution Delay Flag", "dof.oap.cmdcontrol.flag.delay", FT_UINT8
, BASE_HEX
, NULL
, 0x02, NULL
, HFILL
} },
11720 { &hf_oap_1_cmdcontrol_heuristic_flag
,
11721 { "Heuristic Flag", "dof.oap.cmdcontrol.flag.heuristic", FT_UINT8
, BASE_HEX
, NULL
, 0x01, NULL
, HFILL
} },
11723 { &hf_oap_1_cmdcontrol_heuristic
,
11724 { "Heuristic", "dof.oap.cmdcontrol.heuristic", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
} },
11726 { &hf_oap_1_providerid
,
11727 { "Provider ID", "dof.oap.provider-id", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11729 { &hf_oap_1_objectid
,
11730 { "Object ID", "dof.oap.object-id", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11732 { &hf_oap_1_interfaceid
,
11733 { "Interface ID", "dof.oap.interface-id", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11735 { &hf_oap_1_itemid
,
11736 { "Item ID", "dof.oap.item-id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11738 #if 0 /* not used yet */
11739 { &hf_oap_1_distance
,
11740 { "Distance", "dof.oap.distance", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11744 { "Alias", "dof.oap.alias", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11746 { &hf_oap_1_alias_frame
,
11747 { "Alias Frame", "dof.oap.alias-frame", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11749 #if 0 /* not used yet */
11750 { &hf_oap_1_opinfo_start_frame
,
11751 { "Command Frame", "dof.oap.command-frame", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11753 { &hf_oap_1_opinfo_end_frame
,
11754 { "Response Frame", "dof.oap.response-frame", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11756 { &hf_oap_1_opinfo_timeout
,
11757 { "Operation Timeout", "dof.oap.opid.timeout", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11760 { &hf_oap_1_subscription_delta
,
11761 { "Minimum Delta", "dof.oap.subscription.min-delta", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11763 { &hf_oap_1_update_sequence
,
11764 { "Sequence", "dof.oap.sequence", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
11766 { &hf_oap_1_value_list
,
11767 { "OAP Value List", "dof.oap.value_list", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11770 static int *ett
[] =
11773 &ett_oap_1_dsp_options
,
11776 &ett_oap_1_cmdcontrol
,
11777 &ett_oap_1_cmdcontrol_flags
,
11778 &ett_oap_1_cmdcontrol_ack
,
11780 &ett_oap_1_objectid
,
11781 &ett_oap_1_1_providerid
,
11784 static ei_register_info ei
[] =
11786 { &ei_oap_no_session
, { "dof.oap.no_session", PI_PROTOCOL
, PI_ERROR
, "Session not found", EXPFILL
} },
11789 proto_oap_1
= proto_register_protocol("DOF Object Access Protocol", "DOF.OAP", "dof.oap");
11790 proto_oap_1_dsp
= proto_register_protocol("DOF Object Access Protocol DSP Options", "DOF.OAP.DSP", "dof.oap.dsp");
11792 proto_register_field_array(proto_oap_1
, hf
, array_length(hf
));
11793 proto_register_field_array(proto_oap_1_dsp
, hfdsp
, array_length(hfdsp
));
11794 proto_register_subtree_array(ett
, array_length(ett
));
11796 expert_oap
= expert_register_protocol(proto_oap_1
);
11797 expert_register_field_array(expert_oap
, ei
, array_length(ei
));
11801 * The registration hand-off routine
11803 static void dof_reg_handoff_oap_1(void)
11805 dissector_handle_t oap_handle
= create_dissector_handle(dissect_oap
, proto_oap_1
);
11806 dissector_handle_t dsp_handle
= create_dissector_handle(dissect_oap_dsp
, proto_oap_1_dsp
);
11808 dissector_add_uint("dof.app", DOF_PROTOCOL_OAP_1
, oap_handle
);
11809 dissector_add_uint("dof.dsp.options", DSP_OAP_FAMILY
| DOF_PROTOCOL_OAP_1
, dsp_handle
);
11812 static void dof_oap_register(void)
11814 dof_register_oap_1();
11817 static void dof_oap_handoff(void)
11819 dof_reg_handoff_oap_1();
11822 /* SGMP Registration Support */
11824 static void dof_register_sgmp_130(void);
11825 static void dof_reg_handoff_sgmp_130(void);
11827 static void dof_sgmp_reset(void)
11831 static void dof_sgmp_cleanup(void)
11835 static void dof_register_sgmp_130(void)
11837 static hf_register_info hf
[] =
11840 { "Opcode", "dof.sgmp.v1.opcode", FT_UINT8
, BASE_DEC
, VALS(sgmp_opcode_strings
), 0x0, NULL
, HFILL
} },
11843 { "Domain", "dof.sgmp.v1.domain", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11846 { "Epoch", "dof.sgmp.v1.epoch", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11848 { &hf_initiator_block
,
11849 { "Initiator Block", "dof.sgmp.v1.initiator-block", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11851 { &hf_sgmp_security_scope
,
11852 { "Security Scope", "dof.sgmp.v1.security-scope", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11854 { &hf_initial_state
,
11855 { "Initial State", "dof.sgmp.v1.initial-state", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11857 { &hf_latest_version
,
11858 { "Latest SGMP Version", "dof.sgmp.v1.latest-sgmp-version", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11861 { "Desire", "dof.sgmp.v1.desire", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11864 { "Ticket", "dof.sgmp.v1.ticket", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11867 { "TMIN", "dof.sgmp.v1.tmin", FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11870 { "Tie Breaker", "dof.sgmp.v1.tie-breaker", FT_UINT32
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11873 { "Delay", "dof.sgmp.v1.delay", FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
11876 { "Key", "dof.sgmp.v1.key", FT_BYTES
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
11879 static int *ett
[] =
11883 &ett_initiator_block
,
11884 &ett_sgmp_security_scope
,
11885 &ett_initial_state
,
11889 proto_sgmp
= proto_register_protocol("DOF Secure Group Management Protocol", "DOF.SGMP", "dof.sgmp");
11891 proto_register_field_array(proto_sgmp
, hf
, array_length(hf
));
11892 proto_register_subtree_array(ett
, array_length(ett
));
11896 * The registration hand-off routine
11898 static void dof_reg_handoff_sgmp_130(void)
11900 dissector_handle_t sgmp_handle
= create_dissector_handle(dissect_sgmp
, proto_sgmp
);
11902 dissector_add_uint("dof.app", DOF_PROTOCOL_SGMP
, sgmp_handle
);
11905 static void dof_sgmp_register(void)
11907 dof_register_sgmp_130();
11910 static void dof_sgmp_handoff(void)
11912 dof_reg_handoff_sgmp_130();
11915 /* TEP Registration Support */
11917 static void dof_tep_reset(void)
11921 static void dof_tep_cleanup(void)
11925 static void dof_register_tep_128(void)
11927 static hf_register_info hfdsp
[] =
11930 { "Ticket Exchange Protocol Version 1", "dof.tep1.dsp_opt", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11933 static hf_register_info hf
[] =
11935 { &hf_tep_operation
,
11936 { "Operation", "dof.tep1.operation", FT_UINT8
, BASE_DEC
, VALS(tep_opcode_strings
), 0x00, NULL
, HFILL
} },
11938 { &hf_tep_operation_type
,
11939 { "Operation Type", "dof.tep1.operation_type", FT_BOOLEAN
, 8, TFS(&tep_optype_vals
), TEP_OPCODE_RSP
, NULL
, HFILL
} },
11942 { "Opcode", "dof.tep1.opcode", FT_UINT8
, BASE_DEC
, VALS(tep_opcode_strings
), 0x0F, NULL
, HFILL
} },
11945 { "K", "dof.tep1.k", FT_UINT8
, BASE_DEC
, NULL
, 0x10, NULL
, HFILL
} },
11948 { "C", "dof.tep1.c", FT_UINT8
, BASE_DEC
, NULL
, 0x20, NULL
, HFILL
} },
11950 { &hf_tep_reject_code
,
11951 { "Code", "dof.tep1.reject.code", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11953 { &hf_tep_reject_data
,
11954 { "Data", "dof.tep1.reject.data", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11957 { &hf_tep_2_1_domain
,
11958 { "Domain", "dof.2008.4.tep1.2.1.domain", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
11960 { &hf_tep_2_1_initiator_block
,
11961 { "Initiator Block", "dof.2008.4.tep1.2.1.initiator_block", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11963 { &hf_tep_2_1_ticket_confirmation
,
11964 { "Ticket Confirmation", "dof.2008.4.tep1.2.1.ticket_confirmation", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11967 { &hf_tep_2_2_initiator_ticket
,
11968 { "Initiator Ticket", "dof.2008.4.tep1.2.2.initiator_ticket", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11970 { &hf_tep_2_2_ticket_confirmation
,
11971 { "Ticket Confirmation", "dof.2008.4.tep1.2.2.ticket_confirmation", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11973 { &hf_tep_2_2_responder_initialization
,
11974 { "Responder Initialization", "dof.2008.4.tep1.2.2.responder_initialization", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11976 { &hf_tep_2_2_responder_block
,
11977 { "Responder Block", "dof.2008.4.tep1.2.2.responder_block", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11979 { &hf_tep_2_2_authenticator_initialization
,
11980 { "Authenticator Initialization", "dof.2008.4.tep1.2.2.authenticator_initialization", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11983 { &hf_tep_2_2_1_state_identifier
,
11984 { "State Identifier", "dof.2008.4.tep1.2.2.1.state_identifier", FT_UINT32
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
11986 { &hf_tep_2_2_1_initial_state
,
11987 { "Initial State", "dof.2008.4.tep1.2.2.1.initial_state", FT_NONE
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
} },
11989 { &hf_tep_session_key
,
11990 { "Session Key", "dof.session_key", FT_BYTES
, SEP_COLON
, NULL
, 0x00, NULL
, HFILL
} },
11993 static int *ett
[] =
11996 &ett_tep_dsp_options
,
11998 &ett_tep_operation
,
12000 &ett_tep_2_1_domain
,
12001 &ett_tep_2_1_initiator_block
,
12003 &ett_tep_2_2_initiator_ticket
,
12004 &ett_tep_2_2_responder_initialization
,
12005 &ett_tep_2_2_responder_block
,
12006 &ett_tep_2_2_authenticator_initialization
,
12008 &ett_tep_2_2_1_initial_state
,
12011 /* module_t *tep_module;*/
12013 /* No Configuration options to register? */
12015 proto_tep
= proto_register_protocol("DOF Ticket Exchange Protocol Version 1", "DOF.TEP1", "dof.tep1");
12017 proto_tep_dsp
= proto_register_protocol("DOF Ticket Exchange Protocol DSP Options", "DOF.TEP1.DSP", "dof.tep1.dsp");
12019 proto_register_field_array(proto_tep
, hf
, array_length(hf
));
12020 proto_register_field_array(proto_tep_dsp
, hfdsp
, array_length(hfdsp
));
12021 proto_register_subtree_array(ett
, array_length(ett
));
12023 /* tep_module = prefs_register_protocol( proto_tep, NULL );*/
12027 * The registration hand-off routine
12029 static void dof_reg_handoff_tep_128(void)
12031 dissector_handle_t tep_handle
= create_dissector_handle(dissect_tep
, proto_tep
);
12032 dissector_handle_t dsp_handle
= create_dissector_handle(dissect_tep_dsp
, proto_tep_dsp
);
12034 dissector_add_uint("dof.app", DOF_PROTOCOL_TEP
, tep_handle
);
12035 dissector_add_uint("dof.dsp.options", DSP_TEP_FAMILY
| DOF_PROTOCOL_TEP
, dsp_handle
);
12038 static void dof_tep_register(void)
12040 dof_register_tep_128();
12043 static void dof_tep_handoff(void)
12045 dof_reg_handoff_tep_128();
12048 /* TRP Registration Support */
12050 static void dof_trp_reset(void)
12054 static void dof_trp_cleanup(void)
12058 static void dof_register_trp_129(void)
12060 expert_module_t
*expert_trp
;
12062 static hf_register_info hfdsp
[] =
12064 { &hf_trp_dsp_option
,
12065 { "Ticket Request Protocol", "dof.trp.dsp_opt", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12068 static hf_register_info hf
[] =
12071 { "Opcode", "dof.trp.opcode", FT_UINT8
, BASE_DEC
, VALS(trp_opcode_strings
), 0x0, NULL
, HFILL
} },
12074 { "Domain", "dof.trp.domain", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12076 { &hf_identity_resolution
,
12077 { "Identity Resolution", "dof.trp.identity_resolution", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12079 { &hf_initiator_request
,
12080 { "Initiator Request", "dof.trp.initiator_request", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12082 { &hf_responder_request
,
12083 { "Responder Request", "dof.trp.responder_request", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12085 { &hf_initiator_ticket
,
12086 { "Initiator Ticket", "dof.trp.initiator_ticket", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12088 { &hf_responder_ticket
,
12089 { "Responder Ticket", "dof.trp.responder_ticket", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12091 { &hf_authentication_block
,
12092 { "Authentication Block", "dof.trp.authentication_block", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12094 { &hf_group_identifier
,
12095 { "Group Identifier", "dof.trp.group_identifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12097 { &hf_node_identifier
,
12098 { "Node Identifier", "dof.trp.node_identifier", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12101 { "Thb", "dof.trp.thb", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
12104 { "Tmin", "dof.trp.tmin", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
12107 { "Tmax", "dof.trp.tmax", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
12110 { "Epoch", "dof.trp.epoch", FT_UINT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
} },
12113 { "SIDg", "dof.trp.sid_g", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12115 { &hf_security_scope
,
12116 { "Security Scope", "dof.trp.security_scope", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12118 { &hf_security_mode
,
12119 { "Security Mode", "dof.trp.security_mode", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12122 { "SSID", "dof.trp.ssid", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
12124 #if 0 /* not used yet */
12125 { &hf_initiator_pg
,
12126 { "Initiator Permissions", "dof.trp.initiator_pg", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12129 { &hf_initiator_validation
,
12130 { "Initiator Validation", "dof.trp.initiator_validation", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12132 { &hf_responder_pg
,
12133 { "Responder Permissions", "dof.trp.responder_pg", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12135 { &hf_responder_validation
,
12136 { "Responder Validation", "dof.trp.responder_validation", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12138 { &hf_trp_errorcode
,
12139 { "Error Code", "dof.trp.errorcode", FT_UINT8
, BASE_DEC
, VALS(trp_error_strings
), 0x0, NULL
, HFILL
} },
12141 { &hf_trp_duration
,
12142 { "Duration", "dof.trp.duration", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
12144 #if 0 /* not used yet */
12146 { "Requestor Nonce", "dof.trp.rnonce", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12149 { "Provider Nonce", "dof.trp.pnonce", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12152 { "Requestor ID", "dof.trp.reqid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12155 { "Provider ID", "dof.trp.provid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12157 { &hf_trp_perm_count
,
12158 { "Permission Count", "dof.trp.perm.count", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
12160 { &hf_trp_perm_type
,
12161 { "Permission Type", "dof.trp.perm.type", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
12163 { &hf_trp_perm_rflags
,
12164 { "Requestor SRP Flags", "dof.trp.rflags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
12166 { &hf_trp_perm_rcache
,
12167 { "Requestor SRP Cache", "dof.trp.rcache", FT_BOOLEAN
, 8, NULL
, 0x2, NULL
, HFILL
} },
12169 { &hf_trp_perm_rsrp
,
12170 { "Requestor SRP", "dof.trp.rsrp", FT_BOOLEAN
, 8, NULL
, 0x1, NULL
, HFILL
} },
12172 { &hf_trp_perm_rsrp_a
,
12173 { "Requestor SRP A", "dof.trp.rsrp.a", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12175 { &hf_trp_perm_rsrp_u
,
12176 { "Requestor SRP u", "dof.trp.rsrp.u", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12178 { &hf_trp_perm_pflags
,
12179 { "Provider SRP Flags", "dof.trp.pflags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
12181 { &hf_trp_perm_pcache
,
12182 { "Provider SRP Cache", "dof.trp.pcache", FT_BOOLEAN
, 8, NULL
, 0x2, NULL
, HFILL
} },
12184 { &hf_trp_perm_psrp
,
12185 { "Provider SRP", "dof.trp.psrp", FT_BOOLEAN
, 8, NULL
, 0x1, NULL
, HFILL
} },
12187 { &hf_trp_perm_psrp_a
,
12188 { "Provider SRP A", "dof.trp.psrp.a", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12190 { &hf_trp_perm_psrp_u
,
12191 { "Provider SRP u", "dof.trp.psrp.u", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12193 { &hf_trp_perm_psrp_b
,
12194 { "Provider SRP B", "dof.trp.psrp.b", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12196 { &hf_trp_perm_psrp_s
,
12197 { "Provider SRP S", "dof.trp.psrp.s", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12199 { &hf_trp_confirmation
,
12200 { "Confirmation", "dof.trp.confirmation", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12202 { &hf_trp_perm_pke
,
12203 { "Provider Key Expression", "dof.trp.pke", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12205 { &hf_trp_perm_pka
,
12206 { "Provider Key Authenticator", "dof.trp.pka", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
12210 static int *ett
[] =
12215 &ett_identity_resolution
,
12216 &ett_initiator_request
,
12217 &ett_initiator_ticket
,
12218 &ett_responder_request
,
12219 &ett_responder_ticket
,
12220 &ett_authentication_block
,
12221 &ett_group_identifier
,
12222 &ett_node_identifier
,
12224 &ett_security_scope
,
12225 &ett_security_mode
,
12227 &ett_initiator_validation
,
12229 &ett_responder_validation
,
12235 static ei_register_info ei
[] =
12237 { &ei_trp_initiator_id_known
, { "dof.trp.initiator_id_known", PI_PROTOCOL
, PI_COMMENT
, "Initiator identity known", EXPFILL
} },
12238 { &ei_trp_kek_discovered
, { "dof.trp.kek_discovered", PI_PROTOCOL
, PI_COMMENT
, "KEK discovered", EXPFILL
} },
12241 /* No Configuration options to register? */
12243 proto_trp
= proto_register_protocol("DOF Ticket Request Protocol", "DOF.TRP", "dof.trp");
12245 proto_trp_dsp
= proto_register_protocol("DOF Ticket Request Protocol DSP Options", "DOF.TRP.DSP", "dof.trp.dsp");
12247 proto_register_field_array(proto_trp
, hf
, array_length(hf
));
12248 proto_register_field_array(proto_trp_dsp
, hfdsp
, array_length(hfdsp
));
12249 proto_register_subtree_array(ett
, array_length(ett
));
12250 expert_trp
= expert_register_protocol(proto_trp
);
12251 expert_register_field_array(expert_trp
, ei
, array_length(ei
));
12255 * The registration hand-off routine
12257 static void dof_reg_handoff_trp_129(void)
12259 dissector_handle_t trp_handle
= create_dissector_handle(dissect_trp
, proto_trp
);
12260 dissector_handle_t dsp_handle
= create_dissector_handle(dissect_trp_dsp
, proto_trp_dsp
);
12262 dissector_add_uint("dof.app", DOF_PROTOCOL_TRP
, trp_handle
);
12263 dissector_add_uint("dof.dsp.options", DSP_TRP_FAMILY
| DOF_PROTOCOL_TRP
, dsp_handle
);
12266 static void dof_trp_register(void)
12268 dof_register_trp_129();
12271 static void dof_trp_handoff(void)
12273 dof_reg_handoff_trp_129();
12276 /* Wireshark Dissector Registration Proper */
12279 * This is called only during reset (file load, reload, etc.).
12281 static void dof_reset_routine(void)
12297 static void dof_cleanup_routine(void)
12308 dof_sgmp_cleanup();
12314 dof_shutdown_routine(void)
12318 for (i
= 0; i
< global_security
.identity_data_count
; i
++) {
12319 g_free(global_security
.identity_data
[i
].identity
);
12320 g_free(global_security
.identity_data
[i
].domain
);
12321 g_free(global_security
.identity_data
[i
].secret
);
12323 g_free(global_security
.identity_data
);
12325 for (i
= 0; i
< global_security
.group_data_count
; i
++) {
12326 g_free(global_security
.group_data
[i
].domain
);
12327 g_free(global_security
.group_data
[i
].identity
);
12328 g_free(global_security
.group_data
[i
].kek
);
12331 if (addr_port_to_id
)
12332 g_hash_table_destroy(addr_port_to_id
);
12333 if (dpp_opid_to_packet_data
)
12334 g_hash_table_destroy(dpp_opid_to_packet_data
);
12335 if (node_key_to_sid_id
)
12336 g_hash_table_destroy(node_key_to_sid_id
);
12337 if (sid_buffer_to_sid_id
)
12338 g_hash_table_destroy(sid_buffer_to_sid_id
);
12339 if (sid_id_to_sid_buffer
)
12340 g_hash_table_destroy(sid_id_to_sid_buffer
);
12344 * This is the first entry point into the dissector, called on program launch.
12346 void proto_register_dof(void)
12348 dof_tun_register();
12351 dof_dnp_register();
12352 dof_dpp_register();
12354 dof_dsp_register();
12355 dof_ccm_register();
12356 dof_oap_register();
12357 dof_sgmp_register();
12358 dof_tep_register();
12359 dof_trp_register();
12361 register_init_routine(&dof_reset_routine
);
12362 register_cleanup_routine(&dof_cleanup_routine
);
12363 register_shutdown_routine(&dof_shutdown_routine
);
12367 * This routine is called after initialization and whenever the preferences are changed.
12369 void proto_reg_handoff_dof(void)
12380 dof_sgmp_handoff();
12386 * Protocol-specific data attached to a conversation_t structure - protocol
12387 * index and opaque pointer.
12389 typedef struct _dof_proto_data
{
12394 static int p_compare(const void *a
, const void *b
)
12396 const dof_proto_data
*ap
= (const dof_proto_data
*)a
;
12397 const dof_proto_data
*bp
= (const dof_proto_data
*)b
;
12399 if (ap
->proto
> bp
->proto
)
12401 else if (ap
->proto
== bp
->proto
)
12407 #if 0 /* TODO not used yet */
12408 static void dof_session_add_proto_data(dof_session_data
*session
, int proto
, void *proto_data
)
12410 dof_proto_data
*p1
= wmem_new0(wmem_packet_scope(), dof_proto_data
);
12413 p1
->proto_data
= proto_data
;
12415 /* Add it to the list of items for this conversation. */
12417 session
->data_list
= g_slist_insert_sorted(session
->data_list
, (void * *)p1
, p_compare
);
12420 static void *dof_session_get_proto_data(dof_session_data
*session
, int proto
)
12422 dof_proto_data temp
, *p1
;
12425 temp
.proto
= proto
;
12426 temp
.proto_data
= NULL
;
12428 item
= g_slist_find_custom(session
->data_list
, (void * *)&temp
,
12433 p1
= (dof_proto_data
*)item
->data
;
12434 return p1
->proto_data
;
12440 static void dof_session_delete_proto_data(dof_session_data
*session
, int proto
)
12442 dof_proto_data temp
;
12445 temp
.proto
= proto
;
12446 temp
.proto_data
= NULL
;
12448 item
= g_slist_find_custom(session
->data_list
, (void * *)&temp
,
12453 session
->data_list
= g_slist_remove(session
->data_list
, item
->data
);
12459 static void dof_packet_add_proto_data(dof_packet_data
*packet
, int proto
, void *proto_data
)
12461 dof_proto_data
*p1
= wmem_new0(wmem_file_scope(), dof_proto_data
);
12464 p1
->proto_data
= proto_data
;
12466 /* Add it to the list of items for this conversation. */
12468 wmem_list_insert_sorted(packet
->data_list
, (void * *)p1
, p_compare
);
12471 static void *dof_packet_get_proto_data(dof_packet_data
*packet
, int proto
)
12473 dof_proto_data temp
, *p1
;
12474 wmem_list_frame_t
*item
;
12476 temp
.proto
= proto
;
12477 temp
.proto_data
= NULL
;
12479 item
= wmem_list_find_custom(packet
->data_list
, (void * *)&temp
,
12484 p1
= (dof_proto_data
*)wmem_list_frame_data(item
);
12485 return p1
->proto_data
;
12491 static int dof_dissect_pdu_as_field(dissector_t dissector
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int item
, int ett
, void *result
)
12494 tvbuff_t
*start
= tvb_new_subset_remaining(tvb
, offset
);
12495 proto_tree
*my_tree
;
12496 proto_item
*ti
= proto_tree_add_item(tree
, item
, tvb
, offset
, -1, ENC_NA
);
12497 my_tree
= proto_item_add_subtree(ti
, ett
);
12498 block_length
= dof_dissect_pdu(dissector
, start
, pinfo
, my_tree
, result
);
12499 return offset
+ block_length
;
12502 static int dof_dissect_pdu(dissector_t dissector
, tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *result
)
12504 int len
= dissector(tvb
, pinfo
, tree
, result
);
12505 proto_item_set_len(proto_tree_get_parent(tree
), len
);
12510 static int dof_dissect_dnp_length(tvbuff_t
*tvb
, packet_info
*pinfo
, uint8_t version
, int *offset
)
12512 dissector_handle_t dp
;
12514 dp
= dissector_get_uint_handle(dnp_framing_dissectors
, version
);
12518 return call_dissector_only(dp
, tvb
, pinfo
, NULL
, offset
);
12522 * Editor modelines - https://www.wireshark.org/tools/modelines.html
12525 * c-basic-offset: 4
12527 * indent-tabs-mode: nil
12530 * vi: set shiftwidth=4 tabstop=8 expandtab:
12531 * :indentSize=4:tabSize=8:noTabs=true: