Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-dof.c
blobd48ff616b35903fa0e6cb542d48c0a7c74c4558e
1 /* packet-dof.c
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
13 /* INTRODUCTION
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
29 * here:
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:
39 * CCM - Chained mode
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)
80 /* DISSECTOR DESIGN
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
92 * structure.
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
116 * used.
119 /* SESSIONS
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.
133 * The levels are:
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.
162 * MEMBERSHIP
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
166 * from:
167 * 1. The sender.
168 * 2. The receiver (if directed to a receiver).
169 * 3. The session.
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
172 * the sender.
174 * In order to make lookups easier, each unique sender in the system is
175 * assigned a unique identifier.
178 #include <config.h>
180 #include <ctype.h>
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
205 * information.
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
229 unsigned op_sid_id;
230 dof_2009_1_pdu_19_sid op_sid;
231 unsigned op_cnt;
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).
248 int transport_id;
251 * For new sessions, this is left zero. The DPS dissector will
252 * set this value.
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.
299 unsigned sender_id;
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.
314 uint32_t i_valid;
317 * The frame at which this becomes valid for responder packets.
319 uint32_t r_valid;
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
336 * dissector.
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
365 uint8_t *domain;
366 uint8_t domain_length;
367 uint8_t *identity;
368 uint8_t identity_length;
369 uint8_t *kek;
370 } dof_group_data;
373 * This structure contains security keys for non-group identities.
375 typedef struct _dof_identity_data
377 uint8_t *domain;
378 uint8_t domain_length;
379 uint8_t *identity;
380 uint8_t identity_length;
381 uint8_t *secret;
382 } dof_identity_data;
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
389 * DPS.
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; */
408 } dof_security_data;
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
416 uint32_t epoch;
417 uint8_t *kek;
418 unsigned mode_length;
419 uint8_t *mode;
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;
431 uint8_t *domain;
432 uint8_t group_length;
433 uint8_t *group;
434 uint32_t ssid;
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.
459 uint32_t ssid;
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.
471 uint8_t *domain;
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;
489 bool is_2_node;
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.
510 uint32_t session_id;
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.
517 uint8_t dof_id;
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.
529 GSList *data_list;
530 } dof_session_data;
532 /* DOF Security Structures. */
533 /* Return structures for different packets. */
535 typedef struct _dof_2008_16_security_3_1
537 tvbuff_t *identity;
538 } dof_2008_16_security_3_1;
540 typedef struct _dof_2008_16_security_4
542 tvbuff_t *identity;
543 tvbuff_t *nonce;
544 } dof_2008_16_security_4;
546 typedef struct _dof_2008_16_security_6_1
548 tvbuff_t *i_identity;
549 tvbuff_t *i_nonce;
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;
558 tvbuff_t *r_nonce;
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
568 address addr;
569 uint32_t port;
570 } ws_node;
572 typedef struct _dof_session_list
574 dof_session_data *session;
575 struct _dof_session_list *next;
576 } dof_session_list;
579 * DOF PACKET DATA
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.
600 uint32_t frame;
603 * The DPS frame/packet. This number is unique in the entire trace.
605 uint32_t dof_frame;
608 * Packet linked list for all dps packets.
610 struct _dof_packet_data *next;
613 * DPS FIELDS
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.
618 bool processed;
621 * SUMMARY: An operation summary, displayed in the Operation History. This is seasonal
622 * data, managed by the DPP dissector.
624 const char *summary;
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
629 * unique sender.
631 int sender_id;
632 int receiver_id;
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
643 * dissector.
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.
657 bool has_opid;
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
683 * for this packet.
685 void *opid_data;
686 } dof_packet_data;
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;
703 } dof_globals;
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;
736 } dof_api_data;
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
748 INITIALIZE,
749 HEADER,
750 TRAILER
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.
760 uint8_t version;
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);
834 #endif
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"
843 * PORTS
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;
889 /***** TUNNEL *****/
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;
912 /* DNP V0 */
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;
918 /* DNP V1 */
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,
936 NULL
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;
961 /* DPP V0 */
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 */
968 /* DPP V2 */
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]" },
1017 { 0, NULL }
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)" },
1055 { 0, NULL }
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" },
1082 { 255, "General" },
1083 { 0, NULL }
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" },
1116 { 0, NULL }
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" },
1126 { 0, NULL }
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)" },
1132 { 0, NULL }
1134 #endif
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;
1174 #endif
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;
1187 #endif
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,
1213 NULL
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)" },
1288 { 0, NULL }
1291 typedef struct _alias_key
1293 uint32_t session;
1294 uint32_t sender;
1295 uint32_t alias;
1296 } oap_1_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)
1310 return 0;
1312 if (key1->sender != key2->sender)
1313 return 0;
1315 if (key1->alias != key2->alias)
1316 return 0;
1318 return 1;
1321 typedef struct
1323 uint8_t *oid;
1324 uint16_t oid_length;
1325 uint8_t *iid;
1326 uint16_t iid_length;
1327 uint32_t frame;
1328 } oap_1_binding;
1330 typedef struct oap_1_binding_list
1332 oap_1_binding *binding;
1333 struct oap_1_binding_list *next;
1334 } oap_1_binding_list;
1336 typedef struct
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;
1346 proto_item *ti;
1347 proto_tree *options_tree;
1349 if (alias_length == 0)
1350 /* TODO: Output error. */
1351 return offset;
1353 if (session == NULL)
1354 /* TODO: Output error. */
1355 return offset;
1357 ti = proto_tree_add_item(tree, hf_oap_1_alias, tvb, offset, alias_length, ENC_BIG_ENDIAN);
1359 if (resolve)
1361 oap_1_binding *binding = NULL;
1362 oap_1_alias_key key;
1363 int i;
1364 uint32_t alias;
1366 alias = 0;
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;
1372 key.alias = alias;
1373 binding = oap_1_resolve_alias(&key);
1375 if (binding)
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",
1390 binding->frame);
1394 return offset + alias_length;
1397 static int oap_1_tree_add_interface(proto_tree *tree, tvbuff_t *tvb, int offset)
1399 uint8_t registry;
1400 uint8_t len;
1402 registry = tvb_get_uint8(tvb, offset);
1403 len = registry & 0x03;
1404 if (len == 0)
1405 len = 16;
1406 else
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)
1415 uint8_t len;
1416 /* uint8_t cl; */
1418 len = tvb_get_uint8(tvb, offset);
1419 len = len & 0x03;
1420 if (len == 0)
1421 len = 16;
1422 else
1423 len = 1 << (len - 1);
1425 proto_tree_add_item(tree, hf_oap_1_interfaceid, tvb, offset, 1 + len, ENC_NA);
1426 offset += 1 + len;
1428 #if 0 /* this seems to be dead code - check! */
1429 cl = tvb_get_uint8(tvb, offset);
1430 if (cl & 0x80)
1431 len = tvb_get_uint8(tvb, offset + 2);
1432 else
1433 len = tvb_get_uint8(tvb, offset + 1);
1434 #endif
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);
1438 return offset;
1441 static int oap_1_tree_add_cmdcontrol(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset)
1443 proto_item *ti;
1444 proto_tree *opinfo_tree;
1445 uint8_t flags;
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);
1459 offset += 1;
1461 if (flags & 0x01)
1463 /* Heuristic */
1464 int heur_len;
1465 uint16_t heur;
1466 proto_item *pi;
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);
1471 offset += heur_len;
1474 if (flags & 0x04)
1476 /* Ack List */
1477 uint8_t ackcnt;
1478 uint8_t i;
1480 ackcnt = tvb_get_uint8(tvb, offset);
1481 proto_tree_add_item(opinfo_tree, hf_oap_1_cmdcontrol_ackcnt, tvb, offset, 1, ENC_NA);
1482 offset += 1;
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);
1491 if (flags & 0x40)
1493 /* Cache Delay */
1494 int cache_len;
1495 uint16_t cache;
1496 proto_item *pi;
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;
1504 return offset;
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
1514 * order.
1516 * NOTE: The alias is passed as a structure pointer, and must be reallocated if it is stored in
1517 * the hash.
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;
1525 uint32_t sender_id;
1526 oap_1_alias_key key;
1528 if (!session)
1529 return;
1531 session_id = session->session_id;
1532 sender_id = packet->sender_id;
1534 if (!binding)
1535 return;
1537 key.session = session_id;
1538 key.sender = sender_id;
1539 key.alias = alias;
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" };
1581 /* TEP.2.1 */
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;
1588 /* TEP.2.2 */
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;
1599 /* TEP.2.2.1 */
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;
1608 static int ett_tep;
1610 #if 0 /* not used yet */
1611 static const value_string tep_filter_existing[] = {
1612 { 1, "Include Existing Matches" },
1613 { 0, "Exclude Existing Matches" },
1614 { 0, NULL }
1616 #endif
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" },
1642 { 0, NULL }
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" },
1651 { 0, NULL }
1653 #endif
1655 /* Initialized to zero. */
1656 typedef struct tep_rekey_data
1658 /* Stored from the K bit of the Request PDU. */
1659 bool is_rekey;
1661 /* Stored from the key request for non-secure rekeys. Otherwise 0 and NULL. */
1662 uint8_t domain_length;
1663 uint8_t *domain;
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. */
1670 uint8_t *i_nonce;
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. */
1678 uint8_t *r_nonce;
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;
1687 } tep_rekey_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
1694 uint8_t *domain;
1695 uint8_t domain_length;
1696 uint8_t *identity;
1697 uint8_t identity_length;
1698 uint8_t *group;
1699 uint8_t group_length;
1700 uint8_t *block_I;
1701 uint16_t block_I_length;
1702 uint8_t *secret;
1703 bool kek_known;
1704 } trp_packet_data;
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;
1722 static int hf_thb;
1723 static int hf_tmin;
1724 static int hf_tmax;
1725 static int hf_trp_epoch;
1726 static int hf_sidg;
1727 static int hf_security_scope;
1728 static int hf_security_mode;
1729 static int hf_ssid;
1730 #if 0 /* not used yet */
1731 static int hf_initiator_pg;
1732 #endif
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;
1761 #endif
1763 static int ett_trp_dsp;
1764 static int ett_trp;
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" },
1839 { 0, NULL }
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" },
1848 { 6, "High Load" },
1849 { 7, "Bad Mode" },
1850 { 8, "Incompatible Security Identifiers" },
1851 { 127, "Internal Error" },
1853 { 0, NULL }
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;
1861 uint8_t *domain;
1863 uint8_t group_length;
1864 uint8_t *group;
1866 uint16_t epoch;
1867 uint8_t *kek;
1869 unsigned I_length;
1870 uint8_t *I;
1871 unsigned A_length;
1872 uint8_t *A;
1874 dof_session_data *request_session;
1875 } sgmp_packet_data;
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;
1891 static int hf_key;
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)" },
1928 { 0, NULL }
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)
1935 gcry_mac_hd_t hmac;
1936 gcry_error_t result;
1938 result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL);
1939 if (result != 0)
1940 return false;
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));
1947 return result == 0;
1949 #endif
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[] = {
1973 { 1, "256-bit" },
1974 { 2, "192-bit" },
1975 { 3, "128-bit" },
1976 { 0, NULL }
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;
1997 static int ett_ccm;
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. */
2007 uint32_t period;
2008 /* Mapping from wire period to absolute periods. */
2009 uint8_t periods[8];
2010 uint8_t cipher;
2011 bool encrypted;
2012 uint8_t mac_len;
2013 uint32_t client_datagram_number;
2014 uint32_t server_datagram_number;
2015 } ccm_session_data;
2017 typedef struct _ccm_packet_data
2019 uint32_t nid;
2020 uint32_t dn;
2021 uint32_t period;
2022 } ccm_packet_data;
2024 #define CCM_PDU_PROBE (0)
2026 static const value_string ccm_opcode_strings[] = {
2027 { CCM_PDU_PROBE, "Probe" },
2028 { 0, NULL }
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;
2051 static int ett_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;
2058 * EXPERT INFOS
2059 * Expert infos are related to either a PDU type or a specification, and so
2060 * they are listed separately.
2062 #if 0
2063 static expert_field ei_undecoded;
2064 #endif
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;
2070 #if 0
2071 static expert_field ei_dof_13_length_specified;
2072 #endif
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
2112 int transport_id;
2113 int transport_node_id;
2114 int dof_id;
2115 int dof_node_id;
2116 int dof_session_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));
2130 return result;
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;
2138 uint16_t i;
2140 for (i = 0; i <= str[0]; i++)
2141 hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
2143 return hash;
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)
2152 return FALSE;
2154 if (sid_key_ptr1->transport_node_id != sid_key_ptr2->transport_node_id)
2155 return FALSE;
2157 if (sid_key_ptr1->dof_id != sid_key_ptr2->dof_id)
2158 return FALSE;
2160 if (sid_key_ptr1->dof_node_id != sid_key_ptr2->dof_node_id)
2161 return FALSE;
2163 if (sid_key_ptr1->dof_session_id != sid_key_ptr2->dof_session_id)
2164 return FALSE;
2166 return TRUE;
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])
2175 return FALSE;
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
2185 * if needed.
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
2220 * may change).
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)
2238 return FALSE;
2239 if (ptr1->op_sid_id != ptr2->op_sid_id)
2240 return FALSE;
2242 return TRUE;
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;
2269 unsigned client;
2270 unsigned server;
2271 bool is_secure;
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);
2285 if (value)
2287 /* We found a match. */
2288 return value;
2291 return NULL;
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 */
2310 /* Security.1 */
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[] = {
2316 { 1, "Binding" },
2317 { 3, "IAM" },
2318 { 5, "ACTAS" },
2319 { 128, "Requestor" },
2320 { 130, "Provider" },
2321 { 131, "Define" },
2322 { 133, "Tunnel Domain" },
2323 { 0, NULL }
2326 /* Security.2 */
2327 static int hf_security_2_count;
2328 static int ett_security_2_permission;
2329 static int hf_security_2_permission;
2331 /* Security.3.1 */
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;
2337 /* Security.3.2 */
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;
2343 /* Security.4 */
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;
2353 /* Security.5 */
2354 static int hf_security_5_mac;
2355 static int hf_security_5_key;
2357 /* Security.6.1 */
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;
2364 /* Security.6.2 */
2365 static int ett_security_6_2_responder_request;
2366 static int hf_security_6_2_responder_request;
2368 /* Security.6.3 */
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;
2377 /* Security.9 */
2378 static int hf_security_9_length;
2379 static int hf_security_9_initial_state;
2381 /* Security.10 */
2382 static int hf_security_10_count;
2383 static int hf_security_10_permission_group_identifier;
2385 /* Security.11 */
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;
2390 /* Security.12 */
2391 static int hf_security_12_m;
2393 static const value_string dof_2008_16_security_12_m[] = {
2394 { 0, "Reference" },
2395 { 1, "Relative" },
2396 { 2, "Absolute" },
2397 { 3, "Continued" },
2398 { 0, NULL }
2401 static int hf_security_12_count;
2402 static int hf_security_12_permission_group_identifier;
2404 static bool
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 */
2413 return false;
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);
2437 if (option_length)
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_)
2454 int offset = 0;
2455 bool has_length;
2456 uint16_t length;
2458 /* Permission Type */
2460 int start = offset;
2461 uint16_t value;
2462 int val_len;
2463 proto_item *pi;
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);
2470 if (!has_length)
2471 return offset;
2473 /* Length */
2475 int start = offset;
2476 uint16_t value;
2477 int value_len;
2478 proto_item *pi;
2479 offset = read_c2(tvb, offset, &value, &value_len);
2480 length = value;
2481 pi = proto_tree_add_uint(tree, hf_security_1_length, tvb, start, offset - start, value);
2482 validate_c2(pinfo, pi, value, value_len);
2485 /* Data */
2486 proto_tree_add_item(tree, hf_security_1_data, tvb, offset, length, ENC_NA);
2487 offset += length;
2489 return offset;
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_)
2497 int offset = 0;
2498 uint16_t count;
2500 /* Count */
2502 int start = offset;
2503 uint16_t value;
2504 int length;
2505 proto_item *pi;
2506 offset = read_c2(tvb, offset, &value, &length);
2507 count = value;
2508 pi = proto_tree_add_uint(tree, hf_security_2_count, tvb, start, offset - start, value);
2509 validate_c2(pinfo, pi, value, length);
2512 while (count--)
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);
2519 offset += len;
2522 return offset;
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)
2531 int offset = 0;
2532 uint8_t stage;
2533 proto_item *ti;
2534 dof_2008_16_security_3_1 *return_data = (dof_2008_16_security_3_1 *)data;
2536 /* Credential Type */
2538 int start = offset;
2539 uint16_t value;
2540 int length;
2541 proto_item *pi;
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);
2547 /* Stage */
2548 stage = tvb_get_uint8(tvb, offset);
2549 ti = proto_tree_add_item(tree, hf_security_3_1_stage, tvb, offset, 1, ENC_NA);
2550 offset += 1;
2552 if (stage != 0)
2553 expert_add_info(pinfo, ti, &ei_security_3_1_invalid_stage);
2555 /* Security Node Identifier */
2557 int block_length;
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);
2566 if (return_data)
2567 return_data->identity = start;
2570 return offset;
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_)
2578 int offset = 0;
2579 uint16_t length;
2581 /* Credential Type */
2583 int start = offset;
2584 uint16_t value;
2585 int val_len;
2586 proto_item *pi;
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);
2592 /* Stage */
2593 proto_tree_add_item(tree, hf_security_3_2_stage, tvb, offset, 1, ENC_NA);
2594 offset += 1;
2596 /* Length */
2598 int start = offset;
2599 uint16_t value;
2600 int value_len;
2601 proto_item *pi;
2602 offset = read_c2(tvb, offset, &value, &value_len);
2603 length = value;
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);
2608 /* Public Data */
2609 proto_tree_add_item(tree, hf_security_3_2_public_data, tvb, offset, length, ENC_NA);
2610 offset += length;
2612 return offset;
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)
2620 int offset = 0;
2621 uint8_t flag;
2622 dof_2008_16_security_4 *return_data = (dof_2008_16_security_4 *)data;
2624 flag = tvb_get_uint8(tvb, offset);
2625 if (flag & 0x30)
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);
2631 offset += 1;
2634 int block_length;
2635 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2636 proto_item *ti;
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;
2646 if (return_data)
2648 return_data->identity = return_3_1.identity;
2653 tvbuff_t *start = tvb_new_subset_length(tvb, offset, (flag & 0x0F) + 1);
2654 if (return_data)
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;
2662 int block_length;
2663 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2664 proto_item *ti;
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;
2674 return offset;
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_)
2682 int offset = 0;
2684 proto_tree_add_item(tree, hf_security_5_mac, tvb, offset, 32, ENC_NA);
2685 offset += 32;
2687 proto_tree_add_item(tree, hf_security_5_key, tvb, offset, 32, ENC_NA);
2688 offset += 32;
2690 return offset;
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)
2699 int offset = 0;
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);
2706 offset += 1;
2708 /* Desired Security Mode */
2710 int block_length;
2711 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2712 proto_item *ti;
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);
2723 if (return_data)
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 */
2733 int block_length;
2734 dof_2008_16_security_4 output;
2735 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2736 proto_item *ti;
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;
2745 if (return_data)
2747 return_data->i_identity = output.identity;
2748 return_data->i_nonce = output.nonce;
2752 return offset;
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)
2761 int offset = 0;
2762 dof_2008_16_security_6_2 *return_data = (dof_2008_16_security_6_2 *)data;
2764 /* Responder Request */
2766 int block_length;
2767 dof_2008_16_security_4 output;
2768 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2769 proto_item *ti;
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;
2778 if (return_data)
2780 return_data->r_identity = output.identity;
2781 return_data->r_nonce = output.nonce;
2785 return offset;
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_)
2793 int offset = 0;
2795 /* Granted Duration */
2796 proto_tree_add_item(tree, hf_security_6_3_granted_duration, tvb, offset, 1, ENC_NA);
2797 offset += 1;
2799 /* Session Security Scope */
2801 int block_length;
2802 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2803 proto_item *ti;
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 */
2815 int block_length;
2816 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2817 proto_item *ti;
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 */
2829 int block_length;
2830 tvbuff_t *start = tvb_new_subset_remaining(tvb, offset);
2831 proto_item *ti;
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;
2841 return offset;
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. */
2850 int block_length;
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. */
2863 int block_length;
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_)
2877 int offset = 0;
2878 uint16_t length;
2880 /* Length */
2882 int start = offset;
2883 uint16_t value;
2884 int value_len;
2885 proto_item *pi;
2886 offset = read_c2(tvb, offset, &value, &value_len);
2887 length = value;
2888 pi = proto_tree_add_uint(tree, hf_security_9_length, tvb, start, offset - start, value);
2889 validate_c2(pinfo, pi, value, value_len);
2892 if (length > 0)
2894 proto_tree_add_item(tree, hf_security_9_initial_state, tvb, offset, length, ENC_NA);
2895 offset += length;
2898 return offset;
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_)
2906 int offset = 0;
2907 uint16_t count;
2909 /* Count */
2911 int start = offset;
2912 uint16_t value;
2913 int length;
2914 proto_item *pi;
2915 offset = read_c2(tvb, offset, &value, &length);
2916 count = value;
2917 pi = proto_tree_add_uint(tree, hf_security_10_count, tvb, start, offset - start, value);
2918 validate_c2(pinfo, pi, value, length);
2921 while (count--)
2923 const char *def = "";
2925 int start = offset;
2926 uint32_t value;
2927 int length;
2928 proto_item *pi;
2930 offset = read_c4(tvb, offset, &value, &length);
2932 switch (value)
2934 case 0x3FFFFFFF:
2935 def = " (all scopes)";
2936 break;
2937 case 0x3FFFFFFE:
2938 def = " (doesn't mask)";
2939 break;
2940 case 0x3FFFFFFD:
2941 def = " (session scope)";
2942 break;
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);
2949 return offset;
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_)
2957 int offset = 0;
2958 uint16_t count;
2960 /* Count */
2962 int start = offset;
2963 uint16_t value;
2964 int length;
2965 proto_item *pi;
2966 offset = read_c2(tvb, offset, &value, &length);
2967 count = value;
2968 pi = proto_tree_add_uint(tree, hf_security_11_count, tvb, start, offset - start, value);
2969 validate_c2(pinfo, pi, value, length);
2972 while (count--)
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);
2977 int len;
2978 len = dissect_2008_16_security_12(next_tvb, pinfo, subtree, NULL);
2979 proto_item_set_len(ti, len);
2980 offset += len;
2983 return offset;
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_)
2991 int offset = 0;
2992 uint8_t m = tvb_get_uint8(tvb, offset) >> 6;
2993 uint16_t count = tvb_get_uint8(tvb, offset) & 0x3F;
2994 proto_item *pi;
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);
2998 offset += 1;
3000 if (m == 0)
3001 return offset;
3003 while (count--)
3005 const char *def = "";
3007 int start = offset;
3008 uint32_t value;
3009 int length;
3010 offset = read_c4(tvb, offset, &value, &length);
3012 switch (value)
3014 case 0x3FFFFFFF:
3015 def = " (all scopes)";
3016 break;
3017 case 0x3FFFFFFE:
3018 def = " (doesn't mask)";
3019 break;
3020 case 0x3FFFFFFD:
3021 def = " (session scope)";
3022 break;
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);
3029 return offset;
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. */
3038 int block_length;
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
3054 * the OID,
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
3060 * be.
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_)
3067 proto_item *ti;
3068 int start_offset = 0;
3069 int offset = 0;
3070 uint32_t oid_class;
3071 int oid_class_len;
3072 uint8_t oid_len_byte;
3073 proto_tree *oid_tree = tree;
3074 proto_tree *header_tree;
3076 if (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);
3093 offset += 1;
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. */
3113 uint8_t flag;
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);
3133 if (tree)
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" ); */
3141 return offset;
3145 * Dissects a buffer that is pointing at an attribute.
3146 * Adds a subtree with detailed information about the fields of
3147 * the attribute,
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
3151 * attribute.
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
3154 * be.
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)
3161 proto_item *ti;
3162 int offset = 0;
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);
3175 offset += 1;
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);
3179 offset += 1;
3181 switch (attribute_id_byte & 0x7F)
3183 case 1:
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;
3187 break;
3189 case 0:
3190 case 2:
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);
3201 break;
3203 default:
3204 proto_tree_add_item(oid_tree, hf_oid_attribute_data, tvb, offset, attribute_length_byte, ENC_NA);
3205 offset += attribute_length_byte;
3208 return offset;
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 {
3233 char *domain;
3234 char *identity;
3235 char *kek;
3236 } 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 {
3243 char *key;
3244 } seckey_field_t;
3246 /* Structure for secrets (for identities) */
3247 typedef struct _identsecret_field_t {
3248 char *domain;
3249 char *identity;
3250 char *secret;
3251 } identsecret_field_t;
3253 typedef struct _tcp_ignore_data
3255 uint32_t sequence;
3256 bool ignore;
3257 struct _tcp_ignore_data *next;
3258 } tcp_ignore_data;
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
3274 * DPS packets.
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;
3284 } tcp_packet_data;
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
3296 * addresses.
3298 ws_node server;
3299 } udp_session_data;
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.
3314 bool not_dps;
3316 /* For the associated TCP conversation, this tracks the client and server
3317 * addresses.
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;
3327 } tcp_session_data;
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;
3354 uint32_t size;
3356 *err = NULL;
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].");
3362 return false;
3364 else if (!count_hex_bytes(rec->domain))
3366 *err = g_strdup("Invalid domain [must be valid OID].");
3367 return false;
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].");
3374 return false;
3376 else if (!count_hex_bytes(rec->identity))
3378 *err = g_strdup("Invalid identity [must be valid OID].");
3379 return false;
3382 if (count_hex_bytes(rec->kek) != 32)
3384 *err = g_strdup("Invalid KEK [must be 32 byte key].");
3385 return false;
3387 return true;
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);
3399 return new_rec;
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);
3408 g_free(rec->kek);
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;
3423 *err = NULL;
3424 if (count_hex_bytes(rec->key) != 32)
3426 *err = g_strdup("Invalid secret [must be 32 bytes].");
3427 return false;
3429 return true;
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);
3439 return new_rec;
3442 static void seckey_list_free_cb(void *r)
3444 seckey_field_t *rec = (seckey_field_t *)r;
3446 g_free(rec->key);
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;
3462 uint32_t size;
3464 *err = NULL;
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].");
3472 return false;
3475 else if (!count_hex_bytes(rec->domain))
3477 *err = g_strdup("Invalid domain [must be valid OID].");
3478 return false;
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].");
3487 return false;
3490 else if (!count_hex_bytes(rec->identity))
3492 *err = g_strdup("Invalid identity [must be valid OID].");
3493 return false;
3496 if (count_hex_bytes(rec->secret) != 32)
3498 *err = g_strdup("Invalid secret [must be 32 byte key].");
3499 return false;
3501 return true;
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);
3513 return new_rec;
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
3535 address addr;
3536 uint16_t port;
3537 } 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;
3552 uint8_t i;
3554 for (i = 0; i < addr_key->addr.len; i++)
3555 hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + c */
3557 result += hash;
3560 return result;
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)
3569 return FALSE;
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);
3578 g_free(addr_port);
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;
3614 addr_port_key *key;
3615 unsigned value;
3617 /* ensure the address contains actual data */
3618 if (addr->type == AT_NONE)
3619 return 0;
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));
3627 if (value)
3629 /* We found a match. */
3630 return value;
3633 /* No match, need to add a key. */
3634 key = g_new0(addr_port_key, 1);
3635 copy_address(&key->addr, addr);
3636 key->port = port;
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_)
3647 #if 0
3648 char** protos;
3649 char* line = ep_strndup(p, len);
3650 unsigned num_protos, i;
3652 g_strstrip(line);
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]);
3660 if (!num_protos)
3662 *err = g_strdup("No protocols given");
3663 return false;
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]);
3671 return false;
3674 #endif
3675 return true;
3678 /* Utility Methods */
3680 static uint8_t count_hex_bytes(char *str)
3682 uint8_t total = 0;
3684 while (str != NULL && *str != '\0' && *str != '#')
3686 if (!g_ascii_isxdigit(*str))
3688 str += 1;
3689 continue;
3692 if (!g_ascii_isxdigit(str[1]))
3693 return 0;
3695 total += 1;
3696 str += 2;
3699 return total;
3702 static void parse_hex_string(char *str, uint8_t **ptr, uint8_t *len)
3704 uint8_t j = 0;
3705 *len = count_hex_bytes(str);
3706 *ptr = (uint8_t *)g_malloc0(*len);
3708 while (j < *len)
3710 int high, low;
3712 if (!g_ascii_isxdigit(*str))
3714 str += 1;
3715 continue;
3718 high = ws_xton(str[0]);
3719 low = ws_xton(str[1]);
3720 (*ptr)[j++] = (high << 4) | low;
3721 str += 2;
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
3774 uint32_t refCount;
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! */
3777 } DOFObjectID_t;
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)
3800 uint32_t value = 0;
3801 uint8_t used = 0;
3802 uint8_t size = maxSize;
3803 uint8_t mask;
3805 switch (buffer[0] >> 6)
3807 case 0x02:
3808 /* Two Bytes */
3809 if (maxSize > 2)
3810 mask = 0x3F;
3811 else
3812 mask = 0x7F;
3813 size = 2;
3814 break;
3816 case 0x03:
3817 /* Three/Four Bytes */
3818 if (maxSize > 2)
3819 mask = 0x3F;
3820 else
3821 mask = 0x7F;
3822 break;
3824 default:
3825 /* One Byte */
3826 size = 1;
3827 mask = 0x7F;
3828 break;
3831 /* Sanity check */
3832 if (size > *bufLength)
3833 return 0;
3835 value = buffer[used++] & mask;
3836 while (used < size)
3837 value = (value << 8) | buffer[used++];
3839 *bufLength = used;
3840 return (value);
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);
3849 return size;
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]))
3865 nonprintable++;
3866 else if (IS_ESCAPED(data[i]))
3867 escaped++;
3869 if (nonprintable == 0)
3871 /* Printable, so copy as a string, escaping where necessary. */
3872 if (pBuf)
3874 for (i = 0; i < dataSize; i++)
3876 if (IS_ESCAPED(data[i]))
3878 pBuf[len++] = '\\';
3879 pBuf[len++] = data[i];
3881 else
3882 pBuf[len++] = data[i];
3885 else
3887 len = dataSize + escaped; /* Count escaped characters twice. */
3890 else
3892 /* Non-printable, so format as hex string. */
3893 if (pBuf)
3895 pBuf[len++] = '{';
3896 for (i = 0; i < dataSize; i++)
3898 pBuf[len++] = OALString_HexDigitToChar((data[i] >> 4) & 0x0F);
3899 pBuf[len++] = OALString_HexDigitToChar((data[i]) & 0x0F);
3901 pBuf[len++] = '}';
3903 else
3905 len = dataSize * 2 + 2;
3908 return len;
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. */
3916 return NULL;
3919 static uint32_t DOFObjectID_GetIDClass(const DOFObjectID self)
3921 uint32_t size = 4;
3923 return OALMarshal_UncompressValue(DOFOBJECTID_MAX_CLASS_SIZE, &size, self->oid);
3926 static bool DOFObjectID_HasAttributes(const DOFObjectID self)
3928 if (!self)
3929 return false;
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)
3942 uint8_t retVal = 0;
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);
3949 ++retVal;
3950 while (*pNextAttribute & 0x80) /* bit 7: next attribute present flag. */
3952 ++retVal;
3953 pNextAttribute += (2 + *((const uint8_t *)pNextAttribute + 1)); /* 2: attribute marshalling overhead. */
3957 return retVal;
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))
3969 uint8_t count = 0;
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. */
4013 if (1)
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))
4027 bool hasAttr;
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))
4032 goto notvalid;
4033 computedSize += dataLen;
4034 hasAttr = lenByte & 0x80; /* Valid OID base; check attributes. */
4035 while (hasAttr)
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]);
4043 else
4044 goto notvalid;
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;
4053 if (newObjID)
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*/
4061 goto allocErrorOut;
4067 notvalid:
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. */
4070 allocErrorOut :
4071 *length = 0;
4073 return NULL;
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);
4081 if (rval)
4083 if (len != bufferSize)
4085 DOFObjectID_Destroy(rval);
4086 rval = NULL;
4089 return rval;
4092 // NOLINTNEXTLINE(misc-no-recursion)
4093 static uint32_t ObjectID_ToStringLength(const DOFObjectID oid, packet_info *pinfo)
4095 uint32_t len = 0;
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. */
4122 if (i)
4123 len++;
4124 len += 5; /* {xx}: */
4125 /* Handle embedded Object IDs. */
4126 embedOID = DOFObjectID_Create_Bytes(DOFObjectIDAttribute_GetValueSize(avpDescriptor),
4127 DOFObjectIDAttribute_GetValue(avpDescriptor));
4128 if (embedOID)
4130 len += ObjectID_ToStringLength(embedOID, pinfo); /* Recurse to compute string rep length of found OID. */
4131 DOFObjectID_Destroy(embedOID);
4133 else
4135 /* Hex Data. */
4136 len += ObjectID_DataToStringLength(DOFObjectIDAttribute_GetValue(avpDescriptor),
4137 DOFObjectIDAttribute_GetValueSize(avpDescriptor));
4139 } /* end for(). */
4141 decrement_dissection_depth(pinfo);
4143 return len;
4146 static uint32_t InterfaceID_ToString(const uint8_t *iid, char *pBuf)
4148 uint32_t len = 0;
4149 unsigned iid_len = iid[0] & 0x03;
4150 unsigned i;
4152 if (iid_len == 3)
4153 iid_len = 4;
4155 pBuf[len++] = '[';
4156 pBuf[len++] = '{';
4158 pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 6) & 0x0F);
4159 pBuf[len++] = OALString_HexDigitToChar((iid[0] >> 2) & 0x0F);
4161 pBuf[len++] = '}';
4162 pBuf[len++] = ':';
4163 pBuf[len++] = '{';
4165 /* Data */
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);
4172 pBuf[len++] = '}';
4173 pBuf[len++] = ']';
4175 return len;
4178 // NOLINTNEXTLINE(misc-no-recursion)
4179 static uint32_t ObjectID_ToString(const DOFObjectID oid, char *pBuf, packet_info *pinfo)
4181 DOFObjectIDClass oidClass;
4182 uint32_t len = 0;
4184 pBuf[len++] = '[';
4185 pBuf[len++] = '{';
4186 /* Class */
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);
4205 pBuf[len++] = '}';
4206 pBuf[len++] = ':';
4207 /* Data */
4208 len += ObjectID_DataToString(DOFObjectID_GetData(oid), DOFObjectID_GetDataSize(oid), &pBuf[len]);
4209 /* Handle Attributes, if any. */
4210 if (DOFObjectID_HasAttributes(oid))
4212 uint8_t i;
4213 uint8_t attributeCount = DOFObjectID_GetAttributeCount(oid);
4215 pBuf[len++] = '(';
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. */
4224 if (i)
4225 pBuf[len++] = '|';
4226 pBuf[len++] = '{';
4227 pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor) >> 4) & 0x0F);
4228 pBuf[len++] = OALString_HexDigitToChar((DOFObjectIDAttribute_GetType(avpDescriptor)) & 0x0F);
4229 pBuf[len++] = '}';
4230 pBuf[len++] = ':';
4232 /* Handle embedded Object IDs. */
4233 embedOID = DOFObjectID_Create_Bytes(DOFObjectIDAttribute_GetValueSize(avpDescriptor),
4234 DOFObjectIDAttribute_GetValue(avpDescriptor));
4235 if (embedOID)
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);
4242 else
4244 /* Hex Data. */
4245 len += ObjectID_DataToString(DOFObjectIDAttribute_GetValue(avpDescriptor),
4246 DOFObjectIDAttribute_GetValueSize(avpDescriptor), &pBuf[len]);
4248 } /* end for(). */
4249 pBuf[len++] = ')';
4251 pBuf[len++] = ']';
4253 return len;
4256 static const char* dof_iid_create_standard_string(uint32_t bufferSize, const uint8_t *pIIDBuffer)
4258 char *pRetval;
4259 unsigned len = 9 + (bufferSize - 1) * 2; /* Alias is always [{AA}:{01234567}] */
4261 pRetval = (char *)wmem_alloc(wmem_packet_scope(), len + 1);
4262 if (pRetval)
4264 InterfaceID_ToString(pIIDBuffer, pRetval);
4265 pRetval[len] = 0;
4268 return pRetval;
4271 static const char* dof_oid_create_standard_string(uint32_t bufferSize, const uint8_t *pOIDBuffer, packet_info *pinfo)
4273 DOFObjectID oid;
4274 char *pRetval;
4275 uint32_t len = bufferSize;
4277 oid = DOFObjectID_Create_Unmarshal(&len, pOIDBuffer);
4278 if (!oid)
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);
4284 if (pRetval)
4286 ObjectID_ToString(oid, pRetval, pinfo);
4287 pRetval[len] = 0;
4290 return pRetval;
4293 struct parseCtx
4295 const char *oid;
4296 uint8_t *buffer;
4297 uint32_t buffLen;
4298 uint32_t oidLen;
4299 uint32_t currOidPos;
4300 uint32_t currBufferPos;
4301 unsigned depth;
4302 }parseCtx;
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 */
4356 return 1;
4358 PARSECTX_STEP_OID(ctx, 1);
4361 else
4363 return 1;
4366 else
4368 return 1;
4371 PARSECTX_STEP_OID(ctx, 1);
4372 return 0;
4374 return 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)
4392 return 1;
4393 PARSECTX_WRITE_BUF_FROM_OID(ctx);
4395 else
4397 if (VALIDASCIICHAR(curr) && PARSECTX_CHECK_LEN(ctx, 1) == 0)
4398 PARSECTX_WRITE_BUF_FROM_OID(ctx);
4399 else
4400 return 1;
4403 return 0;
4406 static uint8_t OALMarshal_GetCompressedValueSize(uint8_t maxSize, uint32_t value)
4408 uint8_t lenbytes = (1 + (value > 0x7F) + (value > 0x3FFF));
4409 if (lenbytes > 2)
4410 return (maxSize);
4411 return (lenbytes);
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)
4419 return 0;
4420 switch (lenSize)
4422 case 4:
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);
4427 break;
4429 case 3:
4430 *(buffer++) = (uint8_t)((value >> 16) & 0x3F) | 0xC0;
4431 *(buffer++) = (uint8_t)((value >> 8) & 0xFF);
4432 *(buffer++) = (uint8_t)(value & 0xFF);
4433 break;
4435 case 2:
4436 if (maxSize == 2)
4438 *(buffer++) = (uint8_t)((value >> 8) & 0x7F) | 0x80;
4440 else
4442 *(buffer++) = (uint8_t)((value >> 8) & 0x3F) | 0x80;
4444 *(buffer++) = (uint8_t)(value & 0xFF);
4445 break;
4447 case 1:
4448 *(buffer++) = (uint8_t)(value & 0x7F);
4449 break;
4451 default:
4452 /* Invalid computed size! */
4453 break;
4455 return (lenSize);
4458 static uint8_t parseOIDClass(struct parseCtx *ctx)
4460 if (PARSECTX_PEEK_CHAR_OID(ctx) == '{' && PARSECTX_PEEK_NEXT_CHAR_OID(ctx) != '}')
4462 /* Hex */
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)))
4470 oidClass <<= 8;
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 */
4479 return 1;
4481 PARSECTX_STEP_OID(ctx, 1);
4484 else
4486 return 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);
4500 return 0;
4502 else
4504 /* Number */
4505 uint8_t classSize = 0;
4506 uint32_t oidClass = 0;
4507 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx)))
4509 oidClass *= 10;
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);
4523 return 0;
4527 static uint8_t parseAttributeID(struct parseCtx *ctx)
4529 if (PARSECTX_PEEK_CHAR_OID(ctx) == '{')
4531 return parseHexField(ctx);
4533 else
4535 uint8_t avpid = 0;
4536 while (IS_DIGIT(PARSECTX_PEEK_CHAR_OID(ctx)))
4538 avpid *= 10;
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);
4546 return 0;
4549 return 1;
4552 // NOLINTNEXTLINE(misc-no-recursion)
4553 static uint8_t parseAttributeData(struct parseCtx *ctx)
4555 uint8_t ret;
4556 ctx->depth++;
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);
4566 else
4568 ret = parseStringField(ctx);
4570 ctx->depth--;
4571 return ret;
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);
4583 if (length == NULL)
4584 return 0;
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)));
4591 return 0;
4595 return 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);
4607 if (avpID == NULL)
4608 return 0;
4610 if (parseAttribute(ctx) != 0)
4611 return 1;
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);
4621 return 0;
4623 return 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);
4633 /* Get class id */
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);
4642 /* Get data */
4643 if (PARSECTX_PEEK_CHAR_OID(ctx) == '{')
4645 /* hex data */
4646 if (parseHexField(ctx) != 0)
4647 return 1;
4649 else
4651 /* string data */
4652 if (parseStringField(ctx) != 0)
4653 return 1;
4656 /* Write length */
4657 if (length == NULL)
4658 return 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)
4666 return 1;
4669 /* Ends with ] */
4670 if (PARSECTX_READ_CHAR_OID(ctx) == ']')
4672 return 0;
4677 return 1;
4680 static uint8_t dof_oid_create_internal(const char *oid, uint32_t *size, uint8_t *buffer)
4682 struct parseCtx ctx = {0};
4684 ctx.oid = oid;
4685 ctx.buffer = buffer;
4687 if (oid)
4689 if (size)
4691 ctx.buffLen = (*size);
4692 ctx.oidLen = (uint32_t)strlen(oid);
4693 if (PARSECTX_PEEK_CHAR_OID(&ctx) == '[')
4695 /* Format OID */
4696 if (parseFormatOID(&ctx) == 0)
4698 (*size) = ctx.currBufferPos;
4699 return 0;
4702 else if (PARSECTX_PEEK_CHAR_OID(&ctx) == '{')
4704 /* HEX OID */
4705 if (parseHexField(&ctx) == 0)
4707 (*size) = ctx.currBufferPos;
4708 return 0;
4711 (*size) = 0;
4714 return 1;
4717 static void dof_oid_new_standard_string(const char *data, uint32_t *rsize, uint8_t **oid)
4719 if (data)
4721 uint8_t err;
4722 uint32_t size = 0;
4724 /* Call parseInternal to find out how big the buffer needs to be. */
4725 err = dof_oid_create_internal(data, &size, NULL);
4727 if (err == 0)
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. */
4732 if (*oid)
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);
4737 if (err == 0)
4739 *rsize = size;
4740 return;
4743 g_free(*oid);
4748 *rsize = 0;
4749 *oid = NULL;
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)
4762 uint32_t val = 0;
4763 uint8_t len = 0;
4764 uint8_t b = tvb_get_uint8(tvb, offset++);
4765 int i;
4767 if ((b & 0x80) == 0)
4769 len = 1;
4770 b = b & 0x7F;
4772 else if ((b & 0x40) == 0)
4774 len = 2;
4775 b = b & 0x3F;
4777 else
4779 len = 4;
4780 b = b & 0x3F;
4783 val = b;
4784 for (i = 1; i < len; i++)
4785 val = (val << 8) | tvb_get_uint8(tvb, offset++);
4787 if (L)
4788 *L = len;
4789 if (v)
4790 *v = val;
4791 return 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
4818 * returned.
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)
4824 uint32_t val = 0;
4825 uint8_t len = 0;
4826 uint8_t b = tvb_get_uint8(tvb, offset++);
4827 int i;
4829 if ((b & 0x80) == 0)
4831 len = 1;
4832 b = b & 0x7F;
4834 else if ((b & 0x40) == 0)
4836 len = 2;
4837 b = b & 0x3F;
4839 else
4841 len = 3;
4842 b = b & 0x3F;
4845 val = b;
4846 for (i = 1; i < len; i++)
4847 val = (val << 8) | tvb_get_uint8(tvb, offset++);
4849 if (L)
4850 *L = len;
4851 if (v)
4852 *v = val;
4853 return 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)
4885 uint16_t val = 0;
4886 uint8_t b = tvb_get_uint8(tvb, offset++);
4887 if (b & 0x80)
4889 b = b & 0x7F;
4890 val = (b << 8) | tvb_get_uint8(tvb, offset++);
4891 if (L)
4892 *L = 2;
4894 else
4896 val = b;
4897 if (L)
4898 *L = 1;
4901 if (v)
4902 *v = val;
4903 return 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;
4934 unsigned value;
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)
4939 return;
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));
4956 if (value)
4958 void *sid_id_key = GUINT_TO_POINTER(value);
4959 void *sid_buffer;
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);
4966 if (sid_buffer)
4968 /* We found a match. */
4969 packet->sender_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
4972 else
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));
4995 if (value)
4997 void *sid_id_key = GUINT_TO_POINTER(value);
4998 void *sid_buffer;
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);
5005 if (sid_buffer)
5007 /* We found a match. */
5008 packet->receiver_sid = (dof_2009_1_pdu_19_sid)sid_buffer;
5011 else
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
5028 * cases here:
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];
5038 uint8_t *key;
5039 void *value;
5041 /* Validate input. */
5042 if (!api_data)
5044 /* TODO: Print error. */
5045 return;
5048 if (!api_data->packet)
5050 /* TODO: Print error. */
5051 return;
5054 packet = (dof_packet_data *)api_data->packet;
5055 if (!packet->sender_sid_id)
5056 return;
5058 /* Check for sender SID already known. */
5059 if (packet->sender_sid)
5060 return;
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;
5076 return;
5078 else
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;
5087 while (ptr)
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;
5101 ptr = ptr->next;
5105 return;
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;
5128 while (ptr)
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;
5136 ptr = ptr->next;
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];
5147 uint8_t *key;
5148 void *value;
5150 /* Check for sender SID already known. */
5151 if (opid->op_sid)
5152 return;
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;
5164 opid->op_sid = key;
5165 return;
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)
5188 uint16_t i;
5189 uint16_t cnt;
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);
5195 mac[14] = len >> 8;
5196 mac[15] = len & 0xFF;
5198 gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5200 mac[0] ^= (a_len >> 8);
5201 mac[1] ^= (a_len);
5202 i = 2;
5204 for (cnt = 0; cnt < a_len; cnt++, i++)
5206 if (i % 16 == 0)
5207 gcry_cipher_encrypt(cipher_state, mac, 16, NULL, 0);
5209 mac[i % 16] ^= epp[cnt];
5212 i = 0;
5213 for (cnt = 0; cnt < len; cnt++, i++)
5215 if (i % 16 == 0)
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)
5226 unsigned short i;
5228 unsigned char ctr[16];
5229 unsigned char encrypted_ctr[16];
5230 unsigned char mac[16];
5231 unsigned char computed_mac[16];
5232 unsigned int skip;
5233 uint8_t *ekey;
5235 if (data == NULL || len == 0)
5236 return 0;
5238 /* Check the mac length. */
5239 if (session->mac_len < 4 || session->mac_len > 16)
5240 return 0;
5242 if (pdata->period == 0)
5243 ekey = (uint8_t *)session->cipher_data;
5244 else
5245 ekey = (uint8_t *)g_hash_table_lookup(session->cipher_data_table, GUINT_TO_POINTER(pdata->period));
5247 if (!ekey)
5248 return 0;
5250 /* Determine how many blocks are skipped. */
5251 #if 0 /* seems to be dead code... check this! */
5252 skip = a_len + 2;
5253 skip /= 16;
5254 if ((a_len + 2) % 16)
5255 skip += 1;
5256 #endif
5257 skip = 0;
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). */
5261 ctr[0] = 0x03;
5262 memcpy(ctr + 1, nonce, 11);
5263 ctr[12] = 0;
5264 ctr[13] = 0;
5265 ctr[14] = 0;
5266 ctr[15] = skip; /* Preincremented below. */
5269 for (i = 0; i < len - session->mac_len; i++)
5271 if (i % 16 == 0)
5273 if (ctr[15] == 255)
5274 ctr[14] += 1;
5275 ctr[15] += 1;
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);
5285 ctr[12] = 0;
5286 ctr[13] = 0;
5287 ctr[14] = 0;
5288 ctr[15] = 0;
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))
5298 return 1;
5300 /* Failure */
5301 return 0;
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).
5318 uint16_t app;
5319 int app_len;
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);
5333 else
5335 proto_tree_add_protocol_format(tree, proto_2008_1_app, tvb, 0, app_len,
5336 DOF_APPLICATION_PROTOCOL ", Version: %u", app);
5340 return 0;
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;
5363 proto_item *hi;
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);
5380 offset += 1;
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);
5391 if (!api_data)
5392 return 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);
5406 return offset;
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);
5420 return 0;
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);
5455 else
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;
5472 return offset;
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. */
5497 if (packet == NULL)
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. */
5512 proto_item *ti;
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;
5567 int offset = 0;
5569 offset = 0;
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);
5576 uint8_t opcode;
5577 proto_item *ti;
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);
5590 if (opcode == 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).
5609 uint16_t app;
5610 int app_len;
5613 app = tvb_get_uint8(tvb, 0);
5614 app_len = 1;
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);
5626 else
5628 proto_tree_add_protocol_format(tree, proto_2012_1_tunnel, tvb, 0, app_len,
5629 DOF_APPLICATION_PROTOCOL ", Version: %u", app);
5633 return 0;
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;
5654 else
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;
5663 return packet;
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;
5684 return packet;
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;
5702 else
5704 globals.dof_packet_tail->next = packet;
5705 globals.dof_packet_tail = packet;
5708 return 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
5716 * be set up.
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; */
5730 /* {
5731 uint8_t* addr = (uint8_t*) pinfo->dst.data;
5732 if ( (pinfo->dst.type == AT_IPv4) && (addr != NULL) && (addr[0] != 224) )
5733 mcast = true;
5734 } */
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);
5738 if (!conversation)
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);
5748 if (conversation)
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; */
5755 if (!conversation)
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)
5768 return 0;
5770 transport_packet = wmem_new0(wmem_file_scope(), dof_transport_packet);
5771 if (transport_packet == NULL)
5772 return 0;
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;
5805 else
5807 id = packet->from_server_ignore_list;
5810 while (id != NULL && id->sequence != sequence)
5812 id = id->next;
5815 if (id == NULL)
5816 return false;
5818 return id->ignore;
5821 return false;
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;
5838 uint32_t sequence;
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))
5849 ignore = true;
5851 else
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))
5859 ignore = true;
5862 while (id != NULL && id->sequence != tcpinfo->seq)
5864 last = &(id->next);
5865 id = id->next;
5868 *seqptr = sequence;
5869 if (id == NULL)
5871 *last = wmem_new0(wmem_file_scope(), tcp_ignore_data);
5872 id = *last;
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;
5890 uint8_t header;
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.
5899 * Bail...
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
5913 * differently.
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)
5932 return 0;
5934 packet = (tcp_packet_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_2008_1_dof_tcp, 0);
5935 if (packet == NULL)
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))
5942 return 0;
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... */
5950 int offset = 0;
5952 while (offset < (int)tvb_reported_length(tvb))
5954 int available = tvb_ensure_captured_length_remaining(tvb, offset);
5955 int packet_length;
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
5963 * a DPS session.
5965 if (((header & 0x80) == 0) && session->common.negotiation_required && ((pinfo->fd->num < session->common.negotiation_complete_at) || (session->common.negotiation_complete_at == 0)))
5967 packet_length = 2;
5968 if (header > DNP_MAX_VERSION)
5970 session->not_dps = true;
5971 return 0;
5974 else
5976 packet_length = dof_dissect_dnp_length(tvb, pinfo, header & 0x7F, &offset);
5977 if (packet_length < 0)
5979 session->not_dps = true;
5980 return offset;
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))
6000 return 0;
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)
6014 ref_is_new = true;
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;
6021 else
6022 ref = packet->dof_packets;
6024 /* Find the entry for our offset. */
6025 while (ref->start_offset != raw_offset)
6027 if (ref->next)
6029 ref = ref->next;
6030 continue;
6034 tcp_dof_packet_ref *last = ref;
6036 /* This is the default state, NULL and 0. */
6037 ref_is_new = true;
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;
6042 last->next = ref;
6046 if (ref_is_new)
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;
6066 return offset;
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).
6075 #if 0
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);
6089 if (!packet)
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);
6102 #else
6103 static int dissect_tunnel_udp(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_)
6105 #endif
6106 return 0;
6108 #endif
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.
6130 * Bail...
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
6144 * differently.
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);
6163 if (packet == NULL)
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))
6170 return 0;
6172 /* Loop, checking all the packets in this TCP frame.
6175 /* Note that we must handle fragmentation on TCP... */
6176 int offset = 0;
6178 while (offset < (int)tvb_reported_length(tvb))
6180 int available = tvb_reported_length_remaining(tvb, offset);
6181 int packet_length;
6182 int header_length;
6183 int i;
6185 if (available < 3)
6187 pinfo->desegment_offset = offset;
6188 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
6189 return offset + available;
6192 packet_length = 0;
6193 header_length = 3;
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)
6219 ref_is_new = true;
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;
6226 else
6227 ref = packet->dof_packets;
6229 /* Find the entry for our offset. */
6230 while (ref->start_offset != raw_offset)
6232 if (ref->next)
6234 ref = ref->next;
6235 continue;
6239 tcp_dof_packet_ref *last = ref;
6241 /* This is the default state, NULL and 0. */
6242 ref_is_new = true;
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;
6247 last->next = ref;
6251 if (ref_is_new)
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);
6277 /* Dissectors */
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;
6285 offset = 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;
6296 offset += 1;
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");
6308 else
6310 uint8_t first = tvb_get_uint8(tvb, offset);
6311 if (first == 0)
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);
6317 else
6319 /* Response. */
6320 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6321 while (first)
6323 proto_tree_add_item(tree, hf_2008_1_dnp_0_1_1_version, tvb, offset, 1, ENC_NA);
6324 offset += 1;
6325 if (offset == tvb_reported_length(tvb))
6326 break;
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;
6357 uint8_t size;
6358 uint8_t i;
6359 int data_len, header_len;
6361 if (available < 2)
6362 return 0;
6364 header = tvb_get_uint8(tvb, offset);
6365 data_len = 0;
6367 if ((header & 0x80) == 0)
6369 /* The length is fixed in this case... */
6370 data_len = 0;
6371 header_len = 2;
6372 size = 0;
6374 else
6376 flags = tvb_get_uint8(tvb, offset + 1);
6377 size = flags & 0x03;
6378 header_len = 2 + size;
6381 if (available < header_len)
6382 return 0;
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)
6393 int offset = 0;
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;
6405 int i;
6407 proto_tree *dnp_tree = tree;
6409 if (!api_data)
6411 /* TODO: Print error */
6412 return 0;
6415 if (!api_data->packet)
6417 /* TODO: Print error */
6418 return 0;
6421 packet = api_data->packet;
6423 offset = 0;
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;
6438 offset += 1;
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);
6454 offset += 1;
6456 else
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. */
6465 length = 0;
6466 for (i = 0; i < dnp_length_length; i++)
6467 length = (length << 8) | tvb_get_uint8(tvb, offset + i);
6469 /* Validate the length. */
6470 #if 0
6471 if ( (length == 0) && packet->negotiated && session && ! session->connectionless )
6473 expert_add_info( pinfo, NULL, &ei_dof_13_length_specified );
6475 #endif
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;
6489 proto_item *item;
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);
6497 else
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;
6508 proto_item *item;
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);
6515 else
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)
6527 uint32_t client;
6528 uint32_t server;
6530 if (api_data->transport_packet->is_sent_by_client)
6532 client = dnp_src_port;
6533 server = dnp_dst_port;
6535 else
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);
6566 return offset;
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;
6575 offset = 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;
6586 offset += 1;
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");
6598 else
6600 uint8_t first = tvb_get_uint8(tvb, offset);
6601 /* Response. */
6602 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
6603 while (first)
6605 proto_tree_add_item(tree, hf_2008_1_dpp_0_1_1_version, tvb, offset, 1, ENC_NA);
6606 offset += 1;
6607 if (offset == tvb_reported_length(tvb))
6608 break;
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;
6625 int offset = 0;
6626 uint8_t opcode;
6627 uint16_t app;
6628 int app_len;
6629 proto_item *ti;
6630 proto_tree *dpps_tree;
6631 proto_tree *opid_tree;
6633 if (api_data == NULL)
6635 /* TODO: Output error. */
6636 return 0;
6639 packet_data = api_data->packet;
6640 if (packet_data == NULL)
6642 /* TODO: Output error. */
6643 return 0;
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. */
6650 offset = 0;
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)"));
6667 /* Opcode */
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);
6669 offset += 1;
6671 switch (opcode)
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;
6678 /* FALL THROUGH */
6680 case OP_2009_12_CANCEL_ALL_CMD:
6681 case OP_2009_12_NODE_DOWN_CMD:
6682 case OP_2009_12_QUERY_RSP:
6683 /* SID */
6685 proto_tree *oid_tree;
6686 int opid_len;
6687 tvbuff_t *next_tvb;
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");
6693 else
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));
6707 offset += opid_len;
6710 if (packet_data->has_referenced_opid)
6712 uint32_t opcnt;
6713 int opcnt_len;
6714 proto_item *pi;
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;
6724 break;
6726 return offset;
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;
6747 int offset = 0;
6749 proto_tree *dpp_tree = tree;
6751 if (api_data == NULL)
6753 /* TODO: Output error. */
6754 return 0;
6757 packet_data = api_data->packet;
6758 if (packet_data == NULL)
6760 /* TODO: Output error. */
6761 return 0;
6764 /* We should have everything required for determining the SID ID. */
6765 assign_sid_id(api_data);
6767 offset = 0;
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;
6776 offset += 1;
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);
6828 offset += 1;
6830 else
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" );
6839 return 1;
6842 dpp_opid_keytype = (dpp_flags & 0x60) >> 5;
6843 switch (dpp_opid_keytype)
6845 case 0: /* No OPID */
6846 packet_data->has_opid = false;
6847 break;
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;
6853 break;
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;
6859 break;
6861 case 3: /* Explicit. */
6862 packet_data->has_opid = true;
6863 break;
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. */
6875 break;
6877 case 3: /* Explicit. */
6879 proto_tree *oid_tree;
6880 tvbuff_t *next_tvb;
6881 int opid_len;
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);
6897 offset += opid_len;
6900 /* FALL THROUGH */
6902 case 1: /* Implied sender. */
6903 case 2: /* Implied receiver. */
6905 uint32_t opcnt;
6906 int opcnt_len;
6907 proto_item *pi;
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);
6938 if (first == NULL)
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. */
6947 else
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;
6961 else
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;
6978 if (ptr)
6979 proto_tree_add_uint_format(ophistory_tree, hf_2008_1_dpp_first_command,
6980 tvb, 0, 0, ptr->frame,
6981 "First Operation: %u",
6982 ptr->frame);
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
7003 * and after.
7006 dof_packet_data *start = packet_data->opid_first;
7007 unsigned diff = 0;
7008 while (ptr)
7010 if (ptr == packet_data)
7011 break;
7013 ptr = ptr->opid_next;
7014 diff += 1;
7016 if (diff > globals.track_operations_window)
7018 start = start->opid_next;
7019 diff -= 1;
7023 ptr = start;
7024 diff = 0;
7026 while (ptr)
7028 const char *THIS = "";
7030 if (ptr == packet_data)
7032 THIS = "this ";
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,
7042 THIS,
7043 ptr->summary ? ptr->summary : "");
7045 ptr = ptr->opid_next;
7046 if (diff && !--diff)
7047 break;
7052 break;
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;
7064 /* Extract SEQ */
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);
7069 offset += 1;
7072 /* Extract Retry */
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);
7077 offset += 1;
7080 /* Extract Delay */
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);
7087 offset += 1;
7090 packet_data->summary = wmem_strdup_printf(wmem_file_scope(), "command seq %u, retry %u, delay %u", dpp_seq, dpp_retry, dpp_delay);
7092 else
7093 packet_data->summary = "response";
7096 /* Extract session information. */
7097 if (dpp_flags & 0x80)
7099 uint32_t sec_offset = offset;
7100 uint8_t sh_flags;
7101 uint32_t ssid;
7102 proto_tree *security_tree;
7103 proto_tree *sec_flags_tree;
7104 proto_item *item;
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);
7118 offset += 1;
7120 ssid = 0;
7121 if (sh_flags & DPP_V2_SEC_FLAG_S)
7123 int s_offset = offset;
7124 int ssid_len;
7125 proto_item *pi;
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;
7141 while (search)
7143 if (ssid == search->ssid)
7144 break;
7146 search = search->next;
7149 if (search)
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;
7159 uint32_t rdid;
7160 int rdid_len;
7161 proto_item *pi;
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);
7189 return 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);
7196 return 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); */
7204 if (dp)
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);
7220 return 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...
7244 uint16_t app;
7245 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length(tvb) - offset);
7247 read_c2(tvb, offset, &app, NULL);
7248 if (app == 0x7FFF)
7250 offset += dissect_dpp_v2_common(next_tvb, pinfo, proto_item_get_parent(tree), data);
7252 else
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);
7261 return offset;
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);
7272 offset += len;
7275 return offset;
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;
7283 uint8_t opcode;
7284 uint16_t app;
7285 int app_len;
7286 proto_item *ti;
7287 proto_tree *dsp_tree;
7288 proto_tree *options_tree;
7290 if (api_data == NULL)
7292 /* TODO: Output error. */
7293 return 0;
7296 packet_data = api_data->packet;
7297 if (packet_data == NULL)
7299 /* TODO: Output error. */
7300 return 0;
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. */
7307 offset = 0;
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);
7316 #if 0
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");
7323 else
7325 col_set_str(pinfo->cinfo, COL_INFO, "Query Response");
7326 while (offset < tvb_captured_length(tvb))
7328 uint16_t app;
7329 int start = offset;
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);
7335 return offset;
7337 #endif
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);
7344 return offset;
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);
7354 offset += 1;
7355 col_append_sep_str(pinfo->cinfo, COL_INFO, "/", val_to_str(opcode, strings_2008_1_dsp_opcodes, "Unknown Opcode (%d)"));
7357 switch (opcode)
7359 case OP_2008_1_OPEN_CMD: /* 2008.1 DSP.14.1 */
7360 break;
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))
7367 uint16_t ap;
7368 int length;
7369 proto_item *pi;
7370 int start = offset;
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);
7376 break;
7378 case OP_2008_1_QUERY_CMD:
7379 break;
7381 case OP_2008_1_QUERY_RSP:
7382 break;
7384 case OP_2008_1_CONFIG_ACK:
7385 break;
7387 case OP_2008_1_CONFIG_REQ:
7388 /* This will start a session if not existing... */
7389 /* FALL THROUGH */
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);
7399 break;
7401 case OP_2008_1_CONFIG_REJ:
7402 /* TODO: Handle reject. */
7403 break;
7405 case OP_2008_1_TERMINATE_CMD:
7406 case OP_2008_1_TERMINATE_RSP:
7407 /* Nothing */
7408 break;
7411 return offset;
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. */
7417 int offset = 0;
7418 proto_item *parent = proto_tree_get_parent(tree);
7419 uint8_t len, strength_count, i;
7420 proto_item *ti;
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);
7444 offset += 1;
7445 return offset;
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)
7460 return 0;
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)
7468 case INITIALIZE:
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;
7474 int offset = 0;
7475 uint8_t header;
7476 uint16_t length;
7478 if (!ccm_data)
7480 /* We need to parse the initialization data. */
7481 ccm_data = wmem_new0(wmem_file_scope(), ccm_session_data);
7482 if (!ccm_data)
7483 return 0;
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)
7489 return 0;
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)) {
7503 return 0;
7505 break;
7507 default:
7508 return 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;
7520 return 0;
7522 break;
7524 default:
7525 return 0;
7528 /* This mode has a fixed size, so we can return here without parsing further. */
7529 return 2;
7532 offset = read_c2(tvb, offset, &length, NULL);
7533 /* TODO validate C2 */
7534 header = tvb_get_uint8(tvb, offset);
7535 offset += 1;
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)) {
7544 return 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);
7556 return 0;
7558 break;
7560 default:
7561 gcry_cipher_close(ekey);
7562 return 0;
7565 g_hash_table_insert(ccm_data->cipher_data_table, GUINT_TO_POINTER(ccm_data->period), ekey);
7567 else
7569 uint32_t lookup = ccm_data->periods[period];
7571 if (!lookup)
7573 gcry_cipher_hd_t ekey;
7574 if (gcry_cipher_open(&ekey, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0)) {
7575 return 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);
7582 return 0;
7584 break;
7586 default:
7587 gcry_cipher_close(ekey);
7588 return 0;
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);
7595 else
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)) {
7602 return 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);
7609 return 0;
7611 break;
7613 default:
7614 gcry_cipher_close(ekey);
7615 return 0;
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;
7629 case HEADER:
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;
7636 uint8_t ccm_flags;
7637 uint32_t nid;
7638 uint16_t slot = 0;
7639 uint32_t pn = 0;
7640 bool pn_present = false;
7641 uint32_t tnid;
7642 uint32_t nnid;
7643 proto_tree *ccm_flags_tree;
7644 proto_tree *header_tree;
7645 proto_item * item,*header;
7646 ccm_packet_data *pdata;
7647 int offset = 0;
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))
7658 break;
7660 if (!dof_packet->is_sent_by_initiator && (dof_packet->dof_frame > security_data->r_valid))
7661 break;
7663 security_data = security_data->next;
7666 if (security_data)
7667 dof_packet->security_session = security_data;
7668 else
7670 dof_packet->security_session_error = "[Encrypted - No Session Available]";
7671 return offset;
7674 else
7676 dof_packet->security_session = secure_session->session_security_data;
7677 security_data = dof_packet->security_session;
7680 else
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]";
7688 return offset;
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);
7698 tree = header_tree;
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);
7710 offset += 1;
7712 if (ccm_flags & 0x01)
7713 pn_present = true;
7715 pdata = (ccm_packet_data *)dof_packet->security_packet;
7716 if (!pdata)
7718 pdata = wmem_new0(wmem_file_scope(), ccm_packet_data);
7719 if (pdata)
7721 dof_packet->security_packet = pdata;
7723 if (transport_session->is_2_node)
7725 if (dof_packet->is_sent_by_initiator)
7727 pdata->nid = 0;
7728 if (pn_present == false)
7729 pdata->dn = ++session->client_datagram_number;
7730 else
7731 pdata->dn = pn;
7733 else
7735 pdata->nid = 1;
7736 if (pn_present == 0)
7737 pdata->dn = ++session->server_datagram_number;
7738 else
7739 pdata->dn = pn;
7742 else
7744 uint8_t packet_period = (ccm_flags & 0x70) >> 4;
7745 pdata->period = session->periods[packet_period];
7750 if (!pdata)
7751 return offset - secmode_api_data->security_mode_offset;
7753 if (!secure_session->is_2_node)
7755 int nid_len;
7756 proto_item *pi;
7757 read_c4(tvb, offset, &nid, &nid_len);
7758 /* TODO: Do this right, as offset from BNID. */
7759 nid /= 2;
7760 pdata->nid = nid;
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);
7763 offset += nid_len;
7765 else
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)
7773 int slot_len;
7774 proto_item *pi;
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);
7778 offset += slot_len;
7780 else
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)
7788 int pn_len;
7789 proto_item *pi;
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);
7793 pdata->dn = pn;
7794 offset += pn_len;
7796 else
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)
7804 int tnid_len;
7805 proto_item *pi;
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);
7809 offset += tnid_len;
7812 if (ccm_flags & 0x02)
7814 int nnid_len;
7815 proto_item *pi;
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);
7819 offset += 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);
7844 tvbuff_t *app;
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).
7850 uint8_t nonce[11];
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
7865 * current PDU.
7868 app = NULL;
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;
7880 else
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;
7891 else
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;
7905 else
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;
7918 break;
7920 case TRAILER:
7921 /* TODO check this case */
7922 break;
7926 return 0;
7929 static int dissect_ccm_app(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7931 int offset = 0;
7932 uint8_t opcode = 0;
7933 uint16_t app;
7934 int app_len;
7936 proto_item *ti;
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. */
7943 offset = 0;
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)"));
7957 if (tree)
7959 /* Opcode */
7960 proto_tree_add_item(ccm_tree, hf_ccm_opcode, tvb, offset, 1, ENC_NA);
7961 #if 0 /* this needs completion */
7962 offset += 1;
7964 switch (opcode)
7966 case CCM_PDU_PROBE:
7969 break;
7972 #endif
7975 return 1;
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;
7984 int offset;
7985 uint8_t ccm_flags;
7986 uint32_t nid;
7987 uint16_t slot;
7988 uint32_t pn;
7989 uint32_t tnid;
7991 if (api_data == NULL)
7993 fprintf(stderr, "api_data is NULL.");
7994 return 0;
7997 packet = api_data->packet;
7998 if (packet == NULL)
8000 fprintf(stderr, "api_data->packet is NULL.");
8001 return 0;
8004 if (!packet->security_session)
8006 fprintf(stderr, "packet->security_session is NULL");
8007 return 0;
8010 if (packet->security_session->security_mode != DOF_PROTOCOL_CCM)
8012 fprintf(stderr, "packet->security_session->security_mode != DOF_PROTOCOL_CCM");
8013 return 0;
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.
8021 offset = 0;
8023 ccm_flags = tvb_get_uint8(tvb, offset);
8024 offset += 1;
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;
8052 uint16_t e_off;
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,
8060 0x00, 0x00,
8061 0x00,
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;
8072 nonce[9] = pn >> 8;
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
8077 * current PDU.
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))
8087 g_free(buf);
8088 return 1;
8090 else
8092 /* Failure to decrypt or validate the MAC.
8093 * The packet is secure, so there is nothing we can do!
8095 g_free(buf);
8096 return 1;
8100 #endif
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. */
8105 int offset = 0;
8107 /* We don't care except for the treeview. */
8108 if (!tree)
8109 return 0;
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);
8115 return offset;
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;
8123 int offset = 0;
8124 uint8_t opcode = 0;
8125 uint8_t flags = 0;
8126 uint16_t item_id = 0;
8127 uint16_t app;
8128 unsigned app_len;
8130 oap_1_packet_data *oap_packet = NULL;
8132 proto_item *ti;
8133 proto_tree *oap_tree;
8135 if (api_data == NULL)
8137 return 0;
8140 packet_data = api_data->packet;
8141 if (packet_data == NULL)
8143 return 0;
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. */
8151 offset = 0;
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);
8165 return app_len;
8168 oap_packet = (oap_1_packet_data *)dof_packet_get_proto_data(packet_data, proto_oap_1);
8169 if (!oap_packet)
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)"));
8185 /* Opcode */
8187 uint8_t mask = 0x10;
8188 char str[20];
8189 uint8_t no_of_bits = 5;
8190 uint8_t i;
8191 uint8_t bit = 3;
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);
8200 bit++;
8202 if (opcode & mask)
8203 (void) g_strlcat(str, "1", 20);
8204 else
8205 (void) g_strlcat(str, "0", 20);
8207 mask = mask >> 1;
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...
8217 switch (opcode)
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:
8223 case OAP_1_CMD_GET:
8224 case OAP_1_CMD_INVOKE:
8225 case OAP_1_CMD_REGISTER:
8226 case OAP_1_CMD_SET:
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);
8231 if (flags & 0x20)
8233 offset += 1;
8234 offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, offset);
8236 else
8237 offset += 1;
8239 break;
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);
8245 if (flags & 0x20)
8247 offset = oap_1_tree_add_cmdcontrol(pinfo, oap_tree, tvb, ENC_BIG_ENDIAN);
8249 else
8250 offset += 1;
8252 break;
8254 /* No alias, but flag for provider. */
8255 case OAP_1_RSP_GET:
8256 case OAP_1_RSP_INVOKE:
8257 case OAP_1_RSP_REGISTER:
8258 case OAP_1_RSP_SET:
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);
8262 if (flags & 0x20)
8264 offset += 1;
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);
8268 else
8269 offset += 1;
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);
8276 break;
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);
8284 offset += 1;
8285 break;
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);
8292 offset += 1;
8293 break;
8295 /* No flags. */
8296 case OAP_1_CMD_DEFINE:
8297 case OAP_1_RSP_DEFINE:
8298 case OAP_1_RSP_OPEN:
8299 /* TODO: Non-zero not allowed.*/
8300 offset += 1;
8301 break;
8303 default:
8304 /* TODO: Illegal opcode.*/
8305 return offset;
8308 /* Parse off arguments based on opcodes. */
8309 switch (opcode)
8311 case OAP_1_CMD_SUBSCRIBE:
8313 uint8_t alias_len = (flags & 0xC0) >> 6;
8314 if (alias_len == 3)
8315 alias_len = 4;
8317 /* The item identifier comes first, but it is compressed. */
8319 int item_id_len;
8320 proto_item *pi;
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;
8328 if (alias_len > 0)
8330 if (api_data->session == NULL)
8332 expert_add_info(pinfo, ti, &ei_oap_no_session);
8333 return offset;
8335 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8337 else
8338 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8340 /* Read the minimum delta. */
8342 int delta_len;
8343 uint16_t delta;
8344 proto_item *pi;
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;
8352 break;
8354 case OAP_1_CMD_REGISTER:
8356 uint8_t alias_len = (flags & 0xC0) >> 6;
8357 if (alias_len == 3)
8358 alias_len = 4;
8360 /* The item identifier comes first, but it is compressed. */
8362 int item_id_len;
8363 proto_item *pi;
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;
8371 if (alias_len > 0)
8373 if (api_data->session == NULL)
8375 expert_add_info(pinfo, ti, &ei_oap_no_session);
8376 return offset;
8378 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8380 else
8381 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8383 break;
8385 case OAP_1_RSP_REGISTER:
8387 if (flags & 0x20)
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);
8394 offset += 2;
8396 break;
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;
8404 if (alias_len == 3)
8405 alias_len = 4;
8407 if (alias_len > 0)
8409 if (api_data->session == NULL)
8411 expert_add_info(pinfo, ti, &ei_oap_no_session);
8412 return offset;
8414 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8416 else
8417 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8419 break;
8421 case OAP_1_CMD_ADVERTISE:
8422 offset = oap_1_tree_add_binding(oap_tree, pinfo, tvb, offset);
8423 break;
8425 case OAP_1_CMD_GET:
8426 case OAP_1_CMD_INVOKE:
8427 case OAP_1_CMD_SET:
8429 uint8_t alias_len = (flags & 0xC0) >> 6;
8430 if (alias_len == 3)
8431 alias_len = 4;
8433 /* The item identifier comes first, but it is compressed. */
8435 int item_id_len;
8436 proto_item *pi;
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;
8444 if (alias_len > 0)
8446 if (api_data->session == NULL)
8448 expert_add_info(pinfo, ti, &ei_oap_no_session);
8449 return offset;
8451 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8453 else
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);
8462 break;
8464 case OAP_1_CMD_OPEN:
8466 uint8_t alias_len = (flags & 0xC0) >> 6;
8467 if (alias_len == 3)
8468 alias_len = 4;
8470 if (alias_len > 0)
8472 if (api_data->session == NULL)
8474 expert_add_info(pinfo, ti, &ei_oap_no_session);
8475 return offset;
8477 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8479 else
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);
8487 break;
8489 case OAP_1_CMD_PROVIDE:
8491 uint8_t alias_length = flags >> 6;
8492 int alias_offset;
8493 int iid_offset;
8494 int oid_offset;
8496 if (alias_length == 3)
8497 alias_length = 4;
8499 alias_offset = offset;
8500 if (alias_length == 0)
8502 expert_add_info_format(pinfo, ti, &ei_malformed, "alias_length == 0");
8503 return offset;
8505 if (api_data->session == NULL)
8507 expert_add_info(pinfo, ti, &ei_oap_no_session);
8508 return offset;
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)
8521 uint32_t alias;
8522 oap_1_binding *binding = wmem_new0(wmem_file_scope(), oap_1_binding);
8523 int i;
8525 alias = 0;
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);
8541 break;
8543 case OAP_1_CMD_CHANGE:
8544 case OAP_1_CMD_SIGNAL:
8546 uint8_t alias_len = (flags & 0xC0) >> 6;
8547 if (alias_len == 3)
8548 alias_len = 4;
8550 /* The item identifier comes first, but it is compressed. */
8552 int item_id_len;
8553 proto_item *pi;
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;
8561 if (alias_len > 0)
8563 if (api_data->session == NULL)
8565 expert_add_info(pinfo, ti, &ei_oap_no_session);
8566 return offset;
8568 offset = oap_1_tree_add_alias(api_data, oap_packet, packet_data, oap_tree, tvb, pinfo, offset, alias_len, true);
8570 else
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);
8575 offset += 2;
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);
8580 break;
8582 case OAP_1_RSP_EXCEPTION:
8584 if (flags & 0x20)
8586 /* offset = add_oid( tvb, offset, NULL, oap_tree );*/
8589 /* The response code, compressed. */
8591 int rsp_len;
8592 uint16_t rsp;
8594 /* TODO: Validate*/
8595 read_c2(tvb, offset, &rsp, &rsp_len);
8596 /* TODO: Add to tree with error codes. */
8597 offset += rsp_len;
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);
8602 break;
8604 default:
8605 /* TODO: Bad opcode!*/
8606 break;
8609 return offset;
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;
8617 uint8_t opcode;
8618 uint16_t app;
8619 int app_len;
8620 proto_item *ti;
8621 proto_tree *sgmp_tree;
8623 if (api_data == NULL)
8625 /* TODO: Output error. */
8626 return 0;
8629 packet_data = api_data->packet;
8630 if (packet_data == NULL)
8632 /* TODO: Output error. */
8633 return 0;
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. */
8640 offset = 0;
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);
8654 return offset;
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)"));
8665 /* Opcode */
8666 proto_tree_add_item(sgmp_tree, hf_opcode, tvb, offset, 1, ENC_NA);
8667 offset += 1;
8669 switch (opcode)
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);
8676 offset += 2;
8679 /* EPOCH - 2 bytes */
8681 proto_tree_add_item(sgmp_tree, hf_sgmp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN);
8682 offset += 2;
8685 break;
8687 case SGMP_CMD_HEARTBEAT:
8689 int start_offset;
8691 /* Latest SGMP Version - Type.1 */
8693 uint16_t version;
8694 int length;
8695 proto_item *pi;
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);
8706 offset += 1;
8709 /* Tie Breaker - 4 bytes */
8711 proto_tree_add_item(sgmp_tree, hf_tie_breaker, tvb, offset, 4, ENC_BIG_ENDIAN);
8712 offset += 4;
8715 break;
8717 case SGMP_CMD_REKEY:
8718 case SGMP_CMD_REKEY_EPOCH:
8719 case SGMP_CMD_REKEY_MERGE:
8721 #if 0 /*TODO check this */
8722 int start_offset;
8723 tvbuff_t *initial_state;
8724 #endif
8725 uint8_t key[32];
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);
8731 offset += 1;
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);
8740 #endif
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);
8747 offset += 2;
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);
8754 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)
8766 #if 0
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;
8772 int block_length;
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;
8783 #endif
8787 break;
8789 case SGMP_CMD_REQUEST_GROUP:
8791 uint8_t *domain_buf = NULL;
8792 uint8_t domain_length = 0;
8793 int start_offset;
8794 unsigned I_offset = offset;
8795 sgmp_packet_data *sgmp_data = NULL;
8796 uint16_t epoch;
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);
8816 offset += 2;
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);
8868 break;
8870 case SGMP_RSP_REQUEST_GROUP:
8872 int start_offset;
8873 #if 0 /*TODO check this */
8874 unsigned A_offset;
8875 tvbuff_t *initial_state;
8876 unsigned A_end;
8877 #endif
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);
8890 #endif
8893 /* Latest SGMP Version - Type.1 */
8895 uint16_t version;
8896 int length;
8897 proto_item *pi;
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);
8908 offset += 1;
8912 /* END OF A BLOCK */
8913 /* A block data handled in first part of the next block. */
8914 #if 0 /*TODO check this */
8915 A_end = offset;
8916 #endif
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)
8931 #if 0
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;
8947 struct list;
8948 struct list
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);
8958 while (group)
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));
8966 n->group = group;
8967 n->next = to_try;
8968 to_try = n;
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;
8979 auth = group->keys;
8981 while (auth && !discovered_kek)
8983 uint8_t mac[32];
8984 uint8_t key[32];
8985 int j;
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);
8993 if (cipher != NULL)
8995 cipher->GenerateKeyState(ekey, auth->kek);
8996 cipher->Encrypt(ekey, mac);
8997 cipher->Encrypt(ekey, mac + 16);
9000 for (j = 0; j < 32; j++)
9001 key[j] ^= mac[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);
9007 break;
9011 auth = auth->next;
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).
9025 if (discovered_kek)
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))
9037 break;
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));
9064 if (!key_exchange)
9065 return offset;
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;
9077 else
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;
9091 int block_length;
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);
9104 #endif
9107 break;
9109 default:
9110 break;
9113 return offset;
9116 static bool validate_session_key(tep_rekey_data *rekey, unsigned S_length, uint8_t *S, uint8_t *confirmation, uint8_t *key)
9118 uint8_t pad[16];
9119 gcry_mac_hd_t hmac;
9120 gcry_error_t result;
9122 memset(pad, 0, sizeof(pad));
9123 result = gcry_mac_open(&hmac, GCRY_MAC_HMAC_SHA256, 0, NULL);
9124 if (result != 0)
9125 return false;
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);
9135 return result == 0;
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. */
9141 int offset = 0;
9143 /* We don't care except for the treeview. */
9144 if (!tree)
9145 return 0;
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);
9151 return offset;
9154 static int dissect_2008_4_tep_2_2_1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t *ssid, void *data)
9156 int offset = 0;
9157 proto_item *ti;
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. */
9164 return 0;
9167 packet_data = api_data->packet;
9168 if (packet_data == NULL)
9170 /* TODO: Output error. */
9171 return 0;
9174 /* State Identifier - Only if Unsecured */
9175 if (packet_data->decrypted_buffer == NULL)
9177 proto_item *pi;
9178 int ssid_len;
9179 int start = offset;
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);
9185 /* Initial State */
9187 int block_length;
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;
9196 return offset;
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
9204 * them.
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
9211 * used:
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;
9223 uint8_t operation;
9224 uint16_t app;
9225 int app_len;
9226 proto_item *ti;
9227 proto_tree *tep_tree, *operation_tree;
9229 if (api_data == NULL)
9231 /* TODO: Output error. */
9232 return 0;
9235 packet = api_data->packet;
9236 if (packet == NULL)
9238 /* TODO: Output error. */
9239 return 0;
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. */
9246 offset = 0;
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);
9261 return offset;
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);
9285 offset += 1;
9287 switch (operation)
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;
9294 if (!rekey_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);
9319 else
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;
9331 /* FALL THROUGH */
9333 case TEP_PDU_REQUEST:
9335 /* Remember the current request. */
9336 rekey_data = (tep_rekey_data *)packet->opid_data;
9337 if (!rekey_data)
9339 if (api_data->secure_session == NULL)
9341 /* TODO: Output error. */
9342 return 0;
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;
9372 break;
9374 case TEP_PDU_ACCEPT:
9376 uint32_t ssid = 0;
9377 uint8_t *S = NULL;
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;
9384 } identity_key;
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 */
9391 return 0;
9394 rekey_data = (tep_rekey_data *)packet->opid_first->opid_data;
9395 if (!rekey_data)
9396 return tvb_captured_length(tvb);
9398 /* Initiator Ticket */
9400 int start_offset;
9401 uint8_t ticket[64];
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)
9409 int i;
9411 /* Produce a (possibly empty) list of potential keys based on our
9412 * initiator secrets based on identity. These will be validated
9413 * later on.
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;
9419 int j;
9421 if (identity->domain_length != rekey_data->domain_length)
9422 continue;
9423 if (memcmp(identity->domain, rekey_data->domain, identity->domain_length) != 0)
9424 continue;
9425 if (identity->identity_length != rekey_data->i_identity_length)
9426 continue;
9427 if (memcmp(identity->identity, rekey_data->i_identity, identity->identity_length) != 0)
9428 continue;
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);
9460 offset += 32;
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)
9475 int block_length;
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)
9497 #if 0
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;
9508 #endif
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
9542 * rest.
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))
9563 break;
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;
9586 else
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)
9600 int i;
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);
9660 break;
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);
9667 offset += 32;
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. */
9677 if (sk_data)
9678 sk_data->i_valid = packet->dof_frame;
9681 break;
9683 case TEP_PDU_END_SESSION:
9684 case TEP_PDU_SESSION_ENDING:
9685 break;
9687 case TEP_PDU_REJECT:
9689 /* Error Code */
9690 proto_tree_add_item(tep_tree, hf_tep_reject_code, tvb, offset, 1, ENC_NA);
9691 offset += 1;
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);
9697 break;
9699 default:
9700 break;
9702 return offset;
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. */
9708 int offset = 0;
9710 /* We don't care except for the treeview. */
9711 if (!tree)
9712 return 0;
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);
9718 return offset;
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;
9726 uint8_t opcode;
9727 uint16_t app;
9728 int app_len;
9729 proto_item *ti;
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. */
9737 offset = 0;
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");
9749 return offset;
9752 packet_data = api_data->packet;
9753 if (packet_data == NULL)
9755 expert_add_info_format(pinfo, ti, &ei_malformed, "api_data == NULL");
9756 return offset;
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);
9766 return offset;
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)"));
9776 /* Opcode */
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);
9778 offset += 1;
9780 switch (opcode)
9782 case TRP_RSP_REJECT:
9784 /* Error Code */
9785 proto_tree_add_item(trp_tree, hf_trp_errorcode, tvb, offset, 1, ENC_NA);
9786 offset += 1;
9788 break;
9790 case TRP_CMD_REQUEST_KEK:
9792 uint8_t *domain_buf = NULL;
9793 uint8_t domain_length = 0;
9794 int start_offset;
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);
9826 int i;
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)
9838 continue;
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);
9865 if (trp_pkt_data)
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);
9873 if (trp_pkt_data)
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);
9882 break;
9884 case TRP_RSP_REQUEST_KEK:
9886 int start_offset;
9887 uint32_t ssid;
9888 uint8_t *mode;
9889 uint8_t mode_length;
9890 uint8_t *block_A;
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 */
9903 /* A BLOCK */
9905 start_offset = offset;
9907 /* THB */
9909 proto_tree_add_item(trp_tree, hf_thb, tvb, offset, 1, ENC_NA);
9910 offset += 1;
9913 /* TMIN */
9915 proto_tree_add_item(trp_tree, hf_tmin, tvb, offset, 1, ENC_NA);
9916 offset += 1;
9919 /* TMAX */
9921 proto_tree_add_item(trp_tree, hf_tmax, tvb, offset, 1, ENC_NA);
9922 offset += 1;
9925 /* Epoch */
9927 proto_tree_add_item(trp_tree, hf_trp_epoch, tvb, offset, 2, ENC_BIG_ENDIAN);
9928 offset += 2;
9931 /* SIDg - Type.4 */
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;
9959 int ssid_len;
9960 proto_item *pi;
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)
9990 #if 0
9991 trp_packet_data* cmd_data = (trp_packet_data*)dof_packet_get_proto_data(packet_data->opid_first, proto_trp);
9992 uint8_t mac[32];
9993 extern struct BlockCipher BlockCipher_AES_256;
9994 struct BlockCipher* cipher = &BlockCipher_AES_256;
9995 uint8_t* ekey = (uint8_t*)ep_alloc(cipher->keyStateSize);
9997 int i;
9999 if (cmd_data)
10001 uint8_t kek[32];
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++)
10014 kek[i] ^= mac[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. */
10034 if (!trp_data)
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;
10042 while (group)
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))
10049 break;
10051 group = group->next;
10054 if (group == NULL)
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;
10068 while (auth)
10070 if (epoch == auth->epoch)
10071 break;
10073 auth = auth->next;
10076 if (auth == NULL)
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;
10096 #endif
10099 break;
10101 case TRP_CMD_REQUEST_RANDOM:
10103 uint8_t *domain_buf = NULL;
10104 uint8_t domain_length = 0;
10105 int start_offset;
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);
10138 int i;
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)
10150 continue;
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;
10171 if (trp_pkt_data)
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);
10180 break;
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);
10188 break;
10190 case TRP_CMD_REQUEST_SECURITY_SCOPES:
10192 uint8_t *domain_buf = NULL;
10193 uint8_t domain_length = 0;
10194 int start_offset;
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);
10221 offset += 1;
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);
10231 int i;
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)
10243 continue;
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);
10270 if (trp_pk_data)
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);
10278 if (trp_pk_data)
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);
10287 break;
10289 case TRP_RSP_REQUEST_SECURITY_SCOPES:
10291 int start_offset;
10292 uint8_t *block_A;
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 */
10300 /* A BLOCK */
10302 start_offset = offset;
10304 /* Initiator Duration Request */
10305 proto_tree_add_item(trp_tree, hf_trp_duration, tvb, offset, 1, ENC_NA);
10306 offset += 1;
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);
10323 break;
10325 case TRP_CMD_RESOLVE_CREDENTIAL:
10327 uint8_t *domain_buf = NULL;
10328 uint8_t domain_length = 0;
10329 int start_offset;
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);
10346 break;
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);
10354 break;
10356 case TRP_CMD_REQUEST_SESSION:
10358 uint8_t *domain_buf = NULL;
10359 uint8_t domain_length = 0;
10360 int start_offset;
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);
10386 break;
10388 case TRP_RSP_REQUEST_SESSION:
10390 int start_offset;
10391 uint8_t *block_A;
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 */
10404 /* A BLOCK */
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);
10416 break;
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);
10431 break;
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);
10438 break;
10441 return offset;
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;
10510 unsigned i;
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++)
10516 uint8_t kek_len;
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;
10527 unsigned i;
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++)
10544 uint8_t key_len;
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;
10553 unsigned i;
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++)
10572 uint8_t key_len;
10573 uint32_t size;
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));
10580 else
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));
10591 else
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)
10605 unsigned i;
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 } },
10638 /* Security.2 */
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 } },
10645 /* Security.3.1 */
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 } },
10655 /* Security 3.2 */
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 } },
10668 /* Security.4 */
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 } },
10687 /* Security.5 */
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 } },
10694 /* Security.6.1 */
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 } },
10704 /* Security.6.2 */
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 } },
10708 /* Security.6.3 */
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 } },
10721 /* Security.9 */
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 } },
10728 /* Security.10 */
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 } },
10735 /* Security.11 */
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 } },
10742 /* Security.12 */
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[] = {
10773 /* Security.2 */
10774 &ett_security_2_permission,
10775 &ett_security_3_1_security_node_identifier,
10777 /* Security.11 */
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,
10791 &ett_2008_1_dof,
10794 static ei_register_info ei[] =
10796 #if 0
10797 { &ei_undecoded, { "dof.undecoded", PI_UNDECODED, PI_WARN, "DOF: Some protocol octets were not decoded", EXPFILL } },
10798 #endif
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)."),
10812 UAT_END_FIELDS
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)."),
10818 UAT_END_FIELDS
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)."),
10826 UAT_END_FIELDS
10829 module_t *dof_module;
10830 uat_t *secmode_uat;
10831 uat_t *seckey_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",
10854 true,
10855 &secmode_list,
10856 &num_secmode_list,
10857 (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10858 NULL,
10859 secmode_list_copy_cb,
10860 secmode_list_update_cb,
10861 secmode_list_free_cb,
10862 secmode_list_post_update_cb,
10863 NULL,
10864 secmode_uat_fields
10867 seckey_uat = uat_new("DPS Session Keys",
10868 sizeof(seckey_field_t),
10869 "custom_dof_seckey_list",
10870 true,
10871 &seckey_list,
10872 &num_seckey_list,
10873 (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10874 NULL,
10875 seckey_list_copy_cb,
10876 seckey_list_update_cb,
10877 seckey_list_free_cb,
10878 seckey_list_post_update_cb,
10879 NULL,
10880 seckey_uat_fields
10883 identsecret_uat = uat_new("DPS Identity Secrets",
10884 sizeof(identsecret_field_t),
10885 "custom_dof_identsecret_list",
10886 true,
10887 &identsecret_list,
10888 &num_identsecret_list,
10889 (UAT_AFFECTS_DISSECTION | UAT_AFFECTS_FIELDS),
10890 NULL,
10891 identsecret_list_copy_cb,
10892 identsecret_list_update_cb,
10893 identsecret_list_free_cb,
10894 identsecret_list_post_update_cb,
10895 NULL,
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.",
10918 secmode_uat);
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.",
10922 seckey_uat);
10924 prefs_register_uat_preference(dof_module, "custom_dof_identsecret_list", "DPS Identity Secrets",
10925 "A table of secrets for different identities.",
10926 identsecret_uat);
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[] = {
10956 { &hf_oid_class,
10957 { "Class", "dof.oid.class", FT_UINT32, BASE_DEC, NULL, 0, "DPS Object Identifier Class", HFILL }
10959 { &hf_oid_header,
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 }
10965 { &hf_oid_length,
10966 { "Length", "dof.oid.length", FT_UINT8, BASE_DEC, NULL, 0x3F, NULL, HFILL }
10968 { &hf_oid_data,
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[] = {
10995 &ett_oid,
10996 &ett_oid_header,
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);
11034 return result;
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)
11043 return FALSE;
11045 if (session_key_ptr1->client != session_key_ptr2->client)
11046 return FALSE;
11048 if (session_key_ptr1->server != session_key_ptr2->server)
11049 return FALSE;
11051 return TRUE;
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 } },
11134 #if 0
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 } },
11136 #endif
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[] =
11187 &ett_2008_1_dnp,
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[] =
11397 &ett_2008_1_dpp,
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[] =
11556 { &hf_ccm_opcode,
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,
11563 &ett_ccm_dsp,
11564 &ett_ccm,
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,
11596 &ett_header,
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 } },
11681 { &hf_oap_1_flags,
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 } },
11741 #endif
11743 { &hf_oap_1_alias,
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 } },
11758 #endif
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[] =
11772 &ett_oap_1_dsp,
11773 &ett_oap_1_dsp_options,
11774 &ett_oap_1,
11775 &ett_oap_1_opinfo,
11776 &ett_oap_1_cmdcontrol,
11777 &ett_oap_1_cmdcontrol_flags,
11778 &ett_oap_1_cmdcontrol_ack,
11779 &ett_oap_1_alias,
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[] =
11839 { &hf_opcode,
11840 { "Opcode", "dof.sgmp.v1.opcode", FT_UINT8, BASE_DEC, VALS(sgmp_opcode_strings), 0x0, NULL, HFILL } },
11842 { &hf_sgmp_domain,
11843 { "Domain", "dof.sgmp.v1.domain", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11845 { &hf_sgmp_epoch,
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 } },
11860 { &hf_desire,
11861 { "Desire", "dof.sgmp.v1.desire", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
11863 { &hf_ticket,
11864 { "Ticket", "dof.sgmp.v1.ticket", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11866 { &hf_sgmp_tmin,
11867 { "TMIN", "dof.sgmp.v1.tmin", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
11869 { &hf_tie_breaker,
11870 { "Tie Breaker", "dof.sgmp.v1.tie-breaker", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } },
11872 { &hf_delay,
11873 { "Delay", "dof.sgmp.v1.delay", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
11875 { &hf_key,
11876 { "Key", "dof.sgmp.v1.key", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } },
11879 static int *ett[] =
11881 &ett_sgmp,
11882 &ett_sgmp_domain,
11883 &ett_initiator_block,
11884 &ett_sgmp_security_scope,
11885 &ett_initial_state,
11886 &ett_ticket,
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[] =
11929 { &hf_dsp_option,
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 } },
11941 { &hf_tep_opcode,
11942 { "Opcode", "dof.tep1.opcode", FT_UINT8, BASE_DEC, VALS(tep_opcode_strings), 0x0F, NULL, HFILL } },
11944 { &hf_tep_k,
11945 { "K", "dof.tep1.k", FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL } },
11947 { &hf_tep_c,
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 } },
11956 /* TEP.2.1 */
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 } },
11966 /* TEP.2.2 */
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 } },
11982 /* TEP.2.2.1 */
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[] =
11995 &ett_tep_dsp,
11996 &ett_tep_dsp_options,
11997 &ett_tep,
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[] =
12070 { &hf_trp_opcode,
12071 { "Opcode", "dof.trp.opcode", FT_UINT8, BASE_DEC, VALS(trp_opcode_strings), 0x0, NULL, HFILL } },
12073 { &hf_domain,
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 } },
12100 { &hf_thb,
12101 { "Thb", "dof.trp.thb", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12103 { &hf_tmin,
12104 { "Tmin", "dof.trp.tmin", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12106 { &hf_tmax,
12107 { "Tmax", "dof.trp.tmax", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12109 { &hf_trp_epoch,
12110 { "Epoch", "dof.trp.epoch", FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL } },
12112 { &hf_sidg,
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 } },
12121 { &hf_ssid,
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 } },
12127 #endif
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 */
12145 { &hf_trp_rnonce,
12146 { "Requestor Nonce", "dof.trp.rnonce", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12148 { &hf_trp_pnonce,
12149 { "Provider Nonce", "dof.trp.pnonce", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12151 { &hf_trp_reqid,
12152 { "Requestor ID", "dof.trp.reqid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
12154 { &hf_trp_provid,
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 } },
12207 #endif
12210 static int *ett[] =
12212 &ett_trp_dsp,
12213 &ett_trp,
12214 &ett_domain,
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,
12223 &ett_sidg,
12224 &ett_security_scope,
12225 &ett_security_mode,
12226 &ett_initiator_pg,
12227 &ett_initiator_validation,
12228 &ett_responder_pg,
12229 &ett_responder_validation,
12230 &ett_trp_permset,
12231 &ett_srp_flags,
12232 &ett_trp_ticket,
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)
12283 dof_tun_reset();
12284 dof_reset();
12285 oid_reset();
12286 dof_dnp_reset();
12287 dof_dpp_reset();
12288 app_reset();
12289 dof_dsp_reset();
12290 dof_ccm_reset();
12291 dof_oap_reset();
12292 dof_sgmp_reset();
12293 dof_tep_reset();
12294 dof_trp_reset();
12297 static void dof_cleanup_routine(void)
12299 dof_tun_cleanup();
12300 dof_cleanup();
12301 oid_cleanup();
12302 dof_dnp_cleanup();
12303 dof_dpp_cleanup();
12304 app_cleanup();
12305 dof_dsp_cleanup();
12306 dof_ccm_cleanup();
12307 dof_oap_cleanup();
12308 dof_sgmp_cleanup();
12309 dof_tep_cleanup();
12310 dof_trp_cleanup();
12313 static void
12314 dof_shutdown_routine(void)
12316 unsigned i;
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();
12349 dof_register();
12350 oid_register();
12351 dof_dnp_register();
12352 dof_dpp_register();
12353 app_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)
12371 dof_tun_handoff();
12372 dof_handoff();
12373 oid_handoff();
12374 dof_dnp_handoff();
12375 dof_dpp_handoff();
12376 app_handoff();
12377 dof_dsp_handoff();
12378 dof_ccm_handoff();
12379 dof_oap_handoff();
12380 dof_sgmp_handoff();
12381 dof_tep_handoff();
12382 dof_trp_handoff();
12386 * Protocol-specific data attached to a conversation_t structure - protocol
12387 * index and opaque pointer.
12389 typedef struct _dof_proto_data {
12390 int proto;
12391 void *proto_data;
12392 } 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)
12400 return 1;
12401 else if (ap->proto == bp->proto)
12402 return 0;
12403 else
12404 return -1;
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);
12412 p1->proto = proto;
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;
12423 GSList *item;
12425 temp.proto = proto;
12426 temp.proto_data = NULL;
12428 item = g_slist_find_custom(session->data_list, (void * *)&temp,
12429 p_compare);
12431 if (item != NULL)
12433 p1 = (dof_proto_data *)item->data;
12434 return p1->proto_data;
12437 return NULL;
12440 static void dof_session_delete_proto_data(dof_session_data *session, int proto)
12442 dof_proto_data temp;
12443 GSList *item;
12445 temp.proto = proto;
12446 temp.proto_data = NULL;
12448 item = g_slist_find_custom(session->data_list, (void * *)&temp,
12449 p_compare);
12451 while (item)
12453 session->data_list = g_slist_remove(session->data_list, item->data);
12454 item = item->next;
12457 #endif
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);
12463 p1->proto = proto;
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,
12480 p_compare);
12482 if (item != NULL)
12484 p1 = (dof_proto_data *)wmem_list_frame_data(item);
12485 return p1->proto_data;
12488 return NULL;
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)
12493 int block_length;
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);
12507 return 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);
12515 if (!dp)
12516 return -1;
12518 return call_dissector_only(dp, tvb, pinfo, NULL, offset);
12522 * Editor modelines - https://www.wireshark.org/tools/modelines.html
12524 * Local variables:
12525 * c-basic-offset: 4
12526 * tab-width: 8
12527 * indent-tabs-mode: nil
12528 * End:
12530 * vi: set shiftwidth=4 tabstop=8 expandtab:
12531 * :indentSize=4:tabSize=8:noTabs=true: